class_docstr: A model builder that first processes individual observations, concatenates the resulting latent spaces and then
  processes this concatenated output to action and value outputs.
  
  Each input observation is first processed with the specified perception block.
  The required feature dimensionality after this step is 1D!
  In a next step the latent representations of the previous step are concatenated along the last dimension and
  once more processed with a :class:`~maze.perception.blocks.feed_forward.dense.DenseBlock`.
  
  :param modality_config: dictionary mapping perception modalities to blocks and block config parameters.
  :param observation_modality_mapping: A mapping of observation keys to perception modalities.
  :param shared_embedding_keys: The shared embedding keys to use as an input to the critic network where the value
      can be one of the following:
      - None, empty list or dict of empty lists: No shared embeddings are used.
      - A list of str values: The shared embedding keys to use for creating the critic network in each substep
      (the same keys).
      - A dict of lists: Here the keys have to refer to the step-keys of the environment, the corresponding lists
      specify the input keys to the critic network in this step.
class_docstr_tok: ["A","model","builder","that","first","processes","individual","observations",",","concatenates","the","resulting","latent","spaces","and","then","processes","this","concatenated","output","to","action","and","value","outputs",".","Each","input","observation","is","first","processed","with","the","specified","perception","block",".","The","required","feature","dimensionality","after","this","step","is","1D","!","In","a","next","step","the","latent","representations","of","the","previous","step","are","concatenated","along","the","last","dimension","and","once","more","processed","with","a",":","class",":","`","~maze.perception.blocks.feed_forward.dense.DenseBlock","`",".",":","param","modality_config",":","dictionary","mapping","perception","modalities","to","blocks","and","block","config","parameters",".",":","param","observation_modality_mapping",":","A","mapping","of","observation","keys","to","perception","modalities",".",":","param","shared_embedding_keys",":","The","shared","embedding","keys","to","use","as","an","input","to","the","critic","network","where","the","value","can","be","one","of","the","following",":","-","None",",","empty","list","or","dict","of","empty","lists",":","No","shared","embeddings","are","used",".","-","A","list","of","str","values",":","The","shared","embedding","keys","to","use","for","creating","the","critic","network","in","each","substep","(","the","same","keys",")",".","-","A","dict","of","lists",":","Here","the","keys","have","to","refer","to","the","step-keys","of","the","environment",",","the","corresponding","lists","specify","the","input","keys","to","the","critic","network","in","this","step","."]
code: def _check_modality_config(self, modality_config: Dict):
      assert (
          ConcatModelBuilderKeys.RECURRENCE in modality_config
      ), f"make sure to specify a block for {ConcatModelBuilderKeys.RECURRENCE}!"
      assert (
          ConcatModelBuilderKeys.HIDDEN in modality_config
      ), f"make sure to specify a block for {str(ConcatModelBuilderKeys.HIDDEN)}!"
  
      for key, value in modality_config.items():
          if value != {}:
              assert list(value.keys()) == [
                  "block_type",
                  "block_params",
              ], (
                  f"{self.__class__.__name__} requires 'block_type' and 'block_params' as arguments"
                  f" for modality '{key}'."
              )
  
file_path: maze/maze/perception/builders/concat.py
imports: from typing import Dict, Union, Any, Optional, List
  from gym import spaces
  from maze.core.annotations import override
  from maze.core.utils.factory import Factory
  from maze.perception.blocks import PerceptionBlock
  from maze.perception.blocks.general.concat import ConcatenationBlock
  from maze.perception.blocks.inference import InferenceBlock
  from maze.perception.builders.base import BaseModelBuilder
  from maze.utils.bcolors import BColors
label_desc: Use image node_id 3 for calling the ConcatModelBuilder obj's underlying member method code with example usage: obj._check_modality_config(modality_config) without return types