Further enhance and add in advanced General Thinking - Deep Task Understanding with Problem Decomposition (Multi-step Planning). And also Goal-Driven Thought Chains (Meta Reasoning).

```
import g4f
from g4f.client import Client
import logging
import pyperclip  # Library to copy text to the clipboard
import os
import json
from typing import List, Dict
import uuid
import faiss
import numpy as np
from sentence_transformers import SentenceTransformer
import asyncio
import gradio as gr

# Set up logging with rotation
from logging.handlers import RotatingFileHandler

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
handler = RotatingFileHandler("assistant.log", maxBytes=5*1024*1024, backupCount=2)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)

# Initialize the GPT client with the desired provider
client = Client(provider=g4f.Provider.Blackbox)

# File paths for conversation history, memory, and FAISS index
CONVERSATION_LOG_FILE = "conversation_log.json"
MEMORY_FILE = "memory.json"
FAISS_INDEX_FILE = "faiss.index"
MEMORY_METADATA_FILE = "memory_metadata.json"

# Initialize conversation history
messages: List[Dict[str, str]] = []

# Initialize memory
memory: Dict[str, List[Dict[str, str]]] = {}

# Initialize reasoning state
reasoning_state: Dict[str, Dict] = {}

# Initialize Sentence Transformer Model for Embeddings
embedding_model = SentenceTransformer('all-MiniLM-L6-v2')  # Lightweight and effective

# Initialize FAISS Index
def initialize_faiss():
    # Dimension should match the embedding model
    dimension = 384  # 'all-MiniLM-L6-v2' has 384-dimensional embeddings
    if os.path.exists(FAISS_INDEX_FILE):
        try:
            index = faiss.read_index(FAISS_INDEX_FILE)
            logger.info("FAISS index loaded.")
        except Exception as e:
            logger.error(f"Failed to load FAISS index: {e}")
            index = faiss.IndexFlatL2(dimension)
            logger.info("Initialized new FAISS index.")
    else:
        index = faiss.IndexFlatL2(dimension)
        logger.info("FAISS index initialized.")
    return index

faiss_index = initialize_faiss()

# Initialize Metadata Storage
def load_memory_metadata():
    if os.path.exists(MEMORY_METADATA_FILE):
        try:
            with open(MEMORY_METADATA_FILE, "r") as meta_file:
                metadata = json.load(meta_file)
            logger.info("Memory metadata loaded.")
        except Exception as e:
            logger.error(f"Failed to load memory metadata: {e}")
            metadata = []
    else:
        metadata = []
        logger.info("Memory metadata initialized.")
    return metadata

def save_memory_metadata():
    try:
        with open(MEMORY_METADATA_FILE, "w") as meta_file:
            json.dump(memory_metadata, meta_file, indent=4)
        logger.info("Memory metadata saved.")
    except Exception as e:
        logger.error(f"Failed to save memory metadata: {e}")

memory_metadata = load_memory_metadata()

# Load conversation history if it exists
def load_conversation_history():
    global messages
    if os.path.exists(CONVERSATION_LOG_FILE):
        try:
            with open(CONVERSATION_LOG_FILE, "r") as log_file:
                messages = json.load(log_file)
            logger.info("Conversation history loaded.")
        except Exception as e:
            logger.error(f"Failed to load conversation history: {e}")
            messages = []
    else:
        # Add system prompt with chain-of-thought instructions for internal processing
        system_prompt = {
            "role": "system",
            "content": (
                "You are an advanced AI assistant with the ability to reason through problems step-by-step using chain-of-thought. "
                "Maintain context over extended conversations, recall past interactions, and utilize stored memories to provide coherent and contextually relevant responses."
                " Ensure thorough reasoning for complex tasks and provide detailed explanations when required."
            ),
        }
        messages.append(system_prompt)
        logger.info("System prompt initialized.")

# Save conversation history
def save_conversation_history():
    try:
        with open(CONVERSATION_LOG_FILE, "w") as log_file:
            json.dump(messages, log_file, indent=4)
        logger.info("Conversation history saved.")
    except Exception as e:
        logger.error(f"Failed to save conversation history: {e}")

# Load memory if it exists
def load_memory():
    global memory, memory_metadata
    if os.path.exists(MEMORY_FILE):
        try:
            with open(MEMORY_FILE, "r") as memory_file:
                memory = json.load(memory_file)
            logger.info("Memory loaded.")
        except Exception as e:
            logger.error(f"Failed to load memory: {e}")
            memory = {}
    else:
        memory = {}
        logger.info("Memory initialized.")

    # memory_metadata already loaded above

# Save memory
def save_memory():
    try:
        with open(MEMORY_FILE, "w") as memory_file:
            json.dump(memory, memory_file, indent=4)
        logger.info("Memory saved.")
        save_memory_metadata()
    except Exception as e:
        logger.error(f"Failed to save memory: {e}")

# Function to add memory to FAISS
def add_memory_to_faiss(text: str, metadata: Dict):
    try:
        embedding = embedding_model.encode(text)
        faiss_index.add(np.array([embedding]).astype('float32'))
        faiss.write_index(faiss_index, FAISS_INDEX_FILE)
        memory_metadata.append(metadata)
        save_memory_metadata()
        logger.info("Memory added to FAISS index.")
    except Exception as e:
        logger.error(f"Failed to add memory to FAISS: {e}")

# Function to retrieve relevant memories based on user input
def retrieve_relevant_memories(user_input: str, top_k: int = 5) -> List[Dict]:
    try:
        embedding = embedding_model.encode(user_input)
        embedding = np.array([embedding]).astype('float32')
        distances, indices = faiss_index.search(embedding, top_k)
        relevant = []
        for idx in indices[0]:
            if idx < len(memory_metadata):
                relevant.append(memory_metadata[idx])
            else:
                logger.warning(f"FAISS returned out-of-bounds index: {idx}")
        return relevant
    except Exception as e:
        logger.error(f"Failed to retrieve relevant memories: {e}")
        return []

# Function to extract code blocks from text
def extract_code_block(text: str) -> str:
    """
    Extracts the code block from a text enclosed in triple backticks.
    """
    if "```" in text:
        parts = text.split("```")
        if len(parts) >= 3:
            # Case with language specified, e.g., ```python
            return parts[2].strip()
        elif len(parts) == 2:
            # Case without language specification
            return parts[1].strip()
    return ""

