code: import logging
  from threading import Thread
  from typing import Any, List, Optional, Type
  
  from llama_index.core.base.base_query_engine import BaseQueryEngine
  from llama_index.core.base.llms.types import ChatMessage, MessageRole
  from llama_index.core.base.response.schema import RESPONSE_TYPE, StreamingResponse
  from llama_index.core.callbacks import CallbackManager, trace_method
  from llama_index.core.chat_engine.types import (
      AgentChatResponse,
      BaseChatEngine,
      StreamingAgentChatResponse,
  )
  from llama_index.core.chat_engine.utils import response_gen_from_query_engine
  from llama_index.core.embeddings.mock_embed_model import MockEmbedding
  from llama_index.core.base.llms.generic_utils import messages_to_history_str
  from llama_index.core.llms.llm import LLM
  from llama_index.core.memory import BaseMemory, ChatMemoryBuffer
  from llama_index.core.prompts.base import BasePromptTemplate, PromptTemplate
  from llama_index.core.service_context import ServiceContext
  from llama_index.core.service_context_elements.llm_predictor import LLMPredictorType
  from llama_index.core.settings import (
      Settings,
      callback_manager_from_settings_or_context,
  )
  from llama_index.core.tools import ToolOutput
  
  logger = logging.getLogger(__name__)
  
  
  DEFAULT_TEMPLATE = """\
  Given a conversation (between Human and Assistant) and a follow up message from Human, \
  rewrite the message to be a standalone question that captures all relevant context \
  from the conversation.
  
  <Chat History>
  {chat_history}
  
  <Follow Up Message>
  {question}
  
  <Standalone question>
  """
  
  DEFAULT_PROMPT = PromptTemplate(DEFAULT_TEMPLATE)
  
  
  class CondenseQuestionChatEngine(BaseChatEngine):
      """Condense Question Chat Engine.
  
      First generate a standalone question from conversation context and last message,
      then query the query engine for a response.
      """
  
      def __init__(
          self,
          query_engine: BaseQueryEngine,
          condense_question_prompt: BasePromptTemplate,
          memory: BaseMemory,
          llm: LLMPredictorType,
          verbose: bool = False,
          callback_manager: Optional[CallbackManager] = None,
      ) -> None:
          self._query_engine = query_engine
          self._condense_question_prompt = condense_question_prompt
          self._memory = memory
          self._llm = llm
          self._verbose = verbose
          self.callback_manager = callback_manager or CallbackManager([])
  
      @classmethod
      def from_defaults(
          cls,
          query_engine: BaseQueryEngine,
          condense_question_prompt: Optional[BasePromptTemplate] = None,
          chat_history: Optional[List[ChatMessage]] = None,
          memory: Optional[BaseMemory] = None,
          memory_cls: Type[BaseMemory] = ChatMemoryBuffer,
          service_context: Optional[ServiceContext] = None,
          verbose: bool = False,
          system_prompt: Optional[str] = None,
          prefix_messages: Optional[List[ChatMessage]] = None,
          llm: Optional[LLM] = None,
          **kwargs: Any,
      ) -> "CondenseQuestionChatEngine":
          """Initialize a CondenseQuestionChatEngine from default parameters."""
          condense_question_prompt = condense_question_prompt or DEFAULT_PROMPT
  
          if llm is None:
              service_context = service_context or ServiceContext.from_defaults(
                  embed_model=MockEmbedding(embed_dim=2)
              )
              llm = service_context.llm
          else:
              service_context = service_context or ServiceContext.from_defaults(
                  llm=llm, embed_model=MockEmbedding(embed_dim=2)
              )
  
          chat_history = chat_history or []
          memory = memory or memory_cls.from_defaults(chat_history=chat_history, llm=llm)
  
          if system_prompt is not None:
              raise NotImplementedError(
                  "system_prompt is not supported for CondenseQuestionChatEngine."
              )
          if prefix_messages is not None:
              raise NotImplementedError(
                  "prefix_messages is not supported for CondenseQuestionChatEngine."
              )
  
          return cls(
              query_engine,
              condense_question_prompt,
              memory,
              llm,
              verbose=verbose,
              callback_manager=callback_manager_from_settings_or_context(
                  Settings, service_context
              ),
          )
  
      def _condense_question(
          self, chat_history: List[ChatMessage], last_message: str
      ) -> str:
          """
          Generate standalone question from conversation context and last message.
          """
          chat_history_str = messages_to_history_str(chat_history)
          logger.debug(chat_history_str)
  
          return self._llm.predict(
              self._condense_question_prompt,
              question=last_message,
              chat_history=chat_history_str,
          )
  
      async def _acondense_question(
          self, chat_history: List[ChatMessage], last_message: str
      ) -> str:
          """
          Generate standalone question from conversation context and last message.
          """
          chat_history_str = messages_to_history_str(chat_history)
          logger.debug(chat_history_str)
  
          return await self._llm.apredict(
              self._condense_question_prompt,
              question=last_message,
              chat_history=chat_history_str,
          )
  
      def _get_tool_output_from_response(
          self, query: str, response: RESPONSE_TYPE
      ) -> ToolOutput:
          if isinstance(response, StreamingResponse):
              return ToolOutput(
                  content="",
                  tool_name="query_engine",
                  raw_input={"query": query},
                  raw_output=response,
              )
          else:
              return ToolOutput(
                  content=str(response),
                  tool_name="query_engine",
                  raw_input={"query": query},
                  raw_output=response,
              )
  
      @trace_method("chat")
      def chat(
          self, message: str, chat_history: Optional[List[ChatMessage]] = None
      ) -> AgentChatResponse:
          chat_history = chat_history or self._memory.get()
  
          # Generate standalone question from conversation context and last message
          condensed_question = self._condense_question(chat_history, message)
  
          log_str = f"Querying with: {condensed_question}"
          logger.info(log_str)
          if self._verbose:
              print(log_str)
  
          # TODO: right now, query engine uses class attribute to configure streaming,
          #       we are moving towards separate streaming and non-streaming methods.
          #       In the meanwhile, use this hack to toggle streaming.
          from llama_index.core.query_engine.retriever_query_engine import (
              RetrieverQueryEngine,
          )
  
          if isinstance(self._query_engine, RetrieverQueryEngine):
              is_streaming = self._query_engine._response_synthesizer._streaming
              self._query_engine._response_synthesizer._streaming = False
  
          # Query with standalone question
          query_response = self._query_engine.query(condensed_question)
  
          # NOTE: reset streaming flag
          if isinstance(self._query_engine, RetrieverQueryEngine):
              self._query_engine._response_synthesizer._streaming = is_streaming
  
          tool_output = self._get_tool_output_from_response(
              condensed_question, query_response
          )
  
          # Record response
          self._memory.put(ChatMessage(role=MessageRole.USER, content=message))
          self._memory.put(
              ChatMessage(role=MessageRole.ASSISTANT, content=str(query_response))
          )
  
          return AgentChatResponse(response=str(query_response), sources=[tool_output])
  
      @trace_method("chat")
      def stream_chat(
          self, message: str, chat_history: Optional[List[ChatMessage]] = None
      ) -> StreamingAgentChatResponse:
          chat_history = chat_history or self._memory.get()
  
          # Generate standalone question from conversation context and last message
          condensed_question = self._condense_question(chat_history, message)
  
          log_str = f"Querying with: {condensed_question}"
          logger.info(log_str)
          if self._verbose:
              print(log_str)
  
          # TODO: right now, query engine uses class attribute to configure streaming,
          #       we are moving towards separate streaming and non-streaming methods.
          #       In the meanwhile, use this hack to toggle streaming.
          from llama_index.core.query_engine.retriever_query_engine import (
              RetrieverQueryEngine,
          )
  
          if isinstance(self._query_engine, RetrieverQueryEngine):
              is_streaming = self._query_engine._response_synthesizer._streaming
              self._query_engine._response_synthesizer._streaming = True
  
          # Query with standalone question
          query_response = self._query_engine.query(condensed_question)
  
          # NOTE: reset streaming flag
          if isinstance(self._query_engine, RetrieverQueryEngine):
              self._query_engine._response_synthesizer._streaming = is_streaming
  
          tool_output = self._get_tool_output_from_response(
              condensed_question, query_response
          )
  
          # Record response
          if (
              isinstance(query_response, StreamingResponse)
              and query_response.response_gen is not None
          ):
              # override the generator to include writing to chat history
              self._memory.put(ChatMessage(role=MessageRole.USER, content=message))
              response = StreamingAgentChatResponse(
                  chat_stream=response_gen_from_query_engine(query_response.response_gen),
                  sources=[tool_output],
              )
              thread = Thread(
                  target=response.write_response_to_history, args=(self._memory, True)
              )
              thread.start()
          else:
              raise ValueError("Streaming is not enabled. Please use chat() instead.")
          return response
  
      @trace_method("chat")
      async def achat(
          self, message: str, chat_history: Optional[List[ChatMessage]] = None
      ) -> AgentChatResponse:
          chat_history = chat_history or self._memory.get()
  
          # Generate standalone question from conversation context and last message
          condensed_question = await self._acondense_question(chat_history, message)
  
          log_str = f"Querying with: {condensed_question}"
          logger.info(log_str)
          if self._verbose:
              print(log_str)
  
          # TODO: right now, query engine uses class attribute to configure streaming,
          #       we are moving towards separate streaming and non-streaming methods.
          #       In the meanwhile, use this hack to toggle streaming.
          from llama_index.core.query_engine.retriever_query_engine import (
              RetrieverQueryEngine,
          )
  
          if isinstance(self._query_engine, RetrieverQueryEngine):
              is_streaming = self._query_engine._response_synthesizer._streaming
              self._query_engine._response_synthesizer._streaming = False
  
          # Query with standalone question
          query_response = await self._query_engine.aquery(condensed_question)
  
          # NOTE: reset streaming flag
          if isinstance(self._query_engine, RetrieverQueryEngine):
              self._query_engine._response_synthesizer._streaming = is_streaming
  
          tool_output = self._get_tool_output_from_response(
              condensed_question, query_response
          )
  
          # Record response
          self._memory.put(ChatMessage(role=MessageRole.USER, content=message))
          self._memory.put(
              ChatMessage(role=MessageRole.ASSISTANT, content=str(query_response))
          )
  
          return AgentChatResponse(response=str(query_response), sources=[tool_output])
  
      @trace_method("chat")
      async def astream_chat(
          self, message: str, chat_history: Optional[List[ChatMessage]] = None
      ) -> StreamingAgentChatResponse:
          chat_history = chat_history or self._memory.get()
  
          # Generate standalone question from conversation context and last message
          condensed_question = await self._acondense_question(chat_history, message)
  
          log_str = f"Querying with: {condensed_question}"
          logger.info(log_str)
          if self._verbose:
              print(log_str)
  
          # TODO: right now, query engine uses class attribute to configure streaming,
          #       we are moving towards separate streaming and non-streaming methods.
          #       In the meanwhile, use this hack to toggle streaming.
          from llama_index.core.query_engine.retriever_query_engine import (
              RetrieverQueryEngine,
          )
  
          if isinstance(self._query_engine, RetrieverQueryEngine):
              is_streaming = self._query_engine._response_synthesizer._streaming
              self._query_engine._response_synthesizer._streaming = True
  
          # Query with standalone question
          query_response = await self._query_engine.aquery(condensed_question)
  
          # NOTE: reset streaming flag
          if isinstance(self._query_engine, RetrieverQueryEngine):
              self._query_engine._response_synthesizer._streaming = is_streaming
  
          tool_output = self._get_tool_output_from_response(
              condensed_question, query_response
          )
  
          # Record response
          if (
              isinstance(query_response, StreamingResponse)
              and query_response.response_gen is not None
          ):
              # override the generator to include writing to chat history
              # TODO: query engine does not support async generator yet
              self._memory.put(ChatMessage(role=MessageRole.USER, content=message))
              response = StreamingAgentChatResponse(
                  chat_stream=response_gen_from_query_engine(query_response.response_gen),
                  sources=[tool_output],
              )
              thread = Thread(
                  target=response.write_response_to_history, args=(self._memory,)
              )
              thread.start()
          else:
              raise ValueError("Streaming is not enabled. Please use achat() instead.")
          return response
  
      def reset(self) -> None:
          # Clear chat history
          self._memory.reset()
  
      @property
      def chat_history(self) -> List[ChatMessage]:
          """Get chat history."""
          return self._memory.get_all()
  
