class_docstr: Recorder wrapper (specification key: `recorder`).
  
  Args:
      fn_act (callable[states -> actions]): Act-function mapping states to actions which is
          supposed to be recorded.
class_docstr_tok: ["Recorder","wrapper","(","specification","key",":","`","recorder","`",")",".","Args",":","fn_act","(","callable","[","states","-",">","actions","]",")",":","Act-function","mapping","states","to","actions","which","is","supposed","to","be","recorded","."]
code: def act(
      self,
      states,
      internals=None,
      parallel=0,
      independent=False,
      deterministic=True,
      **kwargs,
  ):
      # Independent and internals
      is_internals_none = internals is None
      if independent:
          if parallel != 0:
              raise TensorforceError.invalid(
                  name="Agent.act",
                  argument="parallel",
                  condition="independent is true",
              )
          if is_internals_none and len(self.internals_spec) > 0:
              raise TensorforceError.required(
                  name="Agent.act",
                  argument="internals",
                  condition="independent is true",
              )
      else:
          if not is_internals_none:
              raise TensorforceError.invalid(
                  name="Agent.act",
                  argument="internals",
                  condition="independent is false",
              )
  
      # Process states input and infer batching structure
      (
          states,
          batched,
          num_parallel,
          is_iter_of_dicts,
      ) = self._process_states_input(
          states=states, function_name="Agent.act"
      )
  
      if independent:
          # Independent mode: handle internals argument
          if is_internals_none:
              # Default input internals=None
              pass
  
          elif is_iter_of_dicts or isinstance(internals, (tuple, list)):
              # Input structure iter[dict[internal]]
              if not isinstance(internals, (tuple, list)):
                  raise TensorforceError.type(
                      name="Agent.act",
                      argument="internals",
                      dtype=type(internals),
                      hint="is not tuple/list",
                  )
              internals = [
                  ArrayDict(internal) for internal in internals
              ]
              internals = internals[0].fmap(
                  function=(lambda *xs: np.stack(xs, axis=0)),
                  zip_values=internals[1:],
              )
  
          else:
              # Input structure dict[iter[internal]]
              if not isinstance(internals, dict):
                  raise TensorforceError.type(
                      name="Agent.act",
                      argument="internals",
                      dtype=type(internals),
                      hint="is not dict",
                  )
              internals = ArrayDict(internals)
  
          if not independent or not is_internals_none:
              # Expand inputs if not batched
              if not batched:
                  internals = internals.fmap(
                      function=(lambda x: np.expand_dims(x, axis=0))
                  )
  
              # Check number of inputs
              for name, internal in internals.items():
                  if internal.shape[0] != num_parallel:
                      raise TensorforceError.value(
                          name="Agent.act",
                          argument="len(internals[{}])".format(name),
                          value=internal.shape[0],
                          hint="!= len(states)",
                      )
  
      else:
          # Non-independent mode: handle parallel input
          if batched:
              # Batched input
              parallel = np.asarray(parallel)
  
          elif parallel == 0:
              # Default input parallel=0
              if batched:
                  assert num_parallel == self.parallel_interactions
                  parallel = np.asarray(list(range(num_parallel)))
              else:
                  parallel = np.asarray([parallel])
  
          else:
              # Expand input if not batched
              parallel = np.asarray([parallel])
  
          # Check number of inputs
          if parallel.shape[0] != num_parallel:
              raise TensorforceError.value(
                  name="Agent.act",
                  argument="len(parallel)",
                  value=len(parallel),
                  hint="!= len(states)",
              )
  
      # If not independent, check whether previous timesteps were completed
      if not independent:
          if not self.timestep_completed[parallel].all():
              raise TensorforceError(
                  message="Calling agent.act must be preceded by agent.observe for training, or "
                  "agent.act argument 'independent' must be passed as True."
              )
          self.timestep_completed[parallel] = False
  
      # Buffer inputs for recording
      if (
          self.recorder is not None
          and not independent
          and self.num_episodes >= self.recorder.get("start", 0)
      ):
          for n in range(num_parallel):
              for name in self.states_spec:
                  self.buffers["states"][name][parallel[n]].append(
                      states[name][n]
                  )
  
      # fn_act()
      if self._is_agent:
          actions, internals = self.fn_act(
              states=states,
              internals=internals,
              parallel=parallel,
              independent=independent,
              deterministic=deterministic,
              is_internals_none=is_internals_none,
              num_parallel=num_parallel,
          )
      else:
          if batched:
              assert False
          else:
              states = states.fmap(
                  function=(
                      lambda x: x[0].item() if x.shape == (1,) else x[0]
                  )
              )
              actions = self.fn_act(states.to_kwargs())
              if self.actions_spec.is_singleton():
                  actions = ArrayDict(singleton=np.asarray([actions]))
              else:
                  actions = ArrayDict(actions)
                  actions = actions.fmap(
                      function=(lambda x: np.asarray([x]))
                  )
  
      # Buffer outputs for recording
      if (
          self.recorder is not None
          and not independent
          and self.num_episodes >= self.recorder.get("start", 0)
      ):
          for n in range(num_parallel):
              for name in self.actions_spec:
                  self.buffers["actions"][name][parallel[n]].append(
                      actions[name][n]
                  )
  
      # Unbatch actions
      if batched:
          # If inputs were batched, turn dict of lists into list of dicts
          function = lambda x: x.item() if x.shape == () else x
          # TODO: recursive
          if self.actions_spec.is_singleton():
              actions = actions.singleton()
              if is_iter_of_dicts:
                  actions = [
                      function(actions[n]) for n in range(num_parallel)
                  ]
          else:
              if is_iter_of_dicts:
                  actions = [
                      OrderedDict(
                          (
                              (name, function(x[n]))
                              for name, x in actions.items()
                          )
                      )
                      for n in range(num_parallel)
                  ]
              else:
                  actions = OrderedDict(actions.items())
  
          if independent and not is_internals_none:
              if is_iter_of_dicts:
                  # TODO: recursive
                  internals = [
                      OrderedDict(
                          (
                              (name, function(x[n]))
                              for name, x in internals.items()
                          )
                      )
                      for n in range(num_parallel)
                  ]
              else:
                  internals = OrderedDict(internals.items())
  
      else:
          # If inputs were not batched, unbatch outputs
          function = lambda x: x.item() if x.shape == (1,) else x[0]
          if self.actions_spec.is_singleton():
              actions = function(actions.singleton())
          else:
              actions = actions.fmap(function=function, cls=OrderedDict)
          if independent and not is_internals_none:
              internals = internals.fmap(
                  function=function, cls=OrderedDict
              )
  
      if independent and not is_internals_none:
          return actions, internals
      else:
          return actions
  
file_path: tensorforce/tensorforce/agents/recorder.py
imports: import os
  from collections import OrderedDict
  import numpy
  from tensorforce import TensorforceError, util
  from tensorforce.core import ArrayDict, ListDict, TensorSpec, TensorsSpec
label_desc: Use image node_id 6 for calling the Recorder obj's underlying member method code with example usage: obj.act(states, internals, parallel, independent, deterministic) and returns: actions,  internals, actions