I'm writing an Agent based framework (using AutoGen) w/ 2 agents (user proxy agent and code execution / function calling agent), and running into the following error: 

{'content': None, 'refusal': None, 'role': 'assistant', 'function_call': None, 'tool_calls': [{'id': 'call_KPiZU7WDFB0Uu2IGf4HvIBpT', 'function': {'arguments': '{"report_title":"AAPL Stock Report","stock_data":" Open High Low Close Volume Dividends Stock Splits\nDatetime \n2024-09-17 09:30:00-04:00 215.500000 216.559998 214.500000 216.419998 11537502 0.0 0.0\n2024-09-17 10:30:00-04:00 216.399994 216.899994 215.889999 216.205002 5086619 0.0 0.0\n2024-09-17 11:30:00-04:00 216.210007 216.839996 215.509995 215.759995 4563369 0.0 0.0\n2024-09-17 12:30:00-04:00 215.770004 216.229996 215.229996 216.169998 4929353 0.0 0.0\n2024-09-17 13:30:00-04:00 216.160004 216.389999 215.059998 216.149994 3204596 0.0 0.0\n2024-09-17 14:30:00-04:00 216.139999 216.619995 215.300003 216.610001 3928149 0.0 0.0\n2024-09-17 15:30:00-04:00 216.600006 216.850006 216.169998 216.850006 4733527 0.0 0.0\n2024-09-18 09:30:00-04:00 218.250000 220.735001 218.172195 220.735001 11719770 0.0 0.0\n2024-09-18 10:30:00-04:00 220.730103 221.610001 220.251007 220.630005 8156545 0.0 0.0\n2024-09-18 11:30:00-04:00 220.639999 220.869904 219.520004 220.809998 4730443 0.0 0.0\n2024-09-18 12:30:00-04:00 220.800003 221.350006 220.259995 221.210098 4663209 0.0 0.0\n2024-09-18 13:30:00-04:00 221.220001 222.699997 219.929993 221.407303 7417109 0.0 0.0\n2024-09-18 14:30:00-04:00 221.495895 221.850006 218.929993 221.500000 7309128 0.0 0.0\n2024-09-18 15:30:00-04:00 221.539993 221.809998 219.880005 220.690002 6247706 0.0 0.0\n2024-09-19 09:30:00-04:00 225.000000 229.600006 224.639999 229.494995 18240508 0.0 0.0\n2024-09-19 10:30:00-04:00 229.589996 229.740005 227.660004 228.490005 8846328 0.0 0.0\n2024-09-19 11:30:00-04:00 228.484604 229.179993 228.000000 228.994995 5729594 0.0 0.0\n2024', 'name': 'create_pdf_report'}, 'type': 'function'}]}

{'role': 'tool', 'tool_responses': [{'tool_call_id': 'call_KPiZU7WDFB0Uu2IGf4HvIBpT', 'role': 'tool', 'content': 'Error: Unterminated string starting at: line 1 column 50 (char 49)\n The argument must be in JSON format.'}], 'content': 'Error: Unterminated string starting at: line 1 column 50 (char 49)\n The argument must be in JSON format.'}

