docs: async def execute(ctx):
      """
      execute story part at the current context
      and make one step further
  
      :param ctx:
      :return:
      """
      tail_depth = len(ctx.stack()) - 1
  
      story_part = ctx.get_current_story_part()
      logger.debug('# going to call: {}'.format(story_part.__name__))
      waiting_for = story_part(ctx.message)
      if inspect.iscoroutinefunction(story_part):
          waiting_for = await waiting_for
      logger.debug('# got result {}'.format(waiting_for))
  
      # story part could run callable story and return its context
      if isinstance(waiting_for, story_context.StoryContext):
          # for such cases is very important to know `tail_depth`
          # because story context from callable story already has
          # few stack items above our tail
          ctx = waiting_for.clone()
          ctx.waiting_for = callable.WaitForReturn()
      else:
          ctx = ctx.clone()
          ctx.waiting_for = waiting_for
  
      tail_data = ctx.message['session']['stack'][tail_depth]['data']
      tail_step = ctx.message['session']['stack'][tail_depth]['step']
      if ctx.is_waiting_for_input():
          if isinstance(ctx.waiting_for, callable.EndOfStory):
              if isinstance(ctx.waiting_for.data, dict):
                  new_data = {**ctx.get_user_data(), **ctx.waiting_for.data}
              else:
                  new_data = ctx.waiting_for.data
              ctx.message = {
                  **ctx.message,
                  'session': {
                      **ctx.message['session'],
                      'data': new_data,
                  },
              }
              tail_step += 1
          elif isinstance(ctx.waiting_for, loop.ScopeMatcher):
              # jumping in a loop
              tail_data = matchers.serialize(ctx.waiting_for)
          elif isinstance(ctx.waiting_for, loop.BreakLoop):
              tail_step += 1
          else:
              tail_data = matchers.serialize(
                  matchers.get_validator(ctx.waiting_for)
              )
              tail_step += 1
  
      ctx.message = modify_stack_in_message(ctx.message,
                                            lambda stack: stack[:tail_depth] +
                                                          [{
                                                              'data': tail_data,
                                                              'step': tail_step,
                                                              'topic': stack[tail_depth]['topic'],
                                                          }] +
                                                          stack[tail_depth + 1:])
      logger.debug('# mutated ctx after execute')
      logger.debug(ctx)
      return ctx