rasa-pro 3.14.0.dev20250922__py3-none-any.whl → 3.14.0rc1__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 rasa-pro might be problematic. Click here for more details.

Files changed (290) hide show
  1. rasa/__main__.py +15 -3
  2. rasa/agents/__init__.py +0 -0
  3. rasa/agents/agent_factory.py +122 -0
  4. rasa/agents/agent_manager.py +211 -0
  5. rasa/agents/constants.py +43 -0
  6. rasa/agents/core/__init__.py +0 -0
  7. rasa/agents/core/agent_protocol.py +107 -0
  8. rasa/agents/core/types.py +81 -0
  9. rasa/agents/exceptions.py +38 -0
  10. rasa/agents/protocol/__init__.py +5 -0
  11. rasa/agents/protocol/a2a/__init__.py +0 -0
  12. rasa/agents/protocol/a2a/a2a_agent.py +879 -0
  13. rasa/agents/protocol/mcp/__init__.py +0 -0
  14. rasa/agents/protocol/mcp/mcp_base_agent.py +726 -0
  15. rasa/agents/protocol/mcp/mcp_open_agent.py +327 -0
  16. rasa/agents/protocol/mcp/mcp_task_agent.py +522 -0
  17. rasa/agents/schemas/__init__.py +13 -0
  18. rasa/agents/schemas/agent_input.py +38 -0
  19. rasa/agents/schemas/agent_output.py +26 -0
  20. rasa/agents/schemas/agent_tool_result.py +65 -0
  21. rasa/agents/schemas/agent_tool_schema.py +186 -0
  22. rasa/agents/templates/__init__.py +0 -0
  23. rasa/agents/templates/mcp_open_agent_prompt_template.jinja2 +20 -0
  24. rasa/agents/templates/mcp_task_agent_prompt_template.jinja2 +22 -0
  25. rasa/agents/utils.py +206 -0
  26. rasa/agents/validation.py +485 -0
  27. rasa/api.py +24 -9
  28. rasa/builder/config.py +6 -2
  29. rasa/builder/guardrails/{lakera.py → clients.py} +55 -5
  30. rasa/builder/guardrails/constants.py +3 -0
  31. rasa/builder/guardrails/models.py +45 -10
  32. rasa/builder/guardrails/policy_checker.py +324 -0
  33. rasa/builder/guardrails/utils.py +42 -276
  34. rasa/builder/llm_service.py +32 -5
  35. rasa/builder/models.py +1 -0
  36. rasa/builder/project_generator.py +6 -1
  37. rasa/builder/service.py +16 -13
  38. rasa/builder/training_service.py +18 -24
  39. rasa/builder/validation_service.py +1 -1
  40. rasa/cli/arguments/default_arguments.py +12 -0
  41. rasa/cli/arguments/run.py +2 -0
  42. rasa/cli/arguments/train.py +2 -0
  43. rasa/cli/data.py +10 -8
  44. rasa/cli/dialogue_understanding_test.py +10 -7
  45. rasa/cli/e2e_test.py +9 -6
  46. rasa/cli/evaluate.py +4 -2
  47. rasa/cli/export.py +5 -2
  48. rasa/cli/inspect.py +8 -4
  49. rasa/cli/interactive.py +5 -4
  50. rasa/cli/llm_fine_tuning.py +11 -6
  51. rasa/cli/project_templates/tutorial/credentials.yml +10 -0
  52. rasa/cli/run.py +12 -10
  53. rasa/cli/scaffold.py +4 -4
  54. rasa/cli/shell.py +9 -5
  55. rasa/cli/studio/studio.py +1 -1
  56. rasa/cli/test.py +34 -14
  57. rasa/cli/train.py +41 -28
  58. rasa/cli/utils.py +1 -393
  59. rasa/cli/validation/__init__.py +0 -0
  60. rasa/cli/validation/bot_config.py +223 -0
  61. rasa/cli/validation/config_path_validation.py +257 -0
  62. rasa/cli/x.py +8 -4
  63. rasa/constants.py +7 -1
  64. rasa/core/actions/action.py +51 -10
  65. rasa/core/actions/grpc_custom_action_executor.py +1 -1
  66. rasa/core/agent.py +19 -2
  67. rasa/core/available_agents.py +229 -0
  68. rasa/core/channels/__init__.py +82 -35
  69. rasa/core/channels/development_inspector.py +3 -3
  70. rasa/core/channels/inspector/README.md +25 -13
  71. rasa/core/channels/inspector/dist/assets/{arc-35222594.js → arc-6177260a.js} +1 -1
  72. rasa/core/channels/inspector/dist/assets/{blockDiagram-38ab4fdb-a0efbfd3.js → blockDiagram-38ab4fdb-b054f038.js} +1 -1
  73. rasa/core/channels/inspector/dist/assets/{c4Diagram-3d4e48cf-0584c0f2.js → c4Diagram-3d4e48cf-f25427d5.js} +1 -1
  74. rasa/core/channels/inspector/dist/assets/channel-bf9cbb34.js +1 -0
  75. rasa/core/channels/inspector/dist/assets/{classDiagram-70f12bd4-39f40dbe.js → classDiagram-70f12bd4-c7a2af53.js} +1 -1
  76. rasa/core/channels/inspector/dist/assets/{classDiagram-v2-f2320105-1ad755f3.js → classDiagram-v2-f2320105-58db65c0.js} +1 -1
  77. rasa/core/channels/inspector/dist/assets/clone-8f9083bb.js +1 -0
  78. rasa/core/channels/inspector/dist/assets/{createText-2e5e7dd3-b0f4f0fe.js → createText-2e5e7dd3-088372e2.js} +1 -1
  79. rasa/core/channels/inspector/dist/assets/{edges-e0da2a9e-9039bff9.js → edges-e0da2a9e-58676240.js} +1 -1
  80. rasa/core/channels/inspector/dist/assets/{erDiagram-9861fffd-65c9b127.js → erDiagram-9861fffd-0c14d7c6.js} +1 -1
  81. rasa/core/channels/inspector/dist/assets/{flowDb-956e92f1-4f08b38e.js → flowDb-956e92f1-ea63f85c.js} +1 -1
  82. rasa/core/channels/inspector/dist/assets/{flowDiagram-66a62f08-e95c362a.js → flowDiagram-66a62f08-a2af48cd.js} +1 -1
  83. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-9ecd5b59.js +1 -0
  84. rasa/core/channels/inspector/dist/assets/{flowchart-elk-definition-4a651766-703c3015.js → flowchart-elk-definition-4a651766-6937abe7.js} +1 -1
  85. rasa/core/channels/inspector/dist/assets/{ganttDiagram-c361ad54-699328ea.js → ganttDiagram-c361ad54-7473f357.js} +1 -1
  86. rasa/core/channels/inspector/dist/assets/{gitGraphDiagram-72cf32ee-04cf4b05.js → gitGraphDiagram-72cf32ee-d0c9405e.js} +1 -1
  87. rasa/core/channels/inspector/dist/assets/{graph-ee94449e.js → graph-0a6f8466.js} +1 -1
  88. rasa/core/channels/inspector/dist/assets/{index-3862675e-940162b4.js → index-3862675e-7610671a.js} +1 -1
  89. rasa/core/channels/inspector/dist/assets/index-74e01d94.js +1354 -0
  90. rasa/core/channels/inspector/dist/assets/{infoDiagram-f8f76790-c79c2866.js → infoDiagram-f8f76790-be397dc7.js} +1 -1
  91. rasa/core/channels/inspector/dist/assets/{journeyDiagram-49397b02-84489d30.js → journeyDiagram-49397b02-4cefbf62.js} +1 -1
  92. rasa/core/channels/inspector/dist/assets/{layout-a9aa9858.js → layout-e7fbc2bf.js} +1 -1
  93. rasa/core/channels/inspector/dist/assets/{line-eb73cf26.js → line-a8aa457c.js} +1 -1
  94. rasa/core/channels/inspector/dist/assets/{linear-b3399f9a.js → linear-3351e0d2.js} +1 -1
  95. rasa/core/channels/inspector/dist/assets/{mindmap-definition-fc14e90a-b095bf1a.js → mindmap-definition-fc14e90a-b8cbf605.js} +1 -1
  96. rasa/core/channels/inspector/dist/assets/{pieDiagram-8a3498a8-07644b66.js → pieDiagram-8a3498a8-f327f774.js} +1 -1
  97. rasa/core/channels/inspector/dist/assets/{quadrantDiagram-120e2f19-573a3f9c.js → quadrantDiagram-120e2f19-2854c591.js} +1 -1
  98. rasa/core/channels/inspector/dist/assets/{requirementDiagram-deff3bca-d457e1e1.js → requirementDiagram-deff3bca-964985d5.js} +1 -1
  99. rasa/core/channels/inspector/dist/assets/{sankeyDiagram-04a897e0-9d26e1a2.js → sankeyDiagram-04a897e0-edeb4f33.js} +1 -1
  100. rasa/core/channels/inspector/dist/assets/{sequenceDiagram-704730f1-3a9cde10.js → sequenceDiagram-704730f1-fcf70125.js} +1 -1
  101. rasa/core/channels/inspector/dist/assets/{stateDiagram-587899a1-4f3e8cec.js → stateDiagram-587899a1-0e770395.js} +1 -1
  102. rasa/core/channels/inspector/dist/assets/{stateDiagram-v2-d93cdb3a-e617e5bf.js → stateDiagram-v2-d93cdb3a-af8dcd22.js} +1 -1
  103. rasa/core/channels/inspector/dist/assets/{styles-6aaf32cf-eab30d2f.js → styles-6aaf32cf-36a9e70d.js} +1 -1
  104. rasa/core/channels/inspector/dist/assets/{styles-9a916d00-09994be2.js → styles-9a916d00-884a8b5b.js} +1 -1
  105. rasa/core/channels/inspector/dist/assets/{styles-c10674c1-b7110364.js → styles-c10674c1-dc097813.js} +1 -1
  106. rasa/core/channels/inspector/dist/assets/{svgDrawCommon-08f97a94-3ebc92ad.js → svgDrawCommon-08f97a94-5a2c7eed.js} +1 -1
  107. rasa/core/channels/inspector/dist/assets/{timeline-definition-85554ec2-7d13d2f2.js → timeline-definition-85554ec2-e89c4f6e.js} +1 -1
  108. rasa/core/channels/inspector/dist/assets/{xychartDiagram-e933f94c-488385e1.js → xychartDiagram-e933f94c-afb6fe56.js} +1 -1
  109. rasa/core/channels/inspector/dist/index.html +1 -1
  110. rasa/core/channels/inspector/package.json +18 -18
  111. rasa/core/channels/inspector/src/App.tsx +29 -4
  112. rasa/core/channels/inspector/src/components/DialogueAgentStack.tsx +108 -0
  113. rasa/core/channels/inspector/src/components/{DialogueStack.tsx → DialogueHistoryStack.tsx} +4 -2
  114. rasa/core/channels/inspector/src/helpers/audio/audiostream.ts +7 -4
  115. rasa/core/channels/inspector/src/helpers/formatters.test.ts +4 -0
  116. rasa/core/channels/inspector/src/helpers/formatters.ts +24 -3
  117. rasa/core/channels/inspector/src/helpers/utils.test.ts +127 -0
  118. rasa/core/channels/inspector/src/helpers/utils.ts +66 -1
  119. rasa/core/channels/inspector/src/theme/base/styles.ts +19 -1
  120. rasa/core/channels/inspector/src/types.ts +21 -0
  121. rasa/core/channels/inspector/yarn.lock +336 -189
  122. rasa/core/channels/studio_chat.py +6 -6
  123. rasa/core/channels/telegram.py +4 -9
  124. rasa/core/channels/voice_stream/genesys.py +1 -1
  125. rasa/core/channels/voice_stream/tts/deepgram.py +140 -0
  126. rasa/core/channels/voice_stream/twilio_media_streams.py +5 -1
  127. rasa/core/channels/voice_stream/voice_channel.py +3 -0
  128. rasa/core/config/__init__.py +0 -0
  129. rasa/core/{available_endpoints.py → config/available_endpoints.py} +51 -16
  130. rasa/core/config/configuration.py +260 -0
  131. rasa/core/config/credentials.py +19 -0
  132. rasa/core/config/message_procesing_config.py +34 -0
  133. rasa/core/constants.py +4 -0
  134. rasa/core/policies/enterprise_search_policy.py +5 -3
  135. rasa/core/policies/flow_policy.py +4 -4
  136. rasa/core/policies/flows/agent_executor.py +632 -0
  137. rasa/core/policies/flows/flow_executor.py +136 -75
  138. rasa/core/policies/flows/mcp_tool_executor.py +298 -0
  139. rasa/core/policies/intentless_policy.py +1 -1
  140. rasa/core/policies/ted_policy.py +20 -12
  141. rasa/core/policies/unexpected_intent_policy.py +6 -0
  142. rasa/core/processor.py +68 -44
  143. rasa/core/run.py +37 -8
  144. rasa/core/test.py +4 -0
  145. rasa/core/tracker_stores/tracker_store.py +3 -7
  146. rasa/core/train.py +1 -1
  147. rasa/core/training/interactive.py +20 -18
  148. rasa/core/training/story_conflict.py +5 -5
  149. rasa/core/utils.py +22 -23
  150. rasa/dialogue_understanding/commands/__init__.py +8 -0
  151. rasa/dialogue_understanding/commands/cancel_flow_command.py +19 -5
  152. rasa/dialogue_understanding/commands/chit_chat_answer_command.py +21 -2
  153. rasa/dialogue_understanding/commands/clarify_command.py +20 -2
  154. rasa/dialogue_understanding/commands/continue_agent_command.py +91 -0
  155. rasa/dialogue_understanding/commands/knowledge_answer_command.py +21 -2
  156. rasa/dialogue_understanding/commands/restart_agent_command.py +162 -0
  157. rasa/dialogue_understanding/commands/start_flow_command.py +68 -7
  158. rasa/dialogue_understanding/commands/utils.py +124 -2
  159. rasa/dialogue_understanding/generator/command_parser.py +4 -0
  160. rasa/dialogue_understanding/generator/llm_based_command_generator.py +50 -12
  161. rasa/dialogue_understanding/generator/llm_command_generator.py +1 -1
  162. rasa/dialogue_understanding/generator/multi_step/multi_step_llm_command_generator.py +1 -1
  163. rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v2_claude_3_5_sonnet_20240620_template.jinja2 +66 -0
  164. rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v2_gpt_4o_2024_11_20_template.jinja2 +66 -0
  165. rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v3_claude_3_5_sonnet_20240620_template.jinja2 +89 -0
  166. rasa/dialogue_understanding/generator/prompt_templates/agent_command_prompt_v3_gpt_4o_2024_11_20_template.jinja2 +88 -0
  167. rasa/dialogue_understanding/generator/single_step/compact_llm_command_generator.py +42 -7
  168. rasa/dialogue_understanding/generator/single_step/search_ready_llm_command_generator.py +40 -3
  169. rasa/dialogue_understanding/generator/single_step/single_step_based_llm_command_generator.py +20 -3
  170. rasa/dialogue_understanding/patterns/cancel.py +27 -6
  171. rasa/dialogue_understanding/patterns/clarify.py +3 -14
  172. rasa/dialogue_understanding/patterns/continue_interrupted.py +239 -6
  173. rasa/dialogue_understanding/patterns/default_flows_for_patterns.yml +46 -8
  174. rasa/dialogue_understanding/processor/command_processor.py +136 -15
  175. rasa/dialogue_understanding/stack/dialogue_stack.py +98 -2
  176. rasa/dialogue_understanding/stack/frames/flow_stack_frame.py +57 -0
  177. rasa/dialogue_understanding/stack/utils.py +57 -3
  178. rasa/dialogue_understanding/utils.py +24 -4
  179. rasa/dialogue_understanding_test/du_test_runner.py +8 -3
  180. rasa/e2e_test/e2e_test_runner.py +13 -3
  181. rasa/engine/caching.py +2 -2
  182. rasa/engine/constants.py +1 -1
  183. rasa/engine/recipes/default_components.py +138 -49
  184. rasa/engine/recipes/default_recipe.py +108 -11
  185. rasa/engine/runner/dask.py +8 -5
  186. rasa/engine/validation.py +19 -6
  187. rasa/graph_components/validators/default_recipe_validator.py +86 -28
  188. rasa/hooks.py +5 -5
  189. rasa/llm_fine_tuning/utils.py +2 -2
  190. rasa/model_training.py +60 -47
  191. rasa/nlu/classifiers/diet_classifier.py +198 -98
  192. rasa/nlu/classifiers/logistic_regression_classifier.py +1 -4
  193. rasa/nlu/classifiers/mitie_intent_classifier.py +3 -0
  194. rasa/nlu/classifiers/sklearn_intent_classifier.py +1 -3
  195. rasa/nlu/extractors/crf_entity_extractor.py +9 -10
  196. rasa/nlu/extractors/mitie_entity_extractor.py +3 -0
  197. rasa/nlu/extractors/spacy_entity_extractor.py +3 -0
  198. rasa/nlu/featurizers/dense_featurizer/convert_featurizer.py +4 -0
  199. rasa/nlu/featurizers/dense_featurizer/lm_featurizer.py +5 -0
  200. rasa/nlu/featurizers/dense_featurizer/mitie_featurizer.py +2 -0
  201. rasa/nlu/featurizers/dense_featurizer/spacy_featurizer.py +3 -0
  202. rasa/nlu/featurizers/sparse_featurizer/count_vectors_featurizer.py +4 -2
  203. rasa/nlu/featurizers/sparse_featurizer/lexical_syntactic_featurizer.py +4 -0
  204. rasa/nlu/selectors/response_selector.py +10 -2
  205. rasa/nlu/tokenizers/jieba_tokenizer.py +3 -4
  206. rasa/nlu/tokenizers/mitie_tokenizer.py +3 -2
  207. rasa/nlu/tokenizers/spacy_tokenizer.py +3 -2
  208. rasa/nlu/utils/mitie_utils.py +3 -0
  209. rasa/nlu/utils/spacy_utils.py +3 -2
  210. rasa/plugin.py +8 -8
  211. rasa/privacy/privacy_manager.py +12 -3
  212. rasa/server.py +15 -3
  213. rasa/shared/agents/__init__.py +0 -0
  214. rasa/shared/agents/auth/__init__.py +0 -0
  215. rasa/shared/agents/auth/agent_auth_factory.py +105 -0
  216. rasa/shared/agents/auth/agent_auth_manager.py +92 -0
  217. rasa/shared/agents/auth/auth_strategy/__init__.py +19 -0
  218. rasa/shared/agents/auth/auth_strategy/agent_auth_strategy.py +52 -0
  219. rasa/shared/agents/auth/auth_strategy/api_key_auth_strategy.py +42 -0
  220. rasa/shared/agents/auth/auth_strategy/bearer_token_auth_strategy.py +28 -0
  221. rasa/shared/agents/auth/auth_strategy/oauth2_auth_strategy.py +167 -0
  222. rasa/shared/agents/auth/constants.py +12 -0
  223. rasa/shared/agents/auth/types.py +12 -0
  224. rasa/shared/agents/utils.py +35 -0
  225. rasa/shared/constants.py +8 -0
  226. rasa/shared/core/constants.py +16 -1
  227. rasa/shared/core/domain.py +0 -7
  228. rasa/shared/core/events.py +327 -0
  229. rasa/shared/core/flows/constants.py +5 -0
  230. rasa/shared/core/flows/flows_list.py +21 -5
  231. rasa/shared/core/flows/flows_yaml_schema.json +119 -184
  232. rasa/shared/core/flows/steps/call.py +49 -5
  233. rasa/shared/core/flows/steps/collect.py +98 -13
  234. rasa/shared/core/flows/validation.py +372 -8
  235. rasa/shared/core/flows/yaml_flows_io.py +3 -2
  236. rasa/shared/core/slots.py +2 -2
  237. rasa/shared/core/trackers.py +5 -2
  238. rasa/shared/exceptions.py +16 -0
  239. rasa/shared/importers/rasa.py +1 -1
  240. rasa/shared/importers/utils.py +9 -3
  241. rasa/shared/providers/llm/_base_litellm_client.py +41 -9
  242. rasa/shared/providers/llm/litellm_router_llm_client.py +8 -4
  243. rasa/shared/providers/llm/llm_client.py +7 -3
  244. rasa/shared/providers/llm/llm_response.py +66 -0
  245. rasa/shared/providers/llm/self_hosted_llm_client.py +8 -4
  246. rasa/shared/utils/common.py +24 -0
  247. rasa/shared/utils/health_check/health_check.py +7 -3
  248. rasa/shared/utils/llm.py +39 -16
  249. rasa/shared/utils/mcp/__init__.py +0 -0
  250. rasa/shared/utils/mcp/server_connection.py +247 -0
  251. rasa/shared/utils/mcp/utils.py +20 -0
  252. rasa/shared/utils/schemas/events.py +42 -0
  253. rasa/shared/utils/yaml.py +3 -1
  254. rasa/studio/pull/pull.py +3 -2
  255. rasa/studio/train.py +8 -7
  256. rasa/studio/upload.py +3 -6
  257. rasa/telemetry.py +69 -5
  258. rasa/tracing/config.py +45 -12
  259. rasa/tracing/constants.py +14 -0
  260. rasa/tracing/instrumentation/attribute_extractors.py +142 -9
  261. rasa/tracing/instrumentation/instrumentation.py +626 -21
  262. rasa/tracing/instrumentation/intentless_policy_instrumentation.py +4 -4
  263. rasa/tracing/instrumentation/metrics.py +32 -0
  264. rasa/tracing/metric_instrument_provider.py +68 -0
  265. rasa/utils/common.py +92 -1
  266. rasa/utils/endpoints.py +11 -2
  267. rasa/utils/log_utils.py +96 -5
  268. rasa/utils/ml_utils.py +1 -1
  269. rasa/utils/tensorflow/__init__.py +7 -0
  270. rasa/utils/tensorflow/callback.py +136 -101
  271. rasa/utils/tensorflow/crf.py +1 -1
  272. rasa/utils/tensorflow/data_generator.py +21 -8
  273. rasa/utils/tensorflow/layers.py +21 -11
  274. rasa/utils/tensorflow/metrics.py +7 -3
  275. rasa/utils/tensorflow/models.py +56 -8
  276. rasa/utils/tensorflow/rasa_layers.py +8 -6
  277. rasa/utils/tensorflow/transformer.py +2 -3
  278. rasa/utils/train_utils.py +54 -24
  279. rasa/validator.py +5 -5
  280. rasa/version.py +1 -1
  281. {rasa_pro-3.14.0.dev20250922.dist-info → rasa_pro-3.14.0rc1.dist-info}/METADATA +46 -41
  282. {rasa_pro-3.14.0.dev20250922.dist-info → rasa_pro-3.14.0rc1.dist-info}/RECORD +285 -226
  283. rasa/builder/scrape_rasa_docs.py +0 -97
  284. rasa/core/channels/inspector/dist/assets/channel-8e08bed9.js +0 -1
  285. rasa/core/channels/inspector/dist/assets/clone-78c82dea.js +0 -1
  286. rasa/core/channels/inspector/dist/assets/flowDiagram-v2-96b9c2cf-2b08f601.js +0 -1
  287. rasa/core/channels/inspector/dist/assets/index-c941dcb3.js +0 -1336
  288. {rasa_pro-3.14.0.dev20250922.dist-info → rasa_pro-3.14.0rc1.dist-info}/NOTICE +0 -0
  289. {rasa_pro-3.14.0.dev20250922.dist-info → rasa_pro-3.14.0rc1.dist-info}/WHEEL +0 -0
  290. {rasa_pro-3.14.0.dev20250922.dist-info → rasa_pro-3.14.0rc1.dist-info}/entry_points.txt +0 -0