{'content': None, 'refusal': None, 'role': 'assistant', 'function_call': None, 'tool_calls': [{'id': 'call_GmjuiWcbMudlJsEuxOopHGNz', 'function': {'arguments': '{"report_title":"AAPL Stock Report","stock_data":"Open,High,Low,Close,Volume\n215.50,216.56,214.50,216.42,11537502\n216.40,216.90,215.89,216.21,5086619\n216.21,216.83,215.51,215.76,4563369\n215.77,216.23,215.23,216.17,4929353\n216.16,216.39,215.06,216.15,3204596\n216.14,216.62,215.30,216.61,3928149\n216.60,216.85,216.17,216.85,4733527\n218.25,220.73,218.17,220.74,11719770\n220.73,221.61,220.25,220.63,8156545\n220.64,220.87,219.52,220.81,4730443\n220.80,221.35,220.26,221.21,4663209\n221.22,222.70,219.93,221.41,7417109\n221.50,221.85,218.93,221.50,7309128\n221.54,221.81,219.88,220.69,6247706\n225.00,229.60,224.64,229.49,18240508\n229.59,229.74,227.66,228.49,8846328\n228.48,229.18,228.00,228.99,5729594\n228.99,229.33,228.72,229.17,4098355\n229.17,229.46,228.40,228.87,4410441\n228.87,229.49,228.76,229.47,4815301\n229.46,229.59,228.29,228.82,7376731\n230.13,231.16,229.30,230.03,28984531\n230.02,230.58,229.20,229.77,12497143\n229.76,231.74,229.74,231.73,7914719\n231.72,231.92,230.61,230.75,6485883\n230.74,231.26,229.60,229.78,7870480\n229.77,232.00,229.50,231.98,10546962\n231.98,233.09,227.62,228.53,25542112\n227.34,228.07,225.86,228.01,13371841\n228.01,229.45,227.63,228.65,6527900\n228.66,228.90,226.93,226.94,3575768\n226.94,227.41,226.62,226.74,3228628\n226.75,227.18,226.51,226.68,2921492\n226.69,226.76,225.90,226.29,3625613\n226.28,226.70,225.81,226.45,4397453","image_path":"","output_path":"AAPL_Report.pdf"}', 'name': 'create_pdf_report'}, 'type': 'function'}]}

{'role': 'tool', 'tool_responses': [{'tool_call_id': 'call_GmjuiWcbMudlJsEuxOopHGNz', 'role': 'tool', 'content': "Error: create_pdf_report() missing 1 required positional argument: 'news_items'"}], 'content': "Error: create_pdf_report() missing 1 required positional argument: 'news_items'"}

{'content': None, 'refusal': None, 'role': 'assistant', 'function_call': None, 'tool_calls': [{'id': 'call_qk7W6FXHmTYdDrj4InTCMysu', 'function': {'arguments': '{"report_title":"AAPL Stock Report","stock_data":"Open,High,Low,Close,Volume\n215.50,216.56,214.50,216.42,11537502\n216.40,216.90,215.89,216.21,5086619\n216.21,216.83,215.51,215.76,4563369\n215.77,216.23,215.23,216.17,4929353\n216.16,216.39,215.06,216.15,3204596\n216.14,216.62,215.30,216.61,3928149\n216.60,216.85,216.17,216.85,4733527\n218.25,220.73,218.17,220.74,11719770\n220.73,221.61,220.25,220.63,8156545\n220.64,220.87,219.52,220.81,4730443\n220.80,221.35,220.26,221.21,4663209\n221.22,222.70,219.93,221.41,7417109\n221.50,221.85,218.93,221.50,7309128\n221.54,221.81,219.88,220.69,6247706\n225.00,229.60,224.64,229.49,18240508\n229.59,229.74,227.66,228.49,8846328\n228.48,229.18,228.00,228.99,5729594\n228.99,229.33,228.72,229.17,4098355\n229.17,229.46,228.40,228.87,4410441\n228.87,229.49,228.76,229.47,4815301\n229.46,229.59,228.29,228.82,7376731\n230.13,231.16,229.30,230.03,28984531\n230.02,230.58,229.20,229.77,12497143\n229.76,231.74,229.74,231.73,7914719\n231.72,231.92,230.61,230.75,6485883\n230.74,231.26,229.60,229.78,7870480\n229.77,232.00,229.50,231.98,10546962\n231.98,233.09,227.62,228.53,25542112\n227.34,228.07,225.86,228.01,13371841\n228.01,229.45,227.63,228.65,6527900\n228.66,228.90,226.93,226.94,3575768\n226.94,227.41,226.62,226.74,3228628\n226.75,227.18,226.51,226.68,2921492\n226.69,226.76,225.90,226.29,3625613\n226.28,226.70,225.81,226.45,4397453","news_items":[{"title":"Dow Jones Futures Fall: Magnificent Seven Stocks Amazon, Apple, Microsoft, Tesla Eye New Buy Points","summary":"Dow Jones Futures Fall: Magnificent Seven stocks Amazon, Apple, Meta Platforms, Microsoft and Tesla are in or near buy zones Monday.","sentiment":"Bullish"},{"title":"Analysts rethink key Apple supplier stock price target","summary":"Here’s what could be next for Corning stock.","sentiment":"Neutral"},{"title":"These Stocks Moved the Most Today: Intel, Micron, Tesla, Palantir, Microsoft, GM, Ciena, and More","summary":"Intel stock trades higher following a report that says Apollo Global Management offered to make a $5 billion investment in the chip maker, Tesla stock flirts with turning positive for the year, and shares of Palantir and Microsoft are downgraded.","sentiment":"Bullish"},{"title":"Apple iPhone 16 Early Demand Deemed Healthy","summary":"Early sales data suggests “healthy demand” for Apple’s iPhone 16 family overall, JPMorgan said. Apple stock dipped on Monday.","sentiment":"Bullish"},{"title":"Apple’s Late-Day Plunge Stirs Speculation Over Who Was Selling","summary":"(Bloomberg) -- Friday was supposed to be a good day for the shares of Apple Inc.,', 'name': 'create_pdf_report'}, 'type': 'function'}]}

{'role': 'tool', 'tool_responses': [{'tool_call_id': 'call_qk7W6FXHmTYdDrj4InTCMysu', 'role': 'tool', 'content': 'Error: Unterminated string starting at: line 1 column 2512 (char 2511)\n The argument must be in JSON format.'}], 'content': 'Error: Unterminated string starting at: line 1 column 2512 (char 2511)\n The argument must be in JSON format.'}

Here's the source code: 
import os
import streamlit as st
import asyncio
import feedparser
from textblob import TextBlob
from fpdf import FPDF
import yfinance as yf
from azure.identity import DefaultAzureCredential, get_bearer_token_provider
from autogen import ConversableAgent, register_function
from typing import List, Dict
import json
import requests

# Initialize the DefaultAzureCredential
token_provider = get_bearer_token_provider(
    DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default"
)

# Configuration for the LLM model
llm_config = {
    "config_list": [
        {
            "model":  "gpt4omini",
            "base_url": "https://autogenagents.openai.azure.com/",
            "api_type": "azure",
            "api_version": "2024-02-15-preview",
            "max_tokens": 1000,
            "azure_ad_token_provider": token_provider
        }
    ]
}

# Define PDF class
class PDF(FPDF):
    def header(self):
        self.set_font('Arial', 'B', 12)
        self.cell(0, 10, self.title, 0, 1, 'C')

    def chapter_title(self, title):
        self.set_font('Arial', 'B', 12)
        self.cell(0, 10, title.encode('latin-1', 'replace').decode('latin-1'), 0, 1, 'L')
        self.ln(2)

    def chapter_body(self, body):
        self.set_font('Arial', '', 12)
        self.multi_cell(0, 10, body.encode('latin-1', 'replace').decode('latin-1'))
        self.ln()

    def add_image(self, image_path):
        self.image(image_path, x=10, w=190)
        self.ln()

def create_pdf_report(report_title: str, news_items: List[Dict], stock_data: str, image_path: str, output_path: str) -> None:
    pdf = PDF()
    pdf.title = report_title
    pdf.add_page()

    for item in news_items:
        pdf.chapter_title(item['title'])
        pdf.chapter_body(f"Sentiment: {item['sentiment']}")

    pdf.chapter_title("Stock Price History")
    pdf.chapter_body(stock_data)

    if os.path.exists(image_path):
        pdf.add_image(image_path)

    pdf.output(output_path)

def fetch_latest_news(ticker: str) -> List[Dict]:
    url = f'https://finance.yahoo.com/rss/headline?s={ticker}'
    news_data = feedparser.parse(url)
    news_items = []
    for entry in news_data.entries[:5]:  # Limit to 5 news articles
        news_items.append({
            'title': entry.title,
            'link': entry.link,
            'summary': entry.summary
        })
    return news_items

def analyze_sentiment(news: List[Dict]) -> List[Dict]:
    sentiment_results = []
    for entry in news:
        text = entry['title'] + ' ' + entry['summary']
        analysis = TextBlob(text)
        sentiment = 'Bullish' if analysis.sentiment.polarity > 0 else 'Bearish' if analysis.sentiment.polarity < 0 else 'Neutral'
        sentiment_results.append({'title': entry['title'], 'sentiment': sentiment})
    return sentiment_results

def fetch_stock_price_history(ticker: str) -> str:
    stock = yf.Ticker(ticker)
    hist = stock.history(period="5d", interval="1h")  # Fetch hourly data for the past 5 days
    return hist.to_string()

def validate_json(json_string: str) -> bool:
    try:
        json.loads(json_string)
        return True
    except ValueError:
        return False

def reformat_json_with_gpt4mini(json_string: str) -> str:
    response = requests.post(
        "https://autogenagents.openai.azure.com/openai/deployments/gpt4omini/completions?api-version=2024-02-15-preview",
        headers={
            "Content-Type": "application/json",
            "Authorization": f"Bearer {token_provider.get_token()}"
        },
        json={
            "prompt": f"Reformat the following string into valid JSON:\n\n{json_string}",
            "max_tokens": 1000
        }
    )
    response_json = response.json()
    return response_json['choices'][0]['text'].strip()

# Define TrackableAssistantAgent class
class TrackableAssistantAgent(ConversableAgent):
    def __init__(self, *args, skills=None, **kwargs):
        super().__init__(*args, **kwargs)
        self.skills = skills or []
        
    def _process_received_message(self, message, sender, silent):
        with st.chat_message(sender.name):
            st.markdown(message)
        return super()._process_received_message(message, sender, silent)

# Define TrackableUserProxyAgent class
class TrackableUserProxyAgent(ConversableAgent):
    def _process_received_message(self, message, sender, silent):
        with st.chat_message(sender.name):
            st.markdown(message)
        return super()._process_received_message(message, sender, silent)

# Create a title at the top of the page 
st.write("# SkillUp AI DOCathlon")
st.write("## AutoGen Tools")

# Create a user proxy agent
user_proxy = TrackableUserProxyAgent(
    name="User",
    llm_config=False,
    is_termination_msg=lambda msg: msg.get("content") is not None and "TERMINATE" in msg["content"],
    human_input_mode="NEVER",
)

# Create an assistant agent
assistant = TrackableAssistantAgent(
    name="Assistant",
    system_message="You are a helpful AI assistant. When the user provides a stock ticker symbol, you will fetch the latest news for the given stock ticker, analyze the sentiment of the news articles, fetch the recent stock price history, and create a PDF report with the news, their sentiment, and the stock price history. Reply 'TERMINATE' when everything is done.",
    llm_config=llm_config,
)

# Register functions
register_function(
    fetch_latest_news,
    caller=assistant,
    executor=user_proxy,
    name="fetch_latest_news",
    description="Fetches the latest news for a given stock ticker.",
)

register_function(
    analyze_sentiment,
    caller=assistant,
    executor=user_proxy,
    name="analyze_sentiment",
    description="Analyzes the sentiment of the news articles.",
)

register_function(
    fetch_stock_price_history,
    caller=assistant,
    executor=user_proxy,
    name="fetch_stock_price_history",
    description="Fetches the recent stock price history.",
)

register_function(
    create_pdf_report,
    caller=assistant,
    executor=user_proxy,
    name="create_pdf_report",
    description="Creates a PDF report with the news articles, their sentiment, and stock price history.",
)

if 'chat_initiated' not in st.session_state:
    st.session_state.chat_initiated = False

chatresult = None
with st.container():
    user_input = st.chat_input("Type a stock ticker symbol (e.g., AAPL)...")
    if user_input:
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)

        async def initiate_chat():
            try:
                chatresult = await user_proxy.initiate_chat(
                    assistant,
                    message=user_input,
                    max_consecutive_auto_reply=5,
                    is_termination_msg=lambda x: x.get("content", "").strip().endswith("TERMINATE"),
                )
            except Exception as e:
                st.error(f"An error occurred: {e}")
        
        loop.run_until_complete(initiate_chat())
        loop.close()

        if chatresult:
            # Ensure analyze_sentiment is called with the correct argument
            if 'tool_responses' in chatresult:
                for response in chatresult['tool_responses']:
                    if 'content' in response and 'missing 1 required positional argument' in response['content']:
                        news = fetch_latest_news(user_input)
                        sentiment_results = analyze_sentiment(news)
                        chatresult['tool_responses'].append({
                            'tool_call_id': response['tool_call_id'] + '_retry',
                            'role': 'tool',
                            'content': sentiment_results
                        })

if st.session_state.chat_initiated:
    st.write(chatresult)