apis: llama_index.core.callbacks.CallbackManager llama_index.core.base.llms.generic_utils.messages_to_history_str llama_index.core.settings.callback_manager_from_settings_or_context llama_index.core.base.llms.types.ChatMessage llama_index.core.prompts.base.PromptTemplate llama_index.core.embeddings.mock_embed_model.MockEmbedding llama_index.core.tools.ToolOutput llama_index.core.chat_engine.utils.response_gen_from_query_engine llama_index.core.callbacks.trace_method
extract_api: [((1220, 1247), 'logging.getLogger', 'logging.getLogger', (['__name__'], {}), '(__name__)\n', (1237, 1247), False, 'import logging\n'), ((1579, 1611), 'llama_index.core.prompts.base.PromptTemplate', 'PromptTemplate', (['DEFAULT_TEMPLATE'], {}), '(DEFAULT_TEMPLATE)\n', (1593, 1611), False, 'from llama_index.core.prompts.base import BasePromptTemplate, PromptTemplate\n'), ((5895, 5915), 'llama_index.core.callbacks.trace_method', 'trace_method', (['"""chat"""'], {}), "('chat')\n", (5907, 5915), False, 'from llama_index.core.callbacks import CallbackManager, trace_method\n'), ((7693, 7713), 'llama_index.core.callbacks.trace_method', 'trace_method', (['"""chat"""'], {}), "('chat')\n", (7705, 7713), False, 'from llama_index.core.callbacks import CallbackManager, trace_method\n'), ((9987, 10007), 'llama_index.core.callbacks.trace_method', 'trace_method', (['"""chat"""'], {}), "('chat')\n", (9999, 10007), False, 'from llama_index.core.callbacks import CallbackManager, trace_method\n'), ((11806, 11826), 'llama_index.core.callbacks.trace_method', 'trace_method', (['"""chat"""'], {}), "('chat')\n", (11818, 11826), False, 'from llama_index.core.callbacks import CallbackManager, trace_method\n'), ((4566, 4603), 'llama_index.core.base.llms.generic_utils.messages_to_history_str', 'messages_to_history_str', (['chat_history'], {}), '(chat_history)\n', (4589, 4603), False, 'from llama_index.core.base.llms.generic_utils import messages_to_history_str\n'), ((5057, 5094), 'llama_index.core.base.llms.generic_utils.messages_to_history_str', 'messages_to_history_str', (['chat_history'], {}), '(chat_history)\n', (5080, 5094), False, 'from llama_index.core.base.llms.generic_utils import messages_to_history_str\n'), ((2381, 2400), 'llama_index.core.callbacks.CallbackManager', 'CallbackManager', (['[]'], {}), '([])\n', (2396, 2400), False, 'from llama_index.core.callbacks import CallbackManager, trace_method\n'), ((5491, 5592), 'llama_index.core.tools.ToolOutput', 'ToolOutput', ([], {'content': '""""""', 'tool_name': '"""query_engine"""', 'raw_input': "{'query': query}", 'raw_output': 'response'}), "(content='', tool_name='query_engine', raw_input={'query': query},\n    raw_output=response)\n", (5501, 5592), False, 'from llama_index.core.tools import ToolOutput\n'), ((7430, 7481), 'llama_index.core.base.llms.types.ChatMessage', 'ChatMessage', ([], {'role': 'MessageRole.USER', 'content': 'message'}), '(role=MessageRole.USER, content=message)\n', (7441, 7481), False, 'from llama_index.core.base.llms.types import ChatMessage, MessageRole\n'), ((9724, 9800), 'threading.Thread', 'Thread', ([], {'target': 'response.write_response_to_history', 'args': '(self._memory, True)'}), '(target=response.write_response_to_history, args=(self._memory, True))\n', (9730, 9800), False, 'from threading import Thread\n'), ((11543, 11594), 'llama_index.core.base.llms.types.ChatMessage', 'ChatMessage', ([], {'role': 'MessageRole.USER', 'content': 'message'}), '(role=MessageRole.USER, content=message)\n', (11554, 11594), False, 'from llama_index.core.base.llms.types import ChatMessage, MessageRole\n'), ((13928, 13999), 'threading.Thread', 'Thread', ([], {'target': 'response.write_response_to_history', 'args': '(self._memory,)'}), '(target=response.write_response_to_history, args=(self._memory,))\n', (13934, 13999), False, 'from threading import Thread\n'), ((4216, 4284), 'llama_index.core.settings.callback_manager_from_settings_or_context', 'callback_manager_from_settings_or_context', (['Settings', 'service_context'], {}), '(Settings, service_context)\n', (4257, 4284), False, 'from llama_index.core.settings import Settings, callback_manager_from_settings_or_context\n'), ((9457, 9508), 'llama_index.core.base.llms.types.ChatMessage', 'ChatMessage', ([], {'role': 'MessageRole.USER', 'content': 'message'}), '(role=MessageRole.USER, content=message)\n', (9468, 9508), False, 'from llama_index.core.base.llms.types import ChatMessage, MessageRole\n'), ((13661, 13712), 'llama_index.core.base.llms.types.ChatMessage', 'ChatMessage', ([], {'role': 'MessageRole.USER', 'content': 'message'}), '(role=MessageRole.USER, content=message)\n', (13672, 13712), False, 'from llama_index.core.base.llms.types import ChatMessage, MessageRole\n'), ((9589, 9648), 'llama_index.core.chat_engine.utils.response_gen_from_query_engine', 'response_gen_from_query_engine', (['query_response.response_gen'], {}), '(query_response.response_gen)\n', (9619, 9648), False, 'from llama_index.core.chat_engine.utils import response_gen_from_query_engine\n'), ((13793, 13852), 'llama_index.core.chat_engine.utils.response_gen_from_query_engine', 'response_gen_from_query_engine', (['query_response.response_gen'], {}), '(query_response.response_gen)\n', (13823, 13852), False, 'from llama_index.core.chat_engine.utils import response_gen_from_query_engine\n'), ((3306, 3332), 'llama_index.core.embeddings.mock_embed_model.MockEmbedding', 'MockEmbedding', ([], {'embed_dim': '(2)'}), '(embed_dim=2)\n', (3319, 3332), False, 'from llama_index.core.embeddings.mock_embed_model import MockEmbedding\n'), ((3515, 3541), 'llama_index.core.embeddings.mock_embed_model.MockEmbedding', 'MockEmbedding', ([], {'embed_dim': '(2)'}), '(embed_dim=2)\n', (3528, 3541), False, 'from llama_index.core.embeddings.mock_embed_model import MockEmbedding\n')]