solace-agent-mesh 0.2.4__py3-none-any.whl → 1.0.1__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (518) hide show
  1. solace_agent_mesh/agent/adk/adk_llm.txt +93 -0
  2. solace_agent_mesh/agent/adk/app_llm_agent.py +26 -0
  3. solace_agent_mesh/agent/adk/callbacks.py +1694 -0
  4. solace_agent_mesh/agent/adk/filesystem_artifact_service.py +381 -0
  5. solace_agent_mesh/agent/adk/invocation_monitor.py +295 -0
  6. solace_agent_mesh/agent/adk/models/lite_llm.py +872 -0
  7. solace_agent_mesh/agent/adk/models/models_llm.txt +94 -0
  8. solace_agent_mesh/agent/adk/runner.py +353 -0
  9. solace_agent_mesh/agent/adk/services.py +240 -0
  10. solace_agent_mesh/agent/adk/setup.py +751 -0
  11. solace_agent_mesh/agent/adk/stream_parser.py +214 -0
  12. solace_agent_mesh/agent/adk/tool_wrapper.py +139 -0
  13. solace_agent_mesh/agent/agent_llm.txt +41 -0
  14. solace_agent_mesh/agent/protocol/event_handlers.py +1469 -0
  15. solace_agent_mesh/agent/protocol/protocol_llm.txt +21 -0
  16. solace_agent_mesh/agent/sac/app.py +640 -0
  17. solace_agent_mesh/agent/sac/component.py +3388 -0
  18. solace_agent_mesh/agent/sac/patch_adk.py +111 -0
  19. solace_agent_mesh/agent/sac/sac_llm.txt +105 -0
  20. solace_agent_mesh/agent/sac/task_execution_context.py +176 -0
  21. solace_agent_mesh/agent/testing/__init__.py +3 -0
  22. solace_agent_mesh/agent/testing/debug_utils.py +135 -0
  23. solace_agent_mesh/agent/testing/testing_llm.txt +90 -0
  24. solace_agent_mesh/agent/tools/__init__.py +14 -0
  25. solace_agent_mesh/agent/tools/audio_tools.py +1622 -0
  26. solace_agent_mesh/agent/tools/builtin_artifact_tools.py +1954 -0
  27. solace_agent_mesh/agent/tools/builtin_data_analysis_tools.py +238 -0
  28. solace_agent_mesh/agent/tools/general_agent_tools.py +569 -0
  29. solace_agent_mesh/agent/tools/image_tools.py +1184 -0
  30. solace_agent_mesh/agent/tools/peer_agent_tool.py +289 -0
  31. solace_agent_mesh/agent/tools/registry.py +36 -0
  32. solace_agent_mesh/agent/tools/test_tools.py +135 -0
  33. solace_agent_mesh/agent/tools/tool_definition.py +45 -0
  34. solace_agent_mesh/agent/tools/tools_llm.txt +104 -0
  35. solace_agent_mesh/agent/tools/web_tools.py +381 -0
  36. solace_agent_mesh/agent/utils/artifact_helpers.py +927 -0
  37. solace_agent_mesh/agent/utils/config_parser.py +47 -0
  38. solace_agent_mesh/agent/utils/context_helpers.py +60 -0
  39. solace_agent_mesh/agent/utils/utils_llm.txt +153 -0
  40. solace_agent_mesh/assets/docs/404.html +16 -0
  41. solace_agent_mesh/assets/docs/assets/css/styles.906a1503.css +1 -0
  42. solace_agent_mesh/assets/docs/assets/images/Solace_AI_Framework_With_Broker-85f0a306a9bcdd20b390b7a949f6d862.png +0 -0
  43. solace_agent_mesh/assets/docs/assets/images/sac-flows-80d5b603c6aafd33e87945680ce0abf3.png +0 -0
  44. solace_agent_mesh/assets/docs/assets/images/sac_parts_of_a_component-cb3d0424b1d0c17734c5435cca6b4082.png +0 -0
  45. solace_agent_mesh/assets/docs/assets/js/04989206.674a8007.js +1 -0
  46. solace_agent_mesh/assets/docs/assets/js/0e682baa.79f0ab22.js +1 -0
  47. solace_agent_mesh/assets/docs/assets/js/1001.0182a8bd.js +1 -0
  48. solace_agent_mesh/assets/docs/assets/js/1023fc19.015679ca.js +1 -0
  49. solace_agent_mesh/assets/docs/assets/js/1039.0bd46aa1.js +1 -0
  50. solace_agent_mesh/assets/docs/assets/js/149.b797a808.js +1 -0
  51. solace_agent_mesh/assets/docs/assets/js/1523c6b4.91c7bc01.js +1 -0
  52. solace_agent_mesh/assets/docs/assets/js/165.6a39807d.js +2 -0
  53. solace_agent_mesh/assets/docs/assets/js/165.6a39807d.js.LICENSE.txt +9 -0
  54. solace_agent_mesh/assets/docs/assets/js/166ab619.7d97ccaf.js +1 -0
  55. solace_agent_mesh/assets/docs/assets/js/17896441.a5e82f9b.js +2 -0
  56. solace_agent_mesh/assets/docs/assets/js/17896441.a5e82f9b.js.LICENSE.txt +7 -0
  57. solace_agent_mesh/assets/docs/assets/js/1c6e87d2.23bccffb.js +1 -0
  58. solace_agent_mesh/assets/docs/assets/js/2130.ab9fd314.js +1 -0
  59. solace_agent_mesh/assets/docs/assets/js/21ceee5f.614fa8dd.js +1 -0
  60. solace_agent_mesh/assets/docs/assets/js/2237.5e477fc6.js +1 -0
  61. solace_agent_mesh/assets/docs/assets/js/2334.622a6395.js +1 -0
  62. solace_agent_mesh/assets/docs/assets/js/2a9cab12.8909df92.js +1 -0
  63. solace_agent_mesh/assets/docs/assets/js/3219.adc1d663.js +1 -0
  64. solace_agent_mesh/assets/docs/assets/js/332e10b5.7a103f42.js +1 -0
  65. solace_agent_mesh/assets/docs/assets/js/3624.b524e433.js +1 -0
  66. solace_agent_mesh/assets/docs/assets/js/375.708d48db.js +1 -0
  67. solace_agent_mesh/assets/docs/assets/js/3834.b6cd790e.js +1 -0
  68. solace_agent_mesh/assets/docs/assets/js/3d406171.f722eaf5.js +1 -0
  69. solace_agent_mesh/assets/docs/assets/js/4250.95455b28.js +1 -0
  70. solace_agent_mesh/assets/docs/assets/js/42b3f8d8.36090198.js +1 -0
  71. solace_agent_mesh/assets/docs/assets/js/4356.d169ab5b.js +1 -0
  72. solace_agent_mesh/assets/docs/assets/js/442a8107.5ba94b65.js +1 -0
  73. solace_agent_mesh/assets/docs/assets/js/4458.518e66fa.js +1 -0
  74. solace_agent_mesh/assets/docs/assets/js/4488.c7cc3442.js +1 -0
  75. solace_agent_mesh/assets/docs/assets/js/4494.6ee23046.js +1 -0
  76. solace_agent_mesh/assets/docs/assets/js/4855.fc4444b6.js +1 -0
  77. solace_agent_mesh/assets/docs/assets/js/4866.22daefc0.js +1 -0
  78. solace_agent_mesh/assets/docs/assets/js/4950.ca4caeda.js +1 -0
  79. solace_agent_mesh/assets/docs/assets/js/4c2787c2.66ee00e9.js +1 -0
  80. solace_agent_mesh/assets/docs/assets/js/5388.7a136447.js +1 -0
  81. solace_agent_mesh/assets/docs/assets/js/55f47984.c484bf96.js +1 -0
  82. solace_agent_mesh/assets/docs/assets/js/5607.081356f8.js +1 -0
  83. solace_agent_mesh/assets/docs/assets/js/5864.b0d0e9de.js +1 -0
  84. solace_agent_mesh/assets/docs/assets/js/5b4258a4.bda20761.js +1 -0
  85. solace_agent_mesh/assets/docs/assets/js/5e95c892.558d5167.js +1 -0
  86. solace_agent_mesh/assets/docs/assets/js/6143.0a1464c9.js +1 -0
  87. solace_agent_mesh/assets/docs/assets/js/6395.e9c73649.js +1 -0
  88. solace_agent_mesh/assets/docs/assets/js/6796.51d2c9b7.js +1 -0
  89. solace_agent_mesh/assets/docs/assets/js/6976.379be23b.js +1 -0
  90. solace_agent_mesh/assets/docs/assets/js/6978.ee0b945c.js +1 -0
  91. solace_agent_mesh/assets/docs/assets/js/7040.cb436723.js +1 -0
  92. solace_agent_mesh/assets/docs/assets/js/7195.412f418a.js +1 -0
  93. solace_agent_mesh/assets/docs/assets/js/7280.3fb73bdb.js +1 -0
  94. solace_agent_mesh/assets/docs/assets/js/768e31b0.a12673db.js +1 -0
  95. solace_agent_mesh/assets/docs/assets/js/7845.e33e7c4c.js +1 -0
  96. solace_agent_mesh/assets/docs/assets/js/7900.69516146.js +1 -0
  97. solace_agent_mesh/assets/docs/assets/js/8356.8a379c04.js +1 -0
  98. solace_agent_mesh/assets/docs/assets/js/85387663.6bf41934.js +1 -0
  99. solace_agent_mesh/assets/docs/assets/js/8567.4732c6b7.js +1 -0
  100. solace_agent_mesh/assets/docs/assets/js/8573.cb04eda5.js +1 -0
  101. solace_agent_mesh/assets/docs/assets/js/8577.1d54e766.js +1 -0
  102. solace_agent_mesh/assets/docs/assets/js/8591.d7c16be6.js +2 -0
  103. solace_agent_mesh/assets/docs/assets/js/8591.d7c16be6.js.LICENSE.txt +61 -0
  104. solace_agent_mesh/assets/docs/assets/js/8709.7ecd4047.js +1 -0
  105. solace_agent_mesh/assets/docs/assets/js/8731.49e930c2.js +1 -0
  106. solace_agent_mesh/assets/docs/assets/js/8908.f9d1b506.js +1 -0
  107. solace_agent_mesh/assets/docs/assets/js/9157.b4093d07.js +1 -0
  108. solace_agent_mesh/assets/docs/assets/js/9278.a4fd875d.js +1 -0
  109. solace_agent_mesh/assets/docs/assets/js/945fb41e.74d728aa.js +1 -0
  110. solace_agent_mesh/assets/docs/assets/js/9616.b75c2f6d.js +1 -0
  111. solace_agent_mesh/assets/docs/assets/js/9793.c6d16376.js +1 -0
  112. solace_agent_mesh/assets/docs/assets/js/9eff14a2.1bf8f61c.js +1 -0
  113. solace_agent_mesh/assets/docs/assets/js/a3a92b25.26ca071f.js +1 -0
  114. solace_agent_mesh/assets/docs/assets/js/a7bd4aaa.2204d2f7.js +1 -0
  115. solace_agent_mesh/assets/docs/assets/js/a94703ab.0438dbc2.js +1 -0
  116. solace_agent_mesh/assets/docs/assets/js/aba21aa0.c42a534c.js +1 -0
  117. solace_agent_mesh/assets/docs/assets/js/aba87c2f.d3e2dcc3.js +1 -0
  118. solace_agent_mesh/assets/docs/assets/js/ae4415af.8e279b5d.js +1 -0
  119. solace_agent_mesh/assets/docs/assets/js/b7006a3a.40b10c9d.js +1 -0
  120. solace_agent_mesh/assets/docs/assets/js/bac0be12.f50d9bac.js +1 -0
  121. solace_agent_mesh/assets/docs/assets/js/bb2ef573.207e6990.js +1 -0
  122. solace_agent_mesh/assets/docs/assets/js/c2c06897.63b76e9e.js +1 -0
  123. solace_agent_mesh/assets/docs/assets/js/cc969b05.954186d4.js +1 -0
  124. solace_agent_mesh/assets/docs/assets/js/cd3d4052.ca6eed8c.js +1 -0
  125. solace_agent_mesh/assets/docs/assets/js/ced92a13.fb92e7ca.js +1 -0
  126. solace_agent_mesh/assets/docs/assets/js/cee5d587.f5b73ca1.js +1 -0
  127. solace_agent_mesh/assets/docs/assets/js/f284c35a.ecc3d195.js +1 -0
  128. solace_agent_mesh/assets/docs/assets/js/f897a61a.2c2e152c.js +1 -0
  129. solace_agent_mesh/assets/docs/assets/js/fbfa3e75.aca209c9.js +1 -0
  130. solace_agent_mesh/assets/docs/assets/js/main.7ed3319f.js +2 -0
  131. solace_agent_mesh/assets/docs/assets/js/main.7ed3319f.js.LICENSE.txt +81 -0
  132. solace_agent_mesh/assets/docs/assets/js/runtime~main.d9520ae2.js +1 -0
  133. solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +128 -0
  134. solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +91 -0
  135. solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +201 -0
  136. solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +91 -0
  137. solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +55 -0
  138. solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +82 -0
  139. solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +60 -0
  140. solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +48 -0
  141. solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +54 -0
  142. solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +17 -0
  143. solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +45 -0
  144. solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +76 -0
  145. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +150 -0
  146. solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +54 -0
  147. solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +267 -0
  148. solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +136 -0
  149. solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +116 -0
  150. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +80 -0
  151. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +164 -0
  152. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +57 -0
  153. solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +72 -0
  154. solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +102 -0
  155. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +99 -0
  156. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +90 -0
  157. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +107 -0
  158. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +152 -0
  159. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +103 -0
  160. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +170 -0
  161. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +200 -0
  162. solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +54 -0
  163. solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +69 -0
  164. solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +59 -0
  165. solace_agent_mesh/assets/docs/img/Solace_AI_Framework_README.png +0 -0
  166. solace_agent_mesh/assets/docs/img/Solace_AI_Framework_With_Broker.png +0 -0
  167. solace_agent_mesh/assets/docs/img/logo.png +0 -0
  168. solace_agent_mesh/assets/docs/img/sac-flows.png +0 -0
  169. solace_agent_mesh/assets/docs/img/sac_parts_of_a_component.png +0 -0
  170. solace_agent_mesh/assets/docs/img/solace-logo.png +0 -0
  171. solace_agent_mesh/assets/docs/lunr-index-1753813536522.json +1 -0
  172. solace_agent_mesh/assets/docs/lunr-index.json +1 -0
  173. solace_agent_mesh/assets/docs/search-doc-1753813536522.json +1 -0
  174. solace_agent_mesh/assets/docs/search-doc.json +1 -0
  175. solace_agent_mesh/assets/docs/sitemap.xml +1 -0
  176. solace_agent_mesh/cli/__init__.py +1 -1
  177. solace_agent_mesh/cli/commands/add_cmd/__init__.py +15 -0
  178. solace_agent_mesh/cli/commands/add_cmd/add_cmd_llm.txt +250 -0
  179. solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +659 -0
  180. solace_agent_mesh/cli/commands/add_cmd/gateway_cmd.py +322 -0
  181. solace_agent_mesh/cli/commands/add_cmd/web_add_agent_step.py +93 -0
  182. solace_agent_mesh/cli/commands/add_cmd/web_add_gateway_step.py +118 -0
  183. solace_agent_mesh/cli/commands/docs_cmd.py +57 -0
  184. solace_agent_mesh/cli/commands/eval_cmd.py +64 -0
  185. solace_agent_mesh/cli/commands/init_cmd/__init__.py +404 -0
  186. solace_agent_mesh/cli/commands/init_cmd/broker_step.py +201 -0
  187. solace_agent_mesh/cli/commands/init_cmd/directory_step.py +28 -0
  188. solace_agent_mesh/cli/commands/init_cmd/env_step.py +197 -0
  189. solace_agent_mesh/cli/commands/init_cmd/init_cmd_llm.txt +365 -0
  190. solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +387 -0
  191. solace_agent_mesh/cli/commands/init_cmd/project_files_step.py +38 -0
  192. solace_agent_mesh/cli/commands/init_cmd/web_init_step.py +110 -0
  193. solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +183 -0
  194. solace_agent_mesh/cli/commands/plugin_cmd/__init__.py +18 -0
  195. solace_agent_mesh/cli/commands/plugin_cmd/add_cmd.py +372 -0
  196. solace_agent_mesh/cli/commands/plugin_cmd/build_cmd.py +86 -0
  197. solace_agent_mesh/cli/commands/plugin_cmd/catalog_cmd.py +138 -0
  198. solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +309 -0
  199. solace_agent_mesh/cli/commands/plugin_cmd/official_registry.py +174 -0
  200. solace_agent_mesh/cli/commands/plugin_cmd/plugin_cmd_llm.txt +305 -0
  201. solace_agent_mesh/cli/commands/run_cmd.py +158 -0
  202. solace_agent_mesh/cli/main.py +17 -294
  203. solace_agent_mesh/cli/utils.py +135 -204
  204. solace_agent_mesh/client/webui/frontend/static/assets/authCallback-DvlO62me.js +1 -0
  205. solace_agent_mesh/client/webui/frontend/static/assets/client-bp6u3qVZ.js +49 -0
  206. solace_agent_mesh/client/webui/frontend/static/assets/favicon-BLgzUch9.ico +0 -0
  207. solace_agent_mesh/client/webui/frontend/static/assets/main-An0a5j5k.js +663 -0
  208. solace_agent_mesh/client/webui/frontend/static/assets/main-Bu5-4Bac.css +1 -0
  209. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +14 -0
  210. solace_agent_mesh/client/webui/frontend/static/index.html +15 -0
  211. solace_agent_mesh/common/__init__.py +1 -0
  212. solace_agent_mesh/common/a2a_protocol.py +564 -0
  213. solace_agent_mesh/common/agent_registry.py +42 -0
  214. solace_agent_mesh/common/client/__init__.py +4 -0
  215. solace_agent_mesh/common/client/card_resolver.py +21 -0
  216. solace_agent_mesh/common/client/client.py +85 -0
  217. solace_agent_mesh/common/client/client_llm.txt +133 -0
  218. solace_agent_mesh/common/common_llm.txt +144 -0
  219. solace_agent_mesh/common/constants.py +1 -14
  220. solace_agent_mesh/common/middleware/__init__.py +12 -0
  221. solace_agent_mesh/common/middleware/config_resolver.py +130 -0
  222. solace_agent_mesh/common/middleware/middleware_llm.txt +174 -0
  223. solace_agent_mesh/common/middleware/registry.py +125 -0
  224. solace_agent_mesh/common/server/__init__.py +4 -0
  225. solace_agent_mesh/common/server/server.py +122 -0
  226. solace_agent_mesh/common/server/server_llm.txt +169 -0
  227. solace_agent_mesh/common/server/task_manager.py +291 -0
  228. solace_agent_mesh/common/server/utils.py +28 -0
  229. solace_agent_mesh/common/services/__init__.py +4 -0
  230. solace_agent_mesh/common/services/employee_service.py +162 -0
  231. solace_agent_mesh/common/services/identity_service.py +129 -0
  232. solace_agent_mesh/common/services/providers/__init__.py +4 -0
  233. solace_agent_mesh/common/services/providers/local_file_identity_service.py +148 -0
  234. solace_agent_mesh/common/services/providers/providers_llm.txt +113 -0
  235. solace_agent_mesh/common/services/services_llm.txt +132 -0
  236. solace_agent_mesh/common/types.py +411 -0
  237. solace_agent_mesh/common/utils/__init__.py +7 -0
  238. solace_agent_mesh/common/utils/asyncio_macos_fix.py +86 -0
  239. solace_agent_mesh/common/utils/embeds/__init__.py +33 -0
  240. solace_agent_mesh/common/utils/embeds/constants.py +55 -0
  241. solace_agent_mesh/common/utils/embeds/converter.py +452 -0
  242. solace_agent_mesh/common/utils/embeds/embeds_llm.txt +124 -0
  243. solace_agent_mesh/common/utils/embeds/evaluators.py +394 -0
  244. solace_agent_mesh/common/utils/embeds/modifiers.py +816 -0
  245. solace_agent_mesh/common/utils/embeds/resolver.py +865 -0
  246. solace_agent_mesh/common/utils/embeds/types.py +14 -0
  247. solace_agent_mesh/common/utils/in_memory_cache.py +108 -0
  248. solace_agent_mesh/common/utils/log_formatters.py +44 -0
  249. solace_agent_mesh/common/utils/mime_helpers.py +106 -0
  250. solace_agent_mesh/common/utils/push_notification_auth.py +134 -0
  251. solace_agent_mesh/common/utils/utils_llm.txt +67 -0
  252. solace_agent_mesh/config_portal/backend/common.py +66 -24
  253. solace_agent_mesh/config_portal/backend/plugin_catalog/constants.py +23 -0
  254. solace_agent_mesh/config_portal/backend/plugin_catalog/models.py +49 -0
  255. solace_agent_mesh/config_portal/backend/plugin_catalog/registry_manager.py +160 -0
  256. solace_agent_mesh/config_portal/backend/plugin_catalog/scraper.py +525 -0
  257. solace_agent_mesh/config_portal/backend/plugin_catalog_server.py +216 -0
  258. solace_agent_mesh/config_portal/backend/server.py +550 -181
  259. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-DNxCwAGB.js +48 -0
  260. solace_agent_mesh/config_portal/frontend/static/client/assets/components-B7lKcHVY.js +140 -0
  261. solace_agent_mesh/config_portal/frontend/static/client/assets/{entry.client-DX1misIU.js → entry.client-CEumGClk.js} +3 -3
  262. solace_agent_mesh/config_portal/frontend/static/client/assets/index-DSo1AH_7.js +68 -0
  263. solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-d2b54a97.js +1 -0
  264. solace_agent_mesh/config_portal/frontend/static/client/assets/{root-BApq5dPK.js → root-C4XmHinv.js} +2 -2
  265. solace_agent_mesh/config_portal/frontend/static/client/assets/root-DxRwaWiE.css +1 -0
  266. solace_agent_mesh/config_portal/frontend/static/client/index.html +3 -3
  267. solace_agent_mesh/core_a2a/__init__.py +1 -0
  268. solace_agent_mesh/core_a2a/core_a2a_llm.txt +88 -0
  269. solace_agent_mesh/core_a2a/service.py +331 -0
  270. solace_agent_mesh/evaluation/config_loader.py +657 -0
  271. solace_agent_mesh/evaluation/evaluator.py +667 -0
  272. solace_agent_mesh/evaluation/message_organizer.py +568 -0
  273. solace_agent_mesh/evaluation/report/benchmark_info.html +35 -0
  274. solace_agent_mesh/evaluation/report/chart_section.html +141 -0
  275. solace_agent_mesh/evaluation/report/detailed_breakdown.html +28 -0
  276. solace_agent_mesh/evaluation/report/modal.html +59 -0
  277. solace_agent_mesh/evaluation/report/modal_chart_functions.js +411 -0
  278. solace_agent_mesh/evaluation/report/modal_script.js +296 -0
  279. solace_agent_mesh/evaluation/report/modal_styles.css +340 -0
  280. solace_agent_mesh/evaluation/report/performance_metrics_styles.css +93 -0
  281. solace_agent_mesh/evaluation/report/templates/footer.html +2 -0
  282. solace_agent_mesh/evaluation/report/templates/header.html +340 -0
  283. solace_agent_mesh/evaluation/report_data_processor.py +972 -0
  284. solace_agent_mesh/evaluation/report_generator.py +613 -0
  285. solace_agent_mesh/evaluation/run.py +613 -0
  286. solace_agent_mesh/evaluation/subscriber.py +872 -0
  287. solace_agent_mesh/evaluation/summary_builder.py +775 -0
  288. solace_agent_mesh/evaluation/test_case_loader.py +714 -0
  289. solace_agent_mesh/gateway/base/__init__.py +1 -0
  290. solace_agent_mesh/gateway/base/app.py +266 -0
  291. solace_agent_mesh/gateway/base/base_llm.txt +119 -0
  292. solace_agent_mesh/gateway/base/component.py +1542 -0
  293. solace_agent_mesh/gateway/base/task_context.py +74 -0
  294. solace_agent_mesh/gateway/gateway_llm.txt +125 -0
  295. solace_agent_mesh/gateway/http_sse/app.py +190 -0
  296. solace_agent_mesh/gateway/http_sse/component.py +1602 -0
  297. solace_agent_mesh/gateway/http_sse/components/__init__.py +7 -0
  298. solace_agent_mesh/gateway/http_sse/components/components_llm.txt +65 -0
  299. solace_agent_mesh/gateway/http_sse/components/visualization_forwarder_component.py +108 -0
  300. solace_agent_mesh/gateway/http_sse/dependencies.py +316 -0
  301. solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +63 -0
  302. solace_agent_mesh/gateway/http_sse/main.py +442 -0
  303. solace_agent_mesh/gateway/http_sse/routers/__init__.py +4 -0
  304. solace_agent_mesh/gateway/http_sse/routers/agents.py +41 -0
  305. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +821 -0
  306. solace_agent_mesh/gateway/http_sse/routers/auth.py +212 -0
  307. solace_agent_mesh/gateway/http_sse/routers/config.py +55 -0
  308. solace_agent_mesh/gateway/http_sse/routers/people.py +69 -0
  309. solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +37 -0
  310. solace_agent_mesh/gateway/http_sse/routers/sessions.py +80 -0
  311. solace_agent_mesh/gateway/http_sse/routers/sse.py +138 -0
  312. solace_agent_mesh/gateway/http_sse/routers/tasks.py +294 -0
  313. solace_agent_mesh/gateway/http_sse/routers/users.py +59 -0
  314. solace_agent_mesh/gateway/http_sse/routers/visualization.py +1131 -0
  315. solace_agent_mesh/gateway/http_sse/services/__init__.py +4 -0
  316. solace_agent_mesh/gateway/http_sse/services/agent_service.py +69 -0
  317. solace_agent_mesh/gateway/http_sse/services/people_service.py +158 -0
  318. solace_agent_mesh/gateway/http_sse/services/services_llm.txt +179 -0
  319. solace_agent_mesh/gateway/http_sse/services/task_service.py +121 -0
  320. solace_agent_mesh/gateway/http_sse/session_manager.py +187 -0
  321. solace_agent_mesh/gateway/http_sse/sse_manager.py +328 -0
  322. solace_agent_mesh/llm.txt +228 -0
  323. solace_agent_mesh/llm_detail.txt +2835 -0
  324. solace_agent_mesh/templates/agent_template.yaml +53 -0
  325. solace_agent_mesh/templates/eval_backend_template.yaml +54 -0
  326. solace_agent_mesh/templates/gateway_app_template.py +73 -0
  327. solace_agent_mesh/templates/gateway_component_template.py +400 -0
  328. solace_agent_mesh/templates/gateway_config_template.yaml +43 -0
  329. solace_agent_mesh/templates/main_orchestrator.yaml +55 -0
  330. solace_agent_mesh/templates/plugin_agent_config_template.yaml +122 -0
  331. solace_agent_mesh/templates/plugin_custom_config_template.yaml +27 -0
  332. solace_agent_mesh/templates/plugin_custom_template.py +10 -0
  333. solace_agent_mesh/templates/plugin_gateway_config_template.yaml +63 -0
  334. solace_agent_mesh/templates/plugin_pyproject_template.toml +33 -0
  335. solace_agent_mesh/templates/plugin_readme_template.md +34 -0
  336. solace_agent_mesh/templates/plugin_tools_template.py +224 -0
  337. solace_agent_mesh/templates/shared_config.yaml +66 -0
  338. solace_agent_mesh/templates/templates_llm.txt +147 -0
  339. solace_agent_mesh/templates/webui.yaml +53 -0
  340. solace_agent_mesh-1.0.1.dist-info/METADATA +432 -0
  341. solace_agent_mesh-1.0.1.dist-info/RECORD +359 -0
  342. solace_agent_mesh-1.0.1.dist-info/entry_points.txt +3 -0
  343. {solace_agent_mesh-0.2.4.dist-info → solace_agent_mesh-1.0.1.dist-info}/licenses/LICENSE +1 -1
  344. solace_agent_mesh/agents/base_agent_component.py +0 -256
  345. solace_agent_mesh/agents/global/actions/agent_state_change.py +0 -54
  346. solace_agent_mesh/agents/global/actions/clear_history.py +0 -32
  347. solace_agent_mesh/agents/global/actions/convert_file_to_markdown.py +0 -160
  348. solace_agent_mesh/agents/global/actions/create_file.py +0 -70
  349. solace_agent_mesh/agents/global/actions/error_action.py +0 -45
  350. solace_agent_mesh/agents/global/actions/plantuml_diagram.py +0 -163
  351. solace_agent_mesh/agents/global/actions/plotly_graph.py +0 -152
  352. solace_agent_mesh/agents/global/actions/retrieve_file.py +0 -51
  353. solace_agent_mesh/agents/global/global_agent_component.py +0 -38
  354. solace_agent_mesh/agents/image_processing/actions/create_image.py +0 -75
  355. solace_agent_mesh/agents/image_processing/actions/describe_image.py +0 -115
  356. solace_agent_mesh/agents/image_processing/image_processing_agent_component.py +0 -23
  357. solace_agent_mesh/agents/slack/__init__.py +0 -1
  358. solace_agent_mesh/agents/slack/actions/__init__.py +0 -1
  359. solace_agent_mesh/agents/slack/actions/post_message.py +0 -177
  360. solace_agent_mesh/agents/slack/slack_agent_component.py +0 -59
  361. solace_agent_mesh/agents/web_request/actions/do_image_search.py +0 -84
  362. solace_agent_mesh/agents/web_request/actions/do_news_search.py +0 -47
  363. solace_agent_mesh/agents/web_request/actions/do_suggestion_search.py +0 -34
  364. solace_agent_mesh/agents/web_request/actions/do_web_request.py +0 -135
  365. solace_agent_mesh/agents/web_request/actions/download_file.py +0 -69
  366. solace_agent_mesh/agents/web_request/web_request_agent_component.py +0 -33
  367. solace_agent_mesh/assets/web-visualizer/assets/index-D0qORgkg.css +0 -1
  368. solace_agent_mesh/assets/web-visualizer/assets/index-DnDr1pnu.js +0 -109
  369. solace_agent_mesh/assets/web-visualizer/index.html +0 -14
  370. solace_agent_mesh/assets/web-visualizer/vite.svg +0 -1
  371. solace_agent_mesh/cli/commands/add/__init__.py +0 -3
  372. solace_agent_mesh/cli/commands/add/add.py +0 -88
  373. solace_agent_mesh/cli/commands/add/agent.py +0 -110
  374. solace_agent_mesh/cli/commands/add/copy_from_plugin.py +0 -92
  375. solace_agent_mesh/cli/commands/add/gateway.py +0 -374
  376. solace_agent_mesh/cli/commands/build.py +0 -670
  377. solace_agent_mesh/cli/commands/chat/__init__.py +0 -3
  378. solace_agent_mesh/cli/commands/chat/chat.py +0 -361
  379. solace_agent_mesh/cli/commands/config.py +0 -29
  380. solace_agent_mesh/cli/commands/init/__init__.py +0 -3
  381. solace_agent_mesh/cli/commands/init/ai_provider_step.py +0 -93
  382. solace_agent_mesh/cli/commands/init/broker_step.py +0 -99
  383. solace_agent_mesh/cli/commands/init/builtin_agent_step.py +0 -83
  384. solace_agent_mesh/cli/commands/init/check_if_already_done.py +0 -13
  385. solace_agent_mesh/cli/commands/init/create_config_file_step.py +0 -65
  386. solace_agent_mesh/cli/commands/init/create_other_project_files_step.py +0 -147
  387. solace_agent_mesh/cli/commands/init/file_service_step.py +0 -73
  388. solace_agent_mesh/cli/commands/init/init.py +0 -92
  389. solace_agent_mesh/cli/commands/init/project_structure_step.py +0 -16
  390. solace_agent_mesh/cli/commands/init/web_init_step.py +0 -32
  391. solace_agent_mesh/cli/commands/plugin/__init__.py +0 -3
  392. solace_agent_mesh/cli/commands/plugin/add.py +0 -100
  393. solace_agent_mesh/cli/commands/plugin/build.py +0 -268
  394. solace_agent_mesh/cli/commands/plugin/create.py +0 -117
  395. solace_agent_mesh/cli/commands/plugin/plugin.py +0 -124
  396. solace_agent_mesh/cli/commands/plugin/remove.py +0 -73
  397. solace_agent_mesh/cli/commands/run.py +0 -68
  398. solace_agent_mesh/cli/commands/visualizer.py +0 -138
  399. solace_agent_mesh/cli/config.py +0 -85
  400. solace_agent_mesh/common/action.py +0 -91
  401. solace_agent_mesh/common/action_list.py +0 -37
  402. solace_agent_mesh/common/action_response.py +0 -340
  403. solace_agent_mesh/common/mysql_database.py +0 -40
  404. solace_agent_mesh/common/postgres_database.py +0 -85
  405. solace_agent_mesh/common/prompt_templates.py +0 -28
  406. solace_agent_mesh/common/stimulus_utils.py +0 -152
  407. solace_agent_mesh/common/time.py +0 -24
  408. solace_agent_mesh/common/utils.py +0 -712
  409. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-a-zJ6rLx.js +0 -46
  410. solace_agent_mesh/config_portal/frontend/static/client/assets/components-ZIfdTbrV.js +0 -191
  411. solace_agent_mesh/config_portal/frontend/static/client/assets/index-BJHAE5s4.js +0 -17
  412. solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-44c41103.js +0 -1
  413. solace_agent_mesh/config_portal/frontend/static/client/assets/root-DX4gQ516.css +0 -1
  414. solace_agent_mesh/configs/agent_global.yaml +0 -74
  415. solace_agent_mesh/configs/agent_image_processing.yaml +0 -82
  416. solace_agent_mesh/configs/agent_slack.yaml +0 -64
  417. solace_agent_mesh/configs/agent_web_request.yaml +0 -75
  418. solace_agent_mesh/configs/conversation_to_file.yaml +0 -56
  419. solace_agent_mesh/configs/error_catcher.yaml +0 -56
  420. solace_agent_mesh/configs/monitor.yaml +0 -0
  421. solace_agent_mesh/configs/monitor_stim_and_errors_to_slack.yaml +0 -109
  422. solace_agent_mesh/configs/monitor_user_feedback.yaml +0 -58
  423. solace_agent_mesh/configs/orchestrator.yaml +0 -241
  424. solace_agent_mesh/configs/service_embedding.yaml +0 -81
  425. solace_agent_mesh/configs/service_llm.yaml +0 -265
  426. solace_agent_mesh/configs/visualize_websocket.yaml +0 -55
  427. solace_agent_mesh/gateway/components/gateway_base.py +0 -47
  428. solace_agent_mesh/gateway/components/gateway_input.py +0 -278
  429. solace_agent_mesh/gateway/components/gateway_output.py +0 -298
  430. solace_agent_mesh/gateway/identity/bamboohr_identity.py +0 -18
  431. solace_agent_mesh/gateway/identity/identity_base.py +0 -10
  432. solace_agent_mesh/gateway/identity/identity_provider.py +0 -60
  433. solace_agent_mesh/gateway/identity/no_identity.py +0 -9
  434. solace_agent_mesh/gateway/identity/passthru_identity.py +0 -9
  435. solace_agent_mesh/monitors/base_monitor_component.py +0 -26
  436. solace_agent_mesh/monitors/feedback/user_feedback_monitor.py +0 -75
  437. solace_agent_mesh/monitors/stim_and_errors/stim_and_error_monitor.py +0 -560
  438. solace_agent_mesh/orchestrator/__init__.py +0 -0
  439. solace_agent_mesh/orchestrator/action_manager.py +0 -237
  440. solace_agent_mesh/orchestrator/components/__init__.py +0 -0
  441. solace_agent_mesh/orchestrator/components/orchestrator_action_manager_timeout_component.py +0 -58
  442. solace_agent_mesh/orchestrator/components/orchestrator_action_response_component.py +0 -179
  443. solace_agent_mesh/orchestrator/components/orchestrator_register_component.py +0 -107
  444. solace_agent_mesh/orchestrator/components/orchestrator_stimulus_processor_component.py +0 -527
  445. solace_agent_mesh/orchestrator/components/orchestrator_streaming_output_component.py +0 -260
  446. solace_agent_mesh/orchestrator/orchestrator_main.py +0 -172
  447. solace_agent_mesh/orchestrator/orchestrator_prompt.py +0 -539
  448. solace_agent_mesh/services/__init__.py +0 -0
  449. solace_agent_mesh/services/authorization/providers/base_authorization_provider.py +0 -56
  450. solace_agent_mesh/services/bamboo_hr_service/__init__.py +0 -3
  451. solace_agent_mesh/services/bamboo_hr_service/bamboo_hr.py +0 -182
  452. solace_agent_mesh/services/common/__init__.py +0 -4
  453. solace_agent_mesh/services/common/auto_expiry.py +0 -45
  454. solace_agent_mesh/services/common/singleton.py +0 -18
  455. solace_agent_mesh/services/file_service/__init__.py +0 -14
  456. solace_agent_mesh/services/file_service/file_manager/__init__.py +0 -0
  457. solace_agent_mesh/services/file_service/file_manager/bucket_file_manager.py +0 -149
  458. solace_agent_mesh/services/file_service/file_manager/file_manager_base.py +0 -162
  459. solace_agent_mesh/services/file_service/file_manager/memory_file_manager.py +0 -64
  460. solace_agent_mesh/services/file_service/file_manager/volume_file_manager.py +0 -106
  461. solace_agent_mesh/services/file_service/file_service.py +0 -437
  462. solace_agent_mesh/services/file_service/file_service_constants.py +0 -54
  463. solace_agent_mesh/services/file_service/file_transformations.py +0 -141
  464. solace_agent_mesh/services/file_service/file_utils.py +0 -324
  465. solace_agent_mesh/services/file_service/transformers/__init__.py +0 -5
  466. solace_agent_mesh/services/history_service/__init__.py +0 -3
  467. solace_agent_mesh/services/history_service/history_providers/__init__.py +0 -0
  468. solace_agent_mesh/services/history_service/history_providers/base_history_provider.py +0 -54
  469. solace_agent_mesh/services/history_service/history_providers/file_history_provider.py +0 -74
  470. solace_agent_mesh/services/history_service/history_providers/index.py +0 -40
  471. solace_agent_mesh/services/history_service/history_providers/memory_history_provider.py +0 -33
  472. solace_agent_mesh/services/history_service/history_providers/mongodb_history_provider.py +0 -66
  473. solace_agent_mesh/services/history_service/history_providers/redis_history_provider.py +0 -66
  474. solace_agent_mesh/services/history_service/history_providers/sql_history_provider.py +0 -93
  475. solace_agent_mesh/services/history_service/history_service.py +0 -413
  476. solace_agent_mesh/services/history_service/long_term_memory/__init__.py +0 -0
  477. solace_agent_mesh/services/history_service/long_term_memory/long_term_memory.py +0 -399
  478. solace_agent_mesh/services/llm_service/components/llm_request_component.py +0 -340
  479. solace_agent_mesh/services/llm_service/components/llm_service_component_base.py +0 -152
  480. solace_agent_mesh/services/middleware_service/__init__.py +0 -0
  481. solace_agent_mesh/services/middleware_service/middleware_service.py +0 -20
  482. solace_agent_mesh/templates/action.py +0 -38
  483. solace_agent_mesh/templates/agent.py +0 -29
  484. solace_agent_mesh/templates/agent.yaml +0 -70
  485. solace_agent_mesh/templates/gateway-config-template.yaml +0 -6
  486. solace_agent_mesh/templates/gateway-default-config.yaml +0 -28
  487. solace_agent_mesh/templates/gateway-flows.yaml +0 -78
  488. solace_agent_mesh/templates/gateway-header.yaml +0 -16
  489. solace_agent_mesh/templates/gateway_base.py +0 -15
  490. solace_agent_mesh/templates/gateway_input.py +0 -98
  491. solace_agent_mesh/templates/gateway_output.py +0 -71
  492. solace_agent_mesh/templates/plugin-gateway-default-config.yaml +0 -29
  493. solace_agent_mesh/templates/plugin-pyproject.toml +0 -30
  494. solace_agent_mesh/templates/rest-api-default-config.yaml +0 -31
  495. solace_agent_mesh/templates/rest-api-flows.yaml +0 -81
  496. solace_agent_mesh/templates/slack-default-config.yaml +0 -16
  497. solace_agent_mesh/templates/slack-flows.yaml +0 -81
  498. solace_agent_mesh/templates/solace-agent-mesh-default.yaml +0 -86
  499. solace_agent_mesh/templates/solace-agent-mesh-plugin-default.yaml +0 -8
  500. solace_agent_mesh/templates/web-default-config.yaml +0 -10
  501. solace_agent_mesh/templates/web-flows.yaml +0 -76
  502. solace_agent_mesh/tools/__init__.py +0 -0
  503. solace_agent_mesh/tools/components/__init__.py +0 -0
  504. solace_agent_mesh/tools/components/conversation_formatter.py +0 -111
  505. solace_agent_mesh/tools/components/file_resolver_component.py +0 -58
  506. solace_agent_mesh/tools/config/runtime_config.py +0 -26
  507. solace_agent_mesh-0.2.4.dist-info/METADATA +0 -176
  508. solace_agent_mesh-0.2.4.dist-info/RECORD +0 -193
  509. solace_agent_mesh-0.2.4.dist-info/entry_points.txt +0 -3
  510. /solace_agent_mesh/{agents → agent}/__init__.py +0 -0
  511. /solace_agent_mesh/{agents/global → agent/adk}/__init__.py +0 -0
  512. /solace_agent_mesh/{agents/global/actions → agent/protocol}/__init__.py +0 -0
  513. /solace_agent_mesh/{agents/image_processing → agent/sac}/__init__.py +0 -0
  514. /solace_agent_mesh/{agents/image_processing/actions → agent/utils}/__init__.py +0 -0
  515. /solace_agent_mesh/{agents/web_request → config_portal/backend/plugin_catalog}/__init__.py +0 -0
  516. /solace_agent_mesh/{agents/web_request/actions → evaluation}/__init__.py +0 -0
  517. /solace_agent_mesh/gateway/{components → http_sse}/__init__.py +0 -0
  518. {solace_agent_mesh-0.2.4.dist-info → solace_agent_mesh-1.0.1.dist-info}/WHEEL +0 -0
