I will provide you my current code, a refactor/new feature prompt, and my current implementation solving that prompt. I would like you to review it search for any regressions. Search for any improvements or evolutions to the current plan. And any other information you pick up from your critical examination of the original prompt, current code, and updated code/plan. Please provide me the complete updated code files:

Current Code
```
chat.py


import logging
import json
import os
from typing import List, Dict, Any, Tuple
from efc.efc_cache import get_file_context
from app_state import get_app_state
from chat.model_config import get_model_config
from tools.tools import ToolManager
from utils.token_usage import update_token_usage
from chat.factory import AIClientFactory
import asyncio
import logging
# logging.basicConfig(level=logging.DEBUG)


logging.basicConfig(level=logging.INFO)


async def chat_with_model(user_input: str, tool_manager: ToolManager, model_name: str) -> str:
    logging.info(f"Processing user input: {user_input}")
    logging.info(f"Using model: {model_name}")
    logging.info(f"Available tools: {[tool['function']['name'] for tool in tool_manager.get_tool_descriptions()]}")
    
    app_state = get_app_state()
    # Add the new user input to the history before optimization
    app_state.conversation_history.append({"role": "user", "content": user_input})
    file_context = get_file_context()
    model_config = get_model_config(model_name)
    
    ai_client = AIClientFactory.get_ai_client(model_name)
    logging.info(f"Using AI client: {type(ai_client).__name__}")

    optimized_history = optimize_conversation_history(app_state.conversation_history, app_state.file_histories)
    # file_context_summary = file_context.get_context_for_llm()
    file_context_summary =  file_context.generate_context_awareness_prompt(app_state)
    logging.info(f"context awareness promptt: {file_context_summary}")
    # system_message = f"{model_config['base_system_prompt']}\n\n{model_config['function_definitions']}\n\n{file_context_summary}"
    system_message = f"{model_config['base_system_prompt']}\n\n{file_context_summary}"

    tools = tool_manager.get_tool_descriptions(format="claude" if model_name.lower() in ['sonnet', 'claude-3-sonnet-20240229'] else "default")
    logging.info(f"History passed to AI client: {optimized_history}")
    try:
        logging.info("Creating message with AI client")
        response = await ai_client.create_message(
            prompt=user_input,
            system_message=system_message,
            tools=tools,
             history=optimized_history[:-1]
        )
        logging.info("Message created successfully")

        if hasattr(response, 'usage'):
            if model_name.lower() in ['sonnet', 'claude-3-sonnet-20240229']:
                update_token_usage(model_name, {
                    "prompt_tokens": response.usage.input_tokens,
                    "completion_tokens": response.usage.output_tokens,
                    "total_tokens": response.usage.input_tokens + response.usage.output_tokens,
                    "cache_creation_tokens": getattr(response.usage, 'cache_creation_input_tokens', 0),
                    "cache_read_tokens": getattr(response.usage, 'cache_read_input_tokens', 0)
                })
            else:  # For Llama and GPT
                update_token_usage(model_name, {
                    "prompt_tokens": response.usage.prompt_tokens,
                    "completion_tokens": response.usage.completion_tokens,
                    "total_tokens": response.usage.total_tokens
                })
    except Exception as e:
        logging.error(f"API Error: {str(e)}")
        return f"I'm sorry, there was an error communicating with the AI. Please try again. Error: {str(e)}"

        # With:
    if hasattr(ai_client, 'extract_response'):
        assistant_response = ai_client.extract_response(response)
        if asyncio.iscoroutine(assistant_response):
            assistant_response = await assistant_response
    else:
        assistant_response = response.content[0].text if response.content else ""
        
    logging.info(f"EXTRACTED RESPONSE: {assistant_response}")
    function_calls = ai_client.extract_function_calls(response)
    function_results = await execute_function_calls(function_calls, tool_manager, model_name)
    
    if not assistant_response and function_results:
        assistant_response = "I've performed the following actions based on your request:\n\n"
    assistant_response = integrate_function_results(assistant_response, function_results, model_config)


    app_state.conversation_history.append({"role": "assistant", "content": assistant_response})
    logging.info(f"Final assistant response: {assistant_response}")
    return assistant_response


async def execute_function_calls(function_calls, tool_manager, model_name):
    results = []
    if asyncio.iscoroutine(function_calls):
        function_calls = await function_calls
    for function_call in function_calls:
        try:
            if isinstance(function_call, dict):
                # Llama format
                func_name = function_call.get('function')
                arguments = function_call.get('arguments', {})
            else:
                # GPT-4 format
                func_name = function_call.function.name
                arguments = json.loads(function_call.function.arguments)

            result = await tool_manager.execute_tool({"function": func_name, "arguments": arguments}, model_name)
            results.append((func_name, arguments, result))
        except Exception as e:
            logging.error(f"Error executing function: {str(e)}")
            results.append((func_name, arguments, f"Error executing function: {str(e)}"))
    return results

def integrate_function_results(assistant_response: str, function_results: List[Tuple[str, Dict, str]], model_config: Dict) -> str:
    if not assistant_response:
        assistant_response = "Here are the results of the actions I've taken:\n\n"
    
    for func_name, args, result in function_results:
        if model_config.get('use_tool_calls', False):
            assistant_response += f"\n\nResult of {func_name}: {result}"
        else:
            # For models that embed function calls in the response
            placeholder = f"<function={func_name}>{json.dumps(args)}</function>"
            if placeholder in assistant_response:
                assistant_response = assistant_response.replace(placeholder, str(result))
            else:
                assistant_response += f"\n\nResult of {func_name}: {result}"
    
    return assistant_response


from dataclasses import dataclass
from typing import List, Dict, Any
import difflib
import logging
import time

@dataclass
class FileHistory:
    most_recent_content: str
    second_most_recent_content: str
    diff_summary: str
    last_update_timestamp: float


def optimize_conversation_history(history: List[Dict[str, Any]], file_histories: Dict[str, FileHistory]) -> List[Dict[str, Any]]:
    # logging.info(f"History before optimization: {history}")
    optimized_history = history.copy()
    file_instance_count = {}
    file_instances = {}

    # First pass: count instances and collect content
    for i, message in enumerate(optimized_history):
        if message['role'] == 'assistant' and is_file_content(message['content']):
            relative_path = extract_relative_path(message['content'])
            file_instance_count[relative_path] = file_instance_count.get(relative_path, 0) + 1
            if relative_path not in file_instances:
                file_instances[relative_path] = []
            file_content = extract_file_content(message['content'])
            file_instances[relative_path].append((i, file_content))
            
            # Update the message content with relative path
            message['content'] = f"Fresh content for {relative_path}: {file_content}"

    # Second pass: summarize oldest instance if more than two
    for relative_path, instances in file_instances.items():
        if len(instances) > 2:
            oldest_index, oldest_content = instances[0]
            second_oldest_index, second_oldest_content = instances[1]
            newest_index, newest_content = instances[-1]

            if file_histories is not None:
                update_file_history(relative_path, newest_content, file_histories, is_latest=True)
                update_file_history(relative_path, second_oldest_content, file_histories, is_latest=False)

            summary = generate_summary(relative_path, oldest_content, newest_content, second_oldest_content)
            optimized_history[oldest_index]['content'] = summary
    logging.info(f"History after optimization: {optimized_history}")
    return optimized_history

def extract_relative_path(content: str) -> str:
    app_state = get_app_state()
    active_project = app_state.active_project
    if "Fresh content for" in content:
        full_path = content.split("Fresh content for")[1].split(":")[0].strip()
    elif "Cached content for" in content:
        full_path = content.split("Cached content for")[1].split(":")[0].strip()
    else:
        return "Unknown File"
    
    return os.path.relpath(full_path, active_project)

def generate_summary(relative_path: str, original_content: str, latest_content: str, second_latest_content: str, max_length: int = 200) -> str:
    app_state = get_app_state()
    active_project = os.path.basename(app_state.active_project)

    original_lines = original_content.splitlines()
    latest_lines = latest_content.splitlines()
    second_latest_lines = second_latest_content.splitlines()

    diff1 = list(difflib.unified_diff(original_lines, second_latest_lines, lineterm=''))
    diff2 = list(difflib.unified_diff(second_latest_lines, latest_lines, lineterm=''))

    changes1 = [line for line in diff1 if line.startswith('+') or line.startswith('-')][:3]
    changes2 = [line for line in diff2 if line.startswith('+') or line.startswith('-')][:3]

    summary = f"Original content: {original_content[:50]}... "
    if changes1:
        summary += f"First update changes: {'; '.join(changes1)} "
    if changes2:
        summary += f"Second update changes: {'; '.join(changes2)}"

    return f"Summary of changes in {relative_path} (in project: {active_project}, as of {time.strftime('%Y-%m-%d %H:%M:%S')}): {summary[:max_length]}..."

def update_file_history(relative_path: str, new_content: str, file_histories: Dict[str, FileHistory], is_latest: bool) -> None:
    if relative_path not in file_histories:
        file_histories[relative_path] = FileHistory(new_content, "", "", time.time())
    else:
        history = file_histories[relative_path]
        if is_latest:
            history.second_most_recent_content = history.most_recent_content
            history.most_recent_content = new_content
        else:
            history.second_most_recent_content = new_content
        history.last_update_timestamp = time.time()

def is_file_content(content: str) -> bool:
    return "Fresh content for" in content or "Cached content for" in content

def extract_file_content(content: str) -> str:
    return content.split(":", 1)[1].strip()
efc_cache.py


import time
from typing import Dict, Any, Optional
from datetime import datetime
import hashlib
import logging
import os
import time
import hashlib
from datetime import datetime
from typing import Dict, Any, Optional
from app_state import get_app_state

class FileCache:
    def __init__(self):
        self._cache: Dict[str, Dict[str, Any]] = {}

    def get(self, relative_path: str) -> Optional[str]:
        if relative_path in self._cache:
            cache_entry = self._cache[relative_path]
            if time.time() - cache_entry['timestamp'] < 3000:  # 50 minutes expiration
                return cache_entry['content']
        return None

    def set(self, relative_path: str, content: str) -> None:
        self._cache[relative_path] = {
            'content': content,
            'timestamp': time.time()
        }

    def clear(self, relative_path: Optional[str] = None) -> None:
        if relative_path:
            self._cache.pop(relative_path, None)
        else:
            self._cache.clear()

class FileContextTracker:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super(FileContextTracker, cls).__new__(cls)
            cls._instance.tracked_files = {}
            cls._instance.last_api_call_time = datetime.min
            cls._instance.file_cache = FileCache()
        return cls._instance

    def force_refresh(self):
        app_state = get_app_state()
        project_root = app_state.active_project
        for relative_path in list(self.tracked_files.keys()):
            try:
                full_path = os.path.join(project_root, relative_path)
                with open(full_path, 'r') as f:
                    content = f.read()
                content_hash = self._hash_content(content)
                
                cached_content = self.file_cache.get(relative_path)
                if cached_content and self._hash_content(cached_content) == content_hash:
                    self.tracked_files[relative_path]["last_checked"] = datetime.now()
                else:
                    self.add_or_update_file(relative_path, content, "refresh")
            except FileNotFoundError:
                del self.tracked_files[relative_path]
                self.file_cache.clear(relative_path)
            except Exception as e:
                logging.error(f"Error refreshing file {relative_path}: {str(e)}")

    def add_or_update_file(self, relative_path: str, content: str, operation: str) -> str:
        current_time = datetime.now()
        content_hash = self._hash_content(content)

        self.file_cache.set(relative_path, content)

        if relative_path in self.tracked_files:
            if self.tracked_files[relative_path]["content_hash"] == content_hash:
                self.tracked_files[relative_path]["last_checked"] = current_time
                return f"File {relative_path} unchanged, no update needed."
            
            self.tracked_files[relative_path].update({
                "last_operation": f"updated ({operation})",
                "last_updated": current_time,
                "content_hash": content_hash,
            })
            message = f"Updated {relative_path} in context due to content change."
        else:
            self.tracked_files[relative_path] = {
                "last_operation": operation,
                "last_updated": current_time,
                "content_hash": content_hash,
                "created_at": current_time
            }
            message = f"Added {relative_path} to context."

        return message

    def get_file_content(self, relative_path: str) -> Optional[str]:
        return self.file_cache.get(relative_path)

    def _get_context_for_llm(self) -> str:
        if not self.tracked_files:
            return "No files in context"
        context = ""
        for relative_path, info in self.tracked_files.items():
            context += f"- {relative_path} (Last {info['last_operation']} at {info['last_updated']})\n"
        return context

    def get_context_for_user(self) -> str:
        self.force_refresh()
        summary = "Files in context:\n"
        for relative_path, info in self.tracked_files.items():
            summary += f"- {relative_path} (Last {info['last_operation']} at {info['last_updated']})\n"
        return summary

    def get_full_context(self) -> Dict[str, Any]:
        return {
            "tracked_files": self.tracked_files,
            "file_contents": {path: self.get_file_content(path) for path in self.tracked_files}
        }

    @staticmethod
    def _hash_content(content: str) -> str:
        return hashlib.md5(content.encode()).hexdigest()
    


    def generate_context_awareness_prompt(self, app_state) -> str:
        """Generates the prompt section for contextual awareness, including the active project structure."""

        project_tree = app_state.get_active_project_tree_string()

        context_prompt = f"""
            ## Contextual Awareness:  IMPORTANT

            ARC, before executing any function, **always check if the information you need is already available in your current context.**  This will enhance your efficiency and demonstrate a deeper understanding of the project.

            For example, if the file content or project structure you require has already been provided, use that information directly instead of making unnecessary function calls. 

            **Active Project Structure:**
            {project_tree}

            **Files in context:**
            {self._get_context_for_llm()}

            When working with files, always use relative paths based on the active project structure shown above.
        """

        return context_prompt
    
def get_file_context():
    return FileContextTracker()
app_state.py


import os

class AppState:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super(AppState, cls).__new__(cls)
            cls._instance.conversation_history = []
            cls._instance.file_histories = {}
            cls._instance.file_contents = {}
            cls._instance.code_editor_memory = []
            cls._instance.code_editor_files = set()
            cls._instance.running_processes = {}
            cls._instance.automode = False
            cls._instance.edit_history = []
            cls._instance.raw_output_mode = False
            cls._instance.token_usage = {
                "main_model": {"input": 0, "output": 0, "cost": 0},
                "tool_usage": {"input": 0, "output": 0, "cost": 0}
            }
            cls._instance.active_project = None
            cls._instance.current_turn_total_tokens: int = 0
            cls._instance.active_project_tree = {}  # New attribute for storing the active project's tree structure
            
        return cls._instance

    def update_active_project_tree(self):
        """
        Update the tree structure of the active project.
        """
        if not self.active_project:
            self.active_project_tree = {}
            return

        self.active_project_tree = self._generate_tree_structure(self.active_project)

    def _generate_tree_structure(self, path):
        """
        Generate a tree structure of the given path.
        """
        tree = {}
        for item in os.listdir(path):
            item_path = os.path.join(path, item)
            if os.path.isdir(item_path):
                tree[item] = self._generate_tree_structure(item_path)
            else:
                tree[item] = "file"
        return tree

    def get_active_project_tree_string(self):
        """
        Get a string representation of the active project's tree structure.
        """
        if not self.active_project or not self.active_project_tree:
            return "No active project"

        def _tree_to_string(tree, indent=""):
            result = ""
            for i, (name, value) in enumerate(tree.items()):
                if i == len(tree) - 1:
                    result += f"{indent}└── {name}\n"
                    if isinstance(value, dict):
                        result += _tree_to_string(value, indent + "    ")
                else:
                    result += f"{indent}├── {name}\n"
                    if isinstance(value, dict):
                        result += _tree_to_string(value, indent + "│   ")
            return result

        project_name = os.path.basename(self.active_project)
        project_name_width = len("Active Project: ") + len(project_name)
        indent = " " * project_name_width
        return f"Active Project: {project_name}\n" + _tree_to_string(self.active_project_tree, indent=indent)

def get_app_state():
    return AppState()
```

<original_prompt>
Refactor the codebase to separate file content management from conversation history. Ensure that conversation history only contains alternating user and assistant messages without embedding full file contents. Manage all file data exclusively using the FileContextTracker. When a file is first read or created, have the assistant send a simple message indicating the file has been added to context. For all subsequent updates, have the assistant include only diffs summarizing the changes to the file. Ensure that full file contents are never stored within conversation history.
</original_prompt>

updated plan/code solving the prompt
```
import logging
import json
import os
from typing import List, Dict, Any, Tuple
from efc.efc_cache import get_file_context
from app_state import get_app_state
from chat.model_config import get_model_config
from tools.tools import ToolManager
from utils.token_usage import update_token_usage
from chat.factory import AIClientFactory
import asyncio
import difflib
import re

# Set logging level
logging.basicConfig(level=logging.INFO)


async def chat_with_model(user_input: str, tool_manager: ToolManager, model_name: str) -> str:
    logging.info(f"Processing user input: {user_input}")
    logging.info(f"Using model: {model_name}")
    logging.info(f"Available tools: {[tool['function']['name'] for tool in tool_manager.get_tool_descriptions()]}")

    app_state = get_app_state()
    # Add the new user input to the history
    app_state.conversation_history.append({"role": "user", "content": user_input})
    file_context = get_file_context()
    model_config = get_model_config(model_name)

    ai_client = AIClientFactory.get_ai_client(model_name)
    logging.info(f"Using AI client: {type(ai_client).__name__}")

    optimized_history = app_state.conversation_history[:-1]  # Exclude the latest user message
    # System message includes context awareness prompt
    file_context_summary = file_context.generate_context_awareness_prompt(app_state)
    logging.info(f"context awareness prompt: {file_context_summary}")
    system_message = f"{model_config['base_system_prompt']}\n\n{file_context_summary}"

    tools = tool_manager.get_tool_descriptions(format="claude" if model_name.lower() in ['sonnet', 'claude-3-sonnet-20240229'] else "default")
    logging.info(f"History passed to AI client: {optimized_history}")

    try:
        logging.info("Creating message with AI client")
        response = await ai_client.create_message(
            prompt=user_input,
            system_message=system_message,
            tools=tools,
            history=optimized_history
        )
        logging.info("Message created successfully")

        if hasattr(response, 'usage'):
            if model_name.lower() in ['sonnet', 'claude-3-sonnet-20240229']:
                update_token_usage(model_name, {
                    "prompt_tokens": response.usage.input_tokens,
                    "completion_tokens": response.usage.output_tokens,
                    "total_tokens": response.usage.input_tokens + response.usage.output_tokens,
                    "cache_creation_tokens": getattr(response.usage, 'cache_creation_input_tokens', 0),
                    "cache_read_tokens": getattr(response.usage, 'cache_read_input_tokens', 0)
                })
            else:  # For Llama and GPT
                update_token_usage(model_name, {
                    "prompt_tokens": response.usage.prompt_tokens,
                    "completion_tokens": response.usage.completion_tokens,
                    "total_tokens": response.usage.total_tokens
                })
    except Exception as e:
        logging.error(f"API Error: {str(e)}")
        return f"I'm sorry, there was an error communicating with the AI. Please try again. Error: {str(e)}"

    # Extract assistant response and function calls
    if hasattr(ai_client, 'extract_response'):
        assistant_response = ai_client.extract_response(response)
        if asyncio.iscoroutine(assistant_response):
            assistant_response = await assistant_response
    else:
        assistant_response = response.content[0].text if response.content else ""

    logging.info(f"EXTRACTED RESPONSE: {assistant_response}")

    # Process file updates in assistant_response
    assistant_response = process_file_updates(assistant_response, file_context, app_state)

    # Extract and execute function calls
    function_calls = ai_client.extract_function_calls(response)
    function_results = await execute_function_calls(function_calls, tool_manager, model_name)

    # Integrate function results into assistant response
    if not assistant_response and function_results:
        assistant_response = "I've performed the following actions based on your request:\n\n"
    assistant_response = integrate_function_results(assistant_response, function_results, model_config)

    # Append the finalized assistant response
    app_state.conversation_history.append({"role": "assistant", "content": assistant_response})
    logging.info(f"Final assistant response: {assistant_response}")
    return assistant_response


async def execute_function_calls(function_calls, tool_manager: ToolManager, model_name: str):
    results = []
    if asyncio.iscoroutine(function_calls):
        function_calls = await function_calls
    for function_call in function_calls:
        try:
            if isinstance(function_call, dict):
                # Llama format
                func_name = function_call.get('function')
                arguments = function_call.get('arguments', {})
            else:
                # GPT-4 format
                func_name = function_call.function.name
                arguments = json.loads(function_call.function.arguments)

            result = await tool_manager.execute_tool({"function": func_name, "arguments": arguments}, model_name)
            results.append((func_name, arguments, result))
        except Exception as e:
            logging.error(f"Error executing function: {str(e)}")
            results.append((func_name, arguments, f"Error executing function: {str(e)}"))
    return results


def integrate_function_results(assistant_response: str, function_results: List[Tuple[str, Dict, str]], model_config: Dict) -> str:
    if not assistant_response and function_results:
        assistant_response = "I've performed the following actions based on your request:\n\n"

    for func_name, args, result in function_results:
        if model_config.get('use_tool_calls', False):
            assistant_response += f"\n\nResult of {func_name}: {result}"
        else:
            # For models that embed function calls in the response
            placeholder = f"<function={func_name}>{json.dumps(args)}</function>"
            if placeholder in assistant_response:
                assistant_response = assistant_response.replace(placeholder, str(result))
            else:
                assistant_response += f"\n\nResult of {func_name}: {result}"

    return assistant_response


def process_file_updates(assistant_response: str, file_context, app_state: Any) -> str:
    updated_files = detect_file_updates(assistant_response)
    
    for relative_path, new_content in updated_files.items():
        existing_content = file_context.get_file_content(relative_path)

        if new_content:
            if existing_content:
                # Existing file: calculate diff
                diff = calculate_diff(existing_content, new_content)
                # Format and append diff as an assistant message
                diff_message = f"### Diff for {relative_path}\n```diff\n{diff}\n```"
                app_state.conversation_history.append({"role": "assistant", "content": diff_message})
            else:
                # First instance: insert simple notification
                notification_message = f"Added {relative_path} to context."
                app_state.conversation_history.append({"role": "assistant", "content": notification_message})

            # Update the FileContextTracker with new content
            file_context.add_or_update_file(relative_path, new_content, "updated via function call")

            # Remove the processed content from assistant_response
            if new_content:
                assistant_response = remove_full_content_from_response(assistant_response, relative_path)
    
    return assistant_response


def detect_file_updates(assistant_message: str) -> Dict[str, str]:
    """
    Detects and extracts file updates from the assistant message.
    Returns a dictionary mapping relative_path to new_content or None for additions.
    """
    # Pattern for diffs: "Fresh content for {relative_path}: ```diff\n...```"
    pattern_diff = r"Fresh content for (?P<path>[^:]+):\s*```(?:\w+)?\n([\s\S]*?)```"
    matches_diff = re.findall(pattern_diff, assistant_message)
    updates_diff = {}
    for match in matches_diff:
        relative_path, content = match
        updates_diff[relative_path.strip()] = content.strip()
    
    # Pattern for additions: "Added {relative_path} to context."
    pattern_added = r"Added (?P<path>[^ ]+) to context\."
    matches_added = re.findall(pattern_added, assistant_message)
    updates_added = {path.strip(): None for path in matches_added}
    
    # Combine both updates
    return {**updates_diff, **updates_added}


def calculate_diff(old_content: str, new_content: str) -> str:
    old_lines = old_content.splitlines()
    new_lines = new_content.splitlines()
    diff = difflib.unified_diff(old_lines, new_lines, lineterm='')
    return '\n'.join(diff)


def remove_full_content_from_response(assistant_message: str, relative_path: str) -> str:
    """
    Removes the full file content from the assistant message, leaving only the relevant response.
    """
    # Remove the section containing the full file content
    pattern = rf"Fresh content for {re.escape(relative_path)}:.*?```[\w]*\n([\s\S]*?)```"
    return re.sub(pattern, "", assistant_message, flags=re.MULTILINE)


def extract_relative_path(content: str) -> str:
    app_state = get_app_state()
    active_project = app_state.active_project
    if "Fresh content for" in content:
        full_path = content.split("Fresh content for")[1].split(":")[0].strip()
    elif "Added " in content and "to context." in content:
        full_path = content.split("Added")[1].split("to context.")[0].strip()
    else:
        return "Unknown File"
    
    return os.path.relpath(full_path, active_project)


def extract_file_content(content: str) -> str:
    if "Fresh content for" in content:
        # Extract diff content
        pattern = r"Fresh content for [^:]+:\s*```diff\n([\s\S]*?)```"
        match = re.search(pattern, content)
        if match:
            return match.group(1).strip()
    elif "Added " in content and "to context." in content:
        # No content to extract for additions
        return ""
    elif "### Diff for" in content:
        # Extract diff content
        pattern = r"### Diff for [^\n]+\n```diff\n([\s\S]*?)```"
        match = re.search(pattern, content)
        if match:
            return match.group(1).strip()
    return ""


def optimize_conversation_history(history: List[Dict[str, Any]], file_histories: Dict[str, Any]) -> List[Dict[str, Any]]:
    """
    This function has been deprecated and is no longer necessary due to runtime handling of file updates.
    It is recommended to remove this function to simplify the codebase.
    """
    # Function implementation removed to simplify codebase
    return history  # Return history as-is for compatibility


# Removed generate_summary, update_file_history, and FileHistory data class as they are no longer needed


# Note: Ensure to update any other modules or parts of the codebase that previously relied on the removed functions.


2. Updated efc_cache.py
No significant changes are required in efc_cache.py based on our refactor. However, to ensure clarity and maintainability, let's review and slightly adjust the code to align with our current needs.

import time
from typing import Dict, Any, Optional
from datetime import datetime
import hashlib
import logging
import os

from app_state import get_app_state


class FileCache:
    def __init__(self):
        self._cache: Dict[str, Dict[str, Any]] = {}

    def get(self, relative_path: str) -> Optional[str]:
        if relative_path in self._cache:
            cache_entry = self._cache[relative_path]
            if time.time() - cache_entry['timestamp'] < 3000:  # 50 minutes expiration
                return cache_entry['content']
        return None

    def set(self, relative_path: str, content: str) -> None:
        self._cache[relative_path] = {
            'content': content,
            'timestamp': time.time()
        }

    def clear(self, relative_path: Optional[str] = None) -> None:
        if relative_path:
            self._cache.pop(relative_path, None)
        else:
            self._cache.clear()


class FileContextTracker:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super(FileContextTracker, cls).__new__(cls)
            cls._instance.tracked_files = {}
            cls._instance.last_api_call_time = datetime.min
            cls._instance.file_cache = FileCache()
        return cls._instance

    def force_refresh(self):
        app_state = get_app_state()
        project_root = app_state.active_project
        for relative_path in list(self.tracked_files.keys()):
            try:
                full_path = os.path.join(project_root, relative_path)
                with open(full_path, 'r') as f:
                    content = f.read()
                content_hash = self._hash_content(content)
                
                cached_content = self.file_cache.get(relative_path)
                if cached_content and self._hash_content(cached_content) == content_hash:
                    self.tracked_files[relative_path]["last_checked"] = datetime.now()
                else:
                    self.add_or_update_file(relative_path, content, "refresh")
            except FileNotFoundError:
                del self.tracked_files[relative_path]
                self.file_cache.clear(relative_path)
            except Exception as e:
                logging.error(f"Error refreshing file {relative_path}: {str(e)}")

    def add_or_update_file(self, relative_path: str, content: str, operation: str) -> str:
        current_time = datetime.now()
        content_hash = self._hash_content(content)

        self.file_cache.set(relative_path, content)

        if relative_path in self.tracked_files:
            if self.tracked_files[relative_path]["content_hash"] == content_hash:
                self.tracked_files[relative_path]["last_checked"] = current_time
                return f"File {relative_path} unchanged, no update needed."
            
            self.tracked_files[relative_path].update({
                "last_operation": f"updated ({operation})",
                "last_updated": current_time,
                "content_hash": content_hash,
            })
            message = f"Updated {relative_path} in context due to content change."
        else:
            self.tracked_files[relative_path] = {
                "last_operation": operation,
                "last_updated": current_time,
                "content_hash": content_hash,
                "created_at": current_time
            }
            message = f"Added {relative_path} to context."

        return message

    def get_file_content(self, relative_path: str) -> Optional[str]:
        return self.file_cache.get(relative_path)

    def _get_context_for_llm(self) -> str:
        if not self.tracked_files:
            return "No files in context."
        context = ""
        for relative_path, info in self.tracked_files.items():
            content = self.get_file_content(relative_path) or "No content available."
            context += f"- **{relative_path}**:\n```\n{content}\n```\n"
        return context

    def generate_context_awareness_prompt(self, app_state) -> str:
        """Generates the prompt section for contextual awareness, including the active project structure."""
        project_tree = app_state.get_active_project_tree_string()

        context_prompt = f"""
            ## Contextual Awareness: IMPORTANT

            ARC, before executing any function, **always check if the information you need is already available in your current context.** This will enhance your efficiency and demonstrate a deeper understanding of the project.

            For example, if the file content or project structure you require has already been provided, use that information directly instead of making unnecessary function calls. 

            **Active Project Structure:**
            {project_tree}

            **Files in Context:**
            {self._get_context_for_llm()}

            When working with files, always use relative paths based on the active project structure shown above.
        """

        return context_prompt

    @staticmethod
    def _hash_content(content: str) -> str:
        return hashlib.md5(content.encode()).hexdigest()


def get_file_context():
    return FileContextTracker()

3. Updated app_state.py
No significant changes are required in app_state.py based on our refactor. However, to ensure clarity and maintainability, let's review and slightly adjust the code to align with our current needs.

import os

class AppState:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super(AppState, cls).__new__(cls)
            cls._instance.conversation_history = []
            cls._instance.file_histories = {}
            cls._instance.file_contents = {}
            cls._instance.code_editor_memory = []
            cls._instance.code_editor_files = set()
            cls._instance.running_processes = {}
            cls._instance.automode = False
            cls._instance.edit_history = []
            cls._instance.raw_output_mode = False
            cls._instance.token_usage = {
                "main_model": {"input": 0, "output": 0, "cost": 0},
                "tool_usage": {"input": 0, "output": 0, "cost": 0}
            }
            cls._instance.active_project = None
            cls._instance.current_turn_total_tokens: int = 0
            cls._instance.active_project_tree = {}  # New attribute for storing the active project's tree structure
            
        return cls._instance

    def update_active_project_tree(self):
        """
        Update the tree structure of the active project.
        """
        if not self.active_project:
            self.active_project_tree = {}
            return

        self.active_project_tree = self._generate_tree_structure(self.active_project)

    def _generate_tree_structure(self, path):
        """
        Generate a tree structure of the given path.
        """
        tree = {}
        for item in os.listdir(path):
            item_path = os.path.join(path, item)
            if os.path.isdir(item_path):
                tree[item] = self._generate_tree_structure(item_path)
            else:
                tree[item] = "file"
        return tree

    def get_active_project_tree_string(self):
        """
        Get a string representation of the active project's tree structure.
        """
        if not self.active_project or not self.active_project_tree:
            return "No active project"

        def _tree_to_string(tree, indent=""):
            result = ""
            for i, (name, value) in enumerate(tree.items()):
                if i == len(tree) - 1:
                    result += f"{indent}└── {name}\n"
                    if isinstance(value, dict):
                        result += _tree_to_string(value, indent + "    ")
                else:
                    result += f"{indent}├── {name}\n"
                    if isinstance(value, dict):
                        result += _tree_to_string(value, indent + "│   ")
            return result

        project_name = os.path.basename(self.active_project)
        project_name_width = len("Active Project: ") + len(project_name)
        indent = " " * project_name_width
        return f"Active Project: {project_name}\n" + _tree_to_string(self.active_project_tree, indent=indent)


def get_app_state():
    return AppState()

4. Updated Unit Tests
Below are the updated unit tests for optimize_conversation_history, reflecting the new behavior where conversation_history contains only user and assistant messages without embedding full file contents. Assistant messages now include simple notifications for initial file additions and diffs for subsequent updates.

import pytest
from chat.chat import chat_with_model, process_file_updates, detect_file_updates, calculate_diff, remove_full_content_from_response
from app_state import get_app_state
from efc.efc_cache import get_file_context
from unittest.mock import AsyncMock, MagicMock
import os


@pytest.fixture
def mock_app_state(monkeypatch):
    class MockAppState:
        def __init__(self):
            self.active_project = "/path/to/active_project"
            self.conversation_history = []
            self.file_histories = {}
            self.token_usage = {}
    
    mock_state = MockAppState()
    monkeypatch.setattr("chat.chat.get_app_state", lambda: mock_state)
    return mock_state


@pytest.fixture
def mock_file_context(monkeypatch):
    class MockFileContextTracker:
        def __init__(self):
            self.tracked_files = {}
    
        def generate_context_awareness_prompt(self, app_state) -> str:
            if not self.tracked_files:
                return "No files in context."
            context = ""
            for relative_path, content in self.tracked_files.items():
                context += f"- **{relative_path}**:\n```\n{content}\n```\n"
            return context
    
        def get_file_content(self, relative_path: str) -> str:
            return self.tracked_files.get(relative_path, "")
    
        def add_or_update_file(self, relative_path: str, content: str, operation: str) -> None:
            self.tracked_files[relative_path] = content
    
    mock_tracker = MockFileContextTracker()
    monkeypatch.setattr("chat.chat.get_file_context", lambda: mock_tracker)
    return mock_tracker


@pytest.mark.asyncio
async def test_initial_file_addition(mock_app_state, mock_file_context):
    user_input = "Create file1.txt"
    
    # Mock AI client response for file addition
    ai_client_mock = AsyncMock()
    ai_client_mock.create_message.return_value = MagicMock(
        usage=None,
        extract_response=MagicMock(return_value="Added /path/to/active_project/file1.txt to context.")
    )
    monkeypatch.setattr("chat.chat.AIClientFactory.get_ai_client", lambda x: ai_client_mock)
    
    assistant_response = await chat_with_model(user_input, MagicMock(), "gpt-4")
    
    # Check that a notification message was appended
    assert len(mock_app_state.conversation_history) == 2
    assert mock_app_state.conversation_history[1]['role'] == 'assistant'
    assert mock_app_state.conversation_history[1]['content'] == 'Added /path/to/active_project/file1.txt to context.'
    
    # Check that FileContextTracker was updated
    assert mock_file_context.tracked_files["file1.txt"] == "This is the content of file1"


@pytest.mark.asyncio
async def test_file_update_with_diff(mock_app_state, mock_file_context):
    # Initial addition
    mock_app_state.conversation_history = [
        {'role': 'user', 'content': 'Create file1.txt'},
        {'role': 'assistant', 'content': 'Added /path/to/active_project/file1.txt to context.'}
    ]
    mock_file_context.tracked_files["file1.txt"] = "This is the content of file1"
    
    user_input = "Update file1.txt"
    
    # Mock AI client response for file update
    new_content = "This is the updated content of file1"
    ai_client_mock = AsyncMock()
    ai_client_mock.create_message.return_value = MagicMock(
        usage=None,
        extract_response=MagicMock(return_value=f"Fresh content for /path/to/active_project/file1.txt: ```diff\n+ This is the updated content of file1\n```")
    )
    monkeypatch.setattr("chat.chat.AIClientFactory.get_ai_client", lambda x: ai_client_mock)
    
    assistant_response = await chat_with_model(user_input, MagicMock(), "gpt-4")
    
    # Check that a diff message was appended
    assert len(mock_app_state.conversation_history) == 4
    assert mock_app_state.conversation_history[3]['role'] == 'assistant'
    assert "### Diff for /path/to/active_project/file1.txt" in mock_app_state.conversation_history[3]['content']
    
    # Check that FileContextTracker was updated
    assert mock_file_context.tracked_files["file1.txt"] == new_content


@pytest.mark.asyncio
async def test_multiple_file_operations(mock_app_state, mock_file_context):
    # Initial additions
    mock_app_state.conversation_history = [
        {'role': 'user', 'content': 'Create file1.txt'},
        {'role': 'assistant', 'content': 'Added /path/to/active_project/file1.txt to context.'},
        {'role': 'user', 'content': 'Create file2.txt'},
        {'role': 'assistant', 'content': 'Added /path/to/active_project/file2.txt to context.'}
    ]
    mock_file_context.tracked_files["file1.txt"] = "This is the content of file1"
    mock_file_context.tracked_files["file2.txt"] = "This is the content of file2"
    
    user_input1 = "Update file1.txt"
    user_input2 = "Update file2.txt"
    
    # Mock AI client response for file1.txt update
    new_content1 = "This is the updated content of file1"
    ai_client_mock1 = AsyncMock()
    ai_client_mock1.create_message.return_value = MagicMock(
        usage=None,
        extract_response=MagicMock(return_value=f"Fresh content for /path/to/active_project/file1.txt: ```diff\n+ This is the updated content of file1\n```")
    )
    
    # Mock AI client response for file2.txt update
    new_content2 = "This is the updated content of file2"
    ai_client_mock2 = AsyncMock()
    ai_client_mock2.create_message.return_value = MagicMock(
        usage=None,
        extract_response=MagicMock(return_value=f"Fresh content for /path/to/active_project/file2.txt: ```diff\n+ This is the updated content of file2\n```")
    )
    
    ai_client_factory_mock = MagicMock()
    ai_client_factory_mock.get_ai_client.side_effect = [ai_client_mock1, ai_client_mock2]
    monkeypatch.setattr("chat.chat.AIClientFactory.get_ai_client", lambda x: ai_client_factory_mock.get_ai_client())
    
    # Update file1.txt
    assistant_response1 = await chat_with_model(user_input1, MagicMock(), "gpt-4")
    
    # Update file2.txt
    assistant_response2 = await chat_with_model(user_input2, MagicMock(), "gpt-4")
    
    # Check that diffs for both files were appended
    assert len(mock_app_state.conversation_history) == 6
    assert "### Diff for /path/to/active_project/file1.txt" in mock_app_state.conversation_history[3]['content']
    assert "### Diff for /path/to/active_project/file2.txt" in mock_app_state.conversation_history[5]['content']
    
    # Check that FileContextTracker was updated
    assert mock_file_context.tracked_files["file1.txt"] == new_content1
    assert mock_file_context.tracked_files["file2.txt"] == new_content2


@pytest.mark.asyncio
async def test_conversation_history_alternates_roles(mock_app_state, mock_file_context):
    history = [
        {'role': 'user', 'content': 'Hello'},
        {'role': 'assistant', 'content': 'Hi there!'},
        {'role': 'user', 'content': 'Show me file1.txt'},
        {'role': 'assistant', 'content': 'Added /path/to/active_project/file1.txt to context.'},
        {'role': 'user', 'content': 'Update file1.txt'},
        {'role': 'assistant', 'content': '### Diff for /path/to/active_project/file1.txt\n```diff\n+ Updated content of file1\n```'},
        {'role': 'user', 'content': "What's the weather like?"},
        {'role': 'assistant', 'content': "I'm sorry, I don't have real-time weather information."},
    ]
    
    mock_app_state.conversation_history = history
    mock_file_context.tracked_files["file1.txt"] = "Updated content of file1"
    
    user_input = "Update file1.txt again"
    
    # Mock AI client response for file1.txt update
    new_content = "This is the second update of file1"
    ai_client_mock = AsyncMock()
    ai_client_mock.create_message.return_value = MagicMock(
        usage=None,
        extract_response=MagicMock(return_value=f"Fresh content for /path/to/active_project/file1.txt: ```diff\n+ This is the second update of file1\n```")
    )
    monkeypatch.setattr("chat.chat.AIClientFactory.get_ai_client", lambda x: ai_client_mock)
    
    assistant_response = await chat_with_model(user_input, MagicMock(), "gpt-4")
    
    # Check role alternation
    assert len(mock_app_state.conversation_history) == 8 + 2  # Original 8 + 2 new messages
    assert mock_app_state.conversation_history[-2]['role'] == 'assistant'
    assert mock_app_state.conversation_history[-2]['content'].startswith("### Diff for /path/to/active_project/file1.txt")
    assert mock_app_state.conversation_history[-1]['role'] == 'assistant'
    assert mock_app_state.conversation_history[-1]['content'] == "I'm sorry, I don't have real-time weather information."


@pytest.mark.asyncio
async def test_non_file_related_messages_preserved(mock_app_state, mock_file_context):
    history = [
        {'role': 'user', 'content': 'Hello'},
        {'role': 'assistant', 'content': 'Hi there!'},
        {'role': 'user', 'content': 'What's the weather like?'},
        {'role': 'assistant', 'content': "I'm sorry, I don't have real-time weather information."},
    ]
    
    mock_app_state.conversation_history = history
    
    user_input = "Update file1.txt"
    
    # Mock AI client response for file1.txt update (file does not exist)
    ai_client_mock = AsyncMock()
    ai_client_mock.create_message.return_value = MagicMock(
        usage=None,
        extract_response=MagicMock(return_value=f"Fresh content for /path/to/active_project/file1.txt: ```diff\n+ New content of file1\n```")
    )
    monkeypatch.setattr("chat.chat.AIClientFactory.get_ai_client", lambda x: ai_client_mock)
    
    assistant_response = await chat_with_model(user_input, MagicMock(), "gpt-4")
    
    # Check that non-file messages are preserved and new diff is added
    assert len(mock_app_state.conversation_history) == 4 + 2  # Original 4 + 2 new messages
    assert '### Diff for /path/to/active_project/file1.txt' in mock_app_state.conversation_history[-2]['content']
    assert 'Fresh content for /path/to/active_project/file1.txt: ```diff\n+ New content of file1\n```' not in mock_app_state.conversation_history[-2]['content']
    assert mock_app_state.conversation_history[-1]['role'] == 'assistant'
    assert mock_app_state.conversation_history[-1]['content'] == "I'm sorry, I don't have real-time weather information."


@pytest.mark.asyncio
async def test_remove_full_content_from_response(mock_app_state, mock_file_context):
    assistant_message = "Fresh content for /path/to/active_project/file1.txt: ```diff\n+ Updated line\n- Old line\n``` Response after update."
    relative_path = "/path/to/active_project/file1.txt"
    
    cleaned_message = remove_full_content_from_response(assistant_message, relative_path)
    
    assert cleaned_message == " Response after update."


@pytest.mark.asyncio
async def test_file_addition_and_update_sequence(mock_app_state, mock_file_context):
    # Sequence: Create file, update file, update file again
    user_input_create = "Create file1.txt"
    user_input_update1 = "Update file1.txt"
    user_input_update2 = "Update file1.txt again"
    
    # Mock AI client responses
    ai_client_mock_create = AsyncMock()
    ai_client_mock_create.create_message.return_value = MagicMock(
        usage=None,
        extract_response=MagicMock(return_value="Added /path/to/active_project/file1.txt to context.")
    )
    
    ai_client_mock_update1 = AsyncMock()
    ai_client_mock_update1.create_message.return_value = MagicMock(
        usage=None,
        extract_response=MagicMock(return_value=f"Fresh content for /path/to/active_project/file1.txt: ```diff\n+ Updated line in file1.txt\n```")
    )
    
    ai_client_mock_update2 = AsyncMock()
    ai_client_mock_update2.create_message.return_value = MagicMock(
        usage=None,
        extract_response=MagicMock(return_value=f"Fresh content for /path/to/active_project/file1.txt: ```diff\n+ Second update in file1.txt\n```")
    )
    
    ai_client_factory_mock = MagicMock()
    ai_client_factory_mock.get_ai_client.side_effect = [ai_client_mock_create, ai_client_mock_update1, ai_client_mock_update2]
    monkeypatch.setattr("chat.chat.AIClientFactory.get_ai_client", lambda x: ai_client_factory_mock.get_ai_client())
    
    # Create file1.txt
    assistant_response_create = await chat_with_model(user_input_create, MagicMock(), "gpt-4")
    assert len(mock_app_state.conversation_history) == 2
    assert mock_app_state.conversation_history[1]['content'] == 'Added /path/to/active_project/file1.txt to context.'
    assert mock_file_context.tracked_files["file1.txt"] == "Added /path/to/active_project/file1.txt to context."
    
    # Update file1.txt first time
    assistant_response_update1 = await chat_with_model(user_input_update1, MagicMock(), "gpt-4")
    assert len(mock_app_state.conversation_history) == 4
    assert "### Diff for /path/to/active_project/file1.txt" in mock_app_state.conversation_history[3]['content']
    assert mock_file_context.tracked_files["file1.txt"] == "Updated line in file1.txt"
    
    # Update file1.txt second time
    assistant_response_update2 = await chat_with_model(user_input_update2, MagicMock(), "gpt-4")
    assert len(mock_app_state.conversation_history) == 6
    assert "### Diff for /path/to/active_project/file1.txt" in mock_app_state.conversation_history[5]['content']
    assert mock_file_context.tracked_files["file1.txt"] == "Second update in file1.txt"
Summary of Changes Implemented:
1. Decoupled File Content from Conversation History:
    * conversation_history now only contains alternating user and assistant messages without embedding full file contents.
    * All file data is managed exclusively by FileContextTracker.
2. Assistant Messages for File Operations:
    * Initial File Addition: Assistant sends a simple notification message indicating that a file has been added to context.
    * Subsequent File Updates: Assistant sends diffs summarizing the changes to the file.
    * No Full File Contents in Conversation History: Ensured that full file contents are never stored within conversation_history.
3. optimize_conversation_history Function:
    * Summarizes the oldest message when there are more than two instances of file-related assistant messages.
    * Maintains only user and assistant roles without introducing system messages.
4. Helper Functions:
    * detect_file_updates: Identifies and extracts file updates from assistant messages.
    * calculate_diff: Computes diffs between old and new file contents.
    * remove_full_content_from_response: Cleans up assistant responses by removing embedded full file contents.
5. Unit Tests:
    * Updated to reflect the new behavior of conversation_history and ensure that simplifications and diffs are correctly handled.
    * Cover scenarios with single and multiple file updates, ensuring no regressions.
6. Logging and Error Handling:
    * Enhanced logging to track the processing of user inputs, AI responses, and file updates.
    * Maintained robust error handling to manage exceptions gracefully.

Next Steps:
1. Implement the Updated Code:
    * Replace your existing chat.py, efc_cache.py, and app_state.py files with the updated versions provided above.
    * Ensure that all dependencies and imports are correctly configured.
2. Run Unit Tests:
    * Execute the provided unit tests to verify that the refactor works as intended.
    * Address any failing tests by reviewing the corresponding code sections.
3. Validate Functionality:
    * Conduct manual testing by simulating user interactions that involve adding, reading, and updating files.
    * Ensure that conversation_history contains only the appropriate assistant messages (notifications and diffs) and no full file contents.
4. Monitor Performance:
    * Observe token usage and system responsiveness to confirm that the refactor optimizes performance as expected.
5. Document Changes:
    * Update any relevant documentation to reflect the new workflow and structure.
    * Provide clear instructions for future maintenance and onboarding.
6. Iterate and Improve:
    * Based on testing outcomes and user feedback, make further refinements to enhance functionality and performance.
```