# Function to retrieve the last memory entry of a specific type
def retrieve_last_memory_of_type(memory_type: str) -> str:
    """
    Retrieves the last memory entry of a specific type ('code', 'explanation', etc.).
    """
    # Iterate in reverse to find the latest relevant memory
    for entry in reversed(memory_metadata):
        text_lower = entry["text"].lower()
        if memory_type == "code" and "code" in text_lower:
            # Extract code block
            code_block = extract_code_block(entry["text"])
            if code_block:
                return code_block
        elif memory_type == "explanation" and "explanation" in text_lower:
            return entry["text"]
    return ""

# Update memory based on the latest assistant response
def update_memory(user_input: str, assistant_response: str):
    # Combine user input and assistant response for context
    combined_text = f"User: {user_input}\nAssistant: {assistant_response}"
    # Add to memory dictionary
    timestamp = uuid.uuid4().hex  # Unique identifier
    if timestamp not in memory:
        memory[timestamp] = []
    memory[timestamp].append({
        "user": user_input,
        "assistant": assistant_response
    })
    # Add to FAISS index
    add_memory_to_faiss(combined_text, {
        "id": timestamp,
        "text": combined_text
    })
    logger.info("Memory updated with semantic embeddings.")

# Initialize conversation and memory
load_conversation_history()
load_memory()

print("Welcome to the Enhanced Coding Assistant with Advanced Reasoning and Long-Term Memory! Type 'exit' to end the conversation.")

def copy_code_to_clipboard(code: str):
    """Copies the provided code to the clipboard."""
    try:
        pyperclip.copy(code)
        logger.info("Code copied to clipboard.")
        return "Code copied to clipboard!"
    except Exception as e:
        logger.error(f"Error while copying code to clipboard: {e}", exc_info=True)
        return "An error occurred while trying to copy the code."

# Define AI Worker classes
class AIWorker:
    """Base class for AI Workers."""
    def __init__(self, name: str):
        self.name = name

    async def process(self, task: Dict, context: Dict) -> Dict:
        raise NotImplementedError("Each AIWorker must implement the process method.")

