class_docstr: ConditionalRouter in Haystack 2.x pipelines is designed to manage data routing based on specific conditions.
  This is achieved by defining a list named 'routes'. Each element in this list is a dictionary representing a
  single route.
  
  A route dictionary comprises four key elements:
  - 'condition': A Jinja2 string expression that determines if the route is selected.
  - 'output': A Jinja2 expression defining the route's output value.
  - 'output_type': The type of the output data (e.g., str, List[int]).
  - 'output_name': The name under which the `output` value of the route is published. This name is used to connect
  the router to other components in the pipeline.
  
  Here's an example:
  
  ```python
  from haystack.components.routers import ConditionalRouter
  
  routes = [
      {
          "condition": "{{streams|length > 2}}",
          "output": "{{streams}}",
          "output_name": "enough_streams",
          "output_type": List[int],
      },
      {
          "condition": "{{streams|length <= 2}}",
          "output": "{{streams}}",
          "output_name": "insufficient_streams",
          "output_type": List[int],
      },
  ]
  router = ConditionalRouter(routes)
  # When 'streams' has more than 2 items, 'enough_streams' output will activate, emitting the list [1, 2, 3]
  kwargs = {"streams": [1, 2, 3], "query": "Haystack"}
  result = router.run(**kwargs)
  assert result == {"enough_streams": [1, 2, 3]}
  ```
  
  In this example, we configure two routes. The first route sends the 'streams' value to 'enough_streams' if the
  stream count exceeds two. Conversely, the second route directs 'streams' to 'insufficient_streams' when there
  are two or fewer streams.
  
  In the pipeline setup, the router is connected to other components using the output names. For example, the
  'enough_streams' output might be connected to another component that processes the streams, while the
  'insufficient_streams' output might be connected to a component that fetches more streams, and so on.
  
  Here is a pseudocode example of a pipeline that uses the ConditionalRouter and routes fetched ByteStreams to
  different components depending on the number of streams fetched:
  
  ```
  from typing import List
  from haystack import Pipeline
  from haystack.dataclasses import ByteStream
  from haystack.components.routers import ConditionalRouter
  
  routes = [
      {
          "condition": "{{streams|length > 2}}",
          "output": "{{streams}}",
          "output_name": "enough_streams",
          "output_type": List[ByteStream],
      },
      {
          "condition": "{{streams|length <= 2}}",
          "output": "{{streams}}",
          "output_name": "insufficient_streams",
          "output_type": List[ByteStream],
      },
  ]
  
  pipe = Pipeline()
  pipe.add_component("router", router)
  ...
  pipe.connect("router.enough_streams", "some_component_a.streams")
  pipe.connect("router.insufficient_streams", "some_component_b.streams_or_some_other_input")
  ...
  ```
