rasa-pro 3.11.9__py3-none-any.whl → 3.11.10__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.

@@ -139,6 +139,12 @@ class Conversation:
139
139
  structlogger.warning(
140
140
  "audiocodes.handle.activities.duplicate_activity",
141
141
  activity_id=activity[ACTIVITY_ID_KEY],
142
+ event_info=(
143
+ "Audiocodes might send duplicate activities if the bot has not "
144
+ "responded to the previous one or responded too late. Please "
145
+ "consider enabling the `use_websocket` option to use"
146
+ " Audiocodes Asynchronous API."
147
+ ),
142
148
  )
143
149
  continue
144
150
  self.activity_ids.append(activity[ACTIVITY_ID_KEY])
@@ -390,30 +396,41 @@ class AudiocodesInput(InputChannel):
390
396
  "audiocodes.on_activities.no_conversation", request=request.json
391
397
  )
392
398
  return response.json({})
393
- elif conversation.ws:
399
+
400
+ if self.use_websocket:
401
+ # send an empty response for this request
402
+ # activities are processed in the background
403
+ # chat response is sent via the websocket
394
404
  ac_output: Union[WebsocketOutput, AudiocodesOutput] = WebsocketOutput(
395
405
  conversation.ws, conversation_id
396
406
  )
397
- response_json = {}
398
- else:
399
- # handle non websocket case where messages get returned in json
400
- ac_output = AudiocodesOutput()
401
- response_json = {
407
+ self._create_task(
408
+ conversation_id,
409
+ conversation.handle_activities(
410
+ request.json,
411
+ input_channel_name=self.name(),
412
+ output_channel=ac_output,
413
+ on_new_message=on_new_message,
414
+ ),
415
+ )
416
+ return response.json({})
417
+
418
+ # without websockets, this becomes a blocking call
419
+ # and the response is sent back to the Audiocodes server
420
+ # after the activities are processed
421
+ ac_output = AudiocodesOutput()
422
+ await conversation.handle_activities(
423
+ request.json,
424
+ input_channel_name=self.name(),
425
+ output_channel=ac_output,
426
+ on_new_message=on_new_message,
427
+ )
428
+ return response.json(
429
+ {
402
430
  "conversation": conversation_id,
403
431
  "activities": ac_output.messages,
404
432
  }
405
-
406
- # start a background task to handle activities
407
- self._create_task(
408
- conversation_id,
409
- conversation.handle_activities(
410
- request.json,
411
- input_channel_name=self.name(),
412
- output_channel=ac_output,
413
- on_new_message=on_new_message,
414
- ),
415
433
  )
416
- return response.json(response_json)
417
434
 
418
435
  @ac_webhook.route(
419
436
  "/conversation/<conversation_id>/disconnect", methods=["POST"]
@@ -22,10 +22,11 @@ from rasa.shared.core.flows.flow_step_links import (
22
22
  from rasa.shared.core.flows.flow_step_sequence import FlowStepSequence
23
23
  from rasa.shared.core.flows.nlu_trigger import NLUTriggers
24
24
  from rasa.shared.core.flows.steps import (
25
+ ActionFlowStep,
26
+ CallFlowStep,
25
27
  CollectInformationFlowStep,
26
28
  EndFlowStep,
27
29
  StartFlowStep,
28
- ActionFlowStep,
29
30
  )
30
31
  from rasa.shared.core.flows.steps.constants import (
31
32
  CONTINUE_STEP_PREFIX,
@@ -402,161 +403,156 @@ class Flow:
402
403
  and a set of visited step IDs to prevent revisiting steps.
403
404
  It calls `go_over_steps` to recursively explore and fill the paths list.
404
405
  """
405
- flow_paths_list = FlowPathsList(self.id, paths=[])
406
- steps: List[FlowStep] = self.steps
406
+ all_paths = FlowPathsList(self.id, paths=[])
407
+ start_step: FlowStep = self.first_step_in_flow()
407
408
  current_path: FlowPath = FlowPath(flow=self.id, nodes=[])
408
- step_ids_visited: Set[str] = set()
409
-
410
- self._go_over_steps(steps, current_path, flow_paths_list, step_ids_visited)
409
+ visited_step_ids: Set[str] = set()
411
410
 
412
- if not flow_paths_list.is_path_part_of_list(current_path):
413
- flow_paths_list.paths.append(copy.deepcopy(current_path))
411
+ self._go_over_steps(start_step, current_path, all_paths, visited_step_ids)
414
412
 
415
413
  structlogger.debug(
416
414
  "shared.core.flows.flow.extract_all_paths",
417
415
  comment="Extraction complete",
418
- number_of_paths=len(flow_paths_list.paths),
416
+ number_of_paths=len(all_paths.paths),
419
417
  flow_name=self.name,
420
418
  )
421
- return flow_paths_list
419
+ return all_paths
422
420
 
423
421
  def _go_over_steps(
424
422
  self,
425
- steps_to_go: Union[str, List[FlowStep]],
423
+ current_step: FlowStep,
426
424
  current_path: FlowPath,
427
- completed_paths: FlowPathsList,
428
- step_ids_visited: Set[str],
425
+ all_paths: FlowPathsList,
426
+ visited_step_ids: Set[str],
429
427
  ) -> None:
430
428
  """Processes the flow steps recursively.
431
429
 
432
- Either following direct step IDs or handling conditions, and adds complete
433
- paths to the collected_paths.
434
-
435
430
  Args:
436
- steps_to_go: Either a direct step ID or a list of steps to process.
431
+ current_step: The current step being processed.
437
432
  current_path: The current path being constructed.
438
- completed_paths: The list where completed paths are added.
439
- step_ids_visited: A set of step IDs that have been visited to avoid cycles.
433
+ all_paths: The list where completed paths are added.
434
+ visited_step_ids: A set of steps that have been visited to avoid cycles.
440
435
 
441
436
  Returns:
442
- None: This function modifies collected_paths in place by appending new paths
437
+ None: This function modifies all_paths in place by appending new paths
443
438
  as they are found.
444
439
  """
445
- # Case 1: If the steps_to_go is a custom_id string
446
- # This happens when a "next" of, for example, a IfFlowStepLink is targeting
447
- # a specific step by id
448
- if isinstance(steps_to_go, str):
449
- for i, step in enumerate(self.steps):
450
- # We don't need to check for 'id' as a link can only happen to a
451
- # custom id.
452
- if step.custom_id == steps_to_go:
453
- self._go_over_steps(
454
- self.steps[i:], current_path, completed_paths, step_ids_visited
455
- )
456
-
457
- # Case 2: If steps_to_go is a list of steps
458
- else:
459
- for i, step in enumerate(steps_to_go):
460
- # 1. Check if the step is relevant for testable_paths extraction.
461
- # We only create new path nodes for ActionFlowStep and
462
- # CollectInformationFlowStep because these are externally visible
463
- # changes in the assistant's behaviour (trackable in the e2e tests).
464
- # For other flow steps, we only follow their links.
465
- # We decided to ignore calls to other flows in our coverage analysis.
466
- if not isinstance(step, (CollectInformationFlowStep, ActionFlowStep)):
467
- self._handle_links(
468
- step.next.links,
469
- current_path,
470
- completed_paths,
471
- step_ids_visited,
472
- )
473
- continue
474
-
475
- # 2. Check if already visited this custom step id
476
- # in order to keep track of loops
477
- if step.custom_id is not None and step.custom_id in step_ids_visited:
478
- if not completed_paths.is_path_part_of_list(current_path):
479
- completed_paths.paths.append(copy.deepcopy(current_path))
480
- return # Stop traversing this path if we've revisited a step
481
- elif step.custom_id is not None:
482
- step_ids_visited.add(step.custom_id)
483
-
484
- # 3. Append step info to the path
485
- current_path.nodes.append(
486
- PathNode(
487
- flow=current_path.flow,
488
- step_id=step.id,
489
- lines=step.metadata["line_numbers"],
490
- )
440
+ # Check if the step is relevant for testable_paths extraction.
441
+ # We only create new path nodes for ActionFlowStep, CallFlowStep and
442
+ # CollectInformationFlowStep because these are externally visible
443
+ # changes in the assistant's behaviour (trackable in the e2e tests).
444
+ # For other flow steps, we only follow their links.
445
+ # We decided to ignore calls to other flows in our coverage analysis.
446
+ should_add_node = isinstance(
447
+ current_step, (CollectInformationFlowStep, ActionFlowStep, CallFlowStep)
448
+ )
449
+ if should_add_node:
450
+ # Add current step to the current path that is being constructed.
451
+ current_path.nodes.append(
452
+ PathNode(
453
+ flow=current_path.flow,
454
+ step_id=current_step.id,
455
+ lines=current_step.metadata["line_numbers"],
491
456
  )
457
+ )
492
458
 
493
- # 4. Check if 'END' branch
494
- if (
495
- len(step.next.links) == 1
496
- and isinstance(step.next.links[0], StaticFlowStepLink)
497
- and step.next.links[0].target == END_STEP
498
- ):
499
- if not completed_paths.is_path_part_of_list(current_path):
500
- completed_paths.paths.append(copy.deepcopy(current_path))
501
- return
502
- else:
503
- self._handle_links(
504
- step.next.links,
505
- current_path,
506
- completed_paths,
507
- step_ids_visited,
508
- )
459
+ if current_step.id in visited_step_ids or self.is_end_of_path(current_step):
460
+ # Found a cycle, or reached an end step, do not proceed further.
461
+ all_paths.paths.append(copy.deepcopy(current_path))
462
+ # Remove the last node from the path if it was added.
463
+ if should_add_node:
464
+ current_path.nodes.pop()
465
+ return
466
+
467
+ # Mark current step as visited in this path.
468
+ visited_step_ids.add(current_step.id)
469
+
470
+ # Iterate over all links of the current step.
471
+ for link in current_step.next.links:
472
+ self._handle_link(
473
+ current_path,
474
+ all_paths,
475
+ visited_step_ids,
476
+ link,
477
+ )
509
478
 
510
- def _handle_links(
479
+ # Backtrack the current step and remove it from the path.
480
+ visited_step_ids.remove(current_step.id)
481
+
482
+ # Remove the last node from the path if it was added.
483
+ if should_add_node:
484
+ current_path.nodes.pop()
485
+
486
+ def _handle_link(
511
487
  self,
512
- links: List[FlowStepLink],
513
- path: FlowPath,
514
- collected_paths: FlowPathsList,
515
- step_ids_visited: set,
488
+ current_path: FlowPath,
489
+ all_paths: FlowPathsList,
490
+ visited_step_ids: Set[str],
491
+ link: FlowStepLink,
516
492
  ) -> None:
517
- """Processes the next step in a flow.
518
-
519
- Potentially recursively calling itself to handle conditional paths and
520
- branching.
493
+ """Handles the next step in a flow.
521
494
 
522
495
  Args:
523
- links: Links listed in the "next" attribute.
524
- path: The current path taken in the flow.
525
- collected_paths: A list of paths collected so far.
526
- step_ids_visited: A set of step IDs that have already been visited
527
- to avoid loops.
496
+ current_path: The current path being constructed.
497
+ all_paths: The list where completed paths are added.
498
+ visited_step_ids: A set of steps that have been visited to avoid cycles.
499
+ link: The link to be followed.
528
500
 
529
501
  Returns:
530
- None: Modifies collected_paths in place by appending new paths
531
- as they are completed.
502
+ None: This function modifies all_paths in place by appending new paths
503
+ as they are found.
532
504
  """
533
- steps = self.steps
534
-
535
- for link in links:
536
- # Direct step id reference
537
- if isinstance(link, StaticFlowStepLink):
538
- # Find this id in the flow steps and restart from there
539
- for i, step in enumerate(steps):
540
- if step.id == link.target_step_id:
541
- self._go_over_steps(
542
- steps[i:],
543
- copy.deepcopy(path),
544
- collected_paths,
545
- copy.deepcopy(step_ids_visited),
546
- )
547
-
548
- # If conditions
549
- elif isinstance(link, (IfFlowStepLink, ElseFlowStepLink)):
550
- # Handling conditional paths
551
- target_steps: Union[str, List[FlowStep]]
552
- if isinstance(link.target_reference, FlowStepSequence):
553
- target_steps = link.target_reference.child_steps
554
- else:
555
- target_steps = link.target_reference
556
-
505
+ # StaticFlowStepLink is a direct link to the next step.
506
+ if isinstance(link, StaticFlowStepLink):
507
+ # Find the step by its id and continue the path.
508
+ if step := self._get_step_by_step_id(link.target_step_id):
557
509
  self._go_over_steps(
558
- target_steps,
559
- copy.deepcopy(path),
560
- collected_paths,
561
- copy.deepcopy(step_ids_visited),
510
+ step,
511
+ current_path,
512
+ all_paths,
513
+ visited_step_ids,
562
514
  )
515
+ return
516
+ # IfFlowStepLink and ElseFlowStepLink are conditional links.
517
+ elif isinstance(link, (IfFlowStepLink, ElseFlowStepLink)):
518
+ if isinstance(link.target_reference, FlowStepSequence):
519
+ # If the target is a FlowStepSequence, we need to go over all
520
+ # child steps of the sequence.
521
+ for child_step in link.target_reference.child_steps:
522
+ self._go_over_steps(
523
+ child_step,
524
+ current_path,
525
+ all_paths,
526
+ visited_step_ids,
527
+ )
528
+ return
529
+ else:
530
+ # Find the step by its id and continue the path.
531
+ if step := self._get_step_by_step_id(link.target_reference):
532
+ self._go_over_steps(
533
+ step,
534
+ current_path,
535
+ all_paths,
536
+ visited_step_ids,
537
+ )
538
+ return
539
+
540
+ def is_end_of_path(self, step: FlowStep) -> bool:
541
+ """Check if there is no path available from the current step."""
542
+ if (
543
+ len(step.next.links) == 1
544
+ and isinstance(step.next.links[0], StaticFlowStepLink)
545
+ and step.next.links[0].target == END_STEP
546
+ ):
547
+ return True
548
+ return False
549
+
550
+ def _get_step_by_step_id(
551
+ self,
552
+ step_id: Optional[str],
553
+ ) -> Optional[FlowStep]:
554
+ """Get a step by its id from a list of steps."""
555
+ for step in self.steps:
556
+ if step.id == step_id:
557
+ return step
558
+ return None
rasa/version.py CHANGED
@@ -1,3 +1,3 @@
1
1
  # this file will automatically be changed,
2
2
  # do not add anything but the version number here!
3
- __version__ = "3.11.9"
3
+ __version__ = "3.11.10"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: rasa-pro
3
- Version: 3.11.9
3
+ Version: 3.11.10
4
4
  Summary: State-of-the-art open-core Conversational AI framework for Enterprises that natively leverages generative AI for effortless assistant development.
5
5
  Keywords: nlp,machine-learning,machine-learning-library,bot,bots,botkit,rasa conversational-agents,conversational-ai,chatbot,chatbot-framework,bot-framework
6
6
  Author: Rasa Technologies GmbH
@@ -265,7 +265,7 @@ rasa/core/channels/telegram.py,sha256=5BrNECFM3qe9XjNpDb8Q9fbqCT5aKr5L6IH21W8sum
265
265
  rasa/core/channels/twilio.py,sha256=GsdjfplZdBj0fRB60bSggPF1DXFZ_x18V_dlcDy5VFs,5943
266
266
  rasa/core/channels/vier_cvg.py,sha256=PfvSluQqgJbP0JzZPFUvum3z7H55JPPeobcD-z5zCkw,13544
267
267
  rasa/core/channels/voice_ready/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
268
- rasa/core/channels/voice_ready/audiocodes.py,sha256=esX2BFYB8XIQB56ixERebJiVzEaKGM0EuXUJB92b9aY,21066
268
+ rasa/core/channels/voice_ready/audiocodes.py,sha256=jJmLkqI2RciTvB7cAsvRJi_EL70dRyiwNwPWzVPSUj0,21888
269
269
  rasa/core/channels/voice_ready/jambonz.py,sha256=S7yjdj7nYwQWMalqcGv8eomZGj0c2Dza-51tiNHEpVM,4784
270
270
  rasa/core/channels/voice_ready/jambonz_protocol.py,sha256=OzW-6YMU2SIc88Mur_wktbiE46igHR8vH17DCfRijIU,13139
271
271
  rasa/core/channels/voice_ready/twilio_voice.py,sha256=z2pdausxQnXQP9htGh8AL2q9AvcMIx70Y5tErWpssV4,16224
@@ -594,7 +594,7 @@ rasa/shared/core/conversation.py,sha256=tw1fD2XB3gOdQjDI8hHo5TAAmE2JYNogQGWe3rE9
594
594
  rasa/shared/core/domain.py,sha256=bGjonMV54wbwGLPjKHI2NoWwxr2wyUZwhEvjBWhP-W0,81710
595
595
  rasa/shared/core/events.py,sha256=zdGSP1bNV1RyKC9Z54S7EbQ8TfGne_n9XKj64aoghdI,85803
596
596
  rasa/shared/core/flows/__init__.py,sha256=HszhIvEARpmyxABFc1MKYvj8oy04WiZW1xmCdToakbs,181
597
- rasa/shared/core/flows/flow.py,sha256=n9vB1SKwRczlymxrY19KiWq2BXR-LKpVUr5-Zh9827s,21530
597
+ rasa/shared/core/flows/flow.py,sha256=6RR-CdOR6xS31zCiOe3Fcz-ajCQ-H0M7FxfMa63Ka7A,20820
598
598
  rasa/shared/core/flows/flow_path.py,sha256=xstwahZBU5cfMY46mREA4NoOGlKLBRAqeP_mJ3UZqOI,2283
599
599
  rasa/shared/core/flows/flow_step.py,sha256=6hoVOMXryTKHgT7-p7jzTqH2r9QREmy_6d6bX2OyxI0,4550
600
600
  rasa/shared/core/flows/flow_step_links.py,sha256=zMZV_9rWVjEa8kHIFSIbXCWA1qaUvp8r4uSCK_NsKKs,10548
@@ -779,9 +779,9 @@ rasa/utils/train_utils.py,sha256=f1NWpp5y6al0dzoQyyio4hc4Nf73DRoRSHDzEK6-C4E,212
779
779
  rasa/utils/url_tools.py,sha256=JQcHL2aLqLHu82k7_d9imUoETCm2bmlHaDpOJ-dKqBc,1218
780
780
  rasa/utils/yaml.py,sha256=KjbZq5C94ZP7Jdsw8bYYF7HASI6K4-C_kdHfrnPLpSI,2000
781
781
  rasa/validator.py,sha256=O1wjCeV7ITJ0luvb3GCWy8x1fGgzWVbClEMlPnLBowQ,67265
782
- rasa/version.py,sha256=C7MfeYYWfkktTlYVsyB5Oh2KUgU5K7MVUJ-qSvLwV5c,117
783
- rasa_pro-3.11.9.dist-info/METADATA,sha256=la5nbBfiiEqS02_8oKgOXJbTsxfoUPBPX9kdeWbCwQM,10728
784
- rasa_pro-3.11.9.dist-info/NOTICE,sha256=7HlBoMHJY9CL2GlYSfTQ-PZsVmLmVkYmMiPlTjhuCqA,218
785
- rasa_pro-3.11.9.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
786
- rasa_pro-3.11.9.dist-info/entry_points.txt,sha256=ckJ2SfEyTPgBqj_I6vm_tqY9dZF_LAPJZA335Xp0Q9U,43
787
- rasa_pro-3.11.9.dist-info/RECORD,,
782
+ rasa/version.py,sha256=pyAPlQXkP-rQmG_UV6VI6hvQcb20q31MmlJ3pMgkNik,118
783
+ rasa_pro-3.11.10.dist-info/METADATA,sha256=qWOhRdBx8QpPqHsZGkp2NQaj5blpEUsPyd6VX50_32A,10729
784
+ rasa_pro-3.11.10.dist-info/NOTICE,sha256=7HlBoMHJY9CL2GlYSfTQ-PZsVmLmVkYmMiPlTjhuCqA,218
785
+ rasa_pro-3.11.10.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
786
+ rasa_pro-3.11.10.dist-info/entry_points.txt,sha256=ckJ2SfEyTPgBqj_I6vm_tqY9dZF_LAPJZA335Xp0Q9U,43
787
+ rasa_pro-3.11.10.dist-info/RECORD,,