class CodeGeneratorWorker(AIWorker):
    """AI Worker specialized in generating code."""
    def __init__(self):
        super().__init__("CodeGenerator")

    async def process(self, task: Dict, context: Dict) -> Dict:
        try:
            user_input = task.get("input")
            prompt = (
                "You will be provided with a user request. "
                "Please generate the corresponding Python code within triple backticks. "
                "Use chain-of-thought internally to reason through the problem step-by-step, "
                "but only output the final code without any explanations."
            )
            full_prompt = f"{prompt}\n\nUser Request: {user_input}"
            logger.info(f"{self.name} processing task: {user_input}")
            response = client.chat.completions.create(
                messages=[
                    {"role": "system", "content": full_prompt}
                ],
                model="blackbox",
                # Adjust parameters to allow longer responses
                max_tokens=3500,  # Increased token limit
                temperature=0.7,  # Adjust temperature for creativity
            )
            if response.choices and len(response.choices) > 0:
                code = response.choices[0].message.content
                # Ensure only code block is returned
                code = extract_code_block(code)
                # Handle long code by chunking
                code_chunks = chunk_text(code, max_length=2000)
                return {"code": "\n".join(code_chunks)}
            else:
                code = "I'm sorry, but I couldn't generate the code at this time."
                logger.warning("CodeGeneratorWorker: GPT response choices are empty.")
            return {"code": code}
        except Exception as e:
            logger.error(f"{self.name} encountered an error: {e}", exc_info=True)
            return {"code": "An error occurred while generating the code."}

class ExplanationWorker(AIWorker):
    """AI Worker specialized in explaining code or concepts."""
    def __init__(self):
        super().__init__("Explanation")

    async def process(self, task: Dict, context: Dict) -> Dict:
        try:
            code = task.get("code")
            if not code:
                return {"explanation": "No code provided for explanation."}
            prompt = (
                "You are provided with a Python code snippet. "
                "Use your chain-of-thought reasoning to understand the code step-by-step, "
                "and provide a detailed explanation of what the code does."
                " Ensure the explanation is clear and concise without including the internal reasoning process."
            )
            full_prompt = f"{prompt}\n\nCode:\n```python\n{code}\n```"
            logger.info(f"{self.name} processing task.")
            response = client.chat.completions.create(
                messages=[
                    {"role": "system", "content": full_prompt}
                ],
                model="gpt-4o",
                max_tokens=3000,  # Increased token limit
                temperature=0.7,
            )
            if response.choices and len(response.choices) > 0:
                explanation = response.choices[0].message.content
                # Handle long explanations by chunking
                explanation_chunks = chunk_text(explanation, max_length=2000)
                return {"explanation": "\n".join(explanation_chunks)}
            else:
                explanation = "I'm sorry, but I couldn't provide an explanation at this time."
                logger.warning("ExplanationWorker: GPT response choices are empty.")
            return {"explanation": explanation}
        except Exception as e:
            logger.error(f"{self.name} encountered an error: {e}", exc_info=True)
            return {"explanation": "An error occurred while explaining the code."}

class DataRetrievalWorker(AIWorker):
    """AI Worker specialized in retrieving data or information."""
    def __init__(self):
        super().__init__("DataRetrieval")

    async def process(self, task: Dict, context: Dict) -> Dict:
        try:
            query = task.get("query")
            prompt = (
                "You are provided with a data retrieval request. "
                "Analyze the request using chain-of-thought reasoning to understand the required information. "
                "Provide the final detailed information without any internal explanations."
            )
            full_prompt = f"{prompt}\n\nData Request: {query}"
            logger.info(f"{self.name} processing task: {query}")
            response = client.chat.completions.create(
                messages=[
                    {"role": "system", "content": full_prompt}
                ],
                model="gpt-4o",
                max_tokens=3500,  # Increased token limit
                temperature=0.7,
            )
            if response.choices and len(response.choices) > 0:
                data = response.choices[0].message.content
                # Handle long data by chunking
                data_chunks = chunk_text(data, max_length=2000)
                return {"data": "\n".join(data_chunks)}
            else:
                data = "I'm sorry, but I couldn't retrieve the data at this time."
                logger.warning("DataRetrievalWorker: GPT response choices are empty.")
            return {"data": data}
        except Exception as e:
            logger.error(f"{self.name} encountered an error: {e}", exc_info=True)
            return {"data": "An error occurred while retrieving the data."}