class_docstr_tok: ["ConditionalRouter","in","Haystack","2.x","pipelines","is","designed","to","manage","data","routing","based","on","specific","conditions",".","This","is","achieved","by","defining","a","list","named","'routes","'",".","Each","element","in","this","list","is","a","dictionary","representing","a","single","route",".","A","route","dictionary","comprises","four","key","elements",":","-","'condition","'",":","A","Jinja2","string","expression","that","determines","if","the","route","is","selected",".","-","'output","'",":","A","Jinja2","expression","defining","the","route","'s","output","value",".","-","'output_type","'",":","The","type","of","the","output","data","(","e.g.",",","str",",","List","[","int","]",")",".","-","'output_name","'",":","The","name","under","which","the","`","output","`","value","of","the","route","is","published",".","This","name","is","used","to","connect","the","router","to","other","components","in","the","pipeline",".","Here","'s","an","example",":","``","`","python","from","haystack.components.routers","import","ConditionalRouter","routes","=","[","{","``","condition","''",":","``","{","{","streams|length",">","2","}","}","''",",","``","output","''",":","``","{","{","streams","}","}","''",",","``","output_name","''",":","``","enough_streams","''",",","``","output_type","''",":","List","[","int","]",",","}",",","{","``","condition","''",":","``","{","{","streams|length","<","=","2","}","}","''",",","``","output","''",":","``","{","{","streams","}","}","''",",","``","output_name","''",":","``","insufficient_streams","''",",","``","output_type","''",":","List","[","int","]",",","}",",","]","router","=","ConditionalRouter","(","routes",")","#","When","'streams","'","has","more","than","2","items",",","'enough_streams","'","output","will","activate",",","emitting","the","list","[","1",",","2",",","3","]","kwargs","=","{","``","streams","''",":","[","1",",","2",",","3","]",",","``","query","''",":","``","Haystack","''","}","result","=","router.run","(","*","*","kwargs",")","assert","result","==","{","``","enough_streams","''",":","[","1",",","2",",","3","]","}","``","`","In","this","example",",","we","configure","two","routes",".","The","first","route","sends","the","'streams","'","value","to","'enough_streams","'","if","the","stream","count","exceeds","two",".","Conversely",",","the","second","route","directs","'streams","'","to","'insufficient_streams","'","when","there","are","two","or","fewer","streams",".","In","the","pipeline","setup",",","the","router","is","connected","to","other","components","using","the","output","names",".","For","example",",","the","'enough_streams","'","output","might","be","connected","to","another","component","that","processes","the","streams",",","while","the","'insufficient_streams","'","output","might","be","connected","to","a","component","that","fetches","more","streams",",","and","so","on",".","Here","is","a","pseudocode","example","of","a","pipeline","that","uses","the","ConditionalRouter","and","routes","fetched","ByteStreams","to","different","components","depending","on","the","number","of","streams","fetched",":","``","`","from","typing","import","List","from","haystack","import","Pipeline","from","haystack.dataclasses","import","ByteStream","from","haystack.components.routers","import","ConditionalRouter","routes","=","[","{","``","condition","''",":","``","{","{","streams|length",">","2","}","}","''",",","``","output","''",":","``","{","{","streams","}","}","''",",","``","output_name","''",":","``","enough_streams","''",",","``","output_type","''",":","List","[","ByteStream","]",",","}",",","{","``","condition","''",":","``","{","{","streams|length","<","=","2","}","}","''",",","``","output","''",":","``","{","{","streams","}","}","''",",","``","output_name","''",":","``","insufficient_streams","''",",","``","output_type","''",":","List","[","ByteStream","]",",","}",",","]","pipe","=","Pipeline","(",")","pipe.add_component","(","``","router","''",",","router",")","...","pipe.connect","(","``","router.enough_streams","''",",","``","some_component_a.streams","''",")","pipe.connect","(","``","router.insufficient_streams","''",",","``","some_component_b.streams_or_some_other_input","''",")","...","``","`"]
docstr: Initializes the ConditionalRouter with a list of routes detailing the conditions for routing.
  
  :param routes: A list of dictionaries, each defining a route with a boolean condition expression
                 ('condition'), an output value ('output'), the output type ('output_type') and
                 ('output_name') that defines the output name for the variable defined in 'output'.
docstr_tok: ["Initializes","the","ConditionalRouter","with","a","list","of","routes","detailing","the","conditions","for","routing",".",":","param","routes",":","A","list","of","dictionaries",",","each","defining","a","route","with","a","boolean","condition","expression","(","'condition","'",")",",","an","output","value","(","'output","'",")",",","the","output","type","(","'output_type","'",")","and","(","'output_name","'",")","that","defines","the","output","name","for","the","variable","defined","in","'output","'","."]
code: def __init__(self, routes: List[Dict]):
      """
      Initializes the ConditionalRouter with a list of routes detailing the conditions for routing.
  
      :param routes: A list of dictionaries, each defining a route with a boolean condition expression
                     ('condition'), an output value ('output'), the output type ('output_type') and
                     ('output_name') that defines the output name for the variable defined in 'output'.
      """
      self._validate_routes(routes)
      self.routes: List[dict] = routes
  
      # Create a Jinja native environment to inspect variables in the condition templates
      env = NativeEnvironment()
  
      # Inspect the routes to determine input and output types.
      input_types: Set[
          str
      ] = set()  # let's just store the name, type will always be Any
      output_types: Dict[str, str] = {}
  
      for route in routes:
          # extract inputs
          route_input_names = self._extract_variables(
              env, [route["output"], route["condition"]]
          )
          input_types.update(route_input_names)
  
          # extract outputs
          output_types.update(
              {route["output_name"]: route["output_type"]}
          )
  
      component.set_input_types(
          self, **{var: Any for var in input_types}
      )
      component.set_output_types(self, **output_types)
  
file_path: haystack/haystack/components/routers/conditional_router.py
imports: import logging
  from typing import List, Dict, Any, Set
  from jinja2 import meta, Environment, TemplateSyntaxError
  from jinja2.nativetypes import NativeEnvironment
  from haystack import component, default_from_dict, default_to_dict
  from haystack.utils.type_serialization import serialize_type, deserialize_type
label_desc: Use image node_id 1 to create a new ConditionalRouter object  with example: obj = ConditionalRouter(routes)