@@ -0,0 +1,816 @@
1
+ """
2
+ Defines modifier implementation functions and their contracts.
3
+ """
4
+
5
+ import re
6
+ from typing import Any, Callable, Dict, Optional, Tuple, List
7
+
8
+ from solace_ai_connector.common.log import log
9
+
10
+ from .constants import EARLY_EMBED_TYPES, LATE_EMBED_TYPES
11
+
12
+ try:
13
+ from jsonpath_ng.ext import parse as jsonpath_parse
14
+
15
+ JSONPATH_NG_AVAILABLE = True
16
+ except ImportError:
17
+ JSONPATH_NG_AVAILABLE = False
18
+
19
+ try:
20
+ import pystache
21
+
22
+ PYSTACHE_AVAILABLE = True
23
+ except ImportError:
24
+ PYSTACHE_AVAILABLE = False
25
+
26
+ from google.adk.artifacts import BaseArtifactService
27
+
28
+ from .types import DataFormat
29
+
30
+
31
+ def _apply_jsonpath(
32
+ current_data: Any, expression: str, mime_type: Optional[str], log_id: str
33
+ ) -> Tuple[Any, Optional[str], Optional[str]]:
34
+ """
35
+ Applies a JSONPath expression to parsed JSON data.
36
+
37
+ Args:
38
+ current_data: The input data (expected to be dict or list).
39
+ expression: The JSONPath expression string.
40
+ mime_type: The original mime type (passed through).
41
+ log_id: Identifier for logging.
42
+
43
+ Returns:
44
+ Tuple: (result_data, original_mime_type, error_string)
45
+ result_data is typically a list of matched values.
46
+ """
47
+ if not JSONPATH_NG_AVAILABLE:
48
+ return (
49
+ current_data,
50
+ mime_type,
51
+ "JSONPath modifier skipped: 'jsonpath-ng' not installed.",
52
+ )
53
+
54
+ if not isinstance(current_data, (dict, list)):
55
+ return (
56
+ current_data,
57
+ mime_type,
58
+ f"Input data for 'jsonpath' must be a JSON object or list, got {type(current_data).__name__}.",
59
+ )
60
+
61
+ try:
62
+ jsonpath_expr = jsonpath_parse(expression)
63
+ matches = [match.value for match in jsonpath_expr.find(current_data)]
64
+ return matches, mime_type, None
65
+ except Exception as e:
66
+ return (
67
+ current_data,
68
+ mime_type,
69
+ f"Error applying JSONPath expression '{expression}': {e}",
70
+ )
71
+
72
+
73
+ def _apply_select_cols(
74
+ current_data: List[Dict], cols_str: str, mime_type: Optional[str], log_id: str
75
+ ) -> Tuple[Any, Optional[str], Optional[str]]:
76
+ """
77
+ Selects specific columns from data represented as a list of dictionaries.
78
+
79
+ Args:
80
+ current_data: The input data (expected List[Dict]).
81
+ cols_str: Comma-separated string of column names to keep.
82
+ mime_type: The original mime type (passed through).
83
+ log_id: Identifier for logging.
84
+
85
+ Returns:
86
+ Tuple: (result_data, original_mime_type, error_string)
87
+ result_data is List[Dict] containing only selected columns.
88
+ """
89
+ if not isinstance(current_data, list) or (
90
+ current_data and not isinstance(current_data[0], dict)
91
+ ):
92
+ return (
93
+ current_data,
94
+ mime_type,
95
+ f"Input data for 'select_cols' must be a list of dictionaries, got {type(current_data).__name__}.",
96
+ )
97
+
98
+ if not current_data:
99
+ return [], mime_type, None
100
+
101
+ try:
102
+ header = list(current_data[0].keys())
103
+ target_cols = [col.strip() for col in cols_str.split(",")]
104
+ output_list = []
105
+
106
+ for target_col in target_cols:
107
+ if target_col not in header:
108
+ return (
109
+ current_data,
110
+ mime_type,
111
+ f"Column '{target_col}' not found in data keys: {header}",
112
+ )
113
+
114
+ for row_dict in current_data:
115
+ new_row = {col: row_dict.get(col) for col in target_cols}
116
+ output_list.append(new_row)
117
+
118
+ return output_list, mime_type, None
119
+
120
+ except Exception as e:
121
+ return current_data, mime_type, f"Error selecting columns '{cols_str}': {e}"
122
+
123
+
124
+ def _apply_filter_rows_eq(
125
+ current_data: List[Dict], filter_spec: str, mime_type: Optional[str], log_id: str
126
+ ) -> Tuple[Any, Optional[str], Optional[str]]:
127
+ """
128
+ Filters a list of dictionaries based on a column's value equality.
129
+
130
+ Args:
131
+ current_data: The input data (expected List[Dict]).
132
+ filter_spec: String in the format 'column_name:value'.
133
+ mime_type: The original mime type (passed through).
134
+ log_id: Identifier for logging.
135
+
136
+ Returns:
137
+ Tuple: (result_data, original_mime_type, error_string)
138
+ result_data is List[Dict] containing only filtered rows.
139
+ """
140
+ if not isinstance(current_data, list) or (
141
+ current_data and not isinstance(current_data[0], dict)
142
+ ):
143
+ return (
144
+ current_data,
145
+ mime_type,
146
+ f"Input data for 'filter_rows_eq' must be a list of dictionaries, got {type(current_data).__name__}.",
147
+ )
148
+
149
+ if not current_data:
150
+ return [], mime_type, None
151
+
152
+ try:
153
+ parts = filter_spec.split(":", 1)
154
+ if len(parts) != 2:
155
+ return (
156
+ current_data,
157
+ mime_type,
158
+ f"Invalid filter format '{filter_spec}'. Expected 'column_name:value'.",
159
+ )
160
+ col_name, filter_value = parts[0].strip(), parts[1].strip()
161
+
162
+ header = list(current_data[0].keys())
163
+ if col_name not in header:
164
+ return (
165
+ current_data,
166
+ mime_type,
167
+ f"Filter column '{col_name}' not found in data keys: {header}",
168
+ )
169
+
170
+ output_list = [
171
+ row for row in current_data if str(row.get(col_name)) == filter_value
172
+ ]
173
+
174
+ return output_list, mime_type, None
175
+
176
+ except Exception as e:
177
+ return current_data, mime_type, f"Error filtering rows by '{filter_spec}': {e}"
178
+
179
+
180
+ def _apply_slice_rows(
181
+ current_data: List[Dict], slice_spec: str, mime_type: Optional[str], log_id: str
182
+ ) -> Tuple[Any, Optional[str], Optional[str]]:
183
+ """
184
+ Selects a slice of rows from a list of dictionaries.
185
+
186
+ Args:
187
+ current_data: The input data (expected List[Dict]).
188
+ slice_spec: String in Python slice format 'start:end'.
189
+ mime_type: The original mime type (passed through).
190
+ log_id: Identifier for logging.
191
+
192
+ Returns:
193
+ Tuple: (result_data, original_mime_type, error_string)
194
+ result_data is List[Dict] containing the sliced rows.
195
+ """
196
+ if not isinstance(current_data, list):
197
+ return (
198
+ current_data,
199
+ mime_type,
200
+ f"Input data for 'slice_rows' must be a list, got {type(current_data).__name__}.",
201
+ )
202
+
203
+ try:
204
+ start_str, end_str = None, None
205
+ if ":" in slice_spec:
206
+ parts = slice_spec.split(":", 1)
207
+ start_str, end_str = parts[0].strip(), parts[1].strip()
208
+ else:
209
+ return (
210
+ current_data,
211
+ mime_type,
212
+ f"Invalid slice format '{slice_spec}'. Expected 'start:end'.",
213
+ )
214
+
215
+ start = int(start_str) if start_str else 0
216
+ end = int(end_str) if end_str else None
217
+
218
+ sliced_data = current_data[start:end]
219
+
220
+ return sliced_data, mime_type, None
221
+
222
+ except (ValueError, TypeError) as e:
223
+ return current_data, mime_type, f"Invalid slice indices in '{slice_spec}': {e}"
224
+ except Exception as e:
225
+ return current_data, mime_type, f"Error slicing rows '{slice_spec}': {e}"
226
+
227
+
228
+ def _apply_slice_lines(
229
+ current_data: str, slice_spec: str, mime_type: Optional[str], log_id: str
230
+ ) -> Tuple[Any, Optional[str], Optional[str]]:
231
+ """
232
+ Selects a slice of lines from text data.
233
+
234
+ Args:
235
+ current_data: The input data (expected str).
236
+ slice_spec: String in Python slice format 'start:end'.
237
+ mime_type: The original mime type (passed through).
238
+ log_id: Identifier for logging.
239
+
240
+ Returns:
241
+ Tuple: (result_data, original_mime_type, error_string)
242
+ result_data is str containing the sliced lines.
243
+ """
244
+ if not isinstance(current_data, str):
245
+ return (
246
+ current_data,
247
+ mime_type,
248
+ f"Input data for 'slice_lines' must be a string, got {type(current_data).__name__}.",
249
+ )
250
+
251
+ try:
252
+ start_str, end_str = None, None
253
+ if ":" in slice_spec:
254
+ parts = slice_spec.split(":", 1)
255
+ start_str, end_str = parts[0].strip(), parts[1].strip()
256
+ else:
257
+ return (
258
+ current_data,
259
+ mime_type,
260
+ f"Invalid slice format '{slice_spec}'. Expected 'start:end'.",
261
+ )
262
+
263
+ start = int(start_str) if start_str else 0
264
+ end = int(end_str) if end_str else None
265
+
266
+ lines = current_data.splitlines(keepends=True)
267
+ sliced_lines = lines[start:end]
268
+
269
+ return "".join(sliced_lines), mime_type, None
270
+
271
+ except (ValueError, TypeError) as e:
272
+ return current_data, mime_type, f"Invalid slice indices in '{slice_spec}': {e}"
273
+ except Exception as e:
274
+ return current_data, mime_type, f"Error slicing text lines '{slice_spec}': {e}"
275
+
276
+
277
+ def _apply_grep(
278
+ current_data: str, pattern: str, mime_type: Optional[str], log_id: str
279
+ ) -> Tuple[Any, Optional[str], Optional[str]]:
280
+ """
281
+ Filters lines matching a regex pattern from text data.
282
+
283
+ Args:
284
+ current_data: The input data (expected str).
285
+ pattern: The regex pattern string.
286
+ mime_type: The original mime type (passed through).
287
+ log_id: Identifier for logging.
288
+
289
+ Returns:
290
+ Tuple: (result_data, original_mime_type, error_string)
291
+ result_data is str containing only matching lines.
292
+ """
293
+ if not isinstance(current_data, str):
294
+ return (
295
+ current_data,
296
+ mime_type,
297
+ f"Input data for 'grep' must be a string, got {type(current_data).__name__}.",
298
+ )
299
+
300
+ try:
301
+ regex = re.compile(pattern)
302
+ lines = current_data.splitlines(keepends=True)
303
+ filtered_lines = [line for line in lines if regex.search(line)]
304
+ return "".join(filtered_lines), mime_type, None
305
+ except re.error as e:
306
+ return current_data, mime_type, f"Invalid regex pattern '{pattern}': {e}"
307
+ except Exception as e:
308
+ return current_data, mime_type, f"Error applying grep pattern '{pattern}': {e}"
309
+
310
+
311
+ def _apply_head(
312
+ current_data: str, n_str: str, mime_type: Optional[str], log_id: str
313
+ ) -> Tuple[Any, Optional[str], Optional[str]]:
314
+ """
315
+ Returns the first N lines of text data.
316
+
317
+ Args:
318
+ current_data: The input data (expected str).
319
+ n_str: String representing the number of lines (N).
320
+ mime_type: The original mime type (passed through).
321
+ log_id: Identifier for logging.
322
+
323
+ Returns:
324
+ Tuple: (result_data, original_mime_type, error_string)
325
+ result_data is str containing the first N lines.
326
+ """
327
+ if not isinstance(current_data, str):
328
+ return (
329
+ current_data,
330
+ mime_type,
331
+ f"Input data for 'head' must be a string, got {type(current_data).__name__}.",
332
+ )
333
+
334
+ try:
335
+ n = int(n_str.strip())
336
+ if n < 0:
337
+ return current_data, mime_type, "Head count N cannot be negative."
338
+
339
+ lines = current_data.splitlines(keepends=True)
340
+ head_lines = lines[:n]
341
+ return "".join(head_lines), mime_type, None
342
+ except (ValueError, TypeError) as e:
343
+ return current_data, mime_type, f"Invalid head count N '{n_str}': {e}"
344
+ except Exception as e:
345
+ return current_data, mime_type, f"Error applying head '{n_str}': {e}"
346
+
347
+
348
+ def _apply_tail(
349
+ current_data: str, n_str: str, mime_type: Optional[str], log_id: str
350
+ ) -> Tuple[Any, Optional[str], Optional[str]]:
351
+ """
352
+ Returns the last N lines of text data.
353
+
354
+ Args:
355
+ current_data: The input data (expected str).
356
+ n_str: String representing the number of lines (N).
357
+ mime_type: The original mime type (passed through).
358
+ log_id: Identifier for logging.
359
+
360
+ Returns:
361
+ Tuple: (result_data, original_mime_type, error_string)
362
+ result_data is str containing the last N lines.
363
+ """
364
+ if not isinstance(current_data, str):
365
+ return (
366
+ current_data,
367
+ mime_type,
368
+ f"Input data for 'tail' must be a string, got {type(current_data).__name__}.",
369
+ )
370
+
371
+ try:
372
+ n = int(n_str.strip())
373
+ if n < 0:
374
+ return current_data, mime_type, "Tail count N cannot be negative."
375
+ if n == 0:
376
+ return "", mime_type, None
377
+
378
+ lines = current_data.splitlines(keepends=True)
379
+ tail_lines = lines[-n:]
380
+ return "".join(tail_lines), mime_type, None
381
+ except (ValueError, TypeError) as e:
382
+ return current_data, mime_type, f"Invalid tail count N '{n_str}': {e}"
383
+ except Exception as e:
384
+ return current_data, mime_type, f"Error applying tail '{n_str}': {e}"
385
+
386
+
387
+ def _apply_select_fields(
388
+ current_data: List[Dict], fields_str: str, mime_type: Optional[str], log_id: str
389
+ ) -> Tuple[Any, Optional[str], Optional[str]]:
390
+ """
391
+ Selects specific fields from a list of dictionaries.
392
+
393
+ Args:
394
+ current_data: The input data (expected List[Dict]).
395
+ fields_str: Comma-separated string of field names to keep.
396
+ mime_type: The original mime type (passed through).
397
+ log_id: Identifier for logging.
398
+
399
+ Returns:
400
+ Tuple: (result_data, original_mime_type, error_string)
401
+ result_data is List[Dict] containing only selected fields.
402
+ """
403
+ if not isinstance(current_data, list) or (
404
+ current_data and not isinstance(current_data[0], dict)
405
+ ):
406
+ return (
407
+ current_data,
408
+ mime_type,
409
+ f"Input data for 'select_fields' must be a list of dictionaries, got {type(current_data).__name__}.",
410
+ )
411
+
412
+ target_fields = [field.strip() for field in fields_str.split(",")]
413
+ if not target_fields:
414
+ return current_data, mime_type, "No fields specified for 'select_fields'."
415
+
416
+ output_list = []
417
+ try:
418
+ for item in current_data:
419
+ if isinstance(item, dict):
420
+ new_item = {
421
+ field: item.get(field) for field in target_fields if field in item
422
+ }
423
+ output_list.append(new_item)
424
+ else:
425
+ log.warning(
426
+ "%s Skipping non-dictionary item in list during select_fields.",
427
+ log_id,
428
+ )
429
+ continue
430
+ return output_list, mime_type, None
431
+ except Exception as e:
432
+ return current_data, mime_type, f"Error selecting fields '{fields_str}': {e}"
433
+
434
+
435
+ async def _apply_template(
436
+ current_data: Any,
437
+ template_spec: str,
438
+ mime_type: Optional[str],
439
+ log_id: str,
440
+ context: Any,
441
+ ) -> Tuple[Any, Optional[str], Optional[str]]:
442
+ """
443
+ Applies a Mustache template loaded from an artifact to the input data.
444
+ This version first renders the template, then resolves embeds on the result.
445
+
446
+ Args:
447
+ current_data: The input data (expected dict, list, or str).
448
+ template_spec: String 'template_filename[:version]'.
449
+ mime_type: The original mime type (passed through).
450
+ log_id: Identifier for logging.
451
+ context: The Gateway context dictionary containing artifact_service and session_context.
452
+
453
+ Returns:
454
+ Tuple: (result_data, original_mime_type, error_string)
455
+ result_data is the rendered and resolved string.
456
+ """
457
+ from .resolver import resolve_embeds_recursively_in_string, evaluate_embed
458
+
459
+ if not PYSTACHE_AVAILABLE:
460
+ return (
461
+ current_data,
462
+ mime_type,
463
+ "Template modifier skipped: 'pystache' not installed.",
464
+ )
465
+
466
+ if not isinstance(current_data, (dict, list, str)):
467
+ return (
468
+ current_data,
469
+ mime_type,
470
+ f"Input data for 'apply_to_template' must be dict, list, or string, got {type(current_data).__name__}.",
471
+ )
472
+
473
+ parts = template_spec.strip().split(":", 1)
474
+ template_filename = parts[0]
475
+ template_version_str = parts[1] if len(parts) > 1 else None
476
+ template_version = None
477
+
478
+ if not template_filename:
479
+ return current_data, mime_type, "Template filename cannot be empty."
480
+
481
+ if not isinstance(context, dict):
482
+ return current_data, mime_type, "Invalid context for template loading."
483
+ artifact_service: Optional[BaseArtifactService] = context.get("artifact_service")
484
+ session_context = context.get("session_context")
485
+ if not artifact_service or not session_context:
486
+ return (
487
+ current_data,
488
+ mime_type,
489
+ "ArtifactService or session context not available for template loading.",
490
+ )
491
+
492
+ app_name = session_context.get("app_name")
493
+ user_id = session_context.get("user_id")
494
+ session_id = session_context.get("session_id")
495
+ if not all([app_name, user_id, session_id]):
496
+ return (
497
+ current_data,
498
+ mime_type,
499
+ "Missing required session identifiers in context for template loading.",
500
+ )
501
+
502
+ try:
503
+ if template_version_str:
504
+ template_version = int(template_version_str)
505
+ else:
506
+ versions = await artifact_service.list_versions(
507
+ app_name=app_name,
508
+ user_id=user_id,
509
+ session_id=session_id,
510
+ filename=template_filename,
511
+ )
512
+ if not versions:
513
+ return (
514
+ current_data,
515
+ mime_type,
516
+ f"Template artifact '{template_filename}' (latest) not found.",
517
+ )
518
+ template_version = max(versions)
519
+
520
+ template_part = await artifact_service.load_artifact(
521
+ app_name=app_name,
522
+ user_id=user_id,
523
+ session_id=session_id,
524
+ filename=template_filename,
525
+ version=template_version,
526
+ )
527
+
528
+ if not template_part or not template_part.inline_data:
529
+ return (
530
+ current_data,
531
+ mime_type,
532
+ f"Template artifact '{template_filename}' v{template_version} not found or empty.",
533
+ )
534
+
535
+ template_bytes = template_part.inline_data.data
536
+ try:
537
+ raw_template_string = template_bytes.decode("utf-8")
538
+ except UnicodeDecodeError:
539
+ return (
540
+ current_data,
541
+ mime_type,
542
+ f"Cannot render non-UTF-8 decodable binary template '{template_filename}' v{template_version}.",
543
+ )
544
+
545
+ except FileNotFoundError:
546
+ return (
547
+ current_data,
548
+ mime_type,
549
+ f"Template artifact '{template_filename}' v{template_version_str or 'latest'} not found.",
550
+ )
551
+ except ValueError as e:
552
+ return (
553
+ current_data,
554
+ mime_type,
555
+ f"Invalid version specified for template: '{template_version_str}' or other value error: {e}",
556
+ )
557
+ except Exception as e:
558
+ return (
559
+ current_data,
560
+ mime_type,
561
+ f"Error loading template artifact '{template_filename}' v{template_version_str or 'latest'}: {e}",
562
+ )
563
+
564
+ try:
565
+ log.info(
566
+ "%s [apply_to_template] Preparing render context. Input data type: %s, Original MIME: %s",
567
+ log_id,
568
+ type(current_data).__name__,
569
+ mime_type,
570
+ )
571
+ render_context: Dict[str, Any]
572
+
573
+ if isinstance(current_data, list):
574
+ if mime_type and "csv" in mime_type.lower():
575
+ log.info(
576
+ "%s [apply_to_template] Input is a list and original MIME is CSV. Structuring context with 'headers' and 'data_rows'.",
577
+ log_id,
578
+ )
579
+ if not current_data:
580
+ render_context = {"headers": [], "data_rows": []}
581
+ else:
582
+ if all(isinstance(item, dict) for item in current_data):
583
+ headers = list(current_data[0].keys()) if current_data else []
584
+ data_rows = [list(row.values()) for row in current_data]
585
+ render_context = {"headers": headers, "data_rows": data_rows}
586
+ else:
587
+ log.warning(
588
+ "%s [apply_to_template] Input is list from CSV, but items are not all dictionaries. Falling back to 'items' context.",
589
+ log_id,
590
+ )
591
+ render_context = {"items": current_data}
592
+ else:
593
+ log.info(
594
+ "%s [apply_to_template] Input is a list (from JSON/YAML). Data available under 'items' key.",
595
+ log_id,
596
+ )
597
+ render_context = {"items": current_data}
598
+ elif isinstance(current_data, dict):
599
+ render_context = current_data
600
+ log.info(
601
+ "%s [apply_to_template] Input is dict. Keys directly available in template.",
602
+ log_id,
603
+ )
604
+ elif isinstance(current_data, str):
605
+ render_context = {"text": current_data}
606
+ log.info(
607
+ "%s [apply_to_template] Input is string. Data available under 'text' key.",
608
+ log_id,
609
+ )
610
+ else:
611
+ log.warning(
612
+ "%s [apply_to_template] Input is unexpected type %s. Converting to string and placing under 'value' key.",
613
+ log_id,
614
+ type(current_data).__name__,
615
+ )
616
+ render_context = {"value": str(current_data)}
617
+
618
+ log.info(
619
+ "%s [apply_to_template] Render context keys: %s",
620
+ log_id,
621
+ list(render_context.keys()),
622
+ )
623
+ if "items" in render_context and isinstance(render_context["items"], list):
624
+ log.info(
625
+ "%s [apply_to_template] Render context 'items' length: %d",
626
+ log_id,
627
+ len(render_context["items"]),
628
+ )
629
+
630
+ intermediate_rendered_string = pystache.render(
631
+ raw_template_string, render_context
632
+ )
633
+ log.debug(
634
+ "%s [apply_to_template] Intermediate rendered string: %s",
635
+ log_id,
636
+ intermediate_rendered_string[:200] + "...",
637
+ )
638
+
639
+ except Exception as e:
640
+ return (
641
+ current_data,
642
+ mime_type,
643
+ f"Error preparing context or rendering template '{template_filename}' v{template_version}: {e}",
644
+ )
645
+
646
+ try:
647
+ log.debug(
648
+ "%s [apply_to_template] Resolving embeds on rendered template output.",
649
+ log_id,
650
+ )
651
+ resolver_config = context.get("config", {})
652
+ if not resolver_config:
653
+ log.warning(
654
+ "%s 'config' not found in context for template embed resolution. Using defaults.",
655
+ log_id,
656
+ )
657
+
658
+ final_rendered_string = await resolve_embeds_recursively_in_string(
659
+ text=intermediate_rendered_string,
660
+ context=context,
661
+ resolver_func=evaluate_embed,
662
+ types_to_resolve=EARLY_EMBED_TYPES.union(LATE_EMBED_TYPES),
663
+ log_identifier=f"{log_id}[TemplateEmbeds]",
664
+ config=resolver_config,
665
+ max_depth=resolver_config.get("gateway_recursive_embed_depth", 12),
666
+ current_depth=0,
667
+ visited_artifacts=set(),
668
+ accumulated_size=0,
669
+ max_total_size=resolver_config.get(
670
+ "gateway_max_artifact_resolve_size_bytes", -1
671
+ ),
672
+ )
673
+ log.debug(
674
+ "%s [apply_to_template] Final rendered string after embed resolution: %s",
675
+ log_id,
676
+ final_rendered_string[:200] + "...",
677
+ )
678
+ except Exception as recurse_err:
679
+ log.exception(
680
+ "%s Error during recursive resolution of rendered template: %s",
681
+ log_id,
682
+ recurse_err,
683
+ )
684
+ return (
685
+ current_data,
686
+ mime_type,
687
+ f"Error resolving embeds within rendered template: {recurse_err}",
688
+ )
689
+
690
+ return final_rendered_string, mime_type, None
691
+
692
+
693
+ MODIFIER_IMPLEMENTATIONS: Dict[
694
+ str, Callable[..., Tuple[Any, Optional[str], Optional[str]]]
695
+ ] = {
696
+ "jsonpath": _apply_jsonpath,
697
+ "select_cols": _apply_select_cols,
698
+ "filter_rows_eq": _apply_filter_rows_eq,
699
+ "slice_rows": _apply_slice_rows,
700
+ "slice_lines": _apply_slice_lines,
701
+ "grep": _apply_grep,
702
+ "head": _apply_head,
703
+ "tail": _apply_tail,
704
+ "select_fields": _apply_select_fields,
705
+ "apply_to_template": _apply_template,
706
+ }
707
+
708
+ MODIFIER_DEFINITIONS: Dict[str, Dict[str, Any]] = {
709
+ "jsonpath": {
710
+ "function": _apply_jsonpath,
711
+ "accepts": [DataFormat.JSON_OBJECT],
712
+ "produces": DataFormat.JSON_OBJECT,
713
+ },
714
+ "select_cols": {
715
+ "function": _apply_select_cols,
716
+ "accepts": [DataFormat.LIST_OF_DICTS],
717
+ "produces": DataFormat.LIST_OF_DICTS,
718
+ },
719
+ "filter_rows_eq": {
720
+ "function": _apply_filter_rows_eq,
721
+ "accepts": [DataFormat.LIST_OF_DICTS],
722
+ "produces": DataFormat.LIST_OF_DICTS,
723
+ },
724
+ "slice_rows": {
725
+ "function": _apply_slice_rows,
726
+ "accepts": [DataFormat.LIST_OF_DICTS],
727
+ "produces": DataFormat.LIST_OF_DICTS,
728
+ },
729
+ "slice_lines": {
730
+ "function": _apply_slice_lines,
731
+ "accepts": [DataFormat.STRING],
732
+ "produces": DataFormat.STRING,
733
+ },
734
+ "grep": {
735
+ "function": _apply_grep,
736
+ "accepts": [DataFormat.STRING],
737
+ "produces": DataFormat.STRING,
738
+ },
739
+ "head": {
740
+ "function": _apply_head,
741
+ "accepts": [DataFormat.STRING],
742
+ "produces": DataFormat.STRING,
743
+ },
744
+ "tail": {
745
+ "function": _apply_tail,
746
+ "accepts": [DataFormat.STRING],
747
+ "produces": DataFormat.STRING,
748
+ },
749
+ "select_fields": {
750
+ "function": _apply_select_fields,
751
+ "accepts": [DataFormat.LIST_OF_DICTS],
752
+ "produces": DataFormat.LIST_OF_DICTS,
753
+ },
754
+ "apply_to_template": {
755
+ "function": _apply_template,
756
+ "accepts": [
757
+ DataFormat.JSON_OBJECT,
758
+ DataFormat.LIST_OF_DICTS,
759
+ DataFormat.STRING,
760
+ ],
761
+ "produces": DataFormat.STRING,
762
+ },
763
+ }
764
+
765
+
766
+ def _parse_modifier_chain(
767
+ expression: str,
768
+ ) -> Tuple[str, List[Tuple[str, str]], Optional[str]]:
769
+ """
770
+ Parses the expression part of an artifact_content embed.
771
+
772
+ Separates the artifact specifier, modifier chain, and final format specifier.
773
+
774
+ Args:
775
+ expression: The full expression string after 'artifact_content:'.
776
+
777
+ Returns:
778
+ A tuple containing:
779
+ - artifact_spec (str): The filename and optional version (e.g., "data.csv:1").
780
+ - modifiers (List[Tuple[str, str]]): A list of (prefix, value) tuples for modifiers.
781
+ - output_format (Optional[str]): The final output format string (e.g., "text", "json").
782
+ Returns None if the format step is missing or invalid.
783
+ """
784
+ from .constants import EMBED_CHAIN_DELIMITER
785
+
786
+ parts = expression.split(EMBED_CHAIN_DELIMITER)
787
+ if not parts:
788
+ return expression, [], None
789
+
790
+ artifact_spec = parts[0].strip()
791
+ modifiers = []
792
+ output_format = None
793
+
794
+ for i in range(1, len(parts)):
795
+ part = parts[i].strip()
796
+ if not part:
797
+ continue
798
+
799
+ if i == len(parts) - 1:
800
+ format_match = re.match(r"format:(.*)", part, re.DOTALL)
801
+ if format_match:
802
+ output_format = format_match.group(1).strip()
803
+ continue
804
+
805
+ modifier_parts = part.split(":", 1)
806
+ if len(modifier_parts) == 2:
807
+ prefix = modifier_parts[0].strip()
808
+ value = modifier_parts[1].strip()
809
+ if prefix and value:
810
+ modifiers.append((prefix, value))
811
+ else:
812
+ log.warning("Ignoring invalid modifier step format: '%s'", part)
813
+ else:
814
+ log.warning("Ignoring invalid modifier step format: '%s'", part)
815
+
816
+ return artifact_spec, modifiers, output_format