class PruningWorker(AIWorker):
    """AI Worker specialized in code optimization."""
    def __init__(self):
        super().__init__("Pruning")

    async def process(self, task: Dict, context: Dict) -> Dict:
        try:
            code = task.get("code")
            if not code:
                return {"optimized_code": "No code provided for optimization."}
            prompt = (
                "You are provided with a Python code snippet that implements the Quicksort algorithm. "
                "Use your chain-of-thought reasoning to analyze and optimize the code for better performance and readability. "
                "Provide only the optimized code within triple backticks without any additional explanations."
            )
            full_prompt = f"{prompt}\n\nOriginal Code:\n```python\n{code}\n```"
            logger.info(f"{self.name} processing task.")
            response = client.chat.completions.create(
                messages=[
                    {"role": "system", "content": full_prompt}
                ],
                model="blackbox",
                max_tokens=3500,  # Increased token limit
                temperature=0.7,
            )
            if response.choices and len(response.choices) > 0:
                optimized_code = response.choices[0].message.content
                optimized_code = extract_code_block(optimized_code)
                # Handle long optimized code by chunking
                optimized_code_chunks = chunk_text(optimized_code, max_length=2000)
                return {"optimized_code": "\n".join(optimized_code_chunks)}
            else:
                optimized_code = "I'm sorry, but I couldn't optimize the code at this time."
                logger.warning("PruningWorker: GPT response choices are empty.")
            return {"optimized_code": optimized_code}
        except Exception as e:
            logger.error(f"{self.name} encountered an error: {e}", exc_info=True)
            return {"optimized_code": "An error occurred while optimizing the code."}

# New Worker: SummarizationWorker
class SummarizationWorker(AIWorker):
    """AI Worker specialized in summarizing text."""
    def __init__(self):
        super().__init__("Summarization")

    async def process(self, task: Dict, context: Dict) -> Dict:
        try:
            text = task.get("text")
            if not text:
                return {"summary": "No text provided for summarization."}
            prompt = (
                "Provide a concise summary of the following text. "
                "Ensure the summary captures all key points without adding any new information. "
                "Use clear and precise language."
            )
            full_prompt = f"{prompt}\n\nText:\n{text}"
            logger.info(f"{self.name} processing task.")
            response = client.chat.completions.create(
                messages=[
                    {"role": "system", "content": full_prompt}
                ],
                model="blackbox",
                max_tokens=4500,
                temperature=0.5,
            )
            if response.choices and len(response.choices) > 0:
                summary = response.choices[0].message.content
                # Handle long summaries by chunking
                summary_chunks = chunk_text(summary, max_length=2000)
                return {"summary": "\n".join(summary_chunks)}
            else:
                summary = "I'm sorry, but I couldn't generate a summary at this time."
                logger.warning("SummarizationWorker: GPT response choices are empty.")
            return {"summary": summary}
        except Exception as e:
            logger.error(f"{self.name} encountered an error: {e}", exc_info=True)
            return {"summary": "An error occurred while summarizing the text."}

# New Worker: TranslationWorker
class TranslationWorker(AIWorker):
    """AI Worker specialized in translating text."""
    def __init__(self):
        super().__init__("Translation")

    async def process(self, task: Dict, context: Dict) -> Dict:
        try:
            text = task.get("text")
            target_language = task.get("language", "Spanish")  # Default to Spanish
            if not text:
                return {"translation": "No text provided for translation."}
            prompt = (
                f"Translate the following text into {target_language}. "
                "Ensure the translation is accurate and maintains the original context. "
                "Use proper grammar and syntax."
            )
            full_prompt = f"{prompt}\n\nText:\n{text}"
            logger.info(f"{self.name} processing task.")
            response = client.chat.completions.create(
                messages=[
                    {"role": "system", "content": full_prompt}
                ],
                model="gpt-4o",
                max_tokens=3500,
                temperature=0.3,
            )
            if response.choices and len(response.choices) > 0:
                translation = response.choices[0].message.content
                # Handle long translations by chunking
                translation_chunks = chunk_text(translation, max_length=2000)
                return {"translation": "\n".join(translation_chunks)}
            else:
                translation = "I'm sorry, but I couldn't perform the translation at this time."
                logger.warning("TranslationWorker: GPT response choices are empty.")
            return {"translation": translation}
        except Exception as e:
            logger.error(f"{self.name} encountered an error: {e}", exc_info=True)
            return {"translation": "An error occurred while translating the text."}