@@ -47,7 +47,7 @@ import rasa.shared.utils.io
47
47
  import rasa.utils.io as io_utils
48
48
  from rasa import telemetry
49
49
  from rasa.core import run, utils
50
- from rasa.core.available_endpoints import AvailableEndpoints
50
+ from rasa.core.config.configuration import Configuration
51
51
  from rasa.core.constants import DEFAULT_SERVER_FORMAT, DEFAULT_SERVER_PORT
52
52
  from rasa.shared.constants import (
53
53
  DEFAULT_SENDER_ID,
@@ -91,7 +91,7 @@ from rasa.shared.core.training_data.visualization import (
91
91
  )
92
92
  from rasa.shared.exceptions import InvalidConfigException
93
93
  from rasa.shared.importers.rasa import TrainingDataImporter
94
- from rasa.shared.nlu.constants import INTENT_NAME_KEY, TEXT
94
+ from rasa.shared.nlu.constants import ENTITIES, INTENT, INTENT_NAME_KEY, TEXT
95
95
 
96
96
  # noinspection PyProtectedMember
97
97
  from rasa.shared.nlu.training_data import loading
@@ -789,7 +789,7 @@ def _collect_messages(events: List[Dict[Text, Any]]) -> List[Message]:
789
789
  data = event.get("parse_data", {})
790
790
  rasa_nlu_training_data_utils.remove_untrainable_entities_from(data)
791
791
  msg = Message.build(
792
- data["text"], data["intent"][INTENT_NAME_KEY], data["entities"]
792
+ data[TEXT], data[INTENT][INTENT_NAME_KEY], data[ENTITIES]
793
793
  )
794
794
  messages.append(msg)
795
795
  elif event.get("event") == UserUtteranceReverted.type_name and messages:
@@ -901,13 +901,13 @@ def _get_nlu_target_format(export_path: Text) -> Text:
901
901
 
902
902
  def _entities_from_messages(messages: List[Message]) -> List[Text]:
903
903
  """Return all entities that occur in at least one of the messages."""
904
- return list({e["entity"] for m in messages for e in m.data.get("entities", [])})
904
+ return list({e["entity"] for m in messages for e in m.data.get(ENTITIES, [])})
905
905
 
906
906
 
907
907
  def _intents_from_messages(messages: List[Message]) -> Set[Text]:
908
908
  """Return all intents that occur in at least one of the messages."""
909
909
  # set of distinct intents
910
- distinct_intents = {m.data["intent"] for m in messages if "intent" in m.data}
910
+ distinct_intents = {m.data[INTENT] for m in messages if INTENT in m.data}
911
911
 
912
912
  return distinct_intents
913
913
 
@@ -1191,11 +1191,11 @@ def _as_md_message(parse_data: Dict[Text, Any]) -> Text:
1191
1191
  """Display the parse data of a message in markdown format."""
1192
1192
  from rasa.shared.nlu.training_data.formats.readerwriter import TrainingDataWriter
1193
1193
 
1194
- if parse_data.get("text", "").startswith(INTENT_MESSAGE_PREFIX):
1195
- return parse_data["text"]
1194
+ if parse_data.get(TEXT, "").startswith(INTENT_MESSAGE_PREFIX):
1195
+ return parse_data[TEXT]
1196
1196
 
1197
- if not parse_data.get("entities"):
1198
- parse_data["entities"] = []
1197
+ if not parse_data.get(ENTITIES):
1198
+ parse_data[ENTITIES] = []
1199
1199
 
1200
1200
  return TrainingDataWriter.generate_message(parse_data)
1201
1201
 
@@ -1207,7 +1207,7 @@ def _validate_user_regex(latest_message: Dict[Text, Any], intents: List[Text]) -
1207
1207
  `/greet`. Return `True` if the intent is a known one.
1208
1208
  """
1209
1209
  parse_data = latest_message.get("parse_data", {})
1210
- intent = parse_data.get("intent", {}).get(INTENT_NAME_KEY)
1210
+ intent = parse_data.get(INTENT, {}).get(INTENT_NAME_KEY)
1211
1211
 
1212
1212
  if intent in intents:
1213
1213
  return True
@@ -1224,8 +1224,8 @@ async def _validate_user_text(
1224
1224
  """
1225
1225
  parse_data = latest_message.get("parse_data", {})
1226
1226
  text = _as_md_message(parse_data)
1227
- intent = parse_data.get("intent", {}).get(INTENT_NAME_KEY)
1228
- entities = parse_data.get("entities", [])
1227
+ intent = parse_data.get(INTENT, {}).get(INTENT_NAME_KEY)
1228
+ entities = parse_data.get(ENTITIES, [])
1229
1229
  if entities:
1230
1230
  message = (
1231
1231
  f"Is the intent '{intent}' correct for '{text}' and are "
@@ -1276,9 +1276,9 @@ async def _validate_nlu(
1276
1276
 
1277
1277
  entities = await _correct_entities(latest_message, endpoint, conversation_id)
1278
1278
  corrected_nlu = {
1279
- "intent": corrected_intent,
1280
- "entities": entities,
1281
- "text": latest_message.get("text"),
1279
+ INTENT: corrected_intent,
1280
+ ENTITIES: entities,
1281
+ TEXT: latest_message.get("text"),
1282
1282
  }
1283
1283
 
1284
1284
  await _correct_wrong_nlu(corrected_nlu, events, endpoint, conversation_id)
@@ -1315,9 +1315,9 @@ def _merge_annotated_and_original_entities(
1315
1315
  # overwrite entities which have already been
1316
1316
  # annotated in the original annotation to preserve
1317
1317
  # additional entity parser information
1318
- entities = parse_annotated.get("entities", [])[:]
1318
+ entities = parse_annotated.get(ENTITIES, [])[:]
1319
1319
  for i, entity in enumerate(entities):
1320
- for original_entity in parse_original.get("entities", []):
1320
+ for original_entity in parse_original.get(ENTITIES, []):
1321
1321
  if _is_same_entity_annotation(entity, original_entity):
1322
1322
  entities[i] = original_entity
1323
1323
  break
@@ -1687,7 +1687,9 @@ def run_interactive_learning(
1687
1687
  p = None
1688
1688
 
1689
1689
  app = run.configure_app(port=port, conversation_id="default", enable_api=True)
1690
- endpoints = AvailableEndpoints.get_instance(server_args.get("endpoints"))
1690
+ endpoints = Configuration.initialise_endpoints(
1691
+ endpoints_path=server_args.get("endpoints")
1692
+ ).endpoints
1691
1693
 
1692
1694
  # before_server_start handlers make sure the agent is loaded before the
1693
1695
  # interactive learning IO starts
@@ -14,7 +14,7 @@ from rasa.shared.core.constants import (
14
14
  from rasa.shared.core.domain import Domain, State
15
15
  from rasa.shared.core.events import ActionExecuted, Event
16
16
  from rasa.shared.core.generator import TrackerWithCachedStates
17
- from rasa.shared.nlu.constants import TEXT
17
+ from rasa.shared.nlu.constants import INTENT, TEXT
18
18
  from rasa.shared.nlu.training_data.message import Message
19
19
 
20
20
  logger = logging.getLogger(__name__)
@@ -362,12 +362,12 @@ def _get_previous_event(
362
362
  previous_event_type = "bot utterance"
363
363
  previous_event_name = state[PREVIOUS_ACTION]["action_text"]
364
364
  elif USER in state.keys():
365
- if "intent" in state[USER]:
365
+ if INTENT in state[USER]:
366
366
  previous_event_type = "intent"
367
- previous_event_name = state[USER]["intent"]
368
- elif "text" in state[USER]:
367
+ previous_event_name = state[USER][INTENT]
368
+ elif TEXT in state[USER]:
369
369
  previous_event_type = "user utterance"
370
- previous_event_name = state[USER]["text"]
370
+ previous_event_name = state[USER][TEXT]
371
371
 
372
372
  if not isinstance(previous_event_name, (str, type(None))):
373
373
  # While the Substate type doesn't restrict the value of `action_text` /
rasa/core/utils.py CHANGED
@@ -1,17 +1,16 @@
1
1
  import logging
2
2
  import os
3
+ import re
3
4
  from pathlib import Path
4
5
  from socket import SOCK_DGRAM, SOCK_STREAM
5
- from typing import TYPE_CHECKING, Any, Dict, Optional, Set, Text, Tuple, Union
6
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Text, Tuple, Union
6
7
 
7
8
  import numpy as np
8
9
  import structlog
9
10
  from sanic import Sanic
10
11
 
11
- import rasa.cli.utils as cli_utils
12
12
  import rasa.shared.utils.io
13
13
  from rasa.constants import DEFAULT_SANIC_WORKERS, ENV_SANIC_WORKERS
14
- from rasa.core.available_endpoints import AvailableEndpoints
15
14
  from rasa.core.constants import (
16
15
  ACTIVE_FLOW_METADATA_KEY,
17
16
  DOMAIN_GROUND_TRUTH_METADATA_KEY,
@@ -19,7 +18,7 @@ from rasa.core.constants import (
19
18
  UTTER_SOURCE_METADATA_KEY,
20
19
  )
21
20
  from rasa.core.lock_store import InMemoryLockStore, LockStore, RedisLockStore
22
- from rasa.shared.constants import DEFAULT_ENDPOINTS_PATH, TCP_PROTOCOL
21
+ from rasa.shared.constants import TCP_PROTOCOL
23
22
  from rasa.shared.core.constants import (
24
23
  SlotMappingType,
25
24
  )
@@ -37,25 +36,6 @@ if TYPE_CHECKING:
37
36
  structlogger = structlog.get_logger()
38
37
 
39
38
 
40
- def read_endpoints_from_path(
41
- endpoints_path: Optional[Union[Path, str]] = None,
42
- ) -> AvailableEndpoints:
43
- """Get `AvailableEndpoints` object from specified path.
44
-
45
- Args:
46
- endpoints_path: Path of the endpoints file to be read. If `None` the
47
- default path for that file is used (`endpoints.yml`).
48
-
49
- Returns:
50
- `AvailableEndpoints` object read from endpoints file.
51
-
52
- """
53
- endpoints_config_path = cli_utils.get_validated_path(
54
- endpoints_path, "endpoints", DEFAULT_ENDPOINTS_PATH, True
55
- )
56
- return AvailableEndpoints.get_instance(endpoints_config_path)
57
-
58
-
59
39
  def configure_file_logging(
60
40
  logger_obj: logging.Logger,
61
41
  log_file: Optional[Text],
@@ -359,3 +339,22 @@ def should_force_slot_filling(
359
339
  return True, slot_name
360
340
 
361
341
  return False, None
342
+
343
+
344
+ def get_slot_names_from_exit_conditions(exit_conditions: List[str]) -> List[str]:
345
+ """Extract slot names from exit conditions.
346
+
347
+ Args:
348
+ exit_conditions: The exit conditions to extract slot names from.
349
+
350
+ Returns:
351
+ A list of slot names.
352
+ """
353
+ # Find all unique names matching "slots.<name>"
354
+ return list(
355
+ {
356
+ name
357
+ for condition in exit_conditions
358
+ for name in re.findall(r"\bslots\.(\w+)", condition)
359
+ }
360
+ )
@@ -8,6 +8,9 @@ from rasa.dialogue_understanding.commands.chit_chat_answer_command import (
8
8
  )
9
9
  from rasa.dialogue_understanding.commands.clarify_command import ClarifyCommand
10
10
  from rasa.dialogue_understanding.commands.command import Command
11
+ from rasa.dialogue_understanding.commands.continue_agent_command import (
12
+ ContinueAgentCommand,
13
+ )
11
14
  from rasa.dialogue_understanding.commands.correct_slots_command import (
12
15
  CorrectedSlot,
13
16
  CorrectSlotsCommand,
@@ -29,6 +32,9 @@ from rasa.dialogue_understanding.commands.noop_command import NoopCommand
29
32
  from rasa.dialogue_understanding.commands.repeat_bot_messages_command import (
30
33
  RepeatBotMessagesCommand,
31
34
  )
35
+ from rasa.dialogue_understanding.commands.restart_agent_command import (
36
+ RestartAgentCommand,
37
+ )
32
38
  from rasa.dialogue_understanding.commands.restart_command import RestartCommand
33
39
  from rasa.dialogue_understanding.commands.session_end_command import SessionEndCommand
34
40
  from rasa.dialogue_understanding.commands.session_start_command import (
@@ -62,4 +68,6 @@ __all__ = [
62
68
  "SessionEndCommand",
63
69
  "RepeatBotMessagesCommand",
64
70
  "RestartCommand",
71
+ "ContinueAgentCommand",
72
+ "RestartAgentCommand",
65
73
  ]
@@ -6,6 +6,9 @@ from typing import Any, Dict, List
6
6
 
7
7
  import structlog
8
8
 
9
+ from rasa.core.policies.flows.agent_executor import (
10
+ remove_agent_stack_frame,
11
+ )
9
12
  from rasa.dialogue_understanding.commands.command import Command
10
13
  from rasa.dialogue_understanding.commands.command_syntax_manager import (
11
14
  CommandSyntaxManager,
@@ -18,7 +21,7 @@ from rasa.dialogue_understanding.stack.frames.flow_stack_frame import (
18
21
  UserFlowStackFrame,
19
22
  )
20
23
  from rasa.dialogue_understanding.stack.utils import top_user_flow_frame
21
- from rasa.shared.core.events import Event, FlowCancelled
24
+ from rasa.shared.core.events import AgentCancelled, Event, FlowCancelled
22
25
  from rasa.shared.core.flows import FlowsList
23
26
  from rasa.shared.core.trackers import DialogueStateTracker
24
27
 
@@ -48,8 +51,7 @@ class CancelFlowCommand(Command):
48
51
  """Selects the frames that were canceled.
49
52
 
50
53
  Args:
51
- dialogue_stack: The dialogue stack.
52
- current_flow: The current flow.
54
+ stack: The dialogue stack.
53
55
 
54
56
  Returns:
55
57
  The frames that were canceled.
@@ -71,8 +73,7 @@ class CancelFlowCommand(Command):
71
73
  # we should never get here as we should always find the user flow
72
74
  # that was canceled.
73
75
  raise ValueError(
74
- f"Could not find a user flow frame to cancel. "
75
- f"Current stack: {stack}."
76
+ f"Could not find a user flow frame to cancel. Current stack: {stack}."
76
77
  )
77
78
 
78
79
  def run_command_on_tracker(
@@ -106,6 +107,19 @@ class CancelFlowCommand(Command):
106
107
  )
107
108
  return []
108
109
 
110
+ if agent_frame := original_tracker.stack.find_active_agent_stack_frame_for_flow(
111
+ current_flow.id
112
+ ):
113
+ structlogger.debug(
114
+ "cancel_command.remove_agent_stack_frame",
115
+ command=self,
116
+ frame=agent_frame,
117
+ )
118
+ remove_agent_stack_frame(stack, agent_frame.agent_id)
119
+ applied_events.append(
120
+ AgentCancelled(agent_id=agent_frame.agent_id, flow_id=current_flow.id)
121
+ )
122
+
109
123
  # we pass in the original dialogue stack (before any of the currently
110
124
  # predicted commands were applied) to make sure we don't cancel any
111
125
  # frames that were added by the currently predicted commands.
@@ -12,7 +12,11 @@ from rasa.dialogue_understanding.commands.free_form_answer_command import (
12
12
  FreeFormAnswerCommand,
13
13
  )
14
14
  from rasa.dialogue_understanding.patterns.chitchat import ChitchatPatternFlowStackFrame
15
- from rasa.shared.core.events import Event
15
+ from rasa.dialogue_understanding.stack.frames.flow_stack_frame import (
16
+ AgentStackFrame,
17
+ AgentState,
18
+ )
19
+ from rasa.shared.core.events import AgentInterrupted, Event
16
20
  from rasa.shared.core.flows import FlowsList
17
21
  from rasa.shared.core.trackers import DialogueStateTracker
18
22
 
@@ -52,8 +56,23 @@ class ChitChatAnswerCommand(FreeFormAnswerCommand):
52
56
  The events to apply to the tracker.
53
57
  """
54
58
  stack = tracker.stack
59
+
60
+ applied_events: List[Event] = []
61
+
62
+ # if the top stack frame is an agent stack frame, we need to
63
+ # update the state to INTERRUPTED and add an AgentInterrupted event
64
+ if top_stack_frame := stack.top():
65
+ if isinstance(top_stack_frame, AgentStackFrame):
66
+ applied_events.append(
67
+ AgentInterrupted(
68
+ top_stack_frame.agent_id,
69
+ top_stack_frame.flow_id,
70
+ )
71
+ )
72
+ top_stack_frame.state = AgentState.INTERRUPTED
73
+
55
74
  stack.push(ChitchatPatternFlowStackFrame())
56
- return tracker.create_stack_updated_events(stack)
75
+ return applied_events + tracker.create_stack_updated_events(stack)
57
76
 
58
77
  def __hash__(self) -> int:
59
78
  return hash(self.command())
@@ -13,7 +13,11 @@ from rasa.dialogue_understanding.commands.command_syntax_manager import (
13
13
  )
14
14
  from rasa.dialogue_understanding.commands.utils import extract_cleaned_options
15
15
  from rasa.dialogue_understanding.patterns.clarify import ClarifyPatternFlowStackFrame
16
- from rasa.shared.core.events import Event
16
+ from rasa.dialogue_understanding.stack.frames.flow_stack_frame import (
17
+ AgentStackFrame,
18
+ AgentState,
19
+ )
20
+ from rasa.shared.core.events import AgentInterrupted, Event
17
21
  from rasa.shared.core.flows import FlowsList
18
22
  from rasa.shared.core.trackers import DialogueStateTracker
19
23
 
@@ -85,8 +89,22 @@ class ClarifyCommand(Command):
85
89
  if flow is not None
86
90
  ]
87
91
 
92
+ applied_events: List[Event] = []
93
+
94
+ # if the top stack frame is an agent stack frame, we need to
95
+ # update the state to INTERRUPTED and add an AgentInterrupted event
96
+ if top_stack_frame := stack.top():
97
+ if isinstance(top_stack_frame, AgentStackFrame):
98
+ applied_events.append(
99
+ AgentInterrupted(
100
+ top_stack_frame.agent_id,
101
+ top_stack_frame.flow_id,
102
+ )
103
+ )
104
+ top_stack_frame.state = AgentState.INTERRUPTED
105
+
88
106
  stack.push(ClarifyPatternFlowStackFrame(names=names))
89
- return tracker.create_stack_updated_events(stack)
107
+ return applied_events + tracker.create_stack_updated_events(stack)
90
108
 
91
109
  def __hash__(self) -> int:
92
110
  return hash(tuple(self.options))
@@ -0,0 +1,91 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+ from dataclasses import dataclass
5
+ from typing import Any, Dict, List
6
+
7
+ import structlog
8
+
9
+ from rasa.dialogue_understanding.commands.command import Command
10
+ from rasa.dialogue_understanding.commands.command_syntax_manager import (
11
+ CommandSyntaxManager,
12
+ CommandSyntaxVersion,
13
+ )
14
+ from rasa.shared.core.events import Event
15
+ from rasa.shared.core.flows import FlowsList
16
+ from rasa.shared.core.trackers import DialogueStateTracker
17
+
18
+ structlogger = structlog.get_logger()
19
+
20
+
21
+ @dataclass
22
+ class ContinueAgentCommand(Command):
23
+ """A command to continue the currently active agent's execution."""
24
+
25
+ @classmethod
26
+ def command(cls) -> str:
27
+ """Returns the command type."""
28
+ return "continue agent"
29
+
30
+ @classmethod
31
+ def from_dict(cls, data: Dict[str, Any]) -> ContinueAgentCommand:
32
+ """Converts the dictionary to a command.
33
+
34
+ Returns:
35
+ The converted dictionary.
36
+ """
37
+ return ContinueAgentCommand()
38
+
39
+ def run_command_on_tracker(
40
+ self,
41
+ tracker: DialogueStateTracker,
42
+ all_flows: FlowsList,
43
+ original_tracker: DialogueStateTracker,
44
+ ) -> List[Event]:
45
+ """Runs the command on the tracker.
46
+
47
+ Args:
48
+ tracker: The tracker to run the command on.
49
+ all_flows: All flows in the assistant.
50
+ original_tracker: The tracker before any command was executed.
51
+
52
+ Returns:
53
+ The events to apply to the tracker.
54
+ """
55
+ # do nothing
56
+ return []
57
+
58
+ def __hash__(self) -> int:
59
+ return hash(self.command())
60
+
61
+ def __eq__(self, other: object) -> bool:
62
+ return isinstance(other, ContinueAgentCommand)
63
+
64
+ def to_dsl(self) -> str:
65
+ """Converts the command to a DSL string."""
66
+ mapper = {
67
+ CommandSyntaxVersion.v1: "ContinueAgent()",
68
+ CommandSyntaxVersion.v2: "continue agent",
69
+ CommandSyntaxVersion.v3: "continue agent",
70
+ }
71
+ return mapper.get(
72
+ CommandSyntaxManager.get_syntax_version(),
73
+ mapper[CommandSyntaxManager.get_default_syntax_version()],
74
+ )
75
+
76
+ @classmethod
77
+ def from_dsl(cls, match: re.Match, **kwargs: Any) -> ContinueAgentCommand:
78
+ """Converts a DSL string to a command."""
79
+ return ContinueAgentCommand()
80
+
81
+ @staticmethod
82
+ def regex_pattern() -> str:
83
+ mapper = {
84
+ CommandSyntaxVersion.v1: r"ContinueAgent\(\)",
85
+ CommandSyntaxVersion.v2: r"""^[\s\W\d]*continue agent['"`]*$""",
86
+ CommandSyntaxVersion.v3: r"""^[\s\W\d]*continue agent['"`]*$""",
87
+ }
88
+ return mapper.get(
89
+ CommandSyntaxManager.get_syntax_version(),
90
+ mapper[CommandSyntaxManager.get_default_syntax_version()],
91
+ )
@@ -12,7 +12,11 @@ from rasa.dialogue_understanding.commands.free_form_answer_command import (
12
12
  FreeFormAnswerCommand,
13
13
  )
14
14
  from rasa.dialogue_understanding.patterns.search import SearchPatternFlowStackFrame
15
- from rasa.shared.core.events import Event
15
+ from rasa.dialogue_understanding.stack.frames.flow_stack_frame import (
16
+ AgentStackFrame,
17
+ AgentState,
18
+ )
19
+ from rasa.shared.core.events import AgentInterrupted, Event
16
20
  from rasa.shared.core.flows import FlowsList
17
21
  from rasa.shared.core.trackers import DialogueStateTracker
18
22
 
@@ -52,8 +56,23 @@ class KnowledgeAnswerCommand(FreeFormAnswerCommand):
52
56
  The events to apply to the tracker.
53
57
  """
54
58
  stack = tracker.stack
59
+
60
+ applied_events: List[Event] = []
61
+
62
+ # if the top stack frame is an agent stack frame, we need to
63
+ # update the state to INTERRUPTED and add an AgentInterrupted event
64
+ if top_stack_frame := stack.top():
65
+ if isinstance(top_stack_frame, AgentStackFrame):
66
+ applied_events.append(
67
+ AgentInterrupted(
68
+ top_stack_frame.agent_id,
69
+ top_stack_frame.flow_id,
70
+ )
71
+ )
72
+ top_stack_frame.state = AgentState.INTERRUPTED
73
+
55
74
  stack.push(SearchPatternFlowStackFrame())
56
- return tracker.create_stack_updated_events(stack)
75
+ return applied_events + tracker.create_stack_updated_events(stack)
57
76
 
58
77
  def __hash__(self) -> int:
59
78
  return hash(self.command())
@@ -0,0 +1,162 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+ from dataclasses import dataclass
5
+ from typing import Any, Dict, List, Optional
6
+
7
+ from rasa.dialogue_understanding.commands.command import Command
8
+ from rasa.dialogue_understanding.commands.command_syntax_manager import (
9
+ CommandSyntaxManager,
10
+ CommandSyntaxVersion,
11
+ )
12
+ from rasa.dialogue_understanding.stack.dialogue_stack import DialogueStack
13
+ from rasa.dialogue_understanding.stack.frames.flow_stack_frame import (
14
+ AgentStackFrame,
15
+ AgentState,
16
+ )
17
+ from rasa.shared.core.events import AgentStarted, Event
18
+ from rasa.shared.core.flows import FlowsList
19
+ from rasa.shared.core.flows.steps import CallFlowStep
20
+ from rasa.shared.core.trackers import DialogueStateTracker
21
+
22
+
23
+ @dataclass
24
+ class RestartAgentCommand(Command):
25
+ """A command to restart an agentic loop within a flow."""
26
+
27
+ agent_id: str
28
+
29
+ @classmethod
30
+ def command(cls) -> str:
31
+ """Returns the command type."""
32
+ return "restart agent"
33
+
34
+ @classmethod
35
+ def from_dict(cls, data: Dict[str, Any]) -> RestartAgentCommand:
36
+ """Converts the dictionary to a command.
37
+
38
+ Returns:
39
+ The converted dictionary.
40
+ """
41
+ try:
42
+ return RestartAgentCommand(agent_id=data["agent_id"])
43
+ except KeyError as e:
44
+ raise ValueError(
45
+ f"Missing parameter '{e}' while parsing RestartAgentCommand."
46
+ ) from e
47
+
48
+ def run_command_on_tracker(
49
+ self,
50
+ tracker: DialogueStateTracker,
51
+ all_flows: FlowsList,
52
+ original_tracker: DialogueStateTracker,
53
+ ) -> List[Event]:
54
+ """Runs the command on the tracker.
55
+
56
+ Args:
57
+ tracker: The tracker to run the command on.
58
+ all_flows: All flows in the assistant.
59
+ original_tracker: The tracker before any command was executed.
60
+
61
+ Returns:
62
+ The events to apply to the tracker.
63
+ """
64
+ stack = tracker.stack
65
+
66
+ # get the agent flow
67
+ agent_flow_id = self._get_agent_flow(original_tracker)
68
+
69
+ # create a new agent stack frame to restart the agent
70
+ restart_agent_frame = self.create_restart_agent_stack_frame(
71
+ all_flows, agent_flow_id
72
+ )
73
+
74
+ # if the stack contains an agent stack frame with status
75
+ # "waiting for input" update the status to "interrupted"
76
+ self.update_agent_stack_frames_on_stack(stack)
77
+
78
+ # push the stack frame on the top of the stack
79
+ stack.push(restart_agent_frame)
80
+ return tracker.create_stack_updated_events(stack)
81
+
82
+ def __hash__(self) -> int:
83
+ return hash(self.command())
84
+
85
+ def __eq__(self, other: object) -> bool:
86
+ return isinstance(other, RestartAgentCommand)
87
+
88
+ def to_dsl(self) -> str:
89
+ """Converts the command to a DSL string."""
90
+ mapper = {
91
+ CommandSyntaxVersion.v1: f"RestartAgent({self.agent_id})",
92
+ CommandSyntaxVersion.v2: f"restart agent {self.agent_id}",
93
+ CommandSyntaxVersion.v3: f"restart agent {self.agent_id}",
94
+ }
95
+ return mapper.get(
96
+ CommandSyntaxManager.get_syntax_version(),
97
+ mapper[CommandSyntaxManager.get_default_syntax_version()],
98
+ )
99
+
100
+ @classmethod
101
+ def from_dsl(cls, match: re.Match, **kwargs: Any) -> RestartAgentCommand:
102
+ """Converts a DSL string to a command."""
103
+ return RestartAgentCommand(agent_id=str(match.group(1).strip()))
104
+
105
+ @staticmethod
106
+ def regex_pattern() -> str:
107
+ mapper = {
108
+ CommandSyntaxVersion.v1: r"RestartAgent\(['\"]?([a-zA-Z0-9_-]+)['\"]?\)",
109
+ CommandSyntaxVersion.v2: (
110
+ r"""^[\s\W\d]*restart agent ['"`]?([a-zA-Z0-9_-]+)['"`]*"""
111
+ ),
112
+ CommandSyntaxVersion.v3: (
113
+ r"""^[\s\W\d]*restart agent ['"`]?([a-zA-Z0-9_-]+)['"`]*"""
114
+ ),
115
+ }
116
+ return mapper.get(
117
+ CommandSyntaxManager.get_syntax_version(),
118
+ mapper[CommandSyntaxManager.get_default_syntax_version()],
119
+ )
120
+
121
+ def create_restart_agent_stack_frame(
122
+ self, all_flows: FlowsList, agent_flow_id: str
123
+ ) -> AgentStackFrame:
124
+ # get the agent flow
125
+ agent_flow = all_flows.flow_by_id(agent_flow_id)
126
+ if not agent_flow:
127
+ raise ValueError(f"Agent flow {agent_flow_id} not found")
128
+
129
+ # find the call flow step for the agent
130
+ # set the state to "waiting for input" so that the agent can process
131
+ # the latest user message
132
+ for step in agent_flow.steps:
133
+ if isinstance(step, CallFlowStep) and step.call == self.agent_id:
134
+ return AgentStackFrame(
135
+ frame_id=f"restart_agent_{self.agent_id}",
136
+ flow_id=agent_flow_id,
137
+ step_id=step.id,
138
+ agent_id=self.agent_id,
139
+ state=AgentState.WAITING_FOR_INPUT,
140
+ )
141
+
142
+ raise ValueError(f"Call step in agent flow {agent_flow_id} not found")
143
+
144
+ def update_agent_stack_frames_on_stack(self, stack: DialogueStack) -> None:
145
+ for frame in stack.frames:
146
+ if (
147
+ isinstance(frame, AgentStackFrame)
148
+ and frame.state == AgentState.WAITING_FOR_INPUT
149
+ ):
150
+ frame.state = AgentState.INTERRUPTED
151
+
152
+ def _get_agent_flow(self, tracker: DialogueStateTracker) -> Optional[str]:
153
+ # find events associated with the agent
154
+ agent_started_events = [
155
+ event
156
+ for event in tracker.events
157
+ if type(event) == AgentStarted and event.agent_id == self.agent_id
158
+ ]
159
+ # take the last one if the agent was started multiple times
160
+ if agent_started_events:
161
+ return agent_started_events[-1].flow_id
162
+ return None