i want you to understand something, unless you have a good reason this is my file for chat.py if you want to change something you better be damn sure:

```
import logging
import json
import os
import re
import difflib
from typing import List, Dict, Any, Tuple, Optional
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

# 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 and modify assistant_response accordingly**
    assistant_response = await 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 once**
    app_state.conversation_history.append({"role": "assistant", "content": assistant_response})
    logging.info(f"Final assistant response: {assistant_response}")
    return assistant_response


async def process_file_updates(assistant_response: str, file_context, app_state: Any) -> str:
    updated_files = detect_file_updates(assistant_response)
    notifications = []

    for relative_path, new_content in updated_files.items():
        existing_content = file_context.get_file_content(relative_path)

        if new_content is not None:
            if existing_content:
                # Existing file: calculate diff
                diff = calculate_diff(existing_content, new_content)
                if diff.strip():
                    # Include acknowledgment and diff in the assistant response
                    ack_message = f"I've updated `{relative_path}` to the context."
                    diff_message = f"\n### Diff for {relative_path}\n```diff\n{diff}\n```"
                    assistant_response += f"\n{ack_message}{diff_message}"
                else:
                    # No changes detected
                    no_change_msg = f"\nNo changes detected in {relative_path}."
                    assistant_response += no_change_msg
            else:
                # First instance: notification about addition
                notification_message = f"\nI've added `{relative_path}` to the context."
                assistant_response += notification_message

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

            # Optionally, remove the processed content from assistant_response
            assistant_response = remove_full_content_from_response(assistant_response, relative_path)
        else:
            # Handle additions where no new content is provided
            notification_message = f"\nI've added `{relative_path}` to the context."
            assistant_response += notification_message

            # Update the FileContextTracker to reflect the addition
            file_context.add_or_update_file(relative_path, "", "added via function call")

    return assistant_response.strip()


def detect_file_updates(assistant_message: str) -> Dict[str, Optional[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 file updates: "Fresh content for {relative_path}: ```(diff|language)?\n...```"
    pattern = r"Fresh content for (?P<path>[^\n]+):\s*```(?:[^\n]*)\n(?P<content>[\s\S]*?)```"
    matches = re.finditer(pattern, assistant_message)
    updates = {}
    for match in matches:
        relative_path = match.group('path').strip()
        content = match.group('content').strip()
        updates[relative_path] = content

    # Pattern for additions: "Added {relative_path} to context."
    pattern_added = r"Added (?P<path>[^\n]+) to context\."
    matches_added = re.finditer(pattern_added, assistant_message)
    for match in matches_added:
        relative_path = match.group('path').strip()
        updates[relative_path] = None  # None content for additions

    return updates


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.
    """
    # Pattern captures only the 'Fresh content...' part
    pattern = rf"\s*Fresh content for {re.escape(relative_path)}:.*?```.*?\n[\s\S]*?```"
    cleaned_message = re.sub(pattern, "", assistant_message, flags=re.MULTILINE)
    # Replace multiple spaces with a single space and strip leading/trailing spaces
    cleaned_message = re.sub(r'\s{2,}', ' ', cleaned_message).strip()
    return cleaned_message


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

```

this passes all my tests so far and even advanced the bugs you introduced you need to fix your test here:

```
        # 9.4. Verify FileContextTracker Updates
        assert "file1.txt" in mock_file_context.tracked_files, \
            f"Expected 'file1.txt' to be in tracked_files, got {list(mock_file_context.tracked_files.keys())}"
>       assert mock_file_context.tracked_files["file1.txt"] == "Updated content of file1", \
            f"Expected tracked_files['file1.txt'] to be 'Updated content of file1', got '{mock_file_context.tracked_files.get('file1.txt')}'"
E       AssertionError: Expected tracked_files['file1.txt'] to be 'Updated content of file1', got 'This is the content of file1'
E       assert 'This is the content of file1' == 'Updated content of file1'
E         
E         - Updated content of file1
E         + This is the content of file1

tests/test_chat/test_conversation_history.py:635: AssertionError
------------------------------------------------------------- Captured stdout setup --------------------------------------------------------------
DEBUG: Using selector: KqueueSelector
--------------------------------------------------------------- Captured log setup ---------------------------------------------------------------
DEBUG    asyncio:selector_events.py:64 Using selector: KqueueSelector
-------------------------------------------------------------- Captured stdout call --------------------------------------------------------------
INFO: Processing user input: Hello
INFO: Using model: gpt-4
INFO: Available tools: []
INFO: Using AI client: AsyncMock
INFO: context awareness prompt: No files in context.
INFO: History passed to AI client: []
INFO: Creating message with AI client
INFO: Message created successfully
INFO: EXTRACTED RESPONSE: Hi there!
INFO: Final assistant response: Hi there!
INFO: Processing user input: Show me file1.txt
INFO: Using model: gpt-4
INFO: Available tools: []
INFO: Using AI client: AsyncMock
INFO: context awareness prompt: No files in context.
INFO: History passed to AI client: [{'role': 'user', 'content': 'Hello'}, {'role': 'assistant', 'content': 'Hi there!'}]
INFO: Creating message with AI client
INFO: Message created successfully
INFO: EXTRACTED RESPONSE: Added `file1.txt` to context.
Fresh content for file1.txt: ```diff
This is the content of file1
```
INFO: Final assistant response: Added `file1.txt` to context.
I've added `file1.txt` to the context.
I've added ``file1.txt`` to the context.
INFO: Processing user input: Update file1.txt
INFO: Using model: gpt-4
INFO: Available tools: []
INFO: Using AI client: AsyncMock
INFO: context awareness prompt: - **file1.txt**:
```
This is the content of file1
```
- **`file1.txt`**:
```

```

INFO: History passed to AI client: [{'role': 'user', 'content': 'Hello'}, {'role': 'assistant', 'content': 'Hi there!'}, {'role': 'user', 'content': 'Show me file1.txt'}, {'role': 'assistant', 'content': "Added `file1.txt` to context.\nI've added `file1.txt` to the context.\nI've added ``file1.txt`` to the context."}]
INFO: Creating message with AI client
INFO: Message created successfully
INFO: EXTRACTED RESPONSE: I've updated `file1.txt` to the context.
### Diff for file1.txt
```diff
@@ -1 +1 @@
-This is the content of file1
+Updated content of file1
```
INFO: Final assistant response: I've updated `file1.txt` to the context.
### Diff for file1.txt
```diff
@@ -1 +1 @@
-This is the content of file1
+Updated content of file1
```
INFO: Processing user input: What's the weather like?
INFO: Using model: gpt-4
INFO: Available tools: []
INFO: Using AI client: AsyncMock
INFO: context awareness prompt: - **file1.txt**:
```
This is the content of file1
```
- **`file1.txt`**:
```

```

INFO: History passed to AI client: [{'role': 'user', 'content': 'Hello'}, {'role': 'assistant', 'content': 'Hi there!'}, {'role': 'user', 'content': 'Show me file1.txt'}, {'role': 'assistant', 'content': "Added `file1.txt` to context.\nI've added `file1.txt` to the context.\nI've added ``file1.txt`` to the context."}, {'role': 'user', 'content': 'Update file1.txt'}, {'role': 'assistant', 'content': "I've updated `file1.txt` to the context.\n### Diff for file1.txt\n```diff\n@@ -1 +1 @@\n-This is the content of file1\n+Updated content of file1\n```"}]
INFO: Creating message with AI client
INFO: Message created successfully
INFO: EXTRACTED RESPONSE: I'm sorry, I don't have real-time weather information.
INFO: Final assistant response: I'm sorry, I don't have real-time weather information.
Conversation History: [{'role': 'user', 'content': 'Hello'}, {'role': 'assistant', 'content': 'Hi there!'}, {'role': 'user', 'content': 'Show me file1.txt'}, {'role': 'assistant', 'content': "Added `file1.txt` to context.\nI've added `file1.txt` to the context.\nI've added ``file1.txt`` to the context."}, {'role': 'user', 'content': 'Update file1.txt'}, {'role': 'assistant', 'content': "I've updated `file1.txt` to the context.\n### Diff for file1.txt\n```diff\n@@ -1 +1 @@\n-This is the content of file1\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."}]
Tracked Files: {'file1.txt': 'This is the content of file1', '`file1.txt`': ''}
--------------------------------------------------------------- Captured log call ----------------------------------------------------------------
INFO     root:chat.py:257 Processing user input: Hello
INFO     root:chat.py:258 Using model: gpt-4
INFO     root:chat.py:259 Available tools: []
INFO     root:chat.py:269 Using AI client: AsyncMock
INFO     root:chat.py:275 context awareness prompt: No files in context.
INFO     root:chat.py:279 History passed to AI client: []
INFO     root:chat.py:282 Creating message with AI client
INFO     root:chat.py:289 Message created successfully
INFO     root:chat.py:319 EXTRACTED RESPONSE: Hi there!
INFO     root:chat.py:335 Final assistant response: Hi there!
INFO     root:chat.py:257 Processing user input: Show me file1.txt
INFO     root:chat.py:258 Using model: gpt-4
INFO     root:chat.py:259 Available tools: []
INFO     root:chat.py:269 Using AI client: AsyncMock
INFO     root:chat.py:275 context awareness prompt: No files in context.
INFO     root:chat.py:279 History passed to AI client: [{'role': 'user', 'content': 'Hello'}, {'role': 'assistant', 'content': 'Hi there!'}]
INFO     root:chat.py:282 Creating message with AI client
INFO     root:chat.py:289 Message created successfully
INFO     root:chat.py:319 EXTRACTED RESPONSE: Added `file1.txt` to context.
Fresh content for file1.txt: ```diff
This is the content of file1
```
INFO     root:chat.py:335 Final assistant response: Added `file1.txt` to context.
I've added `file1.txt` to the context.
I've added ``file1.txt`` to the context.
INFO     root:chat.py:257 Processing user input: Update file1.txt
INFO     root:chat.py:258 Using model: gpt-4
INFO     root:chat.py:259 Available tools: []
INFO     root:chat.py:269 Using AI client: AsyncMock
INFO     root:chat.py:275 context awareness prompt: - **file1.txt**:
```
This is the content of file1
```
- **`file1.txt`**:
```

```

INFO     root:chat.py:279 History passed to AI client: [{'role': 'user', 'content': 'Hello'}, {'role': 'assistant', 'content': 'Hi there!'}, {'role': 'user', 'content': 'Show me file1.txt'}, {'role': 'assistant', 'content': "Added `file1.txt` to context.\nI've added `file1.txt` to the context.\nI've added ``file1.txt`` to the context."}]
INFO     root:chat.py:282 Creating message with AI client
INFO     root:chat.py:289 Message created successfully
INFO     root:chat.py:319 EXTRACTED RESPONSE: I've updated `file1.txt` to the context.
### Diff for file1.txt
```diff
@@ -1 +1 @@
-This is the content of file1
+Updated content of file1
```
INFO     root:chat.py:335 Final assistant response: I've updated `file1.txt` to the context.
### Diff for file1.txt
```diff
@@ -1 +1 @@
-This is the content of file1
+Updated content of file1
```
INFO     root:chat.py:257 Processing user input: What's the weather like?
INFO     root:chat.py:258 Using model: gpt-4
INFO     root:chat.py:259 Available tools: []
INFO     root:chat.py:269 Using AI client: AsyncMock
INFO     root:chat.py:275 context awareness prompt: - **file1.txt**:
```
This is the content of file1
```
- **`file1.txt`**:
```

```

INFO     root:chat.py:279 History passed to AI client: [{'role': 'user', 'content': 'Hello'}, {'role': 'assistant', 'content': 'Hi there!'}, {'role': 'user', 'content': 'Show me file1.txt'}, {'role': 'assistant', 'content': "Added `file1.txt` to context.\nI've added `file1.txt` to the context.\nI've added ``file1.txt`` to the context."}, {'role': 'user', 'content': 'Update file1.txt'}, {'role': 'assistant', 'content': "I've updated `file1.txt` to the context.\n### Diff for file1.txt\n```diff\n@@ -1 +1 @@\n-This is the content of file1\n+Updated content of file1\n```"}]
INFO     root:chat.py:282 Creating message with AI client
INFO     root:chat.py:289 Message created successfully
INFO     root:chat.py:319 EXTRACTED RESPONSE: I'm sorry, I don't have real-time weather information.
INFO     root:chat.py:335 Final assistant response: I'm sorry, I don't have real-time weather information.
------------------------------------------------------------ Captured stdout teardown ------------------------------------------------------------
DEBUG: Using selector: KqueueSelector
------------------------------------------------------------- Captured log teardown --------------------------------------------------------------
DEBUG    asyncio:selector_events.py:64 Using selector: KqueueSelector
============================================================ short test summary info =============================================================
FAILED tests/test_chat/test_conversation_history.py::test_conversation_history_alternates_roles - AssertionError: Expected tracked_files['file1.txt'] to be 'Updated content of file1', got 'This is the content of file1'
assert 'This is the content of file1' == 'Updated content of file1'
  
  - Updated content of file1
  + This is the content of file1
```

here is the full test:
```
@pytest.mark.asyncio
async def test_conversation_history_alternates_roles(mock_app_state, mock_file_context, monkeypatch):
    """
    Test that the conversation history alternates between 'user' and 'assistant' roles correctly
    and that file operations are handled properly by checking for key substrings.
    """
    
    # 1. Initial Setup: Reset conversation_history and tracked_files
    mock_app_state.conversation_history = []
    mock_file_context.tracked_files = {}
    
    # 2. Define user inputs and expected assistant response substrings
    user_inputs = [
        'Hello',
        'Show me file1.txt',
        'Update file1.txt',
        "What's the weather like?"
    ]
    
    # Each entry contains substrings that should be present in the assistant's response
    expected_assistant_response_substrings = [
        ['Hi there!'],
        [
            'Added `file1.txt` to context.',
            "I've added `file1.txt` to the context."
        ],
        [
            "I've updated `file1.txt` to the context.",
            '### Diff for file1.txt',
            '```diff',
            '@@ -1 +1 @@',
            '-This is the content of file1',
            '+Updated content of file1',
            '```'
        ],
        ["I'm sorry, I don't have real-time weather information."]
    ]
    
    # 3. Mock AI clients for each interaction
    ai_client_mocks = []
    for i in range(4):
        ai_client_mock = AsyncMock()
        ai_client_mock.create_message.return_value = MagicMock(
            usage=MagicMock(
                prompt_tokens=10 + i*5,
                completion_tokens=15 + i*5,
                total_tokens=25 + i*10,
                cache_creation_input_tokens=0,
                cache_read_input_tokens=0
            )
        )
        
        if i == 0:
            # 'Hello' interaction
            ai_client_mock.extract_response = AsyncMock(return_value='Hi there!')
        elif i == 1:
            # 'Show me file1.txt' interaction
            ai_client_mock.extract_response = AsyncMock(
                return_value='Added `file1.txt` to context.\nFresh content for file1.txt: ```diff\nThis is the content of file1\n```'
            )
        elif i == 2:
            # 'Update file1.txt' interaction
            ai_client_mock.extract_response = AsyncMock(
                return_value="I've updated `file1.txt` to the context.\n### Diff for file1.txt\n```diff\n@@ -1 +1 @@\n-This is the content of file1\n+Updated content of file1\n```"
            )
        elif i == 3:
            # "What's the weather like?" interaction
            ai_client_mock.extract_response = AsyncMock(return_value="I'm sorry, I don't have real-time weather information.")
        
        ai_client_mocks.append(ai_client_mock)
    
    # 4. Setup AIClientFactory.get_ai_client to return the correct mock for each interaction
    ai_client_factory_mock = MagicMock()
    ai_client_factory_mock.get_ai_client.side_effect = ai_client_mocks
    monkeypatch.setattr("chat.chat.AIClientFactory.get_ai_client", lambda x: ai_client_factory_mock.get_ai_client())
    
    # 5. Monkeypatch get_app_state and get_file_context to return the mocks
    monkeypatch.setattr("chat.chat.get_app_state", lambda: mock_app_state)
    monkeypatch.setattr("chat.chat.get_file_context", lambda: mock_file_context)
    
    # 6. Mock the add_or_update_file method to correctly set the content
    def mock_add_or_update_file(path, content, operation):
        mock_file_context.tracked_files[path] = content
    
    mock_file_context.add_or_update_file = MagicMock(side_effect=mock_add_or_update_file)
    
    # 7. Simulate User Interactions and Capture Assistant Responses
    for user_input in user_inputs:
        await chat_with_model(user_input, MagicMock(), "gpt-4")
    
    # 8. Print internal states for debugging (optional)
    print("Conversation History:", mock_app_state.conversation_history)
    print("Tracked Files:", mock_file_context.tracked_files)
    
    # 9. Assertions
    
    # 9.1. Check that conversation_history has 8 messages (4 interactions × 2 messages each)
    expected_conversation_length = 8
    assert len(mock_app_state.conversation_history) == expected_conversation_length, \
        f"Expected {expected_conversation_length} messages in conversation_history, found {len(mock_app_state.conversation_history)}"
    
    # 9.2. Verify that roles alternate correctly between 'user' and 'assistant'
    roles = [message['role'] for message in mock_app_state.conversation_history]
    for i in range(1, len(roles)):
        assert roles[i] != roles[i-1], \
            f"Conversation roles do not alternate at index {i}: {roles[i-1]} followed by {roles[i]}"
    
    # 9.3. Verify Assistant Responses with Substring Checks
    for idx, expected_substrings in zip([1, 3, 5, 7], expected_assistant_response_substrings):
        actual_content = mock_app_state.conversation_history[idx]['content']
        for substring in expected_substrings:
            assert substring in actual_content, \
                f"Expected substring '{substring}' not found in assistant message at index {idx}: {actual_content}"
        
        # 9.3.a. Ensure that no full content is present in 'Show me file1.txt' interaction (index=3)
        if idx == 3:
            assert "Fresh content for file1.txt" not in actual_content, \
                f"Unexpected full file content found in assistant message at index {idx}: {actual_content}"
    
    # 9.4. Verify FileContextTracker Updates
    assert "file1.txt" in mock_file_context.tracked_files, \
        f"Expected 'file1.txt' to be in tracked_files, got {list(mock_file_context.tracked_files.keys())}"
    assert mock_file_context.tracked_files["file1.txt"] == "Updated content of file1", \
        f"Expected tracked_files['file1.txt'] to be 'Updated content of file1', got '{mock_file_context.tracked_files.get('file1.txt')}'"
    
    # 9.5. Ensure No Unexpected Files are Tracked
    assert len(mock_file_context.tracked_files) == 1, \
        f"Expected only 'file1.txt' in tracked_files, got {list(mock_file_context.tracked_files.keys())}"
```