# Additional Worker: DebuggingWorker
class DebuggingWorker(AIWorker):
    """AI Worker specialized in debugging code."""
    def __init__(self):
        super().__init__("Debugging")

    async def process(self, task: Dict, context: Dict) -> Dict:
        try:
            code = task.get("code")
            error_message = task.get("error")
            if not code or not error_message:
                return {"debugging": "Insufficient information provided for debugging."}
            prompt = (
                "You are provided with a Python code snippet and an associated error message. "
                "Use your chain-of-thought reasoning to identify the cause of the error and provide a corrected version of the code. "
                "Include comments explaining the changes made."
            )
            full_prompt = f"{prompt}\n\nOriginal Code:\n```python\n{code}\n```\n\nError Message:\n{error_message}"
            logger.info(f"{self.name} processing task.")
            response = client.chat.completions.create(
                messages=[
                    {"role": "system", "content": full_prompt}
                ],
                model="blackbox",
                max_tokens=3500,
                temperature=0.7,
            )
            if response.choices and len(response.choices) > 0:
                debugging_output = response.choices[0].message.content
                # Handle long debugging outputs by chunking
                debugging_chunks = chunk_text(debugging_output, max_length=2000)
                return {"debugging": "\n".join(debugging_chunks)}
            else:
                debugging_output = "I'm sorry, but I couldn't debug the code at this time."
                logger.warning("DebuggingWorker: GPT response choices are empty.")
            return {"debugging": debugging_output}
        except Exception as e:
            logger.error(f"{self.name} encountered an error: {e}", exc_info=True)
            return {"debugging": "An error occurred while debugging the code."}

# Additional Worker: OptimizationWorker
class OptimizationWorker(AIWorker):
    """AI Worker specialized in optimizing algorithms."""
    def __init__(self):
        super().__init__("Optimization")

    async def process(self, task: Dict, context: Dict) -> Dict:
        try:
            algorithm_description = task.get("algorithm")
            if not algorithm_description:
                return {"optimization": "No algorithm description provided for optimization."}
            prompt = (
                "You are provided with a description of an algorithm. "
                "Use your chain-of-thought reasoning to analyze the algorithm and provide an optimized version. "
                "Focus on improving time and space complexity without compromising correctness."
            )
            full_prompt = f"{prompt}\n\nAlgorithm Description:\n{algorithm_description}"
            logger.info(f"{self.name} processing task.")
            response = client.chat.completions.create(
                messages=[
                    {"role": "system", "content": full_prompt}
                ],
                model="gpt-4o",
                max_tokens=3500,
                temperature=0.7,
            )
            if response.choices and len(response.choices) > 0:
                optimization_output = response.choices[0].message.content
                # Handle long optimization outputs by chunking
                optimization_chunks = chunk_text(optimization_output, max_length=2000)
                return {"optimization": "\n".join(optimization_chunks)}
            else:
                optimization_output = "I'm sorry, but I couldn't optimize the algorithm at this time."
                logger.warning("OptimizationWorker: GPT response choices are empty.")
            return {"optimization": optimization_output}
        except Exception as e:
            logger.error(f"{self.name} encountered an error: {e}", exc_info=True)
            return {"optimization": "An error occurred while optimizing the algorithm."}

# Helper function to chunk text
def chunk_text(text: str, max_length: int = 2000) -> List[str]:
    """
    Splits the text into chunks of specified maximum length.
    """
    return [text[i:i + max_length] for i in range(0, len(text), max_length)]

# Initialize AI Workers with the new additions
ai_workers = {
    "code_generator": CodeGeneratorWorker(),
    "explanation": ExplanationWorker(),
    "data_retrieval": DataRetrievalWorker(),
    "pruning": PruningWorker(),
    "summarization": SummarizationWorker(),  # New Worker
    "translation": TranslationWorker(),        # New Worker
    "debugging": DebuggingWorker(),            # Additional Worker
    "optimization": OptimizationWorker(),      # Additional Worker
}

async def dispatch_tasks_async(tasks: List[Dict], context: Dict) -> Dict:
    """
    Dispatches tasks to the appropriate AI Workers asynchronously and aggregates the results.
    """
    results = {}
    tasks_coroutines = []
    for task in tasks:
        worker_type = task.get("worker")
        if worker_type in ai_workers:
            worker = ai_workers[worker_type]
            tasks_coroutines.append(worker.process(task, context))
        else:
            logger.warning(f"No AI Worker found for type: {worker_type}")
    try:
        tasks_results = await asyncio.gather(*tasks_coroutines, return_exceptions=True)
        for results_item in tasks_results:
            if isinstance(results_item, Exception):
                logger.error(f"Error in AI Worker processing: {results_item}", exc_info=True)
            elif isinstance(results_item, dict):
                results.update(results_item)
    except Exception as e:
        logger.error(f"Error during task dispatching: {e}", exc_info=True)
    return results

# Incremental Reasoning Function with Multi-Step Problem Solving
async def incremental_reasoning_async(user_input: str, context: Dict) -> Dict:
    """
    Performs incremental reasoning by breaking down the user input into tasks,
    dispatching them to AI Workers, and aggregating the results.
    """
    reasoning_id = str(uuid.uuid4())
    reasoning_state[reasoning_id] = {
        "steps": [],
        "results": {}
    }

    # Example: For demonstration, we'll categorize based on keywords
    # In a real implementation, use NLP to parse and categorize the tasks
    tasks = []
    lower_input = user_input.lower()

    # Multi-step optimization for Quicksort
    if "optimize" in lower_input and "quicksort" in lower_input:
        tasks.append({"worker": "pruning", "code": user_input})

    # Code generation
    if "code" in lower_input or "generate" in lower_input:
        tasks.append({"worker": "code_generator", "input": user_input})

    # Code explanation
    if "explain" in lower_input:
        # Retrieve the last generated code if exists
        last_code = retrieve_last_memory_of_type("code")
        if last_code:
            tasks.append({"worker": "explanation", "code": last_code})
        else:
            logger.info("No recent code found for explanation.")

    # Data retrieval
    if "data" in lower_input or "information" in lower_input:
        tasks.append({"worker": "data_retrieval", "query": user_input})

    # Summarization
    if "summarize" in lower_input or "summary" in lower_input:
        tasks.append({"worker": "summarization", "text": user_input})

    # Translation
    if "translate" in lower_input:
        tasks.append({"worker": "translation", "text": user_input, "language": "French"})  # Example target language

    # Debugging
    if "debug" in lower_input or "error" in lower_input:
        # Assume the user provides code and an error message separated by a delimiter, e.g., '||'
        if "||" in user_input:
            code_part, error_part = user_input.split("||", 1)
            tasks.append({"worker": "debugging", "code": code_part.strip(), "error": error_part.strip()})
        else:
            logger.info("Insufficient information for debugging.")

    # Optimization
    if "optimize algorithm" in lower_input or "optimize" in lower_input:
        tasks.append({"worker": "optimization", "algorithm": user_input})

    # Dispatch tasks to AI Workers
    logger.info(f"Dispatching {len(tasks)} tasks for reasoning ID: {reasoning_id}")
    results = await dispatch_tasks_async(tasks, context)

    reasoning_state[reasoning_id]["steps"].extend(tasks)
    reasoning_state[reasoning_id]["results"].update(results)

    return results

# Gradio Interface Function with Advanced Features
async def chat_interface(user_input: str, history: List[Dict[str, str]]):
    if user_input.lower() == "exit":
        response = "Exiting chat..."
        # Append the exit message to history
        history.append({"role": "assistant", "content": response})
        save_conversation_history()  # Save the conversation before exiting
        save_memory()  # Save memory before exiting
        return history, history

    # Append user message in 'role'/'content' format
    history.append({"role": "user", "content": user_input})
    messages.append({"role": "user", "content": user_input})  # Sync with messages list

    # Retrieve relevant memories based on user input
    relevant_memories = retrieve_relevant_memories(user_input)
    if relevant_memories:
        memory_prompt = "\n".join([f"{entry['text']}" for entry in relevant_memories])
        system_message = {
            "role": "system",
            "content": f"Relevant past interactions:\n{memory_prompt}"
        }
        messages.append(system_message)
        history.append(system_message)
        logger.info(f"Retrieved {len(relevant_memories)} relevant memories.")

    # Perform incremental reasoning asynchronously
    reasoning_results = await incremental_reasoning_async(user_input, reasoning_state)

    # Generate assistant response based on reasoning results
    assistant_response = ""
    if "code" in reasoning_results:
        code = reasoning_results['code']
        assistant_response += f"Here is the code you requested:\n```python\n{code}\n```\n\n"

    if "optimized_code" in reasoning_results:
        optimized_code = reasoning_results['optimized_code']
        assistant_response += f"Optimized Code:\n```python\n{optimized_code}\n```\n\n"

    if "explanation" in reasoning_results:
        explanation = reasoning_results['explanation']
        assistant_response += f"**Explanation:**\n{explanation}\n\n"

    if "data" in reasoning_results:
        data = reasoning_results['data']
        assistant_response += f"**Data:**\n{data}\n\n"

    if "summary" in reasoning_results:
        summary = reasoning_results['summary']
        assistant_response += f"**Summary:**\n{summary}\n\n"

    if "translation" in reasoning_results:
        translation = reasoning_results['translation']
        assistant_response += f"**Translation:**\n{translation}\n\n"

    if "debugging" in reasoning_results:
        debugging = reasoning_results['debugging']
        assistant_response += f"**Debugging Information:**\n{debugging}\n\n"

    if "optimization" in reasoning_results:
        optimization = reasoning_results['optimization']
        assistant_response += f"**Algorithm Optimization:**\n{optimization}\n\n"

    # If no specific tasks were dispatched, fall back to general response
    if not assistant_response:
        try:
            response = client.chat.completions.create(
                messages=messages,
                model="gpt-4o",
                max_tokens=4000,  # Increased token limit for longer responses
                temperature=0.7,
            )
            if response.choices and len(response.choices) > 0:
                assistant_response = response.choices[0].message.content
                # Handle long responses by chunking
                response_chunks = chunk_text(assistant_response, max_length=2000)
                assistant_response = "\n".join(response_chunks)
            else:
                assistant_response = "I'm sorry, but I couldn't generate a response at this time."
                logger.warning("Fallback GPT response choices are empty.")
        except Exception as e:
            assistant_response = "An error occurred while generating a response."
            logger.error(f"Fallback GPT error: {e}", exc_info=True)

    # Append assistant message in 'role'/'content' format
    history.append({"role": "assistant", "content": assistant_response})
    messages.append({"role": "assistant", "content": assistant_response})  # Sync with messages list

    # Log the assistant's response
    logger.info(f"Bot: {assistant_response}")

    # Update memory with the latest interaction
    update_memory(user_input, assistant_response)

    return history, history

# Launch Gradio Interface with Advanced Features
def launch_gradio():
    with gr.Blocks(theme="default") as interface:
        gr.Markdown("""
        # 🧑‍💻 **Enhanced Coding Assistant**

        Interact with an AI assistant that can generate, optimize, explain code, summarize texts, translate languages, debug code, and retrieve information. Supports advanced Markdown formatting for rich responses.
        """)
        with gr.Tab("Chat"):
            with gr.Row():
                with gr.Column(scale=8):
                    user_input = gr.Textbox(label="You:", placeholder="Type your message here...", lines=2)
                with gr.Column(scale=2):
                    send_button = gr.Button("Send", variant="primary")
            with gr.Row():
                with gr.Column():
                    chatbot = gr.Chatbot(label="Chat History", type="messages")  # Updated type parameter
            # Hidden state to maintain conversation
            state = gr.State([])

        with gr.Tab("Conversation Log"):
            gr.Markdown("### 📝 Conversation History")
            conversation_display = gr.JSON(label="History", value=messages)

        with gr.Tab("Memory"):
            gr.Markdown("### 🧠 AI Assistant Memory")
            memory_display = gr.JSON(label="Memory", value=memory)

        # Define the action when send button is clicked or Enter is pressed
        send_button.click(fn=chat_interface, inputs=[user_input, state], outputs=[chatbot, state])
        user_input.submit(fn=chat_interface, inputs=[user_input, state], outputs=[chatbot, state])

    # Updated queue parameters
    interface.queue(max_size=10)  # Adjusted from concurrency_count=10 based on latest Gradio

    interface.launch()

# Run the Gradio interface when the script is executed
if __name__ == "__main__":
    try:
        load_conversation_history()
        launch_gradio()
    except KeyboardInterrupt:
        print("\nChatbot terminated by user.")
        logger.info("Chatbot terminated by user via KeyboardInterrupt.")
    except Exception as e:
        print(f"An unexpected error occurred: {e}")
        logger.error(f"Unexpected error: {e}", exc_info=True)