class_docstr: Class for accumulating components of a prompt and then formatting them into an output.
docstr: Validates the messages added so far (reasonable alternation of assistant vs. user, etc.)
  and returns either a regular string (maybe with <|endofprompt|> tokens) or a list of
  HarmonyMessages suitable for use with the /chat/completions endpoint.
  
  The `allow_extra_system_messages` parameter allows the caller to specify that the prompt
  should be allowed to contain system messages after the very first one.
docstr_tok: ["Validates","the","messages","added","so","far","(","reasonable","alternation","of","assistant","vs.","user",",","etc",".",")","and","returns","either","a","regular","string","(","maybe","with","<","|endofprompt|",">","tokens",")","or","a","list","of","HarmonyMessages","suitable","for","use","with","the","\/chat\/completions","endpoint",".","The","`","allow_extra_system_messages","`","parameter","allows","the","caller","to","specify","that","the","prompt","should","be","allowed","to","contain","system","messages","after","the","very","first","one","."]
code: def build(
      self,
      prompt_format: PromptFormat,
      *,
      allow_extra_system_messages: bool = False,
  ) -> Union[str, list[HarmonyMessage]]:
      """
      Validates the messages added so far (reasonable alternation of assistant vs. user, etc.)
      and returns either a regular string (maybe with <|endofprompt|> tokens) or a list of
      HarmonyMessages suitable for use with the /chat/completions endpoint.
  
      The `allow_extra_system_messages` parameter allows the caller to specify that the prompt
      should be allowed to contain system messages after the very first one.
      """
      # Create a deep copy of the messages so we can modify it and so that the caller can't
      # modify the internal state of this object.
      messages = [message.copy() for message in self._messages]
  
      expected_next_role = Role.SYSTEM
      for message in messages:
          role = message["role"]
          assert role == expected_next_role or (
              allow_extra_system_messages and role == Role.SYSTEM
          ), f"Expected message from {expected_next_role} but got message from {role}"
          if role == Role.SYSTEM:
              expected_next_role = Role.USER
          elif role == Role.USER:
              expected_next_role = Role.ASSISTANT
          elif role == Role.ASSISTANT:
              expected_next_role = Role.USER
  
      if prompt_format == PromptFormat.INSTRUCTION_FOLLOWING:
          last_user_message = None
          for message in messages:
              if message["role"] == Role.USER:
                  last_user_message = message
          assert last_user_message is not None
          last_user_message["content"] += "<|endofprompt|>"
  
      if prompt_format == PromptFormat.HARMONY_V4:
          return messages
      elif prompt_format in [
          PromptFormat.NONE,
          PromptFormat.INSTRUCTION_FOLLOWING,
      ]:
          return "".join(message["content"] for message in messages)
      else:
          raise ValueError(f"Unknown prompt format: {prompt_format}")
  
file_path: automated-interpretability/neuron-explainer/neuron_explainer/explanations/prompt_builder.py
imports: from __future__ import annotations
  from enum import Enum
  from typing import TypedDict, Union
  import tiktoken
label_desc: Use image node_id 4 for calling the PromptBuilder obj's underlying member method code with example usage: obj.build(prompt_format) and returns: messages, str