diff --git a/.gitignore b/.gitignore index 6bed53f7c84..49a41e9ed2c 100644 --- a/.gitignore +++ b/.gitignore @@ -182,3 +182,4 @@ test/agentchat/test_agent_scripts/* notebook/result.png +samples/apps/autogen-studio/autogenstudio/models/test/ diff --git a/autogen/agentchat/chat.py b/autogen/agentchat/chat.py index 6d070486373..bd4559ff425 100644 --- a/autogen/agentchat/chat.py +++ b/autogen/agentchat/chat.py @@ -1,11 +1,13 @@ import asyncio +from functools import partial import logging -from collections import defaultdict +from collections import defaultdict, abc from typing import Dict, List, Any, Set, Tuple from dataclasses import dataclass +from .utils import consolidate_chat_info +import datetime import warnings from termcolor import colored -from .utils import consolidate_chat_info logger = logging.getLogger(__name__) @@ -135,22 +137,22 @@ def initiate_chats(chat_queue: List[Dict[str, Any]]) -> List[ChatResult]: """Initiate a list of chats. Args: - chat_queue (List[Dict]): a list of dictionaries containing the information of the chats. - Each dictionary should contain the input arguments for `ConversableAgent.initiate_chat`. - More specifically, each dictionary could include the following fields: - - "sender": the sender agent. - - "recipient": the recipient agent. - - "clear_history" (bool): whether to clear the chat history with the agent. Default is True. - - "silent" (bool or None): (Experimental) whether to print the messages for this conversation. Default is False. - - "cache" (Cache or None): the cache client to be used for this conversation. Default is None. - - "max_turns" (int or None): the maximum number of turns for the chat. If None, the chat will continue until a termination condition is met. Default is None. - - "summary_method" (str or callable): a string or callable specifying the method to get a summary from the chat. Default is DEFAULT_summary_method, i.e., "last_msg". - - "summary_args" (dict): a dictionary of arguments to be passed to the summary_method. Default is {}. - - "message" (str, callable or None): if None, input() will be called to get the initial message. - - **context: additional context information to be passed to the chat. - - "carryover": It can be used to specify the carryover information to be passed to this chat. - If provided, we will combine this carryover with the "message" content when generating the initial chat - message in `generate_init_message`. + chat_queue (List[Dict]): a list of dictionaries containing the information about the chats. + + Each dictionary should contain the input arguments for [`ConversableAgent.initiate_chat`](/docs/reference/agentchat/conversable_agent#initiate_chat). For example: + - "sender": the sender agent. + - "recipient": the recipient agent. + - "clear_history" (bool): whether to clear the chat history with the agent. Default is True. + - "silent" (bool or None): (Experimental) whether to print the messages in this conversation. Default is False. + - "cache" (Cache or None): the cache client to use for this conversation. Default is None. + - "max_turns" (int or None): maximum number of turns for the chat. If None, the chat will continue until a termination condition is met. Default is None. + - "summary_method" (str or callable): a string or callable specifying the method to get a summary from the chat. Default is DEFAULT_summary_method, i.e., "last_msg". + - "summary_args" (dict): a dictionary of arguments to be passed to the summary_method. Default is {}. + - "message" (str, callable or None): if None, input() will be called to get the initial message. + - **context: additional context information to be passed to the chat. + - "carryover": It can be used to specify the carryover information to be passed to this chat. + If provided, we will combine this carryover with the "message" content when generating the initial chat + message in `generate_init_message`. Returns: (list): a list of ChatResult objects corresponding to the finished chats in the chat_queue. @@ -173,6 +175,49 @@ def initiate_chats(chat_queue: List[Dict[str, Any]]) -> List[ChatResult]: return finished_chats +def __system_now_str(): + ct = datetime.datetime.now() + return f" System time at {ct}. " + + +def _on_chat_future_done(chat_future: asyncio.Future, chat_id: int): + """ + Update ChatResult when async Task for Chat is completed. + """ + logger.debug(f"Update chat {chat_id} result on task completion." + __system_now_str()) + chat_result = chat_future.result() + chat_result.chat_id = chat_id + + +async def _dependent_chat_future( + chat_id: int, chat_info: Dict[str, Any], prerequisite_chat_futures: Dict[int, asyncio.Future] +) -> asyncio.Task: + """ + Create an async Task for each chat. + """ + logger.debug(f"Create Task for chat {chat_id}." + __system_now_str()) + _chat_carryover = chat_info.get("carryover", []) + finished_chats = dict() + for chat in prerequisite_chat_futures: + chat_future = prerequisite_chat_futures[chat] + if chat_future.cancelled(): + raise RuntimeError(f"Chat {chat} is cancelled.") + + # wait for prerequisite chat results for the new chat carryover + finished_chats[chat] = await chat_future + + if isinstance(_chat_carryover, str): + _chat_carryover = [_chat_carryover] + chat_info["carryover"] = _chat_carryover + [finished_chats[pre_id].summary for pre_id in finished_chats] + __post_carryover_processing(chat_info) + sender = chat_info["sender"] + chat_res_future = asyncio.create_task(sender.a_initiate_chat(**chat_info)) + call_back_with_args = partial(_on_chat_future_done, chat_id=chat_id) + chat_res_future.add_done_callback(call_back_with_args) + logger.debug(f"Task for chat {chat_id} created." + __system_now_str()) + return chat_res_future + + async def a_initiate_chats(chat_queue: List[Dict[str, Any]]) -> Dict[int, ChatResult]: """(async) Initiate a list of chats. @@ -183,31 +228,25 @@ async def a_initiate_chats(chat_queue: List[Dict[str, Any]]) -> Dict[int, ChatRe returns: (Dict): a dict of ChatId: ChatResult corresponding to the finished chats in the chat_queue. """ - consolidate_chat_info(chat_queue) _validate_recipients(chat_queue) chat_book = {chat_info["chat_id"]: chat_info for chat_info in chat_queue} num_chats = chat_book.keys() prerequisites = __create_async_prerequisites(chat_queue) chat_order_by_id = __find_async_chat_order(num_chats, prerequisites) - finished_chats = dict() + finished_chat_futures = dict() for chat_id in chat_order_by_id: chat_info = chat_book[chat_id] - condition = asyncio.Condition() prerequisite_chat_ids = chat_info.get("prerequisites", []) - async with condition: - await condition.wait_for(lambda: all([id in finished_chats for id in prerequisite_chat_ids])) - # Do the actual work here. - _chat_carryover = chat_info.get("carryover", []) - if isinstance(_chat_carryover, str): - _chat_carryover = [_chat_carryover] - chat_info["carryover"] = _chat_carryover + [ - finished_chats[pre_id].summary for pre_id in prerequisite_chat_ids - ] - __post_carryover_processing(chat_info) - sender = chat_info["sender"] - chat_res = await sender.a_initiate_chat(**chat_info) - chat_res.chat_id = chat_id - finished_chats[chat_id] = chat_res - + pre_chat_futures = dict() + for pre_chat_id in prerequisite_chat_ids: + pre_chat_future = finished_chat_futures[pre_chat_id] + pre_chat_futures[pre_chat_id] = pre_chat_future + current_chat_future = await _dependent_chat_future(chat_id, chat_info, pre_chat_futures) + finished_chat_futures[chat_id] = current_chat_future + await asyncio.gather(*list(finished_chat_futures.values())) + finished_chats = dict() + for chat in finished_chat_futures: + chat_result = finished_chat_futures[chat].result() + finished_chats[chat] = chat_result return finished_chats diff --git a/autogen/agentchat/contrib/gpt_assistant_agent.py b/autogen/agentchat/contrib/gpt_assistant_agent.py index c4c73ed2c51..ea13e761757 100644 --- a/autogen/agentchat/contrib/gpt_assistant_agent.py +++ b/autogen/agentchat/contrib/gpt_assistant_agent.py @@ -28,6 +28,7 @@ def __init__( name="GPT Assistant", instructions: Optional[str] = None, llm_config: Optional[Union[Dict, bool]] = None, + assistant_config: Optional[Dict] = None, overwrite_instructions: bool = False, overwrite_tools: bool = False, **kwargs, @@ -43,8 +44,9 @@ def __init__( AssistantAgent.DEFAULT_SYSTEM_MESSAGE. If the assistant exists, the system message will be set to the existing assistant instructions. llm_config (dict or False): llm inference configuration. - - assistant_id: ID of the assistant to use. If None, a new assistant will be created. - model: Model to use for the assistant (gpt-4-1106-preview, gpt-3.5-turbo-1106). + assistant_config + - assistant_id: ID of the assistant to use. If None, a new assistant will be created. - check_every_ms: check thread run status interval - tools: Give Assistants access to OpenAI-hosted tools like Code Interpreter and Knowledge Retrieval, or build your own tools using Function calling. ref https://platform.openai.com/docs/assistants/tools @@ -57,23 +59,19 @@ def __init__( """ self._verbose = kwargs.pop("verbose", False) + openai_client_cfg, openai_assistant_cfg = self._process_assistant_config(llm_config, assistant_config) + super().__init__( - name=name, system_message=instructions, human_input_mode="NEVER", llm_config=llm_config, **kwargs + name=name, system_message=instructions, human_input_mode="NEVER", llm_config=openai_client_cfg, **kwargs ) - if llm_config is False: - raise ValueError("llm_config=False is not supported for GPTAssistantAgent.") - # Use AutooGen OpenAIWrapper to create a client - openai_client_cfg = copy.deepcopy(llm_config) - # Use the class variable - model_name = GPTAssistantAgent.DEFAULT_MODEL_NAME - # GPTAssistantAgent's azure_deployment param may cause NotFoundError (404) in client.beta.assistants.list() # See: https://github.com/microsoft/autogen/pull/1721 + model_name = self.DEFAULT_MODEL_NAME if openai_client_cfg.get("config_list") is not None and len(openai_client_cfg["config_list"]) > 0: - model_name = openai_client_cfg["config_list"][0].pop("model", GPTAssistantAgent.DEFAULT_MODEL_NAME) + model_name = openai_client_cfg["config_list"][0].pop("model", self.DEFAULT_MODEL_NAME) else: - model_name = openai_client_cfg.pop("model", GPTAssistantAgent.DEFAULT_MODEL_NAME) + model_name = openai_client_cfg.pop("model", self.DEFAULT_MODEL_NAME) logger.warning("OpenAI client config of GPTAssistantAgent(%s) - model: %s", name, model_name) @@ -82,14 +80,17 @@ def __init__( logger.warning("GPT Assistant only supports one OpenAI client. Using the first client in the list.") self._openai_client = oai_wrapper._clients[0]._oai_client - openai_assistant_id = llm_config.get("assistant_id", None) + openai_assistant_id = openai_assistant_cfg.get("assistant_id", None) if openai_assistant_id is None: # try to find assistant by name first candidate_assistants = retrieve_assistants_by_name(self._openai_client, name) if len(candidate_assistants) > 0: # Filter out candidates with the same name but different instructions, file IDs, and function names. candidate_assistants = self.find_matching_assistant( - candidate_assistants, instructions, llm_config.get("tools", []), llm_config.get("file_ids", []) + candidate_assistants, + instructions, + openai_assistant_cfg.get("tools", []), + openai_assistant_cfg.get("file_ids", []), ) if len(candidate_assistants) == 0: @@ -103,9 +104,9 @@ def __init__( self._openai_assistant = self._openai_client.beta.assistants.create( name=name, instructions=instructions, - tools=llm_config.get("tools", []), + tools=openai_assistant_cfg.get("tools", []), model=model_name, - file_ids=llm_config.get("file_ids", []), + file_ids=openai_assistant_cfg.get("file_ids", []), ) else: logger.warning( @@ -135,8 +136,8 @@ def __init__( "overwrite_instructions is False. Provided instructions will be used without permanently modifying the assistant in the API." ) - # Check if tools are specified in llm_config - specified_tools = llm_config.get("tools", None) + # Check if tools are specified in assistant_config + specified_tools = openai_assistant_cfg.get("tools", None) if specified_tools is None: # Check if the current assistant has tools defined @@ -155,7 +156,7 @@ def __init__( ) self._openai_assistant = self._openai_client.beta.assistants.update( assistant_id=openai_assistant_id, - tools=llm_config.get("tools", []), + tools=openai_assistant_cfg.get("tools", []), ) else: # Tools are specified but overwrite_tools is False; do not update the assistant's tools @@ -414,6 +415,10 @@ def assistant_id(self): def openai_client(self): return self._openai_client + @property + def openai_assistant(self): + return self._openai_assistant + def get_assistant_instructions(self): """Return the assistant instructions from OAI assistant API""" return self._openai_assistant.instructions @@ -472,3 +477,31 @@ def find_matching_assistant(self, candidate_assistants, instructions, tools, fil matching_assistants.append(assistant) return matching_assistants + + def _process_assistant_config(self, llm_config, assistant_config): + """ + Process the llm_config and assistant_config to extract the model name and assistant related configurations. + """ + + if llm_config is False: + raise ValueError("llm_config=False is not supported for GPTAssistantAgent.") + + if llm_config is None: + openai_client_cfg = {} + else: + openai_client_cfg = copy.deepcopy(llm_config) + + if assistant_config is None: + openai_assistant_cfg = {} + else: + openai_assistant_cfg = copy.deepcopy(assistant_config) + + # Move the assistant related configurations to assistant_config + # It's important to keep forward compatibility + assistant_config_items = ["assistant_id", "tools", "file_ids", "check_every_ms"] + for item in assistant_config_items: + if openai_client_cfg.get(item) is not None and openai_assistant_cfg.get(item) is None: + openai_assistant_cfg[item] = openai_client_cfg[item] + openai_client_cfg.pop(item, None) + + return openai_client_cfg, openai_assistant_cfg diff --git a/autogen/agentchat/conversable_agent.py b/autogen/agentchat/conversable_agent.py index 86610d86736..838af6e7df7 100644 --- a/autogen/agentchat/conversable_agent.py +++ b/autogen/agentchat/conversable_agent.py @@ -296,18 +296,18 @@ def register_reply( from both sync and async chats. However, an async reply function will only be triggered from async chats (initiated with `ConversableAgent.a_initiate_chat`). If an `async` reply function is registered and a chat is initialized with a sync function, `ignore_async_in_sync_chat` determines the behaviour as follows: - - if `ignore_async_in_sync_chat` is set to `False` (default value), an exception will be raised, and - - if `ignore_async_in_sync_chat` is set to `True`, the reply function will be ignored. + if `ignore_async_in_sync_chat` is set to `False` (default value), an exception will be raised, and + if `ignore_async_in_sync_chat` is set to `True`, the reply function will be ignored. Args: trigger (Agent class, str, Agent instance, callable, or list): the trigger. - - If a class is provided, the reply function will be called when the sender is an instance of the class. - - If a string is provided, the reply function will be called when the sender's name matches the string. - - If an agent instance is provided, the reply function will be called when the sender is the agent instance. - - If a callable is provided, the reply function will be called when the callable returns True. - - If a list is provided, the reply function will be called when any of the triggers in the list is activated. - - If None is provided, the reply function will be called only when the sender is None. - Note: Be sure to register `None` as a trigger if you would like to trigger an auto-reply function with non-empty messages and `sender=None`. + If a class is provided, the reply function will be called when the sender is an instance of the class. + If a string is provided, the reply function will be called when the sender's name matches the string. + If an agent instance is provided, the reply function will be called when the sender is the agent instance. + If a callable is provided, the reply function will be called when the callable returns True. + If a list is provided, the reply function will be called when any of the triggers in the list is activated. + If None is provided, the reply function will be called only when the sender is None. + Note: Be sure to register `None` as a trigger if you would like to trigger an auto-reply function with non-empty messages and `sender=None`. reply_func (Callable): the reply function. The function takes a recipient agent, a list of messages, a sender agent and a config as input and returns a reply message. position: the position of the reply function in the reply function list. @@ -364,6 +364,8 @@ def _summary_from_nested_chats( chat_to_run = [] for i, c in enumerate(chat_queue): current_c = c.copy() + if current_c.get("sender") is None: + current_c["sender"] = recipient message = current_c.get("message") # If message is not provided in chat_queue, we by default use the last message from the original chat history as the first message in this nested chat (for the first chat in the chat queue). # NOTE: This setting is prone to change. @@ -377,7 +379,7 @@ def _summary_from_nested_chats( chat_to_run.append(current_c) if not chat_to_run: return True, None - res = recipient.initiate_chats(chat_to_run) + res = initiate_chats(chat_to_run) return True, res[-1].summary def register_nested_chats( @@ -878,66 +880,71 @@ def initiate_chat( silent (bool or None): (Experimental) whether to print the messages for this conversation. Default is False. cache (Cache or None): the cache client to be used for this conversation. Default is None. max_turns (int or None): the maximum number of turns for the chat between the two agents. One turn means one conversation round trip. Note that this is different from - [max_consecutive_auto_reply](#max_consecutive_auto_reply) which is the maximum number of consecutive auto replies; and it is also different from [max_rounds in GroupChat](./groupchat#groupchat-objects) which is the maximum number of rounds in a group chat session. - If max_turns is set to None, the chat will continue until a termination condition is met. Default is None. - summary_method (string or callable) : a method to get a summary from the chat. Default is DEFAULT_SUMMARY_METHOD, i.e., "last_msg". - - Supported string are "last_msg" and "reflection_with_llm": - when set "last_msg", it returns the last message of the dialog as the summary. - when set "reflection_with_llm", it returns a summary extracted using an llm client. - `llm_config` must be set in either the recipient or sender. - "reflection_with_llm" requires the llm_config to be set in either the sender or the recipient. - - A callable summary_method should take the recipient and sender agent in a chat as input and return a string of summary. E.g, - ```python - def my_summary_method( - sender: ConversableAgent, - recipient: ConversableAgent, - summary_args: dict, - ): - return recipient.last_message(sender)["content"] - ``` + [max_consecutive_auto_reply](#max_consecutive_auto_reply) which is the maximum number of consecutive auto replies; and it is also different from [max_rounds in GroupChat](./groupchat#groupchat-objects) which is the maximum number of rounds in a group chat session. + If max_turns is set to None, the chat will continue until a termination condition is met. Default is None. + summary_method (str or callable): a method to get a summary from the chat. Default is DEFAULT_SUMMARY_METHOD, i.e., "last_msg". + + Supported strings are "last_msg" and "reflection_with_llm": + - when set to "last_msg", it returns the last message of the dialog as the summary. + - when set to "reflection_with_llm", it returns a summary extracted using an llm client. + `llm_config` must be set in either the recipient or sender. + + A callable summary_method should take the recipient and sender agent in a chat as input and return a string of summary. E.g., + + ```python + def my_summary_method( + sender: ConversableAgent, + recipient: ConversableAgent, + summary_args: dict, + ): + return recipient.last_message(sender)["content"] + ``` summary_args (dict): a dictionary of arguments to be passed to the summary_method. - E.g., a string of text used to prompt a LLM-based agent (the sender or receiver agent) to reflext - on the conversation and extract a summary when summary_method is "reflection_with_llm". - Default is DEFAULT_SUMMARY_PROMPT, i.e., "Summarize takeaway from the conversation. Do not add any introductory phrases. If the intended request is NOT properly addressed, please point it out." + One example key is "summary_prompt", and value is a string of text used to prompt a LLM-based agent (the sender or receiver agent) to reflect + on the conversation and extract a summary when summary_method is "reflection_with_llm". + The default summary_prompt is DEFAULT_SUMMARY_PROMPT, i.e., "Summarize takeaway from the conversation. Do not add any introductory phrases. If the intended request is NOT properly addressed, please point it out." message (str, dict or Callable): the initial message to be sent to the recipient. Needs to be provided. Otherwise, input() will be called to get the initial message. - - If a string or a dict is provided, it will be used as the initial message. `generate_init_message` is called to generate the initial message for the agent based on this string and the context. - If dict, it may contain the following reserved fields (either content or function_call need to be provided). - 1. "content": content of the message, can be None. - 2. "function_call": a dictionary containing the function name and arguments. (deprecated in favor of "tool_calls") - 3. "tool_calls": a list of dictionaries containing the function name and arguments. - 4. "role": role of the message, can be "assistant", "user", "function". - This field is only needed to distinguish between "function" or "assistant"/"user". - 5. "name": In most cases, this field is not needed. When the role is "function", this field is needed to indicate the function name. - 6. "context" (dict): the context of the message, which will be passed to - [OpenAIWrapper.create](../oai/client#create). - - If a callable is provided, it will be called to get the initial message in the form of a string or a dict. If the returned value is a dict, it should contain the following reserved fields: + - If a string or a dict is provided, it will be used as the initial message. `generate_init_message` is called to generate the initial message for the agent based on this string and the context. + If dict, it may contain the following reserved fields (either content or tool_calls need to be provided). + + 1. "content": content of the message, can be None. + 2. "function_call": a dictionary containing the function name and arguments. (deprecated in favor of "tool_calls") + 3. "tool_calls": a list of dictionaries containing the function name and arguments. + 4. "role": role of the message, can be "assistant", "user", "function". + This field is only needed to distinguish between "function" or "assistant"/"user". + 5. "name": In most cases, this field is not needed. When the role is "function", this field is needed to indicate the function name. + 6. "context" (dict): the context of the message, which will be passed to + [OpenAIWrapper.create](../oai/client#create). + + - If a callable is provided, it will be called to get the initial message in the form of a string or a dict. If the returned type is dict, it may contain the reserved fields mentioned above. Example of a callable message (returning a string): - ```python - def my_message(sender: ConversableAgent, recipient: ConversableAgent, context: dict) -> Union[str, Dict]: - carryover = context.get("carryover", "") - if isinstance(message, list): - carryover = carryover[-1] - final_msg = "Write a blogpost." + "\nContext: \n" + carryover - return final_msg - ``` + + ```python + def my_message(sender: ConversableAgent, recipient: ConversableAgent, context: dict) -> Union[str, Dict]: + carryover = context.get("carryover", "") + if isinstance(message, list): + carryover = carryover[-1] + final_msg = "Write a blogpost." + "\\nContext: \\n" + carryover + return final_msg + ``` Example of a callable message (returning a dict): - ```python - def my_message(sender: ConversableAgent, recipient: ConversableAgent, context: dict) -> Union[str, Dict]: - final_msg = {} - carryover = context.get("carryover", "") - carryover = context.get("carryover", "") - if isinstance(message, list): - carryover = carryover[-1] - final_msg["content"] = "Write a blogpost." + "\nContext: \n" + carryover - final_msg["context"] = {"prefix": "Today I feel"} - return final_msg - ``` + + ```python + def my_message(sender: ConversableAgent, recipient: ConversableAgent, context: dict) -> Union[str, Dict]: + final_msg = {} + carryover = context.get("carryover", "") + if isinstance(message, list): + carryover = carryover[-1] + final_msg["content"] = "Write a blogpost." + "\\nContext: \\n" + carryover + final_msg["context"] = {"prefix": "Today I feel"} + return final_msg + ``` **context: any context information. It has the following reserved fields: - "carryover": a string or a list of string to specify the carryover information to be passed to this chat. - If provided, we will combine this carryover (by attaching a "context: "string and the carryover content after the message content) with the "message" content when generating the initial chat + - "carryover": a string or a list of string to specify the carryover information to be passed to this chat. + If provided, we will combine this carryover (by attaching a "context: " string and the carryover content after the message content) with the "message" content when generating the initial chat message in `generate_init_message`. Raises: diff --git a/autogen/version.py b/autogen/version.py index 04d1c7c5310..198d6db6273 100644 --- a/autogen/version.py +++ b/autogen/version.py @@ -1 +1 @@ -__version__ = "0.2.19" +__version__ = "0.2.20" diff --git a/notebook/agentchat_multi_task_async_chats.ipynb b/notebook/agentchat_multi_task_async_chats.ipynb index 901624d80e3..091e5575a64 100644 --- a/notebook/agentchat_multi_task_async_chats.ipynb +++ b/notebook/agentchat_multi_task_async_chats.ipynb @@ -27,7 +27,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -59,7 +59,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -89,7 +89,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -115,7 +115,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -124,10 +124,12 @@ "text": [ "\u001b[34m\n", "********************************************************************************\u001b[0m\n", - "\u001b[34mStart a new chat with the following message: \n", + "\u001b[34mStarting a new chat....\n", + "\n", + "Message:\n", "What are the current stock prices of NVDA and TESLA, and how is the performance over the past month in terms of percentage change?\n", "\n", - "With the following carryover: \n", + "Carryover: \n", "\u001b[0m\n", "\u001b[34m\n", "********************************************************************************\u001b[0m\n", @@ -138,99 +140,82 @@ "--------------------------------------------------------------------------------\n", "\u001b[33mFinancial_assistant\u001b[0m (to User):\n", "\n", - "To fetch live stock data, we can make use of the \"yfinance\" library in Python, which allows us to download stock data from Yahoo Finance.\n", + "To obtain current stock prices of NVDA (NVIDIA Corporation) and TSLA (Tesla, Inc.), and calculate their performance over the past month in terms of percentage change, we can use the Yahoo Finance API through the `yfinance` Python package. This process involves the following steps:\n", "\n", - "Install \"yfinance\" by executing the following Python code:\n", - "\n", - "```python\n", - "!pip install yfinance\n", - "```\n", + "1. Install the `yfinance` package (if not already installed).\n", + "2. Use `yfinance` to fetch the current stock prices of NVDA and TSLA.\n", + "3. Fetch historical data for the past month for both stocks.\n", + "4. Calculate the percentage change in the stock prices over the last month based on the historical data.\n", "\n", - "Then, get the current stock prices and compute the performance over the past month using the following code:\n", + "Please execute the following Python code to perform these tasks:\n", "\n", "```python\n", + "# filename: stock_info.py\n", "import yfinance as yf\n", "from datetime import datetime, timedelta\n", "\n", - "# Define the ticker symbols\n", - "tickers = ['NVDA', 'TSLA']\n", - "\n", - "# Get today's date\n", - "today = datetime.today().strftime('%Y-%m-%d')\n", - "\n", - "# Get the date one month ago\n", - "one_month_ago = (datetime.today() - timedelta(days=30)).strftime('%Y-%m-%d')\n", - "\n", - "# Initialize a dictionary to store the data\n", - "data = {}\n", - "\n", - "# Loop through the ticker symbols\n", - "for ticker in tickers:\n", - " # Get the historical data for the past month\n", - " historical_data = yf.download(ticker, start=one_month_ago, end=today)\n", - "\n", - " # Get the most recent data (today's data)\n", - " today_data = historical_data.tail(1)\n", - "\n", - " # Get the earliest data (one month ago's data)\n", - " one_month_ago_data = historical_data.head(1)\n", - "\n", - " # Calculate the percentage change over the past month\n", - " percentage_change = ((today_data['Close'].iloc[0] - one_month_ago_data['Close'].iloc[0]) / one_month_ago_data['Close'].iloc[0]) * 100\n", + "def stock_performance(ticker):\n", + " # Fetching data for the past month\n", + " end_date = datetime.today()\n", + " start_date = end_date - timedelta(days=30) # Approximate for the past month\n", + " \n", + " # Fetch historical data\n", + " data = yf.download(ticker, start=start_date, end=end_date)\n", + " \n", + " # Current and beginning of month prices\n", + " current_price = data['Close'].iloc[-1]\n", + " start_month_price = data['Close'].iloc[0] \n", + " \n", + " # Calculate percentage change over the month\n", + " percent_change = ((current_price - start_month_price) / start_month_price) * 100\n", + " \n", + " return current_price, percent_change\n", "\n", - " # Store the data in the dictionary\n", - " data[ticker] = {\n", - " 'Current Stock Price': today_data['Close'].iloc[0],\n", - " 'Performance Over Past Month (%)': percentage_change\n", - " }\n", + "# NVDA and TSLA stock performance\n", + "nvda_price, nvda_change = stock_performance(\"NVDA\")\n", + "tsla_price, tsla_change = stock_performance(\"TSLA\")\n", "\n", - "# Print the data\n", - "for ticker, d in data.items():\n", - " print(f\"{ticker}:\")\n", - " print(f\"\\tCurrent Stock Price: ${d['Current Stock Price']:.2f}\")\n", - " print(f\"\\tPerformance Over Past Month (%): {d['Performance Over Past Month (%)']:.2f}%\")\n", + "print(f\"NVDA (NVIDIA Corp) current price: ${nvda_price:.2f}, Performance over past month: {nvda_change:.2f}%\")\n", + "print(f\"TSLA (Tesla, Inc.) current price: ${tsla_price:.2f}, Performance over past month: {tsla_change:.2f}%\")\n", "```\n", "\n", - "This Python script retrieves the historical data for the past month for each ticker symbol, calculates the percentage change in stock price over the past month, and prints out the current stock price and the performance over the past month.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[31m\n", - ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n", - "\u001b[33mUser\u001b[0m (to Financial_assistant):\n", - "\n", - "exitcode: 1 (execution failed)\n", - "Code output: \n", - " File \"\", line 1\n", - " !pip install yfinance\n", - " ^\n", - "SyntaxError: invalid syntax\n", - "\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mFinancial_assistant\u001b[0m (to User):\n", - "\n", - "I apologize for the confusion. The \"!\" character is special syntax for Jupyter notebooks. If you are not using a Jupyter notebook for Python execution, the syntax will be invalid. Please replace \"!\" with the proper syntax to install a Python package. \n", - "\n", - "If you're running the code directly in a Python environment, you might need to install yfinance using pip from your shell/command line. Here's the correct command:\n", + "Before running this script, ensure that you have the `yfinance` package installed. If not, install it using the following command:\n", "\n", "```sh\n", "pip install yfinance\n", "```\n", "\n", - "After you've installed the package, you can proceed with the Python code block provided previously to fetch the data.\n", - "\n", - "Sorry for the misunderstanding, and thank you for pointing it out.\n", + "This script will output the current stock prices of NVDA and TSLA, along with their performance over the past month in percentage terms.\n", "\n", "--------------------------------------------------------------------------------\n", "\u001b[31m\n", - ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is sh)...\u001b[0m\n", + ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/workspaces/autogen/autogen/agentchat/chat.py:42: UserWarning: Repetitive recipients detected: The chat history will be cleared by default if a recipient appears more than once. To retain the chat history, please set 'clear_history=False' in the configuration of the repeating agent.\n", + " warnings.warn(\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[31m\n", + ">>>>>>>> EXECUTING CODE BLOCK 1 (inferred language is sh)...\u001b[0m\n", "\u001b[33mUser\u001b[0m (to Financial_assistant):\n", "\n", "exitcode: 0 (execution succeeded)\n", "Code output: \n", + "NVDA (NVIDIA Corp) current price: $878.37, Performance over past month: 20.97%\n", + "TSLA (Tesla, Inc.) current price: $163.57, Performance over past month: -18.19%\n", + "\n", "Defaulting to user installation because normal site-packages is not writeable\n", - "Requirement already satisfied: yfinance in /home/autogen/.local/lib/python3.11/site-packages (0.2.36)\n", - "Requirement already satisfied: pandas>=1.3.0 in /home/autogen/.local/lib/python3.11/site-packages (from yfinance) (2.2.0)\n", + "Requirement already satisfied: yfinance in /home/autogen/.local/lib/python3.11/site-packages (0.2.37)\n", + "Requirement already satisfied: pandas>=1.3.0 in /home/autogen/.local/lib/python3.11/site-packages (from yfinance) (2.2.1)\n", "Requirement already satisfied: numpy>=1.16.5 in /usr/local/lib/python3.11/site-packages (from yfinance) (1.26.4)\n", "Requirement already satisfied: requests>=2.31 in /usr/local/lib/python3.11/site-packages (from yfinance) (2.31.0)\n", "Requirement already satisfied: multitasking>=0.0.7 in /home/autogen/.local/lib/python3.11/site-packages (from yfinance) (0.0.11)\n", @@ -244,171 +229,108 @@ "Requirement already satisfied: soupsieve>1.2 in /usr/local/lib/python3.11/site-packages (from beautifulsoup4>=4.11.1->yfinance) (2.5)\n", "Requirement already satisfied: six>=1.9 in /usr/local/lib/python3.11/site-packages (from html5lib>=1.1->yfinance) (1.16.0)\n", "Requirement already satisfied: webencodings in /usr/local/lib/python3.11/site-packages (from html5lib>=1.1->yfinance) (0.5.1)\n", - "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.11/site-packages (from pandas>=1.3.0->yfinance) (2.8.2)\n", + "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.11/site-packages (from pandas>=1.3.0->yfinance) (2.9.0.post0)\n", "Requirement already satisfied: tzdata>=2022.7 in /home/autogen/.local/lib/python3.11/site-packages (from pandas>=1.3.0->yfinance) (2024.1)\n", "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.11/site-packages (from requests>=2.31->yfinance) (3.3.2)\n", "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.11/site-packages (from requests>=2.31->yfinance) (3.6)\n", - "Requirement already satisfied: urllib3<3,>=1.21.1 in /home/autogen/.local/lib/python3.11/site-packages (from requests>=2.31->yfinance) (1.26.18)\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.11/site-packages (from requests>=2.31->yfinance) (2.2.1)\n", "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.11/site-packages (from requests>=2.31->yfinance) (2024.2.2)\n", "\n", "\n", "--------------------------------------------------------------------------------\n", "\u001b[33mFinancial_assistant\u001b[0m (to User):\n", "\n", - "Great! Now that the yfinance package is properly installed, we can proceed to fetch the data.\n", + "The code execution was successful, and here are the results based on the output:\n", "\n", - "Please execute the Python code as shown below:\n", - "\n", - "```python\n", - "import yfinance as yf\n", - "from datetime import datetime, timedelta\n", - "\n", - "# Define the ticker symbols\n", - "tickers = ['NVDA', 'TSLA']\n", - "\n", - "# Get today's date\n", - "today = datetime.today().strftime('%Y-%m-%d')\n", - "\n", - "# Get the date one month ago\n", - "one_month_ago = (datetime.today() - timedelta(days=30)).strftime('%Y-%m-%d')\n", - "\n", - "# Initialize a dictionary to store the data\n", - "data = {}\n", - "\n", - "# Loop through the ticker symbols\n", - "for ticker in tickers:\n", - " # Get the historical data for the past month\n", - " historical_data = yf.download(ticker, start=one_month_ago, end=today)\n", - "\n", - " # Get the most recent data (today's data)\n", - " today_data = historical_data.tail(1)\n", - "\n", - " # Get the earliest data (one month ago's data)\n", - " one_month_ago_data = historical_data.head(1)\n", - "\n", - " # Calculate the percentage change over the past month\n", - " percentage_change = ((today_data['Close'].iloc[0] - one_month_ago_data['Close'].iloc[0]) / one_month_ago_data['Close'].iloc[0]) * 100\n", - "\n", - " # Store the data in the dictionary\n", - " data[ticker] = {\n", - " 'Current Stock Price': today_data['Close'].iloc[0],\n", - " 'Performance Over Past Month (%)': percentage_change\n", - " }\n", - "\n", - "# Print the data\n", - "for ticker, d in data.items():\n", - " print(f\"{ticker}:\")\n", - " print(f\"\\tCurrent Stock Price: ${d['Current Stock Price']:.2f}\")\n", - " print(f\"\\tPerformance Over Past Month (%): {d['Performance Over Past Month (%)']:.2f}%\")\n", - "```\n", - "\n", - "This script fetches the current stock prices for NVDA and TSLA and the performance over the past one month in terms of percentage change.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[31m\n", - ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n", - "\u001b[33mUser\u001b[0m (to Financial_assistant):\n", - "\n", - "exitcode: 0 (execution succeeded)\n", - "Code output: \n", - "NVDA:\n", - "\tCurrent Stock Price: $726.13\n", - "\tPerformance Over Past Month (%): 21.72%\n", - "TSLA:\n", - "\tCurrent Stock Price: $199.95\n", - "\tPerformance Over Past Month (%): -4.24%\n", + "- **NVIDIA Corporation (NVDA)** has a current stock price of **$878.37**. Over the past month, NVDA has experienced a performance increase of **20.97%**.\n", + "- **Tesla, Inc. (TSLA)** has a current stock price of **$163.57**. Over the past month, TSLA has experienced a performance decrease of **-18.19%**.\n", "\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mFinancial_assistant\u001b[0m (to User):\n", - "\n", - "Great! Here are the results:\n", - "\n", - "- NVDA: \n", - " - Current Stock Price: $726.13\n", - " - Performance Over Past Month (%): 21.72%\n", - "\n", - "- TSLA:\n", - " - Current Stock Price: $199.95\n", - " - Performance Over Past Month (%): -4.24%\n", - "\n", - "Over the past month, the stock price of NVDA increased by 21.72%, while the stock price of TSLA decreased by 4.24%.\n", - " \n", - "Please note that stock prices are subject to market changes and the output values from when you ran this script.\n", - "\n", - "If you have any other tasks or need further assistance, please feel free to ask. \n", + "These figures provide a snapshot of how both companies have performed in the stock market over the last month, reflecting growth for NVIDIA and a decline for Tesla.\n", "\n", "TERMINATE\n", "\n", "--------------------------------------------------------------------------------\n", "\u001b[34m\n", "********************************************************************************\u001b[0m\n", - "\u001b[34mStart a new chat with the following message: \n", + "\u001b[34mStarting a new chat....\n", + "\n", + "Message:\n", "Investigate possible reasons of the stock performance.\n", "\n", - "With the following carryover: \n", - "The NVDA current stock price is $726.13, and the percentage change over the past month is an increase of 21.72%. The TSLA current stock price is $199.95, with a decrease of 4.24% over the past month.\u001b[0m\n", + "Carryover: \n", + "NVIDIA Corporation (NVDA) experienced a stock price increase of 20.97% over the past month, with a current price of $878.37. Tesla, Inc. (TSLA) saw a decrease of 18.19% in the same period, with its current stock price at $163.57.\u001b[0m\n", "\u001b[34m\n", "********************************************************************************\u001b[0m\n", - "\u001b[31m\n", - ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is Shell)...\u001b[0m\n", - "\u001b[31m\n", - ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n", "\u001b[34m\n", "********************************************************************************\u001b[0m\n", - "\u001b[34mStart a new chat with the following message: \n", + "\u001b[34mStarting a new chat....\n", + "\n", + "Message:\n", "Plot a graph comparing the stock prices over the past month.\n", "\n", - "With the following carryover: \n", - "The NVDA current stock price is $726.13, and the percentage change over the past month is an increase of 21.72%. The TSLA current stock price is $199.95, with a decrease of 4.24% over the past month.\u001b[0m\n", + "Carryover: \n", + "NVIDIA Corporation (NVDA) experienced a stock price increase of 20.97% over the past month, with a current price of $878.37. Tesla, Inc. (TSLA) saw a decrease of 18.19% in the same period, with its current stock price at $163.57.\u001b[0m\n", "\u001b[34m\n", "********************************************************************************\u001b[0m\n", + "\u001b[33mUser\u001b[0m (to Researcher):\n", + "\n", + "Investigate possible reasons of the stock performance.\n", + "Context: \n", + "NVIDIA Corporation (NVDA) experienced a stock price increase of 20.97% over the past month, with a current price of $878.37. Tesla, Inc. (TSLA) saw a decrease of 18.19% in the same period, with its current stock price at $163.57.\n", + "\n", + "--------------------------------------------------------------------------------\n", "\u001b[33mUser\u001b[0m (to Financial_assistant):\n", "\n", "Plot a graph comparing the stock prices over the past month.\n", "Context: \n", - "The NVDA current stock price is $726.13, and the percentage change over the past month is an increase of 21.72%. The TSLA current stock price is $199.95, with a decrease of 4.24% over the past month.\n", + "NVIDIA Corporation (NVDA) experienced a stock price increase of 20.97% over the past month, with a current price of $878.37. Tesla, Inc. (TSLA) saw a decrease of 18.19% in the same period, with its current stock price at $163.57.\n", "\n", "--------------------------------------------------------------------------------\n", "\u001b[33mFinancial_assistant\u001b[0m (to User):\n", "\n", - "To complete this task, we need historical stock price data for NVDA and TSLA for the past month. However, as I cannot browse the web or fetch live data directly, let's simulate this by inferring the past month's data based on the provided information.\n", + "To compare the stock prices of NVIDIA Corporation (NVDA) and Tesla, Inc. (TSLA) over the past month, we can calculate their stock prices over this period based on the provided current prices and their percentage changes. Then, we can plot these calculated prices on a graph to visually compare the trends. \n", "\n", - "We have the current stock price and the percentage change for NVDA and TSLA over the past month. We can calculate the stock price one month ago by reversing the percentage change calculation. \n", + "Let's proceed as follows:\n", "\n", - "Let's also assume for the sake of this task that the stock prices changed linearly over the past month. In reality, stock prices fluctuate daily, so the graph would be more complex, but we can't recreate those fluctuations with just two data points. \n", + "1. Calculate the stock price 30 days ago for both companies based on the current price and the given percentage change.\n", + "2. Generate a list of stock prices from 30 days ago to the current date for both companies, assuming a linear trend for simplicity. \n", + "3. Plot these lists against the dates of the past month.\n", "\n", - "We can use the `matplotlib` library in Python to plot this data. Please execute the following Python code:\n", + "I'll start by calculating the stock price 30 days ago for both companies and generating the lists of stock prices. \n", "\n", "```python\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "\n", - "# Current prices and percentage changes\n", - "NVDA_current_price = 726.13\n", - "NVDA_change_pct = 21.72\n", - "TSLA_current_price = 199.95\n", - "TSLA_change_pct = -4.24\n", + "# Constants\n", + "current_price_nvda = 878.37\n", + "change_percent_nvda = 20.97\n", + "current_price_tsla = 163.57\n", + "change_percent_tsla = -18.19\n", "\n", - "# Calculate prices one month ago\n", - "NVDA_price_month_ago = NVDA_current_price / (1 + NVDA_change_pct/100)\n", - "TSLA_price_month_ago = TSLA_current_price / (1 - TSLA_change_pct/100)\n", + "# Calculate the price 30 days ago based on the current price and percentage change\n", + "price_30_days_ago_nvda = current_price_nvda / (1 + change_percent_nvda / 100)\n", + "price_30_days_ago_tsla = current_price_tsla / (1 + change_percent_tsla / 100)\n", "\n", - "# Create arrays for plotting\n", - "dates = np.array(['One month ago', 'Today'])\n", - "NVDA_prices = np.array([NVDA_price_month_ago, NVDA_current_price])\n", - "TSLA_prices = np.array([TSLA_price_month_ago, TSLA_current_price])\n", + "# Generate the dates and stock prices for the past 30 days\n", + "dates = np.arange(-29, 1, 1) # Day -29 to 0, representing the past 30 days\n", + "prices_nvda = np.linspace(price_30_days_ago_nvda, current_price_nvda, 30)\n", + "prices_tsla = np.linspace(price_30_days_ago_tsla, current_price_tsla, 30)\n", "\n", "# Plotting\n", - "plt.plot(dates, NVDA_prices, label='NVDA')\n", - "plt.plot(dates, TSLA_prices, label='TSLA')\n", + "plt.figure(figsize=(10, 6))\n", + "plt.plot(dates, prices_nvda, label=\"NVIDIA (NVDA)\")\n", + "plt.plot(dates, prices_tsla, label=\"Tesla (TSLA)\")\n", + "\n", + "plt.title(\"Stock Price Comparison Over the Past Month\")\n", + "plt.xlabel(\"Days Ago\")\n", + "plt.ylabel(\"Price ($)\")\n", "plt.legend()\n", - "plt.ylabel('Stock price')\n", - "plt.title('Stock prices over the past month')\n", + "plt.grid(True)\n", "plt.show()\n", "```\n", "\n", - "This script plots the \"past\" and current stock prices for NVDA and TSLA. It creates a line graph with the date on the x-axis and the stock price on the y-axis. It also adds a title to the graph and a legend indicating which line corresponds to which stock.\n", + "This code snippet calculates the stock prices for NVDA and TSLA 30 days ago using the provided current prices and percentage changes. It then generates a linear progression of prices over the last month and plots the comparison. Execute this Python script to view the comparison graph.\n", "\n", "--------------------------------------------------------------------------------\n", "\u001b[31m\n", @@ -417,64 +339,152 @@ "\n", "exitcode: 0 (execution succeeded)\n", "Code output: \n", - "Figure(640x480)\n", + "Figure(1000x600)\n", + "\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mResearcher\u001b[0m (to User):\n", + "\n", + "To investigate the possible reasons for the stock performance of NVIDIA Corporation (NVDA) and Tesla, Inc. (TSLA), we can follow these steps:\n", + "\n", + "1. **Market Trends and News:** Look for any recent news or market trends related to NVIDIA and Tesla. This could include product launches, earnings reports, significant partnerships, or changes in the global market that might influence these companies differently.\n", + "2. **Industry Impact:** Assess how changes in the technology and automotive industries might have differently affected NVIDIA and Tesla. For NVIDIA, advancements or demands in gaming, data centers, and AI could play a role, while for Tesla, factors could include electric vehicle (EV) market dynamics, production issues, or regulatory changes.\n", + "3. **Financial Performance:** Analyze recent financial performance reports from both companies to see if there are any indicators of why their stock prices have moved in such opposite directions.\n", + "4. **Investor Sentiment:** Investigate the overall investor sentiment towards these companies. This could involve looking at analyst ratings, investor forums, or news commentary.\n", + "5. **External Factors:** Consider any external factors that might have had an impact, like changes in trade policies, geopolitical tensions, or significant shifts in consumer behavior due to global events.\n", + "\n", + "As we would need real-time data and specific detailed analyses which are best done through current financial news articles, market analyses, and company reports to proceed accurately, I can provide an example code snippet to fetch recent news regarding NVIDIA and Tesla from the web using Python. This might help identify some potential reasons for their stock performance based on recent events.\n", + "\n", + "```python\n", + "# filename: fetch_news.py\n", + "import requests\n", + "from bs4 import BeautifulSoup\n", + "\n", + "def fetch_news(stock_name):\n", + " search_query = stock_name + ' stock news'\n", + " url = f\"https://www.google.com/search?q={search_query.replace(' ', '+')}&tbm=nws\"\n", + " headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'}\n", + " response = requests.get(url, headers=headers)\n", + " soup = BeautifulSoup(response.text, 'html.parser')\n", + "\n", + " for item in soup.find_all('div', attrs={'class': 'dbsr'}):\n", + " title = item.find('div', attrs={'class': 'JheGif nDgy9d'}).text\n", + " source_and_time = item.find('div', attrs={'class': 'SVJrMe'}).text\n", + " link = item.a['href']\n", + " print(f'Title: {title}\\nSource and Time: {source_and_time}\\nLink: {link}\\n')\n", + "\n", + "# Fetch news for NVIDIA\n", + "print('NVIDIA News:')\n", + "fetch_news('NVIDIA')\n", + "\n", + "# Fetch news for Tesla\n", + "print('\\nTesla News:')\n", + "fetch_news('Tesla')\n", + "```\n", + "\n", + "Please run the above Python script. It will scrape Google News for recent articles related to NVIDIA and Tesla, which might provide insights into the reasons behind their recent stock performances. Note, however, that web scraping Google might violate their terms of service and the effectiveness of the script could vary over time due to changes in the Google News page structure. This script is provided for educational purposes to demonstrate a technique for gathering information.\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n", + "\u001b[33mUser\u001b[0m (to Researcher):\n", + "\n", + "exitcode: 0 (execution succeeded)\n", + "Code output: \n", + "NVIDIA News:\n", + "\n", + "Tesla News:\n", "\n", "\n", "--------------------------------------------------------------------------------\n", "\u001b[33mFinancial_assistant\u001b[0m (to User):\n", "\n", - "Great! The code ran successfully. The `Figure(640x480)` statement denotes the size of the displayed figure, but it's not the actual graph. \n", + "The execution of the code was successful, and it generated a plot comparing the stock prices of NVIDIA Corporation (NVDA) and Tesla, Inc. (TSLA) over the past month. The plot should visually depict NVIDIA's stock price increase and Tesla's decrease during this period, based on the linear assumptions we made for simplicity.\n", + "\n", + "Since the plot has been generated as expected, you should now have a visual representation showing how NVDA's stock price trended upwards over the past month, while TSLA's stock price trended downwards. This comparison could provide insights into the overall performance and market sentiment towards these two companies during the last month.\n", + "\n", + "If you have any more requests or need further analysis, feel free to ask!\n", + "\n", + "TERMINATE\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mResearcher\u001b[0m (to User):\n", + "\n", + "It appears that the provided script didn't fetch the news as expected. This limitation might be due to changes in the website structure, anti-scraping measures, or the fact that extracting information from Google's search results can be particularly challenging due to their dynamic nature and terms of service.\n", "\n", - "In a typical interactive Python environment, the `plt.show()` function directly displays the plot. Since the execution environment here may not support interactive display of the graph, you're not seeing the graph as an output. \n", + "Given this, I recommend using alternative methods to investigate the reasons behind NVIDIA's and Tesla's recent stock performance. These can include:\n", "\n", - "You'd usually see a line chart with two lines, one for NVDA and one for TSLA, indicating their price change from one month ago to today.\n", + "1. **Checking Financial News Websites:** Websites like Bloomberg, CNBC, and Reuters often provide up-to-date news and analysis on companies and their stock performances. \n", + "2. **Official Company Press Releases:** Both NVIDIA's and Tesla's official websites have press release sections, where they publish news that could significantly impact their stock prices, such as earnings reports, product launches, or strategic partnerships.\n", + "3. **Financial Analysis Platforms:** Platforms like Yahoo Finance, Google Finance, and Seeking Alpha offer news, financial data, and analyses which can provide insights into recent stock performance.\n", + "4. **Social Media and Forums:** Financial communities on platforms like Twitter, Reddit (especially the r/investing subreddit), and StockTwits can sometimes provide real-time insights and sentiments that might be influencing stock prices.\n", "\n", - "Sorry for the inconvenience caused by the visualization constraints of the current interaction mode. You can try running the exact same code in an interactive Python environment like Jupyter Notebook or Google Colab, and you would be able to see the graph.\n", + "Without specific recent news or data obtained directly from such sources, it's difficult to pinpoint the exact reasons for NVIDIA's and Tesla's recent stock performance. However, based on the context provided:\n", "\n", - "I hope you found my assistance helpful in understanding the logic and code to plot the stock prices of NVDA and TSLA. If you have any further questions or tasks, feel free to ask. \n", + "- **NVIDIA's Increase:** The increase in NVIDIA's stock price could be linked to heightened demand for its GPUs amid trends such as gaming, data center expansion, and AI development. NVIDIA is deeply involved in these rapidly growing sectors, and any positive news or indicators related to them could significantly impact its stock.\n", + " \n", + "- **Tesla's Decrease:** Tesla's decline might be influenced by a variety of factors, from production challenges, competition in the electric vehicle industry increasing, potential regulatory challenges, or even Elon Musk's public statements affecting investor sentiment. Tesla's performance is also highly scrutinized, so broader market trends or operational hiccups can have a pronounced effect on its stock price.\n", + "\n", + "To get the most accurate picture, I recommend visiting the suggested financial news websites and platforms directly to gather the latest insights and analyses on NVIDIA and Tesla. This will provide a more comprehensive understanding of their stock performance drivers.\n", "\n", "TERMINATE\n", "\n", "--------------------------------------------------------------------------------\n", "\u001b[34m\n", "********************************************************************************\u001b[0m\n", - "\u001b[34mStart a new chat with the following message: \n", + "\u001b[34mStarting a new chat....\n", + "\n", + "Message:\n", "Develop an engaging blog post using any information provided.\n", "\n", - "With the following carryover: \n", - "The NVDA current stock price is $726.13, and the percentage change over the past month is an increase of 21.72%. The TSLA current stock price is $199.95, with a decrease of 4.24% over the past month.\n", - "There's been a recent increase in NVDA's stock performance and a decrease in TSLA's. The AI provided a script that fetches news headlines about these stocks to understand their performance. Based on the fetched headlines, some factors driving NVDA's stock increase could include imminent earnings reports and a debate about the company's value. The decrease in TSLA stock price could potentially be linked to uncertainties or confusions about its valuation. However, these interpretations are based only on a limited number of news headlines, and other recent events not covered by these headlines could also be influencing the stocks' performance.\n", - "The assistant provided a detailed way to create a mock graph comparing the stock prices of NVDA and TSLA over the past month, given the current prices and percentage changes. However, due to the assistant's inability to browse the web or fetch live data, and the current platform's inability to display plots, the final graph couldn't be shown. The assistant suggested running the provided Python code in an interactive Python environment like Jupyter Notebook or Google Colab to visualize the graph properly.\u001b[0m\n", + "Carryover: \n", + "NVIDIA Corporation (NVDA) experienced a stock price increase of 20.97% over the past month, with a current price of $878.37. Tesla, Inc. (TSLA) saw a decrease of 18.19% in the same period, with its current stock price at $163.57.\n", + "Investigating the reasons behind the stock performance of NVIDIA Corporation and Tesla, Inc. requires analyzing recent news, market trends, financial performance, investor sentiment, and industry impacts. For NVIDIA, increased stock prices may relate to demand for GPUs, advances in gaming, data centers, and AI development. Tesla's stock decrease could stem from production challenges, rising competition, regulatory issues, or public statements by its CEO affecting investor sentiment. Direct analysis using financial news websites, company press releases, financial analysis platforms, and social media can provide insights into their stock performance. The provided Python script intended to fetch news did not work as expected, underscoring the importance of using alternative, direct methods for obtaining current information from reliable financial news sources.\n", + "NVIDIA Corporation (NVDA) experienced a 20.97% increase in its stock price over the past month, with the current price at $878.37. In contrast, Tesla, Inc. (TSLA) saw an 18.19% decrease in the same period, with its current stock price at $163.57. A plotted comparison based on these percentages and current prices, assuming a linear trend for simplicity, would visually depict NVIDIA's stock price trending upwards and Tesla's trending downwards over the last month.\u001b[0m\n", "\u001b[34m\n", "********************************************************************************\u001b[0m\n", "\u001b[33mUser\u001b[0m (to writer):\n", "\n", "Develop an engaging blog post using any information provided.\n", "Context: \n", - "The NVDA current stock price is $726.13, and the percentage change over the past month is an increase of 21.72%. The TSLA current stock price is $199.95, with a decrease of 4.24% over the past month.\n", - "There's been a recent increase in NVDA's stock performance and a decrease in TSLA's. The AI provided a script that fetches news headlines about these stocks to understand their performance. Based on the fetched headlines, some factors driving NVDA's stock increase could include imminent earnings reports and a debate about the company's value. The decrease in TSLA stock price could potentially be linked to uncertainties or confusions about its valuation. However, these interpretations are based only on a limited number of news headlines, and other recent events not covered by these headlines could also be influencing the stocks' performance.\n", - "The assistant provided a detailed way to create a mock graph comparing the stock prices of NVDA and TSLA over the past month, given the current prices and percentage changes. However, due to the assistant's inability to browse the web or fetch live data, and the current platform's inability to display plots, the final graph couldn't be shown. The assistant suggested running the provided Python code in an interactive Python environment like Jupyter Notebook or Google Colab to visualize the graph properly.\n", + "NVIDIA Corporation (NVDA) experienced a stock price increase of 20.97% over the past month, with a current price of $878.37. Tesla, Inc. (TSLA) saw a decrease of 18.19% in the same period, with its current stock price at $163.57.\n", + "Investigating the reasons behind the stock performance of NVIDIA Corporation and Tesla, Inc. requires analyzing recent news, market trends, financial performance, investor sentiment, and industry impacts. For NVIDIA, increased stock prices may relate to demand for GPUs, advances in gaming, data centers, and AI development. Tesla's stock decrease could stem from production challenges, rising competition, regulatory issues, or public statements by its CEO affecting investor sentiment. Direct analysis using financial news websites, company press releases, financial analysis platforms, and social media can provide insights into their stock performance. The provided Python script intended to fetch news did not work as expected, underscoring the importance of using alternative, direct methods for obtaining current information from reliable financial news sources.\n", + "NVIDIA Corporation (NVDA) experienced a 20.97% increase in its stock price over the past month, with the current price at $878.37. In contrast, Tesla, Inc. (TSLA) saw an 18.19% decrease in the same period, with its current stock price at $163.57. A plotted comparison based on these percentages and current prices, assuming a linear trend for simplicity, would visually depict NVIDIA's stock price trending upwards and Tesla's trending downwards over the last month.\n", "\n", "--------------------------------------------------------------------------------\n", "\u001b[33mwriter\u001b[0m (to User):\n", "\n", - "Title: Navigating the Highs and Lows: A Tale of Two Stocks- NVDA and TSLA\n", + "### The Stock Market Tales of NVIDIA and Tesla: A Comparative Analysis\n", + "\n", + "In the ever-oscillating world of the stock market, where fortunes can be made or lost in the blink of an eye, the recent performances of NVIDIA Corporation (NVDA) and Tesla, Inc. (TSLA) stand out, painting two very different pictures. Over the past month, NVIDIA witnessed an awe-inspiring surge of 20.97% in its stock price, reaching a towering $878.37. Meanwhile, Tesla faced a starkly contrasting fate, with its stock price tumbling down 18.19% to $163.57. But what underlying currents steered these two tech giants in such divergent directions? Let's delve deeper into the whirlpool of market dynamics, technological advancements, and investor sentiment to uncover the story behind these movements.\n", "\n", - "If you've been tracking the stock market recently, you might have noticed some significant activity involving two household names. These tech juggernauts- NVIDIA Corp (NVDA) and Tesla Inc (TSLA), have experienced significantly contrasting fortunes over the past month. \n", + "#### NVIDIA's Stellar Ascent\n", "\n", - "As of now, the NVDA stock price stands at a lofty $726.13, soaring an astonishing 21.72% in the past month. TSLA, however, has had a bumpier ride, with the current price of $199.95 reflecting a 4.24% decrease during the same period. \n", + "NVIDIA, a titan in the realms of graphics processing units (GPUs), artificial intelligence (AI), and data centers, has been on a meteoric rise. The company's stock surge can largely be attributed to the burgeoning demand for GPUs, indispensable not only in gaming but also in a plethora of applications from advanced computing tasks to mining cryptocurrencies. This demand spike has catapulted NVIDIA into a favorable position in the stock market.\n", "\n", - "What's driving the surging ascent of NVDA and the faltering trajectory of TSLA, you might ask? Well, sometimes the answers can be found in the daily news cycle.\n", + "Moreover, NVIDIA's forays into AI development and data centers have underpinned its financial fortitude. As businesses and institutions increasingly leverage AI for efficiency and innovation, NVIDIA's cutting-edge technologies stand at the forefront, driving its stock prices to new heights.\n", "\n", - "According to news headlines fetched by our AI assistant, NVDA's recent skyrocket can potentially be linked to events like imminent earnings reports and a burgeoning debate around the company's value. These factors have managed to cast a positive light on the company. Investors may perceive them as indicators of a prospective growth, triggering increased stock purchases. \n", + "#### Tesla's Turbulent Tide\n", "\n", - "Yet, every coin has two sides. For TSLA, recent news may have spread more confusion and uncertainty than confidence. Headlines pointing to ambiguities about the company's valuation have clouded its fiscal outlook, leading to a softening of the stock price. \n", + "Tesla, Inc., on the other hand, has navigated through rough waters. Known for revolutionizing the electric vehicle (EV) industry, Tesla has recently grappled with a gamut of challenges. Production snags, possibly accentuated by global supply chain disruptions, have hindered Tesla's ability to meet its ambitious production targets. Furthermore, the EV sphere is no longer Tesla's sole dominion; rising competition has emerged as a formidable force, with legacy automakers and new entrants alike vying for a piece of the EV pie.\n", "\n", - "Before attaching too much weight to these possibilities, it's essential to highlight that news headlines offers just a fraction of the full picture. The market's pulse is influenced by a plethora of factors, with many taking place behind headlines. Hence, while headlines undeniably play a role in influencing stock performance, they should be only part of any comprehensive market analysis.\n", + "Regulatory woes and occasional controversial public statements by its charismatic yet polarizing CEO, Elon Musk, have also played a role in swaying investor sentiment, contributing to the stock's decline. These factors combined sketch the backdrop against which Tesla's stock has weathered a downturn.\n", "\n", - "To provide a deeper understanding of these stock trajectories, our AI helper put forth a detailed method to mock up a comparative graph of NVDA and TSLA prices over the past month. However, our current environment lacks the capability for web browsing or live data fetching, so the visualization isn’t available in this post. For those keen to see the graphical view, we recommend inputting the provided Python code into an interactive Python environment like Jupyter Notebook or Google Colab.\n", + "#### The Tale of Two Graphs\n", "\n", - "Whether you're an experienced trader or a budding market enthusiast, understanding the forces moving major stocks like NVDA and TSLA can give you valuable insight into the tech industry's overall health and future direction. So, keep those news alerts on, keep questioning, and keep connecting the dots.\n", + "Visualizing the stock performance of NVIDIA and Tesla over the last month through a simple linear graph vividly elucidates their trajectories — NVIDIA's stock price ascends skyward, while Tesla's takes a steep downturn. This visual comparison starkly captures the fortunes and misfortunes unfolding in the high-stakes world of the stock market.\n", + "\n", + "#### Looking Beyond the Horizon\n", + "\n", + "The stock market is a reflection of myriad factors — technological innovation, market demand, competitive landscape, and investor perception. NVIDIA's ascendancy underscores the growing clout of AI and data centers, heralding an era where these technologies shape market dynamics. Tesla's struggles, meanwhile, highlight the hurdles of scaling production amidst stiffening competition and regulatory scrutiny.\n", + "\n", + "As investors and market aficionados peer into the crystal ball, seeking to divine the future paths of NVIDIA and Tesla, they are reminded of the market's inherent unpredictability. What's certain, though, is that the stories of NVIDIA and Tesla — each fascinating in its own right — will continue to captivate and instruct, offering valuable lessons in resilience, innovation, and the ever-persistent pursuit of progress.\n", + "\n", + "### Conclusion\n", + "\n", + "The contrasting destinies of NVIDIA and Tesla in the stock market serve as a compelling narrative of triumph and tribulation. While NVIDIA rides the wave of technological advancement to new heights, Tesla navigates a challenging course, underlining the complexities of sustaining growth amidst evolving market dynamics. As their stories continue to unfold, both NVIDIA and Tesla offer invaluable insights into the intricate dance of innovation, investment, and influence in shaping the future of technology and industry.\n", + "\n", + "---\n", "\n", "TERMINATE\n", "\n", @@ -508,7 +518,7 @@ " \"prerequisites\": [1],\n", " \"recipient\": research_assistant,\n", " \"message\": financial_tasks[1],\n", - " \"silent\": True,\n", + " \"silent\": False,\n", " \"summary_method\": \"reflection_with_llm\",\n", " },\n", " {\n", @@ -519,7 +529,7 @@ " \"silent\": False,\n", " \"summary_method\": \"reflection_with_llm\",\n", " },\n", - " {\"chat_id\": 4, \"prerequisites\": [1, 2, 3], \"recipient\": writer, \"message\": writing_tasks[0]},\n", + " {\"chat_id\": 4, \"prerequisites\": [1, 2, 3], \"recipient\": writer, \"silent\": False, \"message\": writing_tasks[0]},\n", " ]\n", ")" ] @@ -539,7 +549,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -547,48 +557,62 @@ "output_type": "stream", "text": [ "*****1th chat*******:\n", - "The NVDA current stock price is $726.13, and the percentage change over the past month is an increase of 21.72%. The TSLA current stock price is $199.95, with a decrease of 4.24% over the past month.\n", + "NVIDIA Corporation (NVDA) experienced a stock price increase of 20.97% over the past month, with a current price of $878.37. Tesla, Inc. (TSLA) saw a decrease of 18.19% in the same period, with its current stock price at $163.57.\n", "Human input in the middle: []\n", - "Conversation cost: ({'total_cost': 0.9493499999999998, 'gpt-4-0613': {'cost': 0.9493499999999998, 'prompt_tokens': 22291, 'completion_tokens': 4677, 'total_tokens': 26968}}, {'total_cost': 0.26868, 'gpt-4-0613': {'cost': 0.26868, 'prompt_tokens': 5408, 'completion_tokens': 1774, 'total_tokens': 7182}})\n", + "Conversation cost: ({'total_cost': 0.060149999999999995, 'gpt-4-0125-preview': {'cost': 0.060149999999999995, 'prompt_tokens': 3963, 'completion_tokens': 684, 'total_tokens': 4647}}, {'total_cost': 0.04074, 'gpt-4-0125-preview': {'cost': 0.04074, 'prompt_tokens': 3462, 'completion_tokens': 204, 'total_tokens': 3666}})\n", "\n", "\n", "\n", "*****2th chat*******:\n", - "There's been a recent increase in NVDA's stock performance and a decrease in TSLA's. The AI provided a script that fetches news headlines about these stocks to understand their performance. Based on the fetched headlines, some factors driving NVDA's stock increase could include imminent earnings reports and a debate about the company's value. The decrease in TSLA stock price could potentially be linked to uncertainties or confusions about its valuation. However, these interpretations are based only on a limited number of news headlines, and other recent events not covered by these headlines could also be influencing the stocks' performance.\n", + "Investigating the reasons behind the stock performance of NVIDIA Corporation and Tesla, Inc. requires analyzing recent news, market trends, financial performance, investor sentiment, and industry impacts. For NVIDIA, increased stock prices may relate to demand for GPUs, advances in gaming, data centers, and AI development. Tesla's stock decrease could stem from production challenges, rising competition, regulatory issues, or public statements by its CEO affecting investor sentiment. Direct analysis using financial news websites, company press releases, financial analysis platforms, and social media can provide insights into their stock performance. The provided Python script intended to fetch news did not work as expected, underscoring the importance of using alternative, direct methods for obtaining current information from reliable financial news sources.\n", "Human input in the middle: []\n", - "Conversation cost: ({'total_cost': 0.58845, 'gpt-4-0613': {'cost': 0.58845, 'prompt_tokens': 12177, 'completion_tokens': 3719, 'total_tokens': 15896}}, {'total_cost': 0.36668999999999996, 'gpt-4-0613': {'cost': 0.36668999999999996, 'prompt_tokens': 8801, 'completion_tokens': 1711, 'total_tokens': 10512}})\n", + "Conversation cost: ({'total_cost': 0.06911, 'gpt-4-0125-preview': {'cost': 0.06911, 'prompt_tokens': 3074, 'completion_tokens': 1279, 'total_tokens': 4353}}, {'total_cost': 0.06911, 'gpt-4-0125-preview': {'cost': 0.06911, 'prompt_tokens': 3074, 'completion_tokens': 1279, 'total_tokens': 4353}})\n", "\n", "\n", "\n", "*****3th chat*******:\n", - "The assistant provided a detailed way to create a mock graph comparing the stock prices of NVDA and TSLA over the past month, given the current prices and percentage changes. However, due to the assistant's inability to browse the web or fetch live data, and the current platform's inability to display plots, the final graph couldn't be shown. The assistant suggested running the provided Python code in an interactive Python environment like Jupyter Notebook or Google Colab to visualize the graph properly.\n", + "NVIDIA Corporation (NVDA) experienced a 20.97% increase in its stock price over the past month, with the current price at $878.37. In contrast, Tesla, Inc. (TSLA) saw an 18.19% decrease in the same period, with its current stock price at $163.57. A plotted comparison based on these percentages and current prices, assuming a linear trend for simplicity, would visually depict NVIDIA's stock price trending upwards and Tesla's trending downwards over the last month.\n", "Human input in the middle: []\n", - "Conversation cost: ({'total_cost': 1.0658699999999997, 'gpt-4-0613': {'cost': 1.0658699999999997, 'prompt_tokens': 24657, 'completion_tokens': 5436, 'total_tokens': 30093}}, {'total_cost': 0.26868, 'gpt-4-0613': {'cost': 0.26868, 'prompt_tokens': 5408, 'completion_tokens': 1774, 'total_tokens': 7182}})\n", + "Conversation cost: ({'total_cost': 0.10758999999999999, 'gpt-4-0125-preview': {'cost': 0.10758999999999999, 'prompt_tokens': 6409, 'completion_tokens': 1450, 'total_tokens': 7859}}, {'total_cost': 0.08818, 'gpt-4-0125-preview': {'cost': 0.08818, 'prompt_tokens': 5908, 'completion_tokens': 970, 'total_tokens': 6878}})\n", "\n", "\n", "\n", "*****4th chat*******:\n", - "Title: Navigating the Highs and Lows: A Tale of Two Stocks- NVDA and TSLA\n", + "### The Stock Market Tales of NVIDIA and Tesla: A Comparative Analysis\n", + "\n", + "In the ever-oscillating world of the stock market, where fortunes can be made or lost in the blink of an eye, the recent performances of NVIDIA Corporation (NVDA) and Tesla, Inc. (TSLA) stand out, painting two very different pictures. Over the past month, NVIDIA witnessed an awe-inspiring surge of 20.97% in its stock price, reaching a towering $878.37. Meanwhile, Tesla faced a starkly contrasting fate, with its stock price tumbling down 18.19% to $163.57. But what underlying currents steered these two tech giants in such divergent directions? Let's delve deeper into the whirlpool of market dynamics, technological advancements, and investor sentiment to uncover the story behind these movements.\n", + "\n", + "#### NVIDIA's Stellar Ascent\n", "\n", - "If you've been tracking the stock market recently, you might have noticed some significant activity involving two household names. These tech juggernauts- NVIDIA Corp (NVDA) and Tesla Inc (TSLA), have experienced significantly contrasting fortunes over the past month. \n", + "NVIDIA, a titan in the realms of graphics processing units (GPUs), artificial intelligence (AI), and data centers, has been on a meteoric rise. The company's stock surge can largely be attributed to the burgeoning demand for GPUs, indispensable not only in gaming but also in a plethora of applications from advanced computing tasks to mining cryptocurrencies. This demand spike has catapulted NVIDIA into a favorable position in the stock market.\n", "\n", - "As of now, the NVDA stock price stands at a lofty $726.13, soaring an astonishing 21.72% in the past month. TSLA, however, has had a bumpier ride, with the current price of $199.95 reflecting a 4.24% decrease during the same period. \n", + "Moreover, NVIDIA's forays into AI development and data centers have underpinned its financial fortitude. As businesses and institutions increasingly leverage AI for efficiency and innovation, NVIDIA's cutting-edge technologies stand at the forefront, driving its stock prices to new heights.\n", "\n", - "What's driving the surging ascent of NVDA and the faltering trajectory of TSLA, you might ask? Well, sometimes the answers can be found in the daily news cycle.\n", + "#### Tesla's Turbulent Tide\n", "\n", - "According to news headlines fetched by our AI assistant, NVDA's recent skyrocket can potentially be linked to events like imminent earnings reports and a burgeoning debate around the company's value. These factors have managed to cast a positive light on the company. Investors may perceive them as indicators of a prospective growth, triggering increased stock purchases. \n", + "Tesla, Inc., on the other hand, has navigated through rough waters. Known for revolutionizing the electric vehicle (EV) industry, Tesla has recently grappled with a gamut of challenges. Production snags, possibly accentuated by global supply chain disruptions, have hindered Tesla's ability to meet its ambitious production targets. Furthermore, the EV sphere is no longer Tesla's sole dominion; rising competition has emerged as a formidable force, with legacy automakers and new entrants alike vying for a piece of the EV pie.\n", "\n", - "Yet, every coin has two sides. For TSLA, recent news may have spread more confusion and uncertainty than confidence. Headlines pointing to ambiguities about the company's valuation have clouded its fiscal outlook, leading to a softening of the stock price. \n", + "Regulatory woes and occasional controversial public statements by its charismatic yet polarizing CEO, Elon Musk, have also played a role in swaying investor sentiment, contributing to the stock's decline. These factors combined sketch the backdrop against which Tesla's stock has weathered a downturn.\n", "\n", - "Before attaching too much weight to these possibilities, it's essential to highlight that news headlines offers just a fraction of the full picture. The market's pulse is influenced by a plethora of factors, with many taking place behind headlines. Hence, while headlines undeniably play a role in influencing stock performance, they should be only part of any comprehensive market analysis.\n", + "#### The Tale of Two Graphs\n", "\n", - "To provide a deeper understanding of these stock trajectories, our AI helper put forth a detailed method to mock up a comparative graph of NVDA and TSLA prices over the past month. However, our current environment lacks the capability for web browsing or live data fetching, so the visualization isn’t available in this post. For those keen to see the graphical view, we recommend inputting the provided Python code into an interactive Python environment like Jupyter Notebook or Google Colab.\n", + "Visualizing the stock performance of NVIDIA and Tesla over the last month through a simple linear graph vividly elucidates their trajectories — NVIDIA's stock price ascends skyward, while Tesla's takes a steep downturn. This visual comparison starkly captures the fortunes and misfortunes unfolding in the high-stakes world of the stock market.\n", "\n", - "Whether you're an experienced trader or a budding market enthusiast, understanding the forces moving major stocks like NVDA and TSLA can give you valuable insight into the tech industry's overall health and future direction. So, keep those news alerts on, keep questioning, and keep connecting the dots.\n", + "#### Looking Beyond the Horizon\n", + "\n", + "The stock market is a reflection of myriad factors — technological innovation, market demand, competitive landscape, and investor perception. NVIDIA's ascendancy underscores the growing clout of AI and data centers, heralding an era where these technologies shape market dynamics. Tesla's struggles, meanwhile, highlight the hurdles of scaling production amidst stiffening competition and regulatory scrutiny.\n", + "\n", + "As investors and market aficionados peer into the crystal ball, seeking to divine the future paths of NVIDIA and Tesla, they are reminded of the market's inherent unpredictability. What's certain, though, is that the stories of NVIDIA and Tesla — each fascinating in its own right — will continue to captivate and instruct, offering valuable lessons in resilience, innovation, and the ever-persistent pursuit of progress.\n", + "\n", + "### Conclusion\n", + "\n", + "The contrasting destinies of NVIDIA and Tesla in the stock market serve as a compelling narrative of triumph and tribulation. While NVIDIA rides the wave of technological advancement to new heights, Tesla navigates a challenging course, underlining the complexities of sustaining growth amidst evolving market dynamics. As their stories continue to unfold, both NVIDIA and Tesla offer invaluable insights into the intricate dance of innovation, investment, and influence in shaping the future of technology and industry.\n", + "\n", + "---\n", "\n", "\n", "Human input in the middle: []\n", - "Conversation cost: ({'total_cost': 0.13599, 'gpt-4-0613': {'cost': 0.13599, 'prompt_tokens': 1043, 'completion_tokens': 1745, 'total_tokens': 2788}}, {'total_cost': 0.13599, 'gpt-4-0613': {'cost': 0.13599, 'prompt_tokens': 1043, 'completion_tokens': 1745, 'total_tokens': 2788}})\n", + "Conversation cost: ({'total_cost': 0.02817, 'gpt-4-0125-preview': {'cost': 0.02817, 'prompt_tokens': 387, 'completion_tokens': 810, 'total_tokens': 1197}}, {'total_cost': 0.02817, 'gpt-4-0125-preview': {'cost': 0.02817, 'prompt_tokens': 387, 'completion_tokens': 810, 'total_tokens': 1197}})\n", "\n", "\n", "\n" @@ -617,7 +641,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -626,10 +650,12 @@ "text": [ "\u001b[34m\n", "********************************************************************************\u001b[0m\n", - "\u001b[34mStart a new chat with the following message: \n", + "\u001b[34mStarting a new chat....\n", + "\n", + "Message:\n", "What are the current stock prices of NVDA and TESLA, and how is the performance over the past month in terms of percentage change?\n", "\n", - "With the following carryover: \n", + "Carryover: \n", "\u001b[0m\n", "\u001b[34m\n", "********************************************************************************\u001b[0m\n", @@ -640,60 +666,52 @@ "--------------------------------------------------------------------------------\n", "\u001b[33mFinancial_assistant\u001b[0m (to User):\n", "\n", - "To fetch live stock data, we can make use of the \"yfinance\" library in Python, which allows us to download stock data from Yahoo Finance.\n", - "\n", - "Install \"yfinance\" by executing the following Python code:\n", + "To obtain current stock prices of NVDA (NVIDIA Corporation) and TSLA (Tesla, Inc.), and calculate their performance over the past month in terms of percentage change, we can use the Yahoo Finance API through the `yfinance` Python package. This process involves the following steps:\n", "\n", - "```python\n", - "!pip install yfinance\n", - "```\n", + "1. Install the `yfinance` package (if not already installed).\n", + "2. Use `yfinance` to fetch the current stock prices of NVDA and TSLA.\n", + "3. Fetch historical data for the past month for both stocks.\n", + "4. Calculate the percentage change in the stock prices over the last month based on the historical data.\n", "\n", - "Then, get the current stock prices and compute the performance over the past month using the following code:\n", + "Please execute the following Python code to perform these tasks:\n", "\n", "```python\n", + "# filename: stock_info.py\n", "import yfinance as yf\n", "from datetime import datetime, timedelta\n", "\n", - "# Define the ticker symbols\n", - "tickers = ['NVDA', 'TSLA']\n", - "\n", - "# Get today's date\n", - "today = datetime.today().strftime('%Y-%m-%d')\n", - "\n", - "# Get the date one month ago\n", - "one_month_ago = (datetime.today() - timedelta(days=30)).strftime('%Y-%m-%d')\n", - "\n", - "# Initialize a dictionary to store the data\n", - "data = {}\n", - "\n", - "# Loop through the ticker symbols\n", - "for ticker in tickers:\n", - " # Get the historical data for the past month\n", - " historical_data = yf.download(ticker, start=one_month_ago, end=today)\n", - "\n", - " # Get the most recent data (today's data)\n", - " today_data = historical_data.tail(1)\n", + "def stock_performance(ticker):\n", + " # Fetching data for the past month\n", + " end_date = datetime.today()\n", + " start_date = end_date - timedelta(days=30) # Approximate for the past month\n", + " \n", + " # Fetch historical data\n", + " data = yf.download(ticker, start=start_date, end=end_date)\n", + " \n", + " # Current and beginning of month prices\n", + " current_price = data['Close'].iloc[-1]\n", + " start_month_price = data['Close'].iloc[0] \n", + " \n", + " # Calculate percentage change over the month\n", + " percent_change = ((current_price - start_month_price) / start_month_price) * 100\n", + " \n", + " return current_price, percent_change\n", "\n", - " # Get the earliest data (one month ago's data)\n", - " one_month_ago_data = historical_data.head(1)\n", + "# NVDA and TSLA stock performance\n", + "nvda_price, nvda_change = stock_performance(\"NVDA\")\n", + "tsla_price, tsla_change = stock_performance(\"TSLA\")\n", "\n", - " # Calculate the percentage change over the past month\n", - " percentage_change = ((today_data['Close'].iloc[0] - one_month_ago_data['Close'].iloc[0]) / one_month_ago_data['Close'].iloc[0]) * 100\n", + "print(f\"NVDA (NVIDIA Corp) current price: ${nvda_price:.2f}, Performance over past month: {nvda_change:.2f}%\")\n", + "print(f\"TSLA (Tesla, Inc.) current price: ${tsla_price:.2f}, Performance over past month: {tsla_change:.2f}%\")\n", + "```\n", "\n", - " # Store the data in the dictionary\n", - " data[ticker] = {\n", - " 'Current Stock Price': today_data['Close'].iloc[0],\n", - " 'Performance Over Past Month (%)': percentage_change\n", - " }\n", + "Before running this script, ensure that you have the `yfinance` package installed. If not, install it using the following command:\n", "\n", - "# Print the data\n", - "for ticker, d in data.items():\n", - " print(f\"{ticker}:\")\n", - " print(f\"\\tCurrent Stock Price: ${d['Current Stock Price']:.2f}\")\n", - " print(f\"\\tPerformance Over Past Month (%): {d['Performance Over Past Month (%)']:.2f}%\")\n", + "```sh\n", + "pip install yfinance\n", "```\n", "\n", - "This Python script retrieves the historical data for the past month for each ticker symbol, calculates the percentage change in stock price over the past month, and prints out the current stock price and the performance over the past month.\n", + "This script will output the current stock prices of NVDA and TSLA, along with their performance over the past month in percentage terms.\n", "\n", "--------------------------------------------------------------------------------\n" ] @@ -702,7 +720,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "/workspaces/autogen/autogen/agentchat/chat.py:46: UserWarning: Repetitive recipients detected: The chat history will be cleared by default if a recipient appears more than once. To retain the chat history, please set 'clear_history=False' in the configuration of the repeating agent.\n", + "/workspaces/autogen/autogen/agentchat/chat.py:42: UserWarning: Repetitive recipients detected: The chat history will be cleared by default if a recipient appears more than once. To retain the chat history, please set 'clear_history=False' in the configuration of the repeating agent.\n", " warnings.warn(\n" ] }, @@ -712,193 +730,307 @@ "text": [ "\u001b[33mUser\u001b[0m (to Financial_assistant):\n", "\n", - "Pls add Microsoft information as well.\n", + "Pls add Microsoft as well\n", "\n", "--------------------------------------------------------------------------------\n", "\u001b[33mFinancial_assistant\u001b[0m (to User):\n", "\n", - "Sure, let's add Microsoft (MSFT) to the list of tickers. Here's the updated Python code:\n", + "To include Microsoft (MSFT) in the analysis alongside NVDA (NVIDIA Corporation) and TSLA (Tesla, Inc.), we can modify the provided Python script to fetch and calculate the performance for MSFT as well. The revised script will now include Microsoft's current stock price and its performance over the past month in terms of percentage change. Please execute the updated Python code below:\n", "\n", "```python\n", + "# filename: stock_info_updated.py\n", "import yfinance as yf\n", "from datetime import datetime, timedelta\n", "\n", - "# Define the ticker symbols\n", - "tickers = ['NVDA', 'TSLA', 'MSFT']\n", + "def stock_performance(ticker):\n", + " # Fetching data for the past month\n", + " end_date = datetime.today()\n", + " start_date = end_date - timedelta(days=30) # Approximate for the past month\n", + " \n", + " # Fetch historical data\n", + " data = yf.download(ticker, start=start_date, end=end_date)\n", + " \n", + " # Current and beginning of month prices\n", + " current_price = data['Close'].iloc[-1]\n", + " start_month_price = data['Close'].iloc[0] \n", + " \n", + " # Calculate percentage change over the month\n", + " percent_change = ((current_price - start_month_price) / start_month_price) * 100\n", + " \n", + " return current_price, percent_change\n", "\n", - "# Get today's date\n", - "today = datetime.today().strftime('%Y-%m-%d')\n", + "# Tickers for NVDA, TSLA, and MSFT\n", + "stocks = {\"NVDA\": \"NVIDIA Corp\", \"TSLA\": \"Tesla, Inc.\", \"MSFT\": \"Microsoft Corp\"}\n", "\n", - "# Get the date one month ago\n", - "one_month_ago = (datetime.today() - timedelta(days=30)).strftime('%Y-%m-%d')\n", + "# Iterate through each stock and print information\n", + "for ticker, name in stocks.items():\n", + " price, change = stock_performance(ticker)\n", + " print(f\"{name} (Ticker: {ticker}) current price: ${price:.2f}, Performance over past month: {change:.2f}%\")\n", + "```\n", "\n", - "# Initialize a dictionary to store the data\n", - "data = {}\n", + "This script now includes Microsoft (ticker symbol: MSFT) in the analysis, providing its current stock price and the percentage change over the past month along with NVDA and TSLA. \n", "\n", - "# Loop through the ticker symbols\n", - "for ticker in tickers:\n", - " # Get the historical data for the past month\n", - " historical_data = yf.download(ticker, start=one_month_ago, end=today)\n", + "Before running this script, make sure you have installed the `yfinance` package. Use the `pip install yfinance` command if the package is not already installed. This will ensure that the code can execute successfully and retrieve the stock information.\n", "\n", - " # Get the most recent data (today's data)\n", - " today_data = historical_data.tail(1)\n", + "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> NO HUMAN INPUT RECEIVED.\u001b[0m\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[31m\n", + ">>>>>>>> NO HUMAN INPUT RECEIVED.\u001b[0m\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[31m\n", + ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n", + "\u001b[33mUser\u001b[0m (to Financial_assistant):\n", "\n", - " # Get the earliest data (one month ago's data)\n", - " one_month_ago_data = historical_data.head(1)\n", + "exitcode: 0 (execution succeeded)\n", + "Code output: \n", + "NVIDIA Corp (Ticker: NVDA) current price: $878.37, Performance over past month: 20.97%\n", + "Tesla, Inc. (Ticker: TSLA) current price: $163.57, Performance over past month: -18.19%\n", + "Microsoft Corp (Ticker: MSFT) current price: $416.42, Performance over past month: 3.06%\n", "\n", - " # Calculate the percentage change over the past month\n", - " percentage_change = ((today_data['Close'].iloc[0] - one_month_ago_data['Close'].iloc[0]) / one_month_ago_data['Close'].iloc[0]) * 100\n", "\n", - " # Store the data in the dictionary\n", - " data[ticker] = {\n", - " 'Current Stock Price': today_data['Close'].iloc[0],\n", - " 'Performance Over Past Month (%)': percentage_change\n", - " }\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mFinancial_assistant\u001b[0m (to User):\n", "\n", - "# Print the data\n", - "for ticker, d in data.items():\n", - " print(f\"{ticker}:\")\n", - " print(f\"\\tCurrent Stock Price: ${d['Current Stock Price']:.2f}\")\n", - " print(f\"\\tPerformance Over Past Month (%): {d['Performance Over Past Month (%)']:.2f}%\")\n", - "```\n", + "The execution of the updated script successfully provided the current stock prices and the percentage changes over the past month for NVIDIA Corporation (NVDA), Tesla, Inc. (TSLA), and Microsoft Corp (MSFT):\n", "\n", - "This is essentially the same script as before, but now it also fetches and processes stock data for Microsoft.\n", + "- **NVIDIA Corp (NVDA)**: Current price is **$878.37**, with a performance improvement of **20.97%** over the past month.\n", + "- **Tesla, Inc. (TSLA)**: Current price is **$163.57**, with a performance decrease of **-18.19%** over the past month.\n", + "- **Microsoft Corp (MSFT)**: Current price is **$416.42**, with a performance improvement of **3.06%** over the past month.\n", + "\n", + "These results reflect the respective companies' stock market performance for the duration specified. NVDA has shown significant growth, MSFT has experienced a moderate increase, whereas TSLA has seen a decrease in its stock price.\n", + "\n", + "TERMINATE\n", "\n", "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> NO HUMAN INPUT RECEIVED.\u001b[0m\n", "\u001b[34m\n", "********************************************************************************\u001b[0m\n", - "\u001b[34mStart a new chat with the following message: \n", + "\u001b[34mStarting a new chat....\n", + "\n", + "Message:\n", "Investigate possible reasons of the stock performance.\n", "\n", - "With the following carryover: \n", - "The assistant provided a Python code to fetch the current stock prices and compute performance over the past month in terms of percentage change for the given stock ticker symbols, NVDA (NVIDIA Corp), TSLA (Tesla Inc), and MSFT (Microsoft Corp). This was done using the yfinance library which fetches the data from Yahoo Finance.\u001b[0m\n", + "Carryover: \n", + "The current stock prices and the percentage changes over the past month for NVIDIA Corporation (NVDA), Tesla, Inc. (TSLA), and Microsoft Corp (MSFT) are as follows:\n", + "\n", + "- NVDA: Current price $878.37, with a 20.97% increase.\n", + "- TSLA: Current price $163.57, with an 18.19% decrease.\n", + "- MSFT: Current price $416.42, with a 3.06% increase.\n", + "\n", + "NVDA showed significant growth, MSFT experienced moderate growth, while TSLA saw a decline in its stock price over the last month.\u001b[0m\n", "\u001b[34m\n", "********************************************************************************\u001b[0m\n", "\u001b[34m\n", "********************************************************************************\u001b[0m\n", - "\u001b[34mStart a new chat with the following message: \n", + "\u001b[34mStarting a new chat....\n", + "\n", + "Message:\n", "Plot a graph comparing the stock prices over the past month.\n", "\n", - "With the following carryover: \n", - "The assistant provided a Python code to fetch the current stock prices and compute performance over the past month in terms of percentage change for the given stock ticker symbols, NVDA (NVIDIA Corp), TSLA (Tesla Inc), and MSFT (Microsoft Corp). This was done using the yfinance library which fetches the data from Yahoo Finance.\u001b[0m\n", + "Carryover: \n", + "The current stock prices and the percentage changes over the past month for NVIDIA Corporation (NVDA), Tesla, Inc. (TSLA), and Microsoft Corp (MSFT) are as follows:\n", + "\n", + "- NVDA: Current price $878.37, with a 20.97% increase.\n", + "- TSLA: Current price $163.57, with an 18.19% decrease.\n", + "- MSFT: Current price $416.42, with a 3.06% increase.\n", + "\n", + "NVDA showed significant growth, MSFT experienced moderate growth, while TSLA saw a decline in its stock price over the last month.\u001b[0m\n", "\u001b[34m\n", "********************************************************************************\u001b[0m\n", "\u001b[33mUser\u001b[0m (to Financial_assistant):\n", "\n", "Plot a graph comparing the stock prices over the past month.\n", "Context: \n", - "The assistant provided a Python code to fetch the current stock prices and compute performance over the past month in terms of percentage change for the given stock ticker symbols, NVDA (NVIDIA Corp), TSLA (Tesla Inc), and MSFT (Microsoft Corp). This was done using the yfinance library which fetches the data from Yahoo Finance.\n", + "The current stock prices and the percentage changes over the past month for NVIDIA Corporation (NVDA), Tesla, Inc. (TSLA), and Microsoft Corp (MSFT) are as follows:\n", + "\n", + "- NVDA: Current price $878.37, with a 20.97% increase.\n", + "- TSLA: Current price $163.57, with an 18.19% decrease.\n", + "- MSFT: Current price $416.42, with a 3.06% increase.\n", + "\n", + "NVDA showed significant growth, MSFT experienced moderate growth, while TSLA saw a decline in its stock price over the last month.\n", "\n", "--------------------------------------------------------------------------------\n", "\u001b[33mFinancial_assistant\u001b[0m (to User):\n", "\n", - "Great, I will create a Python script to download historical data for these stocks and plot a comparison graph using libraries such as pandas, yfinance and matplotlib for data handling, financial data fetching and plotting, respectively.\n", + "To compare the stock prices over the past month for NVIDIA Corporation (NVDA), Tesla, Inc. (TSLA), and Microsoft Corp (MSFT), first, we'll calculate their prices a month ago based on the current prices and the percentage change. Then, we will plot the current and past month's prices on a graph for a visual comparison.\n", "\n", - "```python\n", - "# filename: stock_price_comparison.py\n", + "### Calculating the Prices a Month Ago\n", + "To calculate the price a month ago, we can use the formula:\n", "\n", - "import yfinance as yf\n", + "\\[\n", + "\\text{Price a Month Ago} = \\frac{\\text{Current Price}}{1 + \\text{Percentage Change}}\n", + "\\]\n", + "\n", + "For a decrease in price, the percentage change will be considered negative in the calculation.\n", + "\n", + "Let's calculate the stock prices a month ago and proceed to plot the graph in Python:\n", + "\n", + "```python\n", "import matplotlib.pyplot as plt\n", - "import pandas as pd\n", - "from pandas.plotting import register_matplotlib_converters\n", - "register_matplotlib_converters()\n", - "\n", - "# define the ticker symbol\n", - "ticker_list = ['NVDA', 'TSLA', 'MSFT']\n", - "\n", - "# create empty dataframe\n", - "stock_data = pd.DataFrame()\n", - "\n", - "# Fetch the data\n", - "for ticker in ticker_list: \n", - " stock = yf.Ticker(ticker)\n", - " temp = stock.history(period='1mo')\n", - " temp.reset_index(level=0, inplace=True)\n", - " temp['Ticker'] = ticker\n", - " stock_data = stock_data.append(temp)\n", - "\n", - "# Save each stock's closing price and date to a separate .csv\n", - "for ticker in ticker_list:\n", - " temp = stock_data[stock_data['Ticker'] == ticker]\n", - " temp[['Date', 'Close']].to_csv(f'{ticker}_closing_price.csv', index=False)\n", - "\n", - "# plot each stock's closing price in one graph\n", - "plt.figure(figsize=(14, 6))\n", - "for ticker in ticker_list:\n", - " temp = stock_data[stock_data['Ticker'] == ticker]\n", - " plt.plot(temp['Date'], temp['Close'], label=ticker)\n", - "plt.xlabel('Date')\n", - "plt.ylabel('Close Price')\n", - "plt.title('Stock Price over Past Month')\n", - "plt.legend()\n", - "plt.grid()\n", - "plt.savefig('stock_price_comparison.png')\n", "\n", - "print(\"Stock price comparison graph saved as 'stock_price_comparison.png'.\")\n", + "# Current stock prices\n", + "current_prices = {\"NVDA\": 878.37, \"TSLA\": 163.57, \"MSFT\": 416.42}\n", + "\n", + "# Percentage changes (positive for increase, negative for decrease)\n", + "percentage_changes = {\"NVDA\": 20.97, \"TSLA\": -18.19, \"MSFT\": 3.06}\n", + "\n", + "# Calculating prices a month ago\n", + "prices_a_month_ago = {stock: current_prices[stock] / (1 + percentage_changes[stock] / 100) for stock in current_prices}\n", + "\n", + "# Data for plotting\n", + "stocks = list(current_prices.keys())\n", + "current_prices_values = list(current_prices.values())\n", + "prices_a_month_ago_values = list(prices_a_month_ago.values())\n", + "\n", + "# Plotting\n", + "fig, ax = plt.subplots()\n", + "index = range(len(stocks))\n", + "bar_width = 0.35\n", + "\n", + "bars1 = ax.bar(index, prices_a_month_ago_values, bar_width, label='Month Ago')\n", + "bars2 = ax.bar([p + bar_width for p in index], current_prices_values, bar_width, label='Current')\n", + "\n", + "ax.set_xlabel('Stock')\n", + "ax.set_ylabel('Price ($)')\n", + "ax.set_title('Stock Prices Comparison Over the Past Month')\n", + "ax.set_xticks([p + bar_width / 2 for p in index])\n", + "ax.set_xticklabels(stocks)\n", + "ax.legend()\n", "\n", + "plt.tight_layout()\n", + "plt.show()\n", "```\n", - "This script will fetch the stock prices for the past month of the specified companies, then it plots these on the same graph to compare. The graph is saved as a PNG image named \"stock_price_comparison.png\". Each stock's closing price and date data are also saved to a separate .csv file (e.g., \"NVDA_closing_price.csv\"). Please run this script and check the generated graph and files.\n", + "\n", + "This code calculates the stock prices from a month ago based on the given current prices and percentage changes. Then, it plots a grouped bar chart comparing the prices. Execute this Python code to visualize the comparison of stock prices over the past month for NVDA, TSLA, and MSFT.\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> NO HUMAN INPUT RECEIVED.\u001b[0m\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[31m\n", + ">>>>>>>> NO HUMAN INPUT RECEIVED.\u001b[0m\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[31m\n", + ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n", + "\u001b[33mUser\u001b[0m (to Financial_assistant):\n", + "\n", + "exitcode: 0 (execution succeeded)\n", + "Code output: \n", + "Figure(640x480)\n", + "\n", "\n", "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> NO HUMAN INPUT RECEIVED.\u001b[0m\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[31m\n", + ">>>>>>>> NO HUMAN INPUT RECEIVED.\u001b[0m\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[31m\n", + ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n", + "\u001b[33mFinancial_assistant\u001b[0m (to User):\n", + "\n", + "The output indicates that the code executed successfully and generated a plot. Since the visualization itself cannot be displayed directly in this text exchange, it's implied that the figure showed a comparison of the stock prices over the past month for NVIDIA Corporation (NVDA), Tesla, Inc. (TSLA), and Microsoft Corp (MSFT).\n", + "\n", + "From the given data and the intention behind the code:\n", + "\n", + "- NVIDIA (NVDA) would have shown a significant rise from its price a month ago to the current price, illustrating its 20.97% growth.\n", + "- Tesla (TSLA) would have shown a decrease in its stock price, reflecting the 18.19% decline over the past month.\n", + "- Microsoft (MSFT) would have indicated a moderate increase from its price a month ago to its current price, showcasing its 3.06% growth.\n", + "\n", + "This comparison provides insight into each company's stock performance over the last month, highlighting NVDA's significant growth, MSFT's moderate growth, and TSLA's decline. These insights can be valuable for investors, market analysts, and enthusiasts trying to understand market trends or make informed decisions.\n", + "\n", + "If you have any more questions or need further assistance with a different query, feel free to ask. Otherwise, that concludes our task.\n", + "\n", + "TERMINATE\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> NO HUMAN INPUT RECEIVED.\u001b[0m\n", + "\u001b[31m\n", + ">>>>>>>> NO HUMAN INPUT RECEIVED.\u001b[0m\n", "\u001b[34m\n", "********************************************************************************\u001b[0m\n", - "\u001b[34mStart a new chat with the following message: \n", + "\u001b[34mStarting a new chat....\n", + "\n", + "Message:\n", "Develop an engaging blog post using any information provided.\n", "\n", - "With the following carryover: \n", - "The assistant provided a Python code to fetch the current stock prices and compute performance over the past month in terms of percentage change for the given stock ticker symbols, NVDA (NVIDIA Corp), TSLA (Tesla Inc), and MSFT (Microsoft Corp). This was done using the yfinance library which fetches the data from Yahoo Finance.\n", - "The performance of a company's stock price could be influenced by various factors, including earnings reports, company announcements, market trends, economic indicators, and investor sentiment. To find out why a specific stock performed as it did, look out for any news, announcements, earnings report, or significant events that have occurred in the past month for that stock. Also, check the overall market trends and economic indicators during this period, and try to understand the investor sentiment towards the company. To fetch and analyze news related to a company, use the NewsAPI and Python requests library.\n", - "The assistant provided a Python code to fetch and compare the stock prices of NVIDIA Corp (NVDA), Tesla Inc (TSLA), and Microsoft Corp (MSFT) from the past month. The code uses the yfinance library to download historical data, pandas to manage the data, and matplotlib to plot the graph. It fetches the stock prices and plots them on a graph with date on the x-axis and closing price on the y-axis. The script saves the graph as a PNG image and the closing price and date of each stock in separate .csv files.\n", - "\u001b[0m\n", + "Carryover: \n", + "The current stock prices and the percentage changes over the past month for NVIDIA Corporation (NVDA), Tesla, Inc. (TSLA), and Microsoft Corp (MSFT) are as follows:\n", + "\n", + "- NVDA: Current price $878.37, with a 20.97% increase.\n", + "- TSLA: Current price $163.57, with an 18.19% decrease.\n", + "- MSFT: Current price $416.42, with a 3.06% increase.\n", + "\n", + "NVDA showed significant growth, MSFT experienced moderate growth, while TSLA saw a decline in its stock price over the last month.\n", + "NVIDIA Corporation (NVDA) showed significant growth possibly due to strong demand for its GPUs in gaming, professional markets, and advancements in AI technologies. Tesla, Inc. (TSLA) saw a decline in its stock price, which can be affected by production numbers, delivery figures, regulatory concerns, or Elon Musk's public statements. Microsoft Corp (MSFT) experienced moderate growth likely due to its performance in cloud computing, productivity software, and possibly new contracts or partnerships. To obtain specific information on stock performance reasons, consulting financial news websites and company investor relations pages is recommended.\n", + "The conversation involved calculating stock prices from a month ago based on the current prices and percentage changes for NVIDIA Corporation (NVDA), Tesla, Inc. (TSLA), and Microsoft Corp (MSFT). The current price of NVDA was $878.37 with a 20.97% increase, TSLA was $163.57 with an 18.19% decrease, and MSFT was $416.42 with a 3.06% increase. The calculation and subsequent Python code plotted a comparison of these stock prices over the past month, visually representing NVDA's significant growth, MSFT's moderate increase, and TSLA's decline.\u001b[0m\n", "\u001b[34m\n", "********************************************************************************\u001b[0m\n", "\u001b[33mUser\u001b[0m (to writer):\n", "\n", "Develop an engaging blog post using any information provided.\n", "Context: \n", - "The assistant provided a Python code to fetch the current stock prices and compute performance over the past month in terms of percentage change for the given stock ticker symbols, NVDA (NVIDIA Corp), TSLA (Tesla Inc), and MSFT (Microsoft Corp). This was done using the yfinance library which fetches the data from Yahoo Finance.\n", - "The performance of a company's stock price could be influenced by various factors, including earnings reports, company announcements, market trends, economic indicators, and investor sentiment. To find out why a specific stock performed as it did, look out for any news, announcements, earnings report, or significant events that have occurred in the past month for that stock. Also, check the overall market trends and economic indicators during this period, and try to understand the investor sentiment towards the company. To fetch and analyze news related to a company, use the NewsAPI and Python requests library.\n", - "The assistant provided a Python code to fetch and compare the stock prices of NVIDIA Corp (NVDA), Tesla Inc (TSLA), and Microsoft Corp (MSFT) from the past month. The code uses the yfinance library to download historical data, pandas to manage the data, and matplotlib to plot the graph. It fetches the stock prices and plots them on a graph with date on the x-axis and closing price on the y-axis. The script saves the graph as a PNG image and the closing price and date of each stock in separate .csv files.\n", + "The current stock prices and the percentage changes over the past month for NVIDIA Corporation (NVDA), Tesla, Inc. (TSLA), and Microsoft Corp (MSFT) are as follows:\n", + "\n", + "- NVDA: Current price $878.37, with a 20.97% increase.\n", + "- TSLA: Current price $163.57, with an 18.19% decrease.\n", + "- MSFT: Current price $416.42, with a 3.06% increase.\n", "\n", + "NVDA showed significant growth, MSFT experienced moderate growth, while TSLA saw a decline in its stock price over the last month.\n", + "NVIDIA Corporation (NVDA) showed significant growth possibly due to strong demand for its GPUs in gaming, professional markets, and advancements in AI technologies. Tesla, Inc. (TSLA) saw a decline in its stock price, which can be affected by production numbers, delivery figures, regulatory concerns, or Elon Musk's public statements. Microsoft Corp (MSFT) experienced moderate growth likely due to its performance in cloud computing, productivity software, and possibly new contracts or partnerships. To obtain specific information on stock performance reasons, consulting financial news websites and company investor relations pages is recommended.\n", + "The conversation involved calculating stock prices from a month ago based on the current prices and percentage changes for NVIDIA Corporation (NVDA), Tesla, Inc. (TSLA), and Microsoft Corp (MSFT). The current price of NVDA was $878.37 with a 20.97% increase, TSLA was $163.57 with an 18.19% decrease, and MSFT was $416.42 with a 3.06% increase. The calculation and subsequent Python code plotted a comparison of these stock prices over the past month, visually representing NVDA's significant growth, MSFT's moderate increase, and TSLA's decline.\n", "\n", "--------------------------------------------------------------------------------\n", "\u001b[33mwriter\u001b[0m (to User):\n", "\n", - "# Scripting the Stock Market: A Deeper Look into NVIDIA, Tesla, and Microsoft\n", + "### Navigating the Highs and Lows: A Tale of Three Titans\n", "\n", - "Imagine being able to chart the highs and lows of your favorite stocks just by running a bit of code. Whether you're a seasoned investor or a curious newbie, understanding stock trends of top-performing companies like NVIDIA Corp (NVDA), Tesla Inc (TSLA), and Microsoft Corp (MSFT) can offer invaluable insights into the fast-paced world of finance. \n", + "In the dynamic world of stock trading, few tales are as compelling as those of NVIDIA Corporation (NVDA), Tesla, Inc. (TSLA), and Microsoft Corp (MSFT). Over the past month, these tech giants have each narrated a story of market valiance, caution, and resilience. Here, we delve into these narratives, unwrapping the numbers to discover what fuels their journeys.\n", "\n", - "Traditionally, this type of analysis would require countless hours spent poring over dense financial documents, analyzing figures, and making educated guesses. Yet, with Python, the prospect of quickly reviewing stock performances isn't just possible—it's incredibly accessible and surprisingly engaging.\n", + "#### A Soaring Giant: NVIDIA's Unmatched Flight\n", "\n", - "## Harnessing Python and Yahoo Finance Data\n", + "Starting on a high note, NVDA has outpaced expectations, marking a hefty 20.97% increase in its stock price, landing at a stunning $878.37. This surge is not just a number—it's a testament to NVIDIA's stronghold on the GPU market, driven by an insatiable demand in gaming, professional markets, and groundbreaking advancements in AI technologies. As we look behind the curtain, we find a company not merely riding the tech wave but creating it, suggesting that NVIDIA's ascent is built on solid ground.\n", "\n", - "In the world where data reigns supreme, the clever use of Python code makes it a cinch to fetch current stock prices and calculate performance over a given period. The yfinance library proves invaluable here. It fetches data from Yahoo Finance, sparing you the hassle of data collection. \n", + "#### A Turbulent Ride: The Tesla Saga\n", "\n", - "With just a Python script, you can instruct your computer to fetch and analyze the last month's performance for NVDA, TSLA, and MSFT in terms of percentage. This simplifies the process of understanding what’s been happening with these dynamite stocks recently. \n", + "On the flip side of this high-flying story is Tesla, Inc. The electric vehicle behemoth saw its stock price retract by 18.19%, a notable dip to $163.57. At first glance, this might raise alarm bells, hinting at a potential stall in Tesla's meteoric rise. However, those familiar with Tesla's trajectory know this is but a chapter in its rollercoaster narrative. Factors such as production and delivery figures, regulatory landscapes, and the mercurial nature of Elon Musk's public announcements often sway Tesla's stock. Behind the scenes, Tesla's ambition and innovation engine runs full throttle, suggesting this downturn could be a mere blip in its revolutionary path.\n", "\n", - "## Unravel the Mystery Behind Stock Performance\n", + "#### Steady as She Goes: Microsoft's Calculated Climb\n", "\n", - "Of course, knowing a stock's performance is just the first step. Why does a particular stock perform the way it does? There’s not always an easy answer, as stock performance can hinge on various factors. These mandators include company announcements, earnings reports, investor sentiment, market trends, and economic indicators.\n", + "Meanwhile, Microsoft Corp charts a more moderate course. With a 3.06% increase, its stock price reached $416.42. This growth, while not as eye-catching as NVIDIA's, is reflective of Microsoft's strategic positioning in cloud computing, productivity software, and potentially lucrative contracts or partnerships. Unlike the dramatic swings of NVDA and TSLA, MSFT's journey is one of calculated progression, relying on consistent performance and innovation within its stronghold arenas.\n", "\n", - "For those of you hungry to know why NVDA, TSLA, or MSFT experienced a particular spike or dip, consider looking into any significant events, news, or announcements over the past month relating to that stock. Was there a breakthrough product announced? Perhaps a promising earnings report? Or maybe a broader market trend affected technology companies as a whole?\n", + "#### The Bigger Picture\n", "\n", - "## Dive Deeper with the NewsAPI\n", + "What these stories reveal is a complex tapestry of market dynamics. NVIDIA's leap underscores the immense potential and growing demand in cutting-edge technologies. Tesla's situation is a reminder of the volatility inherent to ambitious, disruptive companies. Meanwhile, Microsoft's steady ascent illustrates the power of sustained growth in core areas. For investors and enthusiasts alike, these developments highlight the importance of context and perspective when navigating the stock market seas.\n", "\n", - "One way to stay afloat in the torrent of stock-related news is by using the NewsAPI in conjunction with the Python requests library. This combination assists in fetching and analyzing news related to the companies of your interest, keeping you abreast of events that might directly affect stock performance.\n", + "Understanding the ‘why’ behind stock performance is crucial. While this snapshot offers a glimpse into a month's journey, diving into financial news websites and company investor relations pages can provide deeper insights into these fluctuations.\n", "\n", - "## Visualize the Stock Prices with matplotlib\n", + "As we close this chapter, the saga of NVDA, TSLA, and MSFT continues. Each, in its own way, is a beacon of technological progress and market dynamics. For those watching from the sidelines, these stories are more than financial metrics; they are narratives of human ambition, innovation, and resilience—a reminder that in the world of tech, the only constant is change.\n", "\n", - "Visualization is an absolute game-changer when it comes to understanding data, and yes, stock prices are no different whatsoever. Once you've fetched the stock prices using yfinance, you can use the Python libraries, pandas for data management and matplotlib for plotting. These tools allow you to graph the stocks' closing prices over the given period, providing a clear, visual summary of their performance. \n", + "*To those seeking to chart their course in the stock market waters, let these narratives be your guide, your caution, and your inspiration.*\n", "\n", - "To make the analysis even more concrete, the Python code stores the closing dates and prices of each stock in separate .csv files. This way, you always have a concrete log of the data breaking down the stock performances over time.\n", + "*Happy Investing!*\n", "\n", - "And there you have it! Using Python, even the novice investors among us can dive headfirst into the sea of stock market analysis. As you get comfortable retrieving and analyzing stock data, you'll find the information you glean from this process invaluable, whether you're making personal investments or just following market trends out of interest.\n", + "---\n", "\n", - "Welcome to the new era of stock analysis! Happy data crunching!\n", + "I'm always here to craft more compelling narratives from the world of finance, innovation, or any sphere that catches your intellectual curiosity. Let's embark on the next exploration whenever you're ready. \n", "\n", "TERMINATE\n", "\n", - "--------------------------------------------------------------------------------\n" + "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> NO HUMAN INPUT RECEIVED.\u001b[0m\n" ] } ], @@ -953,7 +1085,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -961,63 +1093,68 @@ "output_type": "stream", "text": [ "*****1th chat*******:\n", - "The assistant provided a Python code to fetch the current stock prices and compute performance over the past month in terms of percentage change for the given stock ticker symbols, NVDA (NVIDIA Corp), TSLA (Tesla Inc), and MSFT (Microsoft Corp). This was done using the yfinance library which fetches the data from Yahoo Finance.\n", - "Human input in the middle: ['Pls add Microsoft information as well.', 'exit']\n", - "Conversation cost: ({'total_cost': 0.56541, 'gpt-4-0613': {'cost': 0.56541, 'prompt_tokens': 13003, 'completion_tokens': 2922, 'total_tokens': 15925}}, {'total_cost': 0.20337, 'gpt-4-0613': {'cost': 0.20337, 'prompt_tokens': 4311, 'completion_tokens': 1234, 'total_tokens': 5545}})\n", + "The current stock prices and the percentage changes over the past month for NVIDIA Corporation (NVDA), Tesla, Inc. (TSLA), and Microsoft Corp (MSFT) are as follows:\n", + "\n", + "- NVDA: Current price $878.37, with a 20.97% increase.\n", + "- TSLA: Current price $163.57, with an 18.19% decrease.\n", + "- MSFT: Current price $416.42, with a 3.06% increase.\n", + "\n", + "NVDA showed significant growth, MSFT experienced moderate growth, while TSLA saw a decline in its stock price over the last month.\n", + "Human input in the middle: ['Pls add Microsoft as well', '', '', '']\n", + "Conversation cost: ({'total_cost': 0.18808000000000002, 'gpt-4-0125-preview': {'cost': 0.18808000000000002, 'prompt_tokens': 10732, 'completion_tokens': 2692, 'total_tokens': 13424}}, {'total_cost': 0.12617, 'gpt-4-0125-preview': {'cost': 0.12617, 'prompt_tokens': 8735, 'completion_tokens': 1294, 'total_tokens': 10029}})\n", "\n", "\n", "\n", "*****2th chat*******:\n", - "The performance of a company's stock price could be influenced by various factors, including earnings reports, company announcements, market trends, economic indicators, and investor sentiment. To find out why a specific stock performed as it did, look out for any news, announcements, earnings report, or significant events that have occurred in the past month for that stock. Also, check the overall market trends and economic indicators during this period, and try to understand the investor sentiment towards the company. To fetch and analyze news related to a company, use the NewsAPI and Python requests library.\n", - "Human input in the middle: ['exit']\n", - "Conversation cost: ({'total_cost': 0.34029, 'gpt-4-0613': {'cost': 0.34029, 'prompt_tokens': 6785, 'completion_tokens': 2279, 'total_tokens': 9064}}, {'total_cost': 0.22940999999999998, 'gpt-4-0613': {'cost': 0.22940999999999998, 'prompt_tokens': 5097, 'completion_tokens': 1275, 'total_tokens': 6372}})\n", + "NVIDIA Corporation (NVDA) showed significant growth possibly due to strong demand for its GPUs in gaming, professional markets, and advancements in AI technologies. Tesla, Inc. (TSLA) saw a decline in its stock price, which can be affected by production numbers, delivery figures, regulatory concerns, or Elon Musk's public statements. Microsoft Corp (MSFT) experienced moderate growth likely due to its performance in cloud computing, productivity software, and possibly new contracts or partnerships. To obtain specific information on stock performance reasons, consulting financial news websites and company investor relations pages is recommended.\n", + "Human input in the middle: ['', '', '', '', '', '']\n", + "Conversation cost: ({'total_cost': 0.13297, 'gpt-4-0125-preview': {'cost': 0.13297, 'prompt_tokens': 6121, 'completion_tokens': 2392, 'total_tokens': 8513}}, {'total_cost': 0.13297, 'gpt-4-0125-preview': {'cost': 0.13297, 'prompt_tokens': 6121, 'completion_tokens': 2392, 'total_tokens': 8513}})\n", "\n", "\n", "\n", "*****3th chat*******:\n", - "The assistant provided a Python code to fetch and compare the stock prices of NVIDIA Corp (NVDA), Tesla Inc (TSLA), and Microsoft Corp (MSFT) from the past month. The code uses the yfinance library to download historical data, pandas to manage the data, and matplotlib to plot the graph. It fetches the stock prices and plots them on a graph with date on the x-axis and closing price on the y-axis. The script saves the graph as a PNG image and the closing price and date of each stock in separate .csv files.\n", - "\n", - "Human input in the middle: ['exit']\n", - "Conversation cost: ({'total_cost': 0.63072, 'gpt-4-0613': {'cost': 0.63072, 'prompt_tokens': 14100, 'completion_tokens': 3462, 'total_tokens': 17562}}, {'total_cost': 0.26868, 'gpt-4-0613': {'cost': 0.26868, 'prompt_tokens': 5408, 'completion_tokens': 1774, 'total_tokens': 7182}})\n", + "The conversation involved calculating stock prices from a month ago based on the current prices and percentage changes for NVIDIA Corporation (NVDA), Tesla, Inc. (TSLA), and Microsoft Corp (MSFT). The current price of NVDA was $878.37 with a 20.97% increase, TSLA was $163.57 with an 18.19% decrease, and MSFT was $416.42 with a 3.06% increase. The calculation and subsequent Python code plotted a comparison of these stock prices over the past month, visually representing NVDA's significant growth, MSFT's moderate increase, and TSLA's decline.\n", + "Human input in the middle: ['', '', '', '', '', '']\n", + "Conversation cost: ({'total_cost': 0.24309000000000003, 'gpt-4-0125-preview': {'cost': 0.24309000000000003, 'prompt_tokens': 13491, 'completion_tokens': 3606, 'total_tokens': 17097}}, {'total_cost': 0.18118, 'gpt-4-0125-preview': {'cost': 0.18118, 'prompt_tokens': 11494, 'completion_tokens': 2208, 'total_tokens': 13702}})\n", "\n", "\n", "\n", "*****4th chat*******:\n", - "# Scripting the Stock Market: A Deeper Look into NVIDIA, Tesla, and Microsoft\n", + "### Navigating the Highs and Lows: A Tale of Three Titans\n", "\n", - "Imagine being able to chart the highs and lows of your favorite stocks just by running a bit of code. Whether you're a seasoned investor or a curious newbie, understanding stock trends of top-performing companies like NVIDIA Corp (NVDA), Tesla Inc (TSLA), and Microsoft Corp (MSFT) can offer invaluable insights into the fast-paced world of finance. \n", + "In the dynamic world of stock trading, few tales are as compelling as those of NVIDIA Corporation (NVDA), Tesla, Inc. (TSLA), and Microsoft Corp (MSFT). Over the past month, these tech giants have each narrated a story of market valiance, caution, and resilience. Here, we delve into these narratives, unwrapping the numbers to discover what fuels their journeys.\n", "\n", - "Traditionally, this type of analysis would require countless hours spent poring over dense financial documents, analyzing figures, and making educated guesses. Yet, with Python, the prospect of quickly reviewing stock performances isn't just possible—it's incredibly accessible and surprisingly engaging.\n", + "#### A Soaring Giant: NVIDIA's Unmatched Flight\n", "\n", - "## Harnessing Python and Yahoo Finance Data\n", + "Starting on a high note, NVDA has outpaced expectations, marking a hefty 20.97% increase in its stock price, landing at a stunning $878.37. This surge is not just a number—it's a testament to NVIDIA's stronghold on the GPU market, driven by an insatiable demand in gaming, professional markets, and groundbreaking advancements in AI technologies. As we look behind the curtain, we find a company not merely riding the tech wave but creating it, suggesting that NVIDIA's ascent is built on solid ground.\n", "\n", - "In the world where data reigns supreme, the clever use of Python code makes it a cinch to fetch current stock prices and calculate performance over a given period. The yfinance library proves invaluable here. It fetches data from Yahoo Finance, sparing you the hassle of data collection. \n", + "#### A Turbulent Ride: The Tesla Saga\n", "\n", - "With just a Python script, you can instruct your computer to fetch and analyze the last month's performance for NVDA, TSLA, and MSFT in terms of percentage. This simplifies the process of understanding what’s been happening with these dynamite stocks recently. \n", + "On the flip side of this high-flying story is Tesla, Inc. The electric vehicle behemoth saw its stock price retract by 18.19%, a notable dip to $163.57. At first glance, this might raise alarm bells, hinting at a potential stall in Tesla's meteoric rise. However, those familiar with Tesla's trajectory know this is but a chapter in its rollercoaster narrative. Factors such as production and delivery figures, regulatory landscapes, and the mercurial nature of Elon Musk's public announcements often sway Tesla's stock. Behind the scenes, Tesla's ambition and innovation engine runs full throttle, suggesting this downturn could be a mere blip in its revolutionary path.\n", "\n", - "## Unravel the Mystery Behind Stock Performance\n", + "#### Steady as She Goes: Microsoft's Calculated Climb\n", "\n", - "Of course, knowing a stock's performance is just the first step. Why does a particular stock perform the way it does? There’s not always an easy answer, as stock performance can hinge on various factors. These mandators include company announcements, earnings reports, investor sentiment, market trends, and economic indicators.\n", + "Meanwhile, Microsoft Corp charts a more moderate course. With a 3.06% increase, its stock price reached $416.42. This growth, while not as eye-catching as NVIDIA's, is reflective of Microsoft's strategic positioning in cloud computing, productivity software, and potentially lucrative contracts or partnerships. Unlike the dramatic swings of NVDA and TSLA, MSFT's journey is one of calculated progression, relying on consistent performance and innovation within its stronghold arenas.\n", "\n", - "For those of you hungry to know why NVDA, TSLA, or MSFT experienced a particular spike or dip, consider looking into any significant events, news, or announcements over the past month relating to that stock. Was there a breakthrough product announced? Perhaps a promising earnings report? Or maybe a broader market trend affected technology companies as a whole?\n", + "#### The Bigger Picture\n", "\n", - "## Dive Deeper with the NewsAPI\n", + "What these stories reveal is a complex tapestry of market dynamics. NVIDIA's leap underscores the immense potential and growing demand in cutting-edge technologies. Tesla's situation is a reminder of the volatility inherent to ambitious, disruptive companies. Meanwhile, Microsoft's steady ascent illustrates the power of sustained growth in core areas. For investors and enthusiasts alike, these developments highlight the importance of context and perspective when navigating the stock market seas.\n", "\n", - "One way to stay afloat in the torrent of stock-related news is by using the NewsAPI in conjunction with the Python requests library. This combination assists in fetching and analyzing news related to the companies of your interest, keeping you abreast of events that might directly affect stock performance.\n", + "Understanding the ‘why’ behind stock performance is crucial. While this snapshot offers a glimpse into a month's journey, diving into financial news websites and company investor relations pages can provide deeper insights into these fluctuations.\n", "\n", - "## Visualize the Stock Prices with matplotlib\n", + "As we close this chapter, the saga of NVDA, TSLA, and MSFT continues. Each, in its own way, is a beacon of technological progress and market dynamics. For those watching from the sidelines, these stories are more than financial metrics; they are narratives of human ambition, innovation, and resilience—a reminder that in the world of tech, the only constant is change.\n", "\n", - "Visualization is an absolute game-changer when it comes to understanding data, and yes, stock prices are no different whatsoever. Once you've fetched the stock prices using yfinance, you can use the Python libraries, pandas for data management and matplotlib for plotting. These tools allow you to graph the stocks' closing prices over the given period, providing a clear, visual summary of their performance. \n", + "*To those seeking to chart their course in the stock market waters, let these narratives be your guide, your caution, and your inspiration.*\n", "\n", - "To make the analysis even more concrete, the Python code stores the closing dates and prices of each stock in separate .csv files. This way, you always have a concrete log of the data breaking down the stock performances over time.\n", + "*Happy Investing!*\n", "\n", - "And there you have it! Using Python, even the novice investors among us can dive headfirst into the sea of stock market analysis. As you get comfortable retrieving and analyzing stock data, you'll find the information you glean from this process invaluable, whether you're making personal investments or just following market trends out of interest.\n", + "---\n", "\n", - "Welcome to the new era of stock analysis! Happy data crunching!\n", + "I'm always here to craft more compelling narratives from the world of finance, innovation, or any sphere that catches your intellectual curiosity. Let's embark on the next exploration whenever you're ready. \n", "\n", "\n", - "Human input in the middle: ['exit']\n", - "Conversation cost: ({'total_cost': 0.09408, 'gpt-4-0613': {'cost': 0.09408, 'prompt_tokens': 702, 'completion_tokens': 1217, 'total_tokens': 1919}}, {'total_cost': 0.09408, 'gpt-4-0613': {'cost': 0.09408, 'prompt_tokens': 702, 'completion_tokens': 1217, 'total_tokens': 1919}})\n", + "Human input in the middle: ['']\n", + "Conversation cost: ({'total_cost': 0.05552, 'gpt-4-0125-preview': {'cost': 0.05552, 'prompt_tokens': 833, 'completion_tokens': 1573, 'total_tokens': 2406}}, {'total_cost': 0.05552, 'gpt-4-0125-preview': {'cost': 0.05552, 'prompt_tokens': 833, 'completion_tokens': 1573, 'total_tokens': 2406}})\n", "\n", "\n", "\n" @@ -1051,10 +1188,12 @@ "text": [ "\u001b[34m\n", "********************************************************************************\u001b[0m\n", - "\u001b[34mStart a new chat with the following message: \n", + "\u001b[34mStarting a new chat....\n", + "\n", + "Message:\n", "What are the current stock prices of NVDA and TESLA, and how is the performance over the past month in terms of percentage change?\n", "\n", - "With the following carryover: \n", + "Carryover: \n", "\u001b[0m\n", "\u001b[34m\n", "********************************************************************************\u001b[0m\n", @@ -1065,112 +1204,134 @@ "--------------------------------------------------------------------------------\n", "\u001b[33mResearcher\u001b[0m (to User):\n", "\n", - "To obtain the current stock prices of NVDA (Nvidia Corporation) and TSLA (Tesla, Inc.), as well as their performance over the past month in terms of percentage change, I will use Python code to fetch this information from a financial data API. For this task, we can use the Yahoo Finance API through the `yfinance` library, which allows us to collect stock information programmatically.\n", + "To obtain current stock prices of NVDA (NVIDIA Corporation) and TSLA (Tesla, Inc.), and calculate their performance over the past month in terms of percentage change, we can use the Yahoo Finance API through the `yfinance` Python package. This process involves the following steps:\n", "\n", - "Here is the plan:\n", - "1. Use Python code to access the required stock data via the `yfinance` library.\n", - "2. Fetch the current prices of NVDA and TSLA.\n", - "3. Calculate the percentage change in their stock prices over the past month.\n", + "1. Install the `yfinance` package (if not already installed).\n", + "2. Use `yfinance` to fetch the current stock prices of NVDA and TSLA.\n", + "3. Fetch historical data for the past month for both stocks.\n", + "4. Calculate the percentage change in the stock prices over the last month based on the historical data.\n", "\n", - "First, you'll need to ensure that the `yfinance` library is installed. If it's not already installed, you can install it using pip. Execute the following Python code to perform the tasks:\n", + "Please execute the following Python code to perform these tasks:\n", "\n", "```python\n", "# filename: stock_info.py\n", - "\n", "import yfinance as yf\n", "from datetime import datetime, timedelta\n", "\n", - "# Define the tickers for Nvidia and Tesla\n", - "tickers = [\"NVDA\", \"TSLA\"]\n", - "\n", - "# Define the time period: end date is today, start date is one month ago\n", - "end_date = datetime.today()\n", - "start_date = end_date - timedelta(days=30)\n", - "\n", - "# Function to fetch and display stock info\n", - "def fetch_and_display_info(ticker):\n", - " stock = yf.Ticker(ticker)\n", + "def stock_performance(ticker):\n", + " # Fetching data for the past month\n", + " end_date = datetime.today()\n", + " start_date = end_date - timedelta(days=30) # Approximate for the past month\n", " \n", - " # Fetch historical data for the past month\n", - " hist = stock.history(start=start_date, end=end_date)\n", + " # Fetch historical data\n", + " data = yf.download(ticker, start=start_date, end=end_date)\n", " \n", - " # Get the last closing price (most recent date)\n", - " last_close_price = hist['Close'].iloc[-1]\n", + " # Current and beginning of month prices\n", + " current_price = data['Close'].iloc[-1]\n", + " start_month_price = data['Close'].iloc[0] \n", " \n", - " # Calculate the percentage change over the past month\n", - " start_price = hist['Close'].iloc[0] # First day's closing price in the hist data\n", - " percentage_change = ((last_close_price - start_price) / start_price) * 100\n", + " # Calculate percentage change over the month\n", + " percent_change = ((current_price - start_month_price) / start_month_price) * 100\n", " \n", - " print(f\"{ticker} Current Price: ${last_close_price:.2f}\")\n", - " print(f\"{ticker} Performance Over The Past Month: {percentage_change:.2f}%\\n\")\n", + " return current_price, percent_change\n", + "\n", + "# NVDA and TSLA stock performance\n", + "nvda_price, nvda_change = stock_performance(\"NVDA\")\n", + "tsla_price, tsla_change = stock_performance(\"TSLA\")\n", "\n", - "# Fetch and display info for each ticker\n", - "for ticker in tickers:\n", - " fetch_and_display_info(ticker)\n", + "print(f\"NVDA (NVIDIA Corp) current price: ${nvda_price:.2f}, Performance over past month: {nvda_change:.2f}%\")\n", + "print(f\"TSLA (Tesla, Inc.) current price: ${tsla_price:.2f}, Performance over past month: {tsla_change:.2f}%\")\n", "```\n", "\n", - "Please save the above code in a file named `stock_info.py` and execute it. This script will output the current prices of NVDA and TSLA, along with the percentage changes in their stock prices over the past month.\n", + "Before running this script, ensure that you have the `yfinance` package installed. If not, install it using the following command:\n", + "\n", + "```sh\n", + "pip install yfinance\n", + "```\n", "\n", - "If you encounter any issues or have any questions regarding the execution or results, please let me know!\n", + "This script will output the current stock prices of NVDA and TSLA, along with their performance over the past month in percentage terms.\n", "\n", "--------------------------------------------------------------------------------\n", "\u001b[31m\n", ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n", + "\u001b[31m\n", + ">>>>>>>> EXECUTING CODE BLOCK 1 (inferred language is sh)...\u001b[0m\n", "\u001b[33mUser\u001b[0m (to Researcher):\n", "\n", "exitcode: 0 (execution succeeded)\n", "Code output: \n", - "NVDA Current Price: $726.13\n", - "NVDA Performance Over The Past Month: 21.72%\n", - "\n", - "TSLA Current Price: $199.95\n", - "TSLA Performance Over The Past Month: -4.24%\n", + "NVDA (NVIDIA Corp) current price: $878.37, Performance over past month: 20.97%\n", + "TSLA (Tesla, Inc.) current price: $163.57, Performance over past month: -18.19%\n", "\n", + "Defaulting to user installation because normal site-packages is not writeable\n", + "Requirement already satisfied: yfinance in /home/autogen/.local/lib/python3.11/site-packages (0.2.37)\n", + "Requirement already satisfied: pandas>=1.3.0 in /home/autogen/.local/lib/python3.11/site-packages (from yfinance) (2.2.1)\n", + "Requirement already satisfied: numpy>=1.16.5 in /usr/local/lib/python3.11/site-packages (from yfinance) (1.26.4)\n", + "Requirement already satisfied: requests>=2.31 in /usr/local/lib/python3.11/site-packages (from yfinance) (2.31.0)\n", + "Requirement already satisfied: multitasking>=0.0.7 in /home/autogen/.local/lib/python3.11/site-packages (from yfinance) (0.0.11)\n", + "Requirement already satisfied: lxml>=4.9.1 in /home/autogen/.local/lib/python3.11/site-packages (from yfinance) (5.1.0)\n", + "Requirement already satisfied: appdirs>=1.4.4 in /home/autogen/.local/lib/python3.11/site-packages (from yfinance) (1.4.4)\n", + "Requirement already satisfied: pytz>=2022.5 in /home/autogen/.local/lib/python3.11/site-packages (from yfinance) (2024.1)\n", + "Requirement already satisfied: frozendict>=2.3.4 in /home/autogen/.local/lib/python3.11/site-packages (from yfinance) (2.4.0)\n", + "Requirement already satisfied: peewee>=3.16.2 in /home/autogen/.local/lib/python3.11/site-packages (from yfinance) (3.17.1)\n", + "Requirement already satisfied: beautifulsoup4>=4.11.1 in /usr/local/lib/python3.11/site-packages (from yfinance) (4.12.3)\n", + "Requirement already satisfied: html5lib>=1.1 in /home/autogen/.local/lib/python3.11/site-packages (from yfinance) (1.1)\n", + "Requirement already satisfied: soupsieve>1.2 in /usr/local/lib/python3.11/site-packages (from beautifulsoup4>=4.11.1->yfinance) (2.5)\n", + "Requirement already satisfied: six>=1.9 in /usr/local/lib/python3.11/site-packages (from html5lib>=1.1->yfinance) (1.16.0)\n", + "Requirement already satisfied: webencodings in /usr/local/lib/python3.11/site-packages (from html5lib>=1.1->yfinance) (0.5.1)\n", + "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.11/site-packages (from pandas>=1.3.0->yfinance) (2.9.0.post0)\n", + "Requirement already satisfied: tzdata>=2022.7 in /home/autogen/.local/lib/python3.11/site-packages (from pandas>=1.3.0->yfinance) (2024.1)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.11/site-packages (from requests>=2.31->yfinance) (3.3.2)\n", + "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.11/site-packages (from requests>=2.31->yfinance) (3.6)\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.11/site-packages (from requests>=2.31->yfinance) (2.2.1)\n", + "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.11/site-packages (from requests>=2.31->yfinance) (2024.2.2)\n", "\n", "\n", "--------------------------------------------------------------------------------\n", "\u001b[33mResearcher\u001b[0m (to User):\n", "\n", - "The execution of the provided Python code successfully fetched the current stock prices and the performance over the past month for Nvidia Corporation (NVDA) and Tesla, Inc. (TSLA). Here are the results:\n", - "\n", - "- **Nvidia Corporation (NVDA):**\n", - " - Current Price: $726.13\n", - " - Performance Over The Past Month: +21.72%\n", - "\n", - "- **Tesla, Inc. (TSLA):**\n", - " - Current Price: $199.95\n", - " - Performance Over The Past Month: -4.24%\n", - "\n", - "This data indicates that over the past month, NVDA's stock has seen a significant positive increase in its price, with a 21.72% rise, showcasing strong performance. On the other hand, TSLA's stock has experienced a slight decline, with a 4.24% decrease in its price.\n", + "The code execution was successful, and here are the results based on the output:\n", "\n", - "These performance metrics can be useful for investors and traders to understand recent trends in these companies' stock values.\n", + "- **NVIDIA Corporation (NVDA)** has a current stock price of **$878.37**. Over the past month, NVDA has experienced a performance increase of **20.97%**.\n", + "- **Tesla, Inc. (TSLA)** has a current stock price of **$163.57**. Over the past month, TSLA has experienced a performance decrease of **-18.19%**.\n", "\n", - "If you have any more questions or need further assistance, feel free to ask. Otherwise, we can conclude here.\n", + "These figures provide a snapshot of how both companies have performed in the stock market over the last month, reflecting growth for NVIDIA and a decline for Tesla.\n", "\n", "TERMINATE\n", "\n", "--------------------------------------------------------------------------------\n", "\u001b[34m\n", "********************************************************************************\u001b[0m\n", - "\u001b[34mStart a new chat with the following message: \n", + "\u001b[34mStarting a new chat....\n", + "\n", + "Message:\n", "Investigate possible reasons of the stock performance.\n", "\n", - "With the following carryover: \n", - "The execution of the provided Python code successfully fetched the current stock prices and the performance over the past month for Nvidia Corporation (NVDA) and Tesla, Inc. (TSLA). Here are the results:\n", + "Carryover: \n", + "The code execution was successful, and here are the results based on the output:\n", + "\n", + "- **NVIDIA Corporation (NVDA)** has a current stock price of **$878.37**. Over the past month, NVDA has experienced a performance increase of **20.97%**.\n", + "- **Tesla, Inc. (TSLA)** has a current stock price of **$163.57**. Over the past month, TSLA has experienced a performance decrease of **-18.19%**.\n", + "\n", + "These figures provide a snapshot of how both companies have performed in the stock market over the last month, reflecting growth for NVIDIA and a decline for Tesla.\n", "\n", - "- **Nvidia Corporation (NVDA):**\n", - " - Current Price: $726.13\n", - " - Performance Over The Past Month: +21.72%\n", + "\u001b[0m\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[34mStarting a new chat....\n", "\n", - "- **Tesla, Inc. (TSLA):**\n", - " - Current Price: $199.95\n", - " - Performance Over The Past Month: -4.24%\n", + "Message:\n", + "Plot a graph comparing the stock prices over the past month.\n", "\n", - "This data indicates that over the past month, NVDA's stock has seen a significant positive increase in its price, with a 21.72% rise, showcasing strong performance. On the other hand, TSLA's stock has experienced a slight decline, with a 4.24% decrease in its price.\n", + "Carryover: \n", + "The code execution was successful, and here are the results based on the output:\n", "\n", - "These performance metrics can be useful for investors and traders to understand recent trends in these companies' stock values.\n", + "- **NVIDIA Corporation (NVDA)** has a current stock price of **$878.37**. Over the past month, NVDA has experienced a performance increase of **20.97%**.\n", + "- **Tesla, Inc. (TSLA)** has a current stock price of **$163.57**. Over the past month, TSLA has experienced a performance decrease of **-18.19%**.\n", "\n", - "If you have any more questions or need further assistance, feel free to ask. Otherwise, we can conclude here.\n", + "These figures provide a snapshot of how both companies have performed in the stock market over the last month, reflecting growth for NVIDIA and a decline for Tesla.\n", "\n", "\u001b[0m\n", "\u001b[34m\n", @@ -1179,187 +1340,281 @@ "\n", "Investigate possible reasons of the stock performance.\n", "Context: \n", - "The execution of the provided Python code successfully fetched the current stock prices and the performance over the past month for Nvidia Corporation (NVDA) and Tesla, Inc. (TSLA). Here are the results:\n", + "The code execution was successful, and here are the results based on the output:\n", + "\n", + "- **NVIDIA Corporation (NVDA)** has a current stock price of **$878.37**. Over the past month, NVDA has experienced a performance increase of **20.97%**.\n", + "- **Tesla, Inc. (TSLA)** has a current stock price of **$163.57**. Over the past month, TSLA has experienced a performance decrease of **-18.19%**.\n", + "\n", + "These figures provide a snapshot of how both companies have performed in the stock market over the last month, reflecting growth for NVIDIA and a decline for Tesla.\n", + "\n", "\n", - "- **Nvidia Corporation (NVDA):**\n", - " - Current Price: $726.13\n", - " - Performance Over The Past Month: +21.72%\n", "\n", - "- **Tesla, Inc. (TSLA):**\n", - " - Current Price: $199.95\n", - " - Performance Over The Past Month: -4.24%\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mUser\u001b[0m (to Research_manager):\n", "\n", - "This data indicates that over the past month, NVDA's stock has seen a significant positive increase in its price, with a 21.72% rise, showcasing strong performance. On the other hand, TSLA's stock has experienced a slight decline, with a 4.24% decrease in its price.\n", + "Plot a graph comparing the stock prices over the past month.\n", + "Context: \n", + "The code execution was successful, and here are the results based on the output:\n", "\n", - "These performance metrics can be useful for investors and traders to understand recent trends in these companies' stock values.\n", + "- **NVIDIA Corporation (NVDA)** has a current stock price of **$878.37**. Over the past month, NVDA has experienced a performance increase of **20.97%**.\n", + "- **Tesla, Inc. (TSLA)** has a current stock price of **$163.57**. Over the past month, TSLA has experienced a performance decrease of **-18.19%**.\n", "\n", - "If you have any more questions or need further assistance, feel free to ask. Otherwise, we can conclude here.\n", + "These figures provide a snapshot of how both companies have performed in the stock market over the last month, reflecting growth for NVIDIA and a decline for Tesla.\n", "\n", "\n", "\n", "--------------------------------------------------------------------------------\n", "\u001b[33mResearcher\u001b[0m (to Research_manager):\n", "\n", - "To investigate the possible reasons behind the stock performance of Nvidia Corporation (NVDA) and Tesla, Inc. (TSLA), we need to consider various factors that could influence their stock prices. Here's a step-by-step plan for our investigation:\n", + "To compare the stock prices of NVIDIA Corporation (NVDA) and Tesla, Inc. (TSLA) over the past month graphically, we will plot their growth percentages over a timeline. Since direct daily stock prices over the past month are not provided, we'll illustrate the overall performance based on the percentage changes provided.\n", + "\n", + "We'll assume the starting stock price of both companies a month ago was 100% (their stock price at the beginning of the timeline), and then we'll plot the end point using the percentage increase and decrease for NVDA and TSLA, respectively. This approach provides a simplified visualization of relative growth.\n", + "\n", + "For this purpose, I'll provide Python code that uses matplotlib for plotting. The code will represent the starting point (a month ago) and the current point, reflecting the change.\n", "\n", - "1. **Market News and Events:** We will look for any recent news, announcements, or events related to Nvidia and Tesla that could influence investor sentiment and stock performance. This includes financial reports, product launches, regulatory changes, or significant partnerships.\n", + "```python\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# Names of the companies\n", + "companies = ['NVDA', 'TSLA']\n", + "\n", + "# Performance over the past month (in percentage)\n", + "performance = [20.97, -18.19] # NVDA increased by 20.97%, TSLA decreased by -18.19%\n", + "\n", + "# Plot\n", + "plt.figure(figsize=(10, 6))\n", + "for i, perf in enumerate(performance):\n", + " plt.plot(['1 Month Ago', 'Now'], [100, 100 + perf], label=companies[i], marker='o')\n", + "\n", + "# Add title and labels\n", + "plt.title('Stock Performance Over the Last Month')\n", + "plt.ylabel('Performance (%) Relative to 1 Month Ago')\n", + "\n", + "# Add a legend\n", + "plt.legend()\n", + "\n", + "# Show the plot\n", + "plt.grid(True)\n", + "plt.show()\n", + "```\n", + "\n", + "Execute this Python code to generate the plot comparing the stock performance of NVIDIA Corporation (NVDA) and Tesla, Inc. (TSLA) over the past month. The plot starts with the assumption that both stocks were at a relative performance level of 100% a month ago. NVIDIA's line will show an upward trend indicating growth, while Tesla's line will show a downward trend, indicating a decrease in stock value.\n", "\n", - "2. **Industry Trends:** The performance of a company's stock is also influenced by broader industry trends. For Nvidia, this might include the demand for GPUs for gaming, data centers, and AI applications. For Tesla, factors might include electric vehicle (EV) market trends, competition, and regulatory changes affecting the automotive industry.\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mResearcher\u001b[0m (to Research_manager):\n", "\n", - "3. **Economic Indicators:** General economic conditions, such as interest rates, inflation, and consumer spending, can impact stock performance. A growing economy might fuel investments in technology and innovation, benefiting companies like Nvidia and Tesla.\n", + "Given the performance of NVIDIA Corporation (NVDA) and Tesla, Inc. (TSLA) over the last month, let's calculate their stock prices at the beginning of the period. This will allow us to plot a graph showing the comparison of their stock prices over the past month.\n", "\n", - "4. **Technological Innovations:** Any groundbreaking technological advancements announced by either company could affect stock prices. For Nvidia, this might be related to advancements in AI, while for Tesla, innovations in battery technology or autonomous driving could be significant.\n", + "Step 1: Calculate the price one month ago based on the given performance percentage.\n", + "- For NVDA, with a current price of $878.37 and a performance increase of 20.97%, we can calculate its price a month ago.\n", + "- For TSLA, with a current price of $163.57 and a performance decrease of -18.19%, we can also calculate its price a month ago.\n", "\n", - "5. **Company-specific Factors:** Factors such as changes in leadership, legal issues, or supply chain disruptions could also impact the stock prices of Nvidia and Tesla.\n", + "Step 2: Plot a graph based on the calculated starting prices and the current prices. This will highlight how the stock prices have shifted over the past month.\n", "\n", - "I will now search the web for the most recent news and information related to Nvidia (NVDA) and Tesla (TSLA) that could shed light on their recent stock performance. This will include looking into financial news, industry-related updates, and any recent announcements made by the companies themselves.\n", + "First, let's calculate the starting prices for both NVDA and TSLA a month ago using Python. Then, we'll move on to plotting the graph in the next step.\n", "\n", "```python\n", - "# filename: fetch_news.py\n", - "import requests\n", - "from bs4 import BeautifulSoup\n", + "# Calculate starting prices one month ago based on given percentages\n", "\n", - "def search_news(company):\n", - " # Searching for news on Google News\n", - " url = f'https://www.google.com/search?q={company}+stock+news&tbm=nws'\n", - " response = requests.get(url)\n", - " soup = BeautifulSoup(response.text, 'html.parser')\n", - " # Looking for headlines\n", - " headlines = soup.find_all('div', {'class': 'BVG0Nb'})\n", - " links = soup.find_all('a', href=True)\n", - " news_items = []\n", - " for headline, link in zip(headlines, links):\n", - " news_items.append({'title': headline.text, 'link': link['href']})\n", - " return news_items[:5] # Returning the first 5 news items\n", - "\n", - "# Searching for news related to Nvidia and Tesla\n", - "nvidia_news = search_news('Nvidia Corporation NVDA')\n", - "tesla_news = search_news('Tesla Inc TSLA')\n", - "\n", - "# Printing out the news items\n", - "print('Nvidia Corporation (NVDA) Recent News:')\n", - "for news in nvidia_news:\n", - " print(f\"- {news['title']} {news['link']}\")\n", - "\n", - "print('\\nTesla, Inc. (TSLA) Recent News:')\n", - "for news in tesla_news:\n", - " print(f\"- {news['title']} {news['link']}\")\n", + "# NVDA details\n", + "nvda_current_price = 878.37\n", + "nvda_performance_increase = 20.97 # Percentage\n", + "\n", + "# TSLA details\n", + "tsla_current_price = 163.57\n", + "tsla_performance_decrease = -18.19 # Percentage\n", + "\n", + "# Calculate starting prices\n", + "nvda_starting_price = nvda_current_price / (1 + nvda_performance_increase / 100)\n", + "tsla_starting_price = tsla_current_price / (1 + tsla_performance_decrease / 100)\n", + "\n", + "# Print starting prices\n", + "print(f'NVIDIA Corporation (NVDA) starting price one month ago: ${nvda_starting_price:.2f}')\n", + "print(f'Tesla, Inc. (TSLA) starting price one month ago: ${tsla_starting_price:.2f}')\n", "```\n", "\n", - "Please execute the provided Python script to search for the latest news regarding Nvidia Corporation (NVDA) and Tesla, Inc. (TSLA). This will give us a starting point to understand the factors influencing their recent stock performance.\n", + "Please run the provided Python code to calculate and print the starting prices of NVDA and TSLA stocks one month ago. After that, we will proceed to plotting the graph.\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n", + "\u001b[33mUser_proxy\u001b[0m (to Research_manager):\n", + "\n", + "exitcode: 0 (execution succeeded)\n", + "Code output: \n", + "NVIDIA Corporation (NVDA) starting price one month ago: $726.11\n", + "Tesla, Inc. (TSLA) starting price one month ago: $199.94\n", + "\n", "\n", "--------------------------------------------------------------------------------\n", "\u001b[33mCritic\u001b[0m (to Research_manager):\n", "\n", - "The plan is logical and thorough, covering most essential factors that can affect the stock performance of Nvidia Corporation (NVDA) and Tesla, Inc. (TSLA). Here are a few feedback points and suggestions to ensure a comprehensive investigation:\n", + "With the calculated starting prices for NVIDIA Corporation (NVDA) and Tesla, Inc. (TSLA) a month ago being $726.11 and $199.94 respectively, and knowing their current prices, we can now plot a graph comparing the stock prices over the past month. This graph will visually depict the growth of NVDA and the decline of TSLA within the given period.\n", + "\n", + "Let's proceed with plotting this comparison using Python and matplotlib. The plot will use the starting and current prices to show the trajectory of both stocks over the past month.\n", "\n", - "1. **Execution Note:** Considering that the provided Python script uses web scraping to fetch the latest news from Google search results, it's important to note that this method might encounter challenges due to the dynamic nature of web content and potential anti-scraping measures. Users should ensure they are compliant with Google's Terms of Service and consider using official APIs for reliable data retrieval when possible.\n", + "```python\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# Stock prices one month ago\n", + "starting_prices = [726.11, 199.94]\n", + "# Current stock prices\n", + "current_prices = [878.37, 163.57]\n", "\n", - "2. **Financial Performance:** While the plan mentions looking into general market news and events, it's specifically crucial to analyze the companies' latest financial reports (quarterly/annually). Insights into revenue, profit margins, growth forecasts, and analyst ratings could provide a more concrete basis for understanding stock performance.\n", + "# Company names\n", + "companies = ['NVDA', 'TSLA']\n", "\n", - "3. **Comparison with Competitors:** Adding a comparative analysis of competitors within the same industries (e.g., AMD for Nvidia and Ford or Rivian for Tesla) could offer additional context. Performance might not only be due to internal factors but also how these companies are doing relative to their peers.\n", + "# Dates representing the timeline: '1 Month Ago' and 'Now'\n", + "dates = ['1 Month Ago', 'Now']\n", "\n", - "4. **Sentiment Analysis:** Analyzing investor sentiment, perhaps by looking at social media or investor forums, could give an idea of how market perceptions are influencing stock prices beyond just factual news.\n", + "# Plotting the stock prices over the past month\n", + "plt.figure(figsize=(10, 6))\n", + "for i in range(len(companies)):\n", + " plt.plot(dates, [starting_prices[i], current_prices[i]], label=companies[i], marker='o')\n", "\n", - "5. **Technological Roadmaps:** For companies like Nvidia and Tesla, where innovation is key, looking into their technology roadmaps or any patents they might have filed recently could provide insights into their future potential and how it's being valued by the market.\n", + "# Adding details to the plot\n", + "plt.title('NVDA vs TSLA Stock Prices Over the Past Month')\n", + "plt.ylabel('Stock Price ($)')\n", + "plt.legend()\n", + "plt.grid(True)\n", "\n", - "6. **Environmental, Social, and Governance (ESG) Factors:** With increasing attention on sustainable investing, ESG factors might also play a role in a company's stock performance. For Tesla, environmental factors might be particularly relevant.\n", + "# Show the plot\n", + "plt.show()\n", + "```\n", "\n", - "7. **Source Verification:** The plan mentions that the executed Python script will fetch the most recent news for analysis. It’s important to cross-verify the information obtained from the news with reliable sources or directly from the company’s announcements to ensure accuracy.\n", + "This code snippet will generate a line graph comparing the stock price movements of NVDA and TSLA over the past month, starting from the calculated values a month ago to their current values. The increasing trend for NVDA and the decreasing trend for TSLA over the specified timeline are expected to be clearly visible in this plot. \n", "\n", - "Following these suggestions, adjusting the plan for data reliability, and incorporating a broader analysis spectrum will likely yield a more comprehensive understanding of the stock performance for Nvidia and Tesla.\n", + "Ensure this code is executed in an environment where Python and matplotlib are installed to visualize the comparison effectively.\n", "\n", "TERMINATE\n", "\n", "--------------------------------------------------------------------------------\n", - "\u001b[34m\n", - "********************************************************************************\u001b[0m\n", - "\u001b[34mStart a new chat with the following message: \n", - "Develop an engaging blog post using any information provided.\n", + "\u001b[33mCritic\u001b[0m (to Research_manager):\n", + "\n", + "The calculated starting prices for NVIDIA Corporation (NVDA) and Tesla, Inc. (TSLA) one month ago are $726.11 and $199.94, respectively. Given these starting prices and the current prices ($878.37 for NVDA and $163.57 for TSLA), we can plot a graph to visually compare the stock price movement of these two companies over the past month.\n", + "\n", + "Now, using these starting and current prices, we will plot a graph to illustrate the price changes. The x-axis will represent the time interval (from '1 Month Ago' to 'Now'), and the y-axis will represent the stock prices in USD.\n", "\n", - "With the following carryover: \n", - "The execution of the provided Python code successfully fetched the current stock prices and the performance over the past month for Nvidia Corporation (NVDA) and Tesla, Inc. (TSLA). Here are the results:\n", + "```python\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# Time points\n", + "time_points = ['1 Month Ago', 'Now']\n", "\n", - "- **Nvidia Corporation (NVDA):**\n", - " - Current Price: $726.13\n", - " - Performance Over The Past Month: +21.72%\n", + "# Stock prices for NVDA\n", + "nvda_prices = [726.11, 878.37]\n", "\n", - "- **Tesla, Inc. (TSLA):**\n", - " - Current Price: $199.95\n", - " - Performance Over The Past Month: -4.24%\n", + "# Stock prices for TSLA\n", + "tsla_prices = [199.94, 163.57]\n", "\n", - "This data indicates that over the past month, NVDA's stock has seen a significant positive increase in its price, with a 21.72% rise, showcasing strong performance. On the other hand, TSLA's stock has experienced a slight decline, with a 4.24% decrease in its price.\n", + "# Plot for NVDA\n", + "plt.plot(time_points, nvda_prices, marker='o', label='NVDA')\n", "\n", - "These performance metrics can be useful for investors and traders to understand recent trends in these companies' stock values.\n", + "# Plot for TSLA\n", + "plt.plot(time_points, tsla_prices, marker='o', label='TSLA')\n", "\n", - "If you have any more questions or need further assistance, feel free to ask. Otherwise, we can conclude here.\n", + "# Adding title and labels\n", + "plt.title('Stock Price Comparison Over the Past Month')\n", + "plt.xlabel('Time')\n", + "plt.ylabel('Stock Price (USD)')\n", "\n", + "# Adding legend\n", + "plt.legend()\n", "\n", - "To investigate the stock performance of Nvidia Corporation (NVDA) and Tesla, Inc. (TSLA), it's recommended to consider market news, industry trends, economic indicators, and company-specific factors including technological innovations. The plan includes executing a Python script to fetch the latest news. Feedback emphasizes ensuring compliance with Google's Terms of Service, analyzing financial reports, comparing competitors, sentiment analysis, investigating technological roadmaps, considering ESG factors, and verifying sources for accuracy. This comprehensive approach, adjusting for data reliability and a broader analysis spectrum, will aid in understanding the reasons behind the stock performance of Nvidia and Tesla.\u001b[0m\n", + "# Showing the plot\n", + "plt.grid(True)\n", + "plt.show()\n", + "```\n", + "\n", + "Execute the above Python code to generate a line graph. This graph compares the stock price movements of NVIDIA (NVDA) and Tesla (TSLA) over the last month. The graph uses the starting prices as calculated based on the performance percentages previously provided and the current prices. It visually illustrates the price trends, showing NVDA's growth and TSLA's decline during the period.\n", + "\n", + "TERMINATE\n", + "\n", + "--------------------------------------------------------------------------------\n", "\u001b[34m\n", "********************************************************************************\u001b[0m\n", - "\u001b[33mUser\u001b[0m (to Writing_manager):\n", + "\u001b[34mStarting a new chat....\n", "\n", + "Message:\n", "Develop an engaging blog post using any information provided.\n", - "Context: \n", - "The execution of the provided Python code successfully fetched the current stock prices and the performance over the past month for Nvidia Corporation (NVDA) and Tesla, Inc. (TSLA). Here are the results:\n", "\n", - "- **Nvidia Corporation (NVDA):**\n", - " - Current Price: $726.13\n", - " - Performance Over The Past Month: +21.72%\n", + "Carryover: \n", + "The code execution was successful, and here are the results based on the output:\n", "\n", - "- **Tesla, Inc. (TSLA):**\n", - " - Current Price: $199.95\n", - " - Performance Over The Past Month: -4.24%\n", + "- **NVIDIA Corporation (NVDA)** has a current stock price of **$878.37**. Over the past month, NVDA has experienced a performance increase of **20.97%**.\n", + "- **Tesla, Inc. (TSLA)** has a current stock price of **$163.57**. Over the past month, TSLA has experienced a performance decrease of **-18.19%**.\n", "\n", - "This data indicates that over the past month, NVDA's stock has seen a significant positive increase in its price, with a 21.72% rise, showcasing strong performance. On the other hand, TSLA's stock has experienced a slight decline, with a 4.24% decrease in its price.\n", + "These figures provide a snapshot of how both companies have performed in the stock market over the last month, reflecting growth for NVIDIA and a decline for Tesla.\n", "\n", - "These performance metrics can be useful for investors and traders to understand recent trends in these companies' stock values.\n", "\n", - "If you have any more questions or need further assistance, feel free to ask. Otherwise, we can conclude here.\n", + "The conversation involved calculating the starting prices of NVIDIA Corporation (NVDA) and Tesla, Inc. (TSLA) stocks a month ago, based on their current prices and recent performance. NVDA's starting price was determined to be $726.11, considering a 20.97% increase to its current price of $878.37. TSLA's starting price was calculated at $199.94, given an 18.19% decrease to its current price of $163.57. The discussion then provided Python code for plotting a graph comparing the stock prices of NVDA and TSLA over the past month, highlighting NVDA's growth and TSLA's decline.\n", + "The conversation involved calculating the starting stock prices of NVIDIA Corporation (NVDA) and Tesla, Inc. (TSLA) a month ago based on their current prices and performance percentages. NVDA's starting price a month ago was calculated to be $726.11, considering a 20.97% increase to its current price of $878.37. TSLA's starting price was calculated to be $199.94, considering an 18.19% decrease to its current price of $163.57. Following the calculations, a Python script using matplotlib was provided to plot a graph comparing the stock prices of NVDA and TSLA over the past month, visually representing NVDA's growth and TSLA's decline.\u001b[0m\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[33mUser\u001b[0m (to Writing_manager):\n", "\n", + "Develop an engaging blog post using any information provided.\n", + "Context: \n", + "The code execution was successful, and here are the results based on the output:\n", "\n", - "To investigate the stock performance of Nvidia Corporation (NVDA) and Tesla, Inc. (TSLA), it's recommended to consider market news, industry trends, economic indicators, and company-specific factors including technological innovations. The plan includes executing a Python script to fetch the latest news. Feedback emphasizes ensuring compliance with Google's Terms of Service, analyzing financial reports, comparing competitors, sentiment analysis, investigating technological roadmaps, considering ESG factors, and verifying sources for accuracy. This comprehensive approach, adjusting for data reliability and a broader analysis spectrum, will aid in understanding the reasons behind the stock performance of Nvidia and Tesla.\n", + "- **NVIDIA Corporation (NVDA)** has a current stock price of **$878.37**. Over the past month, NVDA has experienced a performance increase of **20.97%**.\n", + "- **Tesla, Inc. (TSLA)** has a current stock price of **$163.57**. Over the past month, TSLA has experienced a performance decrease of **-18.19%**.\n", + "\n", + "These figures provide a snapshot of how both companies have performed in the stock market over the last month, reflecting growth for NVIDIA and a decline for Tesla.\n", + "\n", + "\n", + "The conversation involved calculating the starting prices of NVIDIA Corporation (NVDA) and Tesla, Inc. (TSLA) stocks a month ago, based on their current prices and recent performance. NVDA's starting price was determined to be $726.11, considering a 20.97% increase to its current price of $878.37. TSLA's starting price was calculated at $199.94, given an 18.19% decrease to its current price of $163.57. The discussion then provided Python code for plotting a graph comparing the stock prices of NVDA and TSLA over the past month, highlighting NVDA's growth and TSLA's decline.\n", + "The conversation involved calculating the starting stock prices of NVIDIA Corporation (NVDA) and Tesla, Inc. (TSLA) a month ago based on their current prices and performance percentages. NVDA's starting price a month ago was calculated to be $726.11, considering a 20.97% increase to its current price of $878.37. TSLA's starting price was calculated to be $199.94, considering an 18.19% decrease to its current price of $163.57. Following the calculations, a Python script using matplotlib was provided to plot a graph comparing the stock prices of NVDA and TSLA over the past month, visually representing NVDA's growth and TSLA's decline.\n", "\n", "--------------------------------------------------------------------------------\n", "\u001b[33mWriter\u001b[0m (to Writing_manager):\n", "\n", - "# Tech Titans in Turmoil? Deciphering the Divergent Paths of Nvidia and Tesla\n", + "# A Tale of Two Titans: NVIDIA and Tesla Navigate the Winds of the Stock Market\n", "\n", - "In the ever-dynamic world of technology stocks, recent market activities have drawn sharp attention to two behemoths: Nvidia Corporation (NVDA) and Tesla, Inc. (TSLA). With the execution of a specialized Python script, intriguing insights into their stock performances over the past month have emerged, revealing a fascinating divergence in their trajectory. Nvidia's stocks have surged, showcasing a robust growth of 21.72%, while Tesla has unexpectedly stumbled, recording a 4.24% decline in stock value. This unexpected dichotomy in the fortunes of two of Silicon Valley's most luminary companies offers a compelling case study into the undercurrents shaping the tech industry today.\n", + "In the grand theater of the stock market, two protagonists have captured the attention of investors and enthusiasts alike: NVIDIA Corporation (NVDA) and Tesla, Inc. (TSLA). Over the past month, these titans have navigated through turbulent financial seas, charting courses that veer in dramatically different directions. Today, we embark on an analytical voyage, exploring the performance of NVDA and TSLA through the lens of recent stock market trends.\n", "\n", - "## The Surge of Nvidia: Riding the Wave of Innovation\n", + "## The Surge of NVIDIA Corporation (NVDA)\n", "\n", - "Nvidia's impressive stock performance, ballooning by 21.72%, paints a picture of a company at the zenith of its powers. The secret to Nvidia's success could largely be attributed to its strategic positioning at the heart of burgeoning tech trends, including AI, machine learning, and gaming. Nvidia's GPUs are not only the \"engine\" behind gaming PCs but are also crucial for AI research and data centers, industries that have seen exponential growth in recent years.\n", + "At the helm of technological innovation stands NVIDIA, a behemoth renowned for its cutting-edge graphics processing units (GPUs). A beacon in the dark, NVIDIA's current stock price gleams at $878.37. This illuminating figure is the culmination of a staggering 20.97% upward surge over the past month, showcasing the company's robust growth and investor confidence.\n", "\n", - "Moreover, Nvidia's forward-looking approach and continuous innovation have cemented its status as a cornerstone in the tech space. Recent developments in AI and deep learning technologies, where Nvidia is a recognized leader, have further bolstered investor confidence. Their strategic partnerships and expansion into new, high-growth markets have likely contributed to their positive financial outlook, evident in the substantial stock price increase.\n", + "To grasp the magnitude of NVIDIA's ascent, let's journey back a month in time. The starting line for NVDA was drawn at $726.11. Through a blend of strategic maneuvers and market favorability, NVIDIA has sprinted towards financial growth, positioning itself as a juggernaut in the technology sector. The company's stellar performance could be attributed to several factors, from groundbreaking product releases to strategic partnerships that fortify its market presence.\n", "\n", - "## Tesla's Unanticipated Detour: A Bump in the Road?\n", + "## Tesla, Inc. (TSLA) Faces Headwinds\n", "\n", - "On the flip side, Tesla's slight retreat, with a 4.24% drop, poses intriguing questions about the underlying factors dampening investor enthusiasm. Tesla, under the visionary leadership of Elon Musk, has revolutionized the automotive industry, making electric vehicles (EVs) mainstream. Yet, even pioneers aren't immune to market forces and operational challenges.\n", + "Contrasting NVIDIA's euphoric climb, Tesla, the electric vehicle pioneer led by the enigmatic Elon Musk, has weathered a storm of challenges. With a current stock price of $163.57, TSLA has witnessed its share value recede by -18.19% over the last month.\n", "\n", - "Analysts might speculate that Tesla's decline could be attributed to a variety of factors, including production delays, competition heating up from legacy automakers venturing into the EV space, and perhaps geopolitical tensions affecting supply chains. Additionally, the broader market's sentiment, influenced by economic indicators and shifts in consumer behavior, may have played a role in Tesla's recent stock performance downturn.\n", + "Rewinding time to a month ago reveals a starting stock price of $199.94 for Tesla. This descent highlights the volatility and rugged terrain that Tesla has encountered. Factors ranging from production disruptions to regulatory hurdles, and perhaps the unpredictable musings of its CEO, might have contributed to this downtrend. Despite these obstacles, Tesla's foundational strength in innovation and its visionary approach to sustainable transportation continue to underpin its long-term value proposition.\n", "\n", - "## Beyond the Numbers: A Closer Look at the Forces at Play\n", + "## Charting the Course: A Visual Comparison\n", "\n", - "To truly comprehend the divergence in Nvidia's and Tesla's stock market performances, one must delve deeper beyond mere financial metrics. Exploring market news, industry trends, economic indicators, and company-specific dynamics offers richer context.\n", + "To visually navigate the contrasting trajectories of NVIDIA and Tesla, a Python script was employed, wielding the power of matplotlib to create a compelling graphical representation. This chart not only captures NVDA's impressive ascent and TSLA's decline but also offers a narrative of resilience, innovation, and the unpredictable nature of the stock market.\n", "\n", - "For Nvidia, its stride might be bolstered by advancements in technology and a robust product line catering to future needs. For Tesla, despite its recent dip, the long-term outlook remains positive, given its pioneering status and relentless pursuit of innovation.\n", + "The plotted graph serves as a testament to the dynamic and often unpredictable nature of investing. For NVIDIA, the upward trend signifies a period of growth and optimism, fueled by technological advancements and strategic success. On the flip side, Tesla's downward curve reflects the inherent risks and challenges faced by industry pioneers, underscored by market volatility and external pressures.\n", "\n", - "Inherent in the analysis of stock performances is the necessity to consider technological roadmaps, environmental, social, and governance (ESG) factors, and competitive landscapes. These components, combined with meticulous sentiment analysis and a keen eye on financial reports, provide a multidimensional view of Nvidia's and Tesla's market positions.\n", + "## Navigating Tomorrow's Horizon\n", "\n", - "## Looking Ahead: Charting the Course\n", + "As we stand at the crossroads of possibility, the journeys of NVIDIA and Tesla through the stock market's tumultuous waters shed light on the complexities of investing in technology giants. While NVIDIA rides the wave of growth, basking in the glow of success, Tesla navigates through stormy seas, bracing for the challenges that lie ahead.\n", "\n", - "As investors and enthusiasts keenly watch these unfolding narratives, the contrasting fortunes of Nvidia and Tesla underscore the volatile and unpredictable nature of the tech stock market. The journey ahead for both companies promises to be lined with opportunities and obstacles, making their stories not just a study of stock prices but a reflection of the broader technological and economic landscapes they operate within.\n", + "These tales of triumph and tribulation underscore a fundamental truth about the stock market: it is a realm of high stakes and high rewards, where fortune favors the brave and the visionary. As investors and spectators alike watch these titans chart their course, the future remains a canvas of endless possibilities, painted by the decisions, innovations, and resilience of companies like NVIDIA and Tesla.\n", "\n", - "Navigating this ever-evolving terrain requires a nuanced understanding of market dynamics, a commitment to innovation, and an unwavering focus on long-term value creation. As Nvidia and Tesla chart their paths forward, they not only shape their destinies but also the future of technology itself. Therefore, keeping a close watch on these titans' next moves becomes not just an interest but a necessity for those vested in the future of tech.\n", + "Let us then cling to our seats as we witness the unfolding saga of these industry giants, remembering that in the world of stocks, the only constant is change.\n", "\n", - "In the interplay of market forces, innovation, and strategic visions, the contrasting trajectories of Nvidia and Tesla present a nuanced narrative, ripe for exploration and reflection. As we advance, their stories remind us of the transformative power of technology and the endless possibilities that lie within the volatile realm of the stock market.\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mCritic\u001b[0m (to Writing_manager):\n", "\n", - "So, whether you're an investor, a tech enthusiast, or simply a curious observer, the unfolding saga of Nvidia and Tesla offers a captivating glimpse into the future of technology and finance, woven together in the complex tapestry of the stock market's highs and lows.\n", + "The blog post titled \"A Tale of Two Titans: NVIDIA and Tesla Navigate the Winds of the Stock Market\" adeptly captures the recent financial performances of NVIDIA Corporation (NVDA) and Tesla, Inc. (TSLA). Utilizing vivid storytelling and concise analysis, it provides readers with a clear understanding of the companies' trajectories over the past month. However, several elements can be enhanced further to improve clarity, accuracy, and engagement:\n", "\n", - "---\n", - "I hope you found this exploration into the fortunes of Nvidia and Tesla insightful and thought-provoking. Stay tuned for more analyses that bring the world of technology and finance to life in compelling narratives.\n", + "1. **Verification and Sources**: The post lacks external verification of the data presented. Including sources or referencing financial reports would significantly enhance credibility. It's recommended to hyperlink to authoritative financial news websites, stock analysis platforms, or directly to the companies' investor relations pages where readers can verify the stock price movements and company performances.\n", + "\n", + "2. **More In-depth Analysis**: While the post does an excellent job of painting the general picture of NVIDIA’s growth and Tesla’s decline, incorporating a deeper analysis would enrich the reader's understanding. Discussing the specific reasons behind NVIDIA's success, such as key product launches or capitalizing on market trends like AI and deep learning, would offer insights into its growth drivers. Similarly, exploring Tesla's challenges, like supply chain issues or global economic factors, would provide a more nuanced view.\n", + "\n", + "3. **Interactivity and Visuals**: Mentioning the use of Python and matplotlib for plotting stock price movements is excellent. However, including the actual graph within the blog post would significantly enhance its value, making the comparison between NVDA and TSLA visually accessible. If the blog format allows, embedding interactive charts where readers can hover over data points for more information would further increase engagement.\n", + "\n", + "4. **Future Outlook**: The concluding section intriguingly touches upon the uncertainties and opportunities ahead for both companies. Expanding this outlook by including expert predictions, potential market movements, or upcoming events that might influence these stocks (e.g., product launches, earnings reports) could offer readers valuable forward-looking insights.\n", + "\n", + "5. **Clarity and Brevity**: Overall, the narrative is engaging and creatively written. However, ensuring that every paragraph directly contributes to the reader's understanding of NVIDIA and Tesla's stock performance will help maintain focus and engagement. Avoiding overly complex sentences can also make the content more accessible to a broader audience.\n", + "\n", + "Incorporating these suggestions would not only bolster the article's informative value but also its appeal to readers seeking a blend of financial analysis and narrative storytelling.\n", "\n", "TERMINATE\n", "\n", @@ -1369,9 +1624,10 @@ { "data": { "text/plain": [ - "{1: ChatResult(chat_id=1, chat_history=[{'content': 'What are the current stock prices of NVDA and TESLA, and how is the performance over the past month in terms of percentage change?', 'role': 'assistant'}, {'content': 'To obtain the current stock prices of NVDA (Nvidia Corporation) and TSLA (Tesla, Inc.), as well as their performance over the past month in terms of percentage change, I will use Python code to fetch this information from a financial data API. For this task, we can use the Yahoo Finance API through the `yfinance` library, which allows us to collect stock information programmatically.\\n\\nHere is the plan:\\n1. Use Python code to access the required stock data via the `yfinance` library.\\n2. Fetch the current prices of NVDA and TSLA.\\n3. Calculate the percentage change in their stock prices over the past month.\\n\\nFirst, you\\'ll need to ensure that the `yfinance` library is installed. If it\\'s not already installed, you can install it using pip. Execute the following Python code to perform the tasks:\\n\\n```python\\n# filename: stock_info.py\\n\\nimport yfinance as yf\\nfrom datetime import datetime, timedelta\\n\\n# Define the tickers for Nvidia and Tesla\\ntickers = [\"NVDA\", \"TSLA\"]\\n\\n# Define the time period: end date is today, start date is one month ago\\nend_date = datetime.today()\\nstart_date = end_date - timedelta(days=30)\\n\\n# Function to fetch and display stock info\\ndef fetch_and_display_info(ticker):\\n stock = yf.Ticker(ticker)\\n \\n # Fetch historical data for the past month\\n hist = stock.history(start=start_date, end=end_date)\\n \\n # Get the last closing price (most recent date)\\n last_close_price = hist[\\'Close\\'].iloc[-1]\\n \\n # Calculate the percentage change over the past month\\n start_price = hist[\\'Close\\'].iloc[0] # First day\\'s closing price in the hist data\\n percentage_change = ((last_close_price - start_price) / start_price) * 100\\n \\n print(f\"{ticker} Current Price: ${last_close_price:.2f}\")\\n print(f\"{ticker} Performance Over The Past Month: {percentage_change:.2f}%\\\\n\")\\n\\n# Fetch and display info for each ticker\\nfor ticker in tickers:\\n fetch_and_display_info(ticker)\\n```\\n\\nPlease save the above code in a file named `stock_info.py` and execute it. This script will output the current prices of NVDA and TSLA, along with the percentage changes in their stock prices over the past month.\\n\\nIf you encounter any issues or have any questions regarding the execution or results, please let me know!', 'role': 'user'}, {'content': 'exitcode: 0 (execution succeeded)\\nCode output: \\nNVDA Current Price: $726.13\\nNVDA Performance Over The Past Month: 21.72%\\n\\nTSLA Current Price: $199.95\\nTSLA Performance Over The Past Month: -4.24%\\n\\n', 'role': 'assistant'}, {'content': \"The execution of the provided Python code successfully fetched the current stock prices and the performance over the past month for Nvidia Corporation (NVDA) and Tesla, Inc. (TSLA). Here are the results:\\n\\n- **Nvidia Corporation (NVDA):**\\n - Current Price: $726.13\\n - Performance Over The Past Month: +21.72%\\n\\n- **Tesla, Inc. (TSLA):**\\n - Current Price: $199.95\\n - Performance Over The Past Month: -4.24%\\n\\nThis data indicates that over the past month, NVDA's stock has seen a significant positive increase in its price, with a 21.72% rise, showcasing strong performance. On the other hand, TSLA's stock has experienced a slight decline, with a 4.24% decrease in its price.\\n\\nThese performance metrics can be useful for investors and traders to understand recent trends in these companies' stock values.\\n\\nIf you have any more questions or need further assistance, feel free to ask. Otherwise, we can conclude here.\\n\\nTERMINATE\", 'role': 'user'}], summary=\"The execution of the provided Python code successfully fetched the current stock prices and the performance over the past month for Nvidia Corporation (NVDA) and Tesla, Inc. (TSLA). Here are the results:\\n\\n- **Nvidia Corporation (NVDA):**\\n - Current Price: $726.13\\n - Performance Over The Past Month: +21.72%\\n\\n- **Tesla, Inc. (TSLA):**\\n - Current Price: $199.95\\n - Performance Over The Past Month: -4.24%\\n\\nThis data indicates that over the past month, NVDA's stock has seen a significant positive increase in its price, with a 21.72% rise, showcasing strong performance. On the other hand, TSLA's stock has experienced a slight decline, with a 4.24% decrease in its price.\\n\\nThese performance metrics can be useful for investors and traders to understand recent trends in these companies' stock values.\\n\\nIf you have any more questions or need further assistance, feel free to ask. Otherwise, we can conclude here.\\n\\n\", cost=({'total_cost': 0.038180000000000006, 'gpt-4-0125-preview': {'cost': 0.038180000000000006, 'prompt_tokens': 1592, 'completion_tokens': 742, 'total_tokens': 2334}}, {'total_cost': 0.038180000000000006, 'gpt-4-0125-preview': {'cost': 0.038180000000000006, 'prompt_tokens': 1592, 'completion_tokens': 742, 'total_tokens': 2334}}), human_input=[]),\n", - " 2: ChatResult(chat_id=2, chat_history=[{'content': \"Investigate possible reasons of the stock performance.\\nContext: \\nThe execution of the provided Python code successfully fetched the current stock prices and the performance over the past month for Nvidia Corporation (NVDA) and Tesla, Inc. (TSLA). Here are the results:\\n\\n- **Nvidia Corporation (NVDA):**\\n - Current Price: $726.13\\n - Performance Over The Past Month: +21.72%\\n\\n- **Tesla, Inc. (TSLA):**\\n - Current Price: $199.95\\n - Performance Over The Past Month: -4.24%\\n\\nThis data indicates that over the past month, NVDA's stock has seen a significant positive increase in its price, with a 21.72% rise, showcasing strong performance. On the other hand, TSLA's stock has experienced a slight decline, with a 4.24% decrease in its price.\\n\\nThese performance metrics can be useful for investors and traders to understand recent trends in these companies' stock values.\\n\\nIf you have any more questions or need further assistance, feel free to ask. Otherwise, we can conclude here.\\n\\n\", 'role': 'assistant'}], summary=\"To investigate the stock performance of Nvidia Corporation (NVDA) and Tesla, Inc. (TSLA), it's recommended to consider market news, industry trends, economic indicators, and company-specific factors including technological innovations. The plan includes executing a Python script to fetch the latest news. Feedback emphasizes ensuring compliance with Google's Terms of Service, analyzing financial reports, comparing competitors, sentiment analysis, investigating technological roadmaps, considering ESG factors, and verifying sources for accuracy. This comprehensive approach, adjusting for data reliability and a broader analysis spectrum, will aid in understanding the reasons behind the stock performance of Nvidia and Tesla.\", cost=({'total_cost': 0.03351, 'gpt-4-0125-preview': {'cost': 0.03351, 'prompt_tokens': 2970, 'completion_tokens': 127, 'total_tokens': 3097}}, {'total_cost': 0.03351, 'gpt-4-0125-preview': {'cost': 0.03351, 'prompt_tokens': 2970, 'completion_tokens': 127, 'total_tokens': 3097}}), human_input=[]),\n", - " 3: ChatResult(chat_id=3, chat_history=[{'content': \"Develop an engaging blog post using any information provided.\\nContext: \\nThe execution of the provided Python code successfully fetched the current stock prices and the performance over the past month for Nvidia Corporation (NVDA) and Tesla, Inc. (TSLA). Here are the results:\\n\\n- **Nvidia Corporation (NVDA):**\\n - Current Price: $726.13\\n - Performance Over The Past Month: +21.72%\\n\\n- **Tesla, Inc. (TSLA):**\\n - Current Price: $199.95\\n - Performance Over The Past Month: -4.24%\\n\\nThis data indicates that over the past month, NVDA's stock has seen a significant positive increase in its price, with a 21.72% rise, showcasing strong performance. On the other hand, TSLA's stock has experienced a slight decline, with a 4.24% decrease in its price.\\n\\nThese performance metrics can be useful for investors and traders to understand recent trends in these companies' stock values.\\n\\nIf you have any more questions or need further assistance, feel free to ask. Otherwise, we can conclude here.\\n\\n\\nTo investigate the stock performance of Nvidia Corporation (NVDA) and Tesla, Inc. (TSLA), it's recommended to consider market news, industry trends, economic indicators, and company-specific factors including technological innovations. The plan includes executing a Python script to fetch the latest news. Feedback emphasizes ensuring compliance with Google's Terms of Service, analyzing financial reports, comparing competitors, sentiment analysis, investigating technological roadmaps, considering ESG factors, and verifying sources for accuracy. This comprehensive approach, adjusting for data reliability and a broader analysis spectrum, will aid in understanding the reasons behind the stock performance of Nvidia and Tesla.\", 'role': 'assistant'}], summary=\"Develop an engaging blog post using any information provided.\\nContext: \\nThe execution of the provided Python code successfully fetched the current stock prices and the performance over the past month for Nvidia Corporation (NVDA) and Tesla, Inc. (TSLA). Here are the results:\\n\\n- **Nvidia Corporation (NVDA):**\\n - Current Price: $726.13\\n - Performance Over The Past Month: +21.72%\\n\\n- **Tesla, Inc. (TSLA):**\\n - Current Price: $199.95\\n - Performance Over The Past Month: -4.24%\\n\\nThis data indicates that over the past month, NVDA's stock has seen a significant positive increase in its price, with a 21.72% rise, showcasing strong performance. On the other hand, TSLA's stock has experienced a slight decline, with a 4.24% decrease in its price.\\n\\nThese performance metrics can be useful for investors and traders to understand recent trends in these companies' stock values.\\n\\nIf you have any more questions or need further assistance, feel free to ask. Otherwise, we can conclude here.\\n\\n\\nTo investigate the stock performance of Nvidia Corporation (NVDA) and Tesla, Inc. (TSLA), it's recommended to consider market news, industry trends, economic indicators, and company-specific factors including technological innovations. The plan includes executing a Python script to fetch the latest news. Feedback emphasizes ensuring compliance with Google's Terms of Service, analyzing financial reports, comparing competitors, sentiment analysis, investigating technological roadmaps, considering ESG factors, and verifying sources for accuracy. This comprehensive approach, adjusting for data reliability and a broader analysis spectrum, will aid in understanding the reasons behind the stock performance of Nvidia and Tesla.\", cost=({'total_cost': 0.0058200000000000005, 'gpt-4-0125-preview': {'cost': 0.0058200000000000005, 'prompt_tokens': 579, 'completion_tokens': 1, 'total_tokens': 580}}, {'total_cost': 0.0058200000000000005, 'gpt-4-0125-preview': {'cost': 0.0058200000000000005, 'prompt_tokens': 579, 'completion_tokens': 1, 'total_tokens': 580}}), human_input=[])}" + "{1: ChatResult(chat_id=1, chat_history=[{'content': 'What are the current stock prices of NVDA and TESLA, and how is the performance over the past month in terms of percentage change?', 'role': 'assistant'}, {'content': 'To obtain current stock prices of NVDA (NVIDIA Corporation) and TSLA (Tesla, Inc.), and calculate their performance over the past month in terms of percentage change, we can use the Yahoo Finance API through the `yfinance` Python package. This process involves the following steps:\\n\\n1. Install the `yfinance` package (if not already installed).\\n2. Use `yfinance` to fetch the current stock prices of NVDA and TSLA.\\n3. Fetch historical data for the past month for both stocks.\\n4. Calculate the percentage change in the stock prices over the last month based on the historical data.\\n\\nPlease execute the following Python code to perform these tasks:\\n\\n```python\\n# filename: stock_info.py\\nimport yfinance as yf\\nfrom datetime import datetime, timedelta\\n\\ndef stock_performance(ticker):\\n # Fetching data for the past month\\n end_date = datetime.today()\\n start_date = end_date - timedelta(days=30) # Approximate for the past month\\n \\n # Fetch historical data\\n data = yf.download(ticker, start=start_date, end=end_date)\\n \\n # Current and beginning of month prices\\n current_price = data[\\'Close\\'].iloc[-1]\\n start_month_price = data[\\'Close\\'].iloc[0] \\n \\n # Calculate percentage change over the month\\n percent_change = ((current_price - start_month_price) / start_month_price) * 100\\n \\n return current_price, percent_change\\n\\n# NVDA and TSLA stock performance\\nnvda_price, nvda_change = stock_performance(\"NVDA\")\\ntsla_price, tsla_change = stock_performance(\"TSLA\")\\n\\nprint(f\"NVDA (NVIDIA Corp) current price: ${nvda_price:.2f}, Performance over past month: {nvda_change:.2f}%\")\\nprint(f\"TSLA (Tesla, Inc.) current price: ${tsla_price:.2f}, Performance over past month: {tsla_change:.2f}%\")\\n```\\n\\nBefore running this script, ensure that you have the `yfinance` package installed. If not, install it using the following command:\\n\\n```sh\\npip install yfinance\\n```\\n\\nThis script will output the current stock prices of NVDA and TSLA, along with their performance over the past month in percentage terms.', 'role': 'user'}, {'content': 'exitcode: 0 (execution succeeded)\\nCode output: \\nNVDA (NVIDIA Corp) current price: $878.37, Performance over past month: 20.97%\\nTSLA (Tesla, Inc.) current price: $163.57, Performance over past month: -18.19%\\n\\nDefaulting to user installation because normal site-packages is not writeable\\nRequirement already satisfied: yfinance in /home/autogen/.local/lib/python3.11/site-packages (0.2.37)\\nRequirement already satisfied: pandas>=1.3.0 in /home/autogen/.local/lib/python3.11/site-packages (from yfinance) (2.2.1)\\nRequirement already satisfied: numpy>=1.16.5 in /usr/local/lib/python3.11/site-packages (from yfinance) (1.26.4)\\nRequirement already satisfied: requests>=2.31 in /usr/local/lib/python3.11/site-packages (from yfinance) (2.31.0)\\nRequirement already satisfied: multitasking>=0.0.7 in /home/autogen/.local/lib/python3.11/site-packages (from yfinance) (0.0.11)\\nRequirement already satisfied: lxml>=4.9.1 in /home/autogen/.local/lib/python3.11/site-packages (from yfinance) (5.1.0)\\nRequirement already satisfied: appdirs>=1.4.4 in /home/autogen/.local/lib/python3.11/site-packages (from yfinance) (1.4.4)\\nRequirement already satisfied: pytz>=2022.5 in /home/autogen/.local/lib/python3.11/site-packages (from yfinance) (2024.1)\\nRequirement already satisfied: frozendict>=2.3.4 in /home/autogen/.local/lib/python3.11/site-packages (from yfinance) (2.4.0)\\nRequirement already satisfied: peewee>=3.16.2 in /home/autogen/.local/lib/python3.11/site-packages (from yfinance) (3.17.1)\\nRequirement already satisfied: beautifulsoup4>=4.11.1 in /usr/local/lib/python3.11/site-packages (from yfinance) (4.12.3)\\nRequirement already satisfied: html5lib>=1.1 in /home/autogen/.local/lib/python3.11/site-packages (from yfinance) (1.1)\\nRequirement already satisfied: soupsieve>1.2 in /usr/local/lib/python3.11/site-packages (from beautifulsoup4>=4.11.1->yfinance) (2.5)\\nRequirement already satisfied: six>=1.9 in /usr/local/lib/python3.11/site-packages (from html5lib>=1.1->yfinance) (1.16.0)\\nRequirement already satisfied: webencodings in /usr/local/lib/python3.11/site-packages (from html5lib>=1.1->yfinance) (0.5.1)\\nRequirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.11/site-packages (from pandas>=1.3.0->yfinance) (2.9.0.post0)\\nRequirement already satisfied: tzdata>=2022.7 in /home/autogen/.local/lib/python3.11/site-packages (from pandas>=1.3.0->yfinance) (2024.1)\\nRequirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.11/site-packages (from requests>=2.31->yfinance) (3.3.2)\\nRequirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.11/site-packages (from requests>=2.31->yfinance) (3.6)\\nRequirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.11/site-packages (from requests>=2.31->yfinance) (2.2.1)\\nRequirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.11/site-packages (from requests>=2.31->yfinance) (2024.2.2)\\n', 'role': 'assistant'}, {'content': 'The code execution was successful, and here are the results based on the output:\\n\\n- **NVIDIA Corporation (NVDA)** has a current stock price of **$878.37**. Over the past month, NVDA has experienced a performance increase of **20.97%**.\\n- **Tesla, Inc. (TSLA)** has a current stock price of **$163.57**. Over the past month, TSLA has experienced a performance decrease of **-18.19%**.\\n\\nThese figures provide a snapshot of how both companies have performed in the stock market over the last month, reflecting growth for NVIDIA and a decline for Tesla.\\n\\nTERMINATE', 'role': 'user'}], summary='The code execution was successful, and here are the results based on the output:\\n\\n- **NVIDIA Corporation (NVDA)** has a current stock price of **$878.37**. Over the past month, NVDA has experienced a performance increase of **20.97%**.\\n- **Tesla, Inc. (TSLA)** has a current stock price of **$163.57**. Over the past month, TSLA has experienced a performance decrease of **-18.19%**.\\n\\nThese figures provide a snapshot of how both companies have performed in the stock market over the last month, reflecting growth for NVIDIA and a decline for Tesla.\\n\\n', cost=({'total_cost': 0.04235, 'gpt-4-0125-preview': {'cost': 0.04235, 'prompt_tokens': 2384, 'completion_tokens': 617, 'total_tokens': 3001}}, {'total_cost': 0}), human_input=[]),\n", + " 2: ChatResult(chat_id=2, chat_history=[{'content': 'Plot a graph comparing the stock prices over the past month.\\nContext: \\nThe code execution was successful, and here are the results based on the output:\\n\\n- **NVIDIA Corporation (NVDA)** has a current stock price of **$878.37**. Over the past month, NVDA has experienced a performance increase of **20.97%**.\\n- **Tesla, Inc. (TSLA)** has a current stock price of **$163.57**. Over the past month, TSLA has experienced a performance decrease of **-18.19%**.\\n\\nThese figures provide a snapshot of how both companies have performed in the stock market over the last month, reflecting growth for NVIDIA and a decline for Tesla.\\n\\n', 'role': 'assistant'}], summary=\"The conversation involved calculating the starting prices of NVIDIA Corporation (NVDA) and Tesla, Inc. (TSLA) stocks a month ago, based on their current prices and recent performance. NVDA's starting price was determined to be $726.11, considering a 20.97% increase to its current price of $878.37. TSLA's starting price was calculated at $199.94, given an 18.19% decrease to its current price of $163.57. The discussion then provided Python code for plotting a graph comparing the stock prices of NVDA and TSLA over the past month, highlighting NVDA's growth and TSLA's decline.\", cost=({'total_cost': 0.08263999999999999, 'gpt-4-0125-preview': {'cost': 0.08263999999999999, 'prompt_tokens': 7367, 'completion_tokens': 299, 'total_tokens': 7666}}, {'total_cost': 0.08263999999999999, 'gpt-4-0125-preview': {'cost': 0.08263999999999999, 'prompt_tokens': 7367, 'completion_tokens': 299, 'total_tokens': 7666}}), human_input=[]),\n", + " 3: ChatResult(chat_id=3, chat_history=[{'content': 'Plot a graph comparing the stock prices over the past month.\\nContext: \\nThe code execution was successful, and here are the results based on the output:\\n\\n- **NVIDIA Corporation (NVDA)** has a current stock price of **$878.37**. Over the past month, NVDA has experienced a performance increase of **20.97%**.\\n- **Tesla, Inc. (TSLA)** has a current stock price of **$163.57**. Over the past month, TSLA has experienced a performance decrease of **-18.19%**.\\n\\nThese figures provide a snapshot of how both companies have performed in the stock market over the last month, reflecting growth for NVIDIA and a decline for Tesla.\\n\\n', 'role': 'assistant'}], summary=\"The conversation involved calculating the starting stock prices of NVIDIA Corporation (NVDA) and Tesla, Inc. (TSLA) a month ago based on their current prices and performance percentages. NVDA's starting price a month ago was calculated to be $726.11, considering a 20.97% increase to its current price of $878.37. TSLA's starting price was calculated to be $199.94, considering an 18.19% decrease to its current price of $163.57. Following the calculations, a Python script using matplotlib was provided to plot a graph comparing the stock prices of NVDA and TSLA over the past month, visually representing NVDA's growth and TSLA's decline.\", cost=({'total_cost': 0.0596, 'gpt-4-0125-preview': {'cost': 0.0596, 'prompt_tokens': 5483, 'completion_tokens': 159, 'total_tokens': 5642}}, {'total_cost': 0.0596, 'gpt-4-0125-preview': {'cost': 0.0596, 'prompt_tokens': 5483, 'completion_tokens': 159, 'total_tokens': 5642}}), human_input=[]),\n", + " 4: ChatResult(chat_id=4, chat_history=[{'content': \"Develop an engaging blog post using any information provided.\\nContext: \\nThe code execution was successful, and here are the results based on the output:\\n\\n- **NVIDIA Corporation (NVDA)** has a current stock price of **$878.37**. Over the past month, NVDA has experienced a performance increase of **20.97%**.\\n- **Tesla, Inc. (TSLA)** has a current stock price of **$163.57**. Over the past month, TSLA has experienced a performance decrease of **-18.19%**.\\n\\nThese figures provide a snapshot of how both companies have performed in the stock market over the last month, reflecting growth for NVIDIA and a decline for Tesla.\\n\\n\\nThe conversation involved calculating the starting prices of NVIDIA Corporation (NVDA) and Tesla, Inc. (TSLA) stocks a month ago, based on their current prices and recent performance. NVDA's starting price was determined to be $726.11, considering a 20.97% increase to its current price of $878.37. TSLA's starting price was calculated at $199.94, given an 18.19% decrease to its current price of $163.57. The discussion then provided Python code for plotting a graph comparing the stock prices of NVDA and TSLA over the past month, highlighting NVDA's growth and TSLA's decline.\\nThe conversation involved calculating the starting stock prices of NVIDIA Corporation (NVDA) and Tesla, Inc. (TSLA) a month ago based on their current prices and performance percentages. NVDA's starting price a month ago was calculated to be $726.11, considering a 20.97% increase to its current price of $878.37. TSLA's starting price was calculated to be $199.94, considering an 18.19% decrease to its current price of $163.57. Following the calculations, a Python script using matplotlib was provided to plot a graph comparing the stock prices of NVDA and TSLA over the past month, visually representing NVDA's growth and TSLA's decline.\", 'role': 'assistant'}], summary=\"Develop an engaging blog post using any information provided.\\nContext: \\nThe code execution was successful, and here are the results based on the output:\\n\\n- **NVIDIA Corporation (NVDA)** has a current stock price of **$878.37**. Over the past month, NVDA has experienced a performance increase of **20.97%**.\\n- **Tesla, Inc. (TSLA)** has a current stock price of **$163.57**. Over the past month, TSLA has experienced a performance decrease of **-18.19%**.\\n\\nThese figures provide a snapshot of how both companies have performed in the stock market over the last month, reflecting growth for NVIDIA and a decline for Tesla.\\n\\n\\nThe conversation involved calculating the starting prices of NVIDIA Corporation (NVDA) and Tesla, Inc. (TSLA) stocks a month ago, based on their current prices and recent performance. NVDA's starting price was determined to be $726.11, considering a 20.97% increase to its current price of $878.37. TSLA's starting price was calculated at $199.94, given an 18.19% decrease to its current price of $163.57. The discussion then provided Python code for plotting a graph comparing the stock prices of NVDA and TSLA over the past month, highlighting NVDA's growth and TSLA's decline.\\nThe conversation involved calculating the starting stock prices of NVIDIA Corporation (NVDA) and Tesla, Inc. (TSLA) a month ago based on their current prices and performance percentages. NVDA's starting price a month ago was calculated to be $726.11, considering a 20.97% increase to its current price of $878.37. TSLA's starting price was calculated to be $199.94, considering an 18.19% decrease to its current price of $163.57. Following the calculations, a Python script using matplotlib was provided to plot a graph comparing the stock prices of NVDA and TSLA over the past month, visually representing NVDA's growth and TSLA's decline.\", cost=({'total_cost': 0.02109, 'gpt-4-0125-preview': {'cost': 0.02109, 'prompt_tokens': 2100, 'completion_tokens': 3, 'total_tokens': 2103}}, {'total_cost': 0.02109, 'gpt-4-0125-preview': {'cost': 0.02109, 'prompt_tokens': 2100, 'completion_tokens': 3, 'total_tokens': 2103}}), human_input=[])}" ] }, "execution_count": 8, @@ -1479,8 +1735,10 @@ ], "metadata": { "front_matter": { - "tags": ["sequential chat"], - "description": "Use conversational agents to solve a set of tasks with a sequence of async chats." + "description": "Use conversational agents to solve a set of tasks with a sequence of async chats.", + "tags": [ + "sequential chat" + ] }, "kernelspec": { "display_name": "Python 3", diff --git a/notebook/agentchat_nested_sequential_chats.ipynb b/notebook/agentchat_nested_sequential_chats.ipynb new file mode 100644 index 00000000000..2f591c2530a --- /dev/null +++ b/notebook/agentchat_nested_sequential_chats.ipynb @@ -0,0 +1,1210 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "# Solving Complex Tasks with A Sequence of Nested Chats\n", + "\n", + "This notebook shows how you can leverage **nested chats** to solve complex task with AutoGen. Nested chats is a sequence of chats created by a receiver agent after receiving a message from a sender agent and finished before the receiver agent replies to this message. Nested chats allow AutoGen agents to use other agents as their inner monologue to accomplish tasks. This abstraction is powerful as it allows you to compose agents in rich ways. This notebook shows how you can nest a pretty complex sequence of chats among _inner_ agents inside an _outer_ agent.\n", + "\n", + "\\:\\:\\:info Requirements\n", + "\n", + "Install `pyautogen`:\n", + "```bash\n", + "pip install pyautogen\n", + "```\n", + "\n", + "For more information, please refer to the [installation guide](/docs/installation/).\n", + "\n", + "\\:\\:\\:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import autogen\n", + "\n", + "config_list = autogen.config_list_from_json(env_or_file=\"OAI_CONFIG_LIST\")\n", + "llm_config = {\"config_list\": config_list}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\\:\\:\\:tip\n", + "\n", + "Learn more about the various ways to configure LLM endpoints [here](/docs/topics/llm_configuration).\n", + "\n", + "\\:\\:\\:" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Example Task\n", + "\n", + "Suppose we want the agents to complete the following sequence of tasks:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "tasks = [\n", + " \"\"\"On which days in 2024 was Microsoft Stock higher than $400? Comment on the stock performance.\"\"\",\n", + " \"\"\"Make a pleasant joke about it.\"\"\",\n", + "]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Since the first task could be complex to solve, lets construct new agents that can serve as an inner monologue.\n", + "\n", + "### Step 1. Define Agents\n", + "\n", + "#### A Group Chat for Inner Monologue\n", + "Below, we construct a group chat manager which manages an `inner_assistant` agent and an `inner_code_interpreter` agent. \n", + "Later we will use this group chat inside another agent.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "inner_assistant = autogen.AssistantAgent(\n", + " \"Inner-assistant\",\n", + " llm_config=llm_config,\n", + " is_termination_msg=lambda x: x.get(\"content\", \"\").find(\"TERMINATE\") >= 0,\n", + ")\n", + "\n", + "inner_code_interpreter = autogen.UserProxyAgent(\n", + " \"Inner-code-interpreter\",\n", + " human_input_mode=\"NEVER\",\n", + " code_execution_config={\n", + " \"work_dir\": \"coding\",\n", + " \"use_docker\": False,\n", + " },\n", + " default_auto_reply=\"\",\n", + " is_termination_msg=lambda x: x.get(\"content\", \"\").find(\"TERMINATE\") >= 0,\n", + ")\n", + "\n", + "groupchat = autogen.GroupChat(\n", + " agents=[inner_assistant, inner_code_interpreter],\n", + " messages=[],\n", + " speaker_selection_method=\"round_robin\", # With two agents, this is equivalent to a 1:1 conversation.\n", + " allow_repeat_speaker=False,\n", + " max_round=8,\n", + ")\n", + "\n", + "manager = autogen.GroupChatManager(\n", + " groupchat=groupchat,\n", + " is_termination_msg=lambda x: x.get(\"content\", \"\").find(\"TERMINATE\") >= 0,\n", + " llm_config=llm_config,\n", + " code_execution_config={\n", + " \"work_dir\": \"coding\",\n", + " \"use_docker\": False,\n", + " },\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Inner- and Outer-Level Individual Agents\n", + "\n", + "Now we will construct a number of individual agents that will assume role of outer and inner agents." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "assistant_1 = autogen.AssistantAgent(\n", + " name=\"Assistant_1\",\n", + " llm_config={\"config_list\": config_list},\n", + ")\n", + "\n", + "assistant_2 = autogen.AssistantAgent(\n", + " name=\"Assistant_2\",\n", + " llm_config={\"config_list\": config_list},\n", + ")\n", + "\n", + "writer = autogen.AssistantAgent(\n", + " name=\"Writer\",\n", + " llm_config={\"config_list\": config_list},\n", + " system_message=\"\"\"\n", + " You are a professional writer, known for\n", + " your insightful and engaging articles.\n", + " You transform complex concepts into compelling narratives.\n", + " \"\"\",\n", + ")\n", + "\n", + "reviewer = autogen.AssistantAgent(\n", + " name=\"Reviewer\",\n", + " llm_config={\"config_list\": config_list},\n", + " system_message=\"\"\"\n", + " You are a compliance reviewer, known for your thoroughness and commitment to standards.\n", + " Your task is to scrutinize content for any harmful elements or regulatory violations, ensuring\n", + " all materials align with required guidelines.\n", + " You must review carefully, identify potential issues, and maintain the integrity of the organization.\n", + " Your role demands fairness, a deep understanding of regulations, and a focus on protecting against\n", + " harm while upholding a culture of responsibility.\n", + " \"\"\",\n", + ")\n", + "\n", + "user = autogen.UserProxyAgent(\n", + " name=\"User\",\n", + " human_input_mode=\"NEVER\",\n", + " is_termination_msg=lambda x: x.get(\"content\", \"\").find(\"TERMINATE\") >= 0,\n", + " code_execution_config={\n", + " \"last_n_messages\": 1,\n", + " \"work_dir\": \"tasks\",\n", + " \"use_docker\": False,\n", + " }, # Please set use_docker=True if docker is available to run the generated code. Using docker is safer than running the generated code directly.\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Step 2: Orchestrate Nested Chats to Solve Tasks\n", + "\n", + "#### Outer Level\n", + "In the following code block, at the outer level, we have communication between:\n", + "\n", + "- `user` - `assistant_1` for solving the first task, i.e., `tasks[0]`.\n", + "- `user` - `assistant_2` for solving the second task, i.e., `tasks[1]`.\n", + "\n", + "#### Inner Level (Nested Chats)\n", + "Since the first task is quite complicated, we created a sequence of _nested chats_ as the inner monologue of Assistant_1.\n", + "\n", + "1. `assistant_1` - `manager`: This chat intends to delegate the task received by Assistant_1 to the Manager to solve.\n", + "\n", + "2. `assistant_1` - `writer`: This chat takes the output from Nested Chat 1, i.e., Assistant_1 vs. Manager, and lets the Writer polish the content to make an engaging and nicely formatted blog post, which is realized through the writing_message function.\n", + "\n", + "3. `assistant_1` - `reviewer`: This chat takes the output from Nested Chat 2 and intends to let the Reviewer agent review the content from Nested Chat 2.\n", + "\n", + "4. `assistant_1` - `writer`: This chat takes the output from previous nested chats and intends to let the Writer agent finalize a blog post.\n", + "\n", + "The sequence of nested chats can be realized with the `register_nested_chats` function, which allows one to register one or a sequence of chats to a particular agent (in this example, the `assistant_1` agent).\n", + "\n", + "Information about the sequence of chats can be specified in the `chat_queue` argument of the `register_nested_chats` function. The following fields are especially useful:\n", + "- `recipient` (required) specifies the nested agent;\n", + "- `message` specifies what message to send to the nested recipient agent. In a sequence of nested chats, if the `message` field is not specified, we will use the last message the registering agent received as the initial message in the first chat and will skip any subsequent chat in the queue that does not have the `message` field. You can either provide a string or define a callable that returns a string.\n", + "- `summary_method` decides what to get out of the nested chat. You can either select from existing options including `\"last_msg\"` and `\"reflection_with_llm\"`, or or define your own way on what to get from the nested chat with a Callable.\n", + "- `max_turns` determines how many turns of conversation to have between the concerned agent pairs." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[34mStart a new chat with the following message: \n", + "On which days in 2024 was Microsoft Stock higher than $400? Comment on the stock performance.\n", + "\n", + "With the following carryover: \n", + "\u001b[0m\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[33mUser\u001b[0m (to Assistant_1):\n", + "\n", + "On which days in 2024 was Microsoft Stock higher than $400? Comment on the stock performance.\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[34mStart a new chat with the following message: \n", + "On which days in 2024 was Microsoft Stock higher than $400? Comment on the stock performance.\n", + "\n", + "With the following carryover: \n", + "\u001b[0m\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[33mAssistant_1\u001b[0m (to chat_manager):\n", + "\n", + "On which days in 2024 was Microsoft Stock higher than $400? Comment on the stock performance.\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mInner-assistant\u001b[0m (to chat_manager):\n", + "\n", + "To find out on which specific days Microsoft's stock (ticker symbol: MSFT) closed above $400 in 2024, we will need to access historical stock price data for Microsoft from a reliable financial data source. This kind of data is typically available on financial websites such as Yahoo Finance, Google Finance, or through financial data APIs such as Alpha Vantage or IEX Cloud.\n", + "\n", + "Since I cannot directly browse the web or access external APIs, I will provide you with a Python script that uses the `yfinance` library to fetch historical stock data for Microsoft and filter the dates when the stock price was higher than $400.\n", + "\n", + "Firstly, you need to install the `yfinance` module if it's not already installed. You can do so using pip by executing `pip install yfinance` in your shell.\n", + "\n", + "After installation, here is the Python code that you can execute to fetch the data and filter the specific dates:\n", + "\n", + "```python\n", + "# filename: msft_stock_analysis.py\n", + "import yfinance as yf\n", + "from datetime import datetime\n", + "\n", + "# Define the ticker symbol for Microsoft\n", + "ticker_symbol = \"MSFT\"\n", + "\n", + "# Fetch historical stock data for Microsoft for the year 2024\n", + "start_date = \"2024-01-01\"\n", + "end_date = \"2024-12-31\"\n", + "msft_data = yf.download(ticker_symbol, start=start_date, end=end_date)\n", + "\n", + "# Filter the days when the closing price was higher than $400\n", + "days_above_400 = msft_data[msft_data['Close'] > 400]\n", + "\n", + "# Print the dates and closing prices on those dates\n", + "print(\"Dates when Microsoft's stock closed above $400 in 2024:\")\n", + "print(days_above_400[['Close']])\n", + "\n", + "# Comment on the stock performance\n", + "if not days_above_400.empty:\n", + " days_count = len(days_above_400)\n", + " print(f\"\\nMicrosoft's stock closed above $400 on {days_count} days in 2024.\")\n", + "else:\n", + " print(\"\\nMicrosoft's stock did not close above $400 on any day in 2024.\")\n", + "```\n", + "\n", + "Please save the above code to a file named `msft_stock_analysis.py` and run it. This will print out the dates when Microsoft's stock was higher than $400 in 2024 and comment on the stock performance based on the results. \n", + "\n", + "Keep in mind that the `yfinance` library fetches real-time data, and since we are in 2023, data for 2024 is not available yet. Therefore, when you run the script, it will show that the stock did not close above $400, which is expected since 2024 has not occurred yet. For actual analysis, you would have to run the script after the end of 2024 or modify the date range to a past range where data is available.\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/qingyunwu/Documents/github/autogen/autogen/agentchat/chat.py:46: UserWarning: Repetitive recipients detected: The chat history will be cleared by default if a recipient appears more than once. To retain the chat history, please set 'clear_history=False' in the configuration of the repeating agent.\n", + " warnings.warn(\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[33mInner-code-interpreter\u001b[0m (to chat_manager):\n", + "\n", + "exitcode: 0 (execution succeeded)\n", + "Code output: \n", + "Dates when Microsoft's stock closed above $400 in 2024:\n", + " Close\n", + "Date \n", + "2024-01-24 402.559998\n", + "2024-01-25 404.869995\n", + "2024-01-26 403.929993\n", + "2024-01-29 409.720001\n", + "2024-01-30 408.589996\n", + "2024-02-01 403.779999\n", + "2024-02-02 411.220001\n", + "2024-02-05 405.649994\n", + "2024-02-06 405.489990\n", + "2024-02-07 414.049988\n", + "2024-02-08 414.109985\n", + "2024-02-09 420.549988\n", + "2024-02-12 415.260010\n", + "2024-02-13 406.320007\n", + "2024-02-14 409.489990\n", + "2024-02-15 406.559998\n", + "2024-02-16 404.059998\n", + "2024-02-20 402.790009\n", + "2024-02-21 402.179993\n", + "2024-02-22 411.649994\n", + "2024-02-23 410.339996\n", + "\n", + "Microsoft's stock closed above $400 on 21 days in 2024.\n", + "\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mInner-assistant\u001b[0m (to chat_manager):\n", + "\n", + "Based on the output from the code execution, Microsoft's stock (MSFT) closed above $400 on 21 separate days in 2024. The closing prices on those days ranged from slightly above $400 to highs around $420. This indicates periods of strong performance, during which the stock reached significant value.\n", + "\n", + "Here is a brief comment on the stock performance:\n", + "\n", + "The data shows that Microsoft's stock had several instances where it exceeded the $400 mark in early 2024, with notable peaks in February, which suggests a bullish trend during that period. Specific days like February 9th, where the stock hit around $420, indicate particularly strong performance.\n", + "\n", + "Having such a number of days with closing prices above $400 signals a robust market valuation for Microsoft at those times. Investors who held the stock on these dates may have seen appreciable gains, depending on their portfolio strategies.\n", + "\n", + "It's also noteworthy that stock prices fluctuate due to a variety of factors, including market sentiment, company performance, industry trends, and general economic conditions. This data provides a snapshot of Microsoft's stock performance but a deeper analysis would require more context on the market conditions, news, and events surrounding these dates.\n", + "\n", + "TERMINATE\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[34mStart a new chat with the following message: \n", + "Polish the content to make an engaging and nicely formatted blog post. \n", + "\n", + " On which days in 2024 was Microsoft Stock higher than $400? Comment on the stock performance.\n", + "\n", + "With the following carryover: \n", + "Microsoft's stock (MSFT) closed above $400 on 21 separate days in 2024, demonstrating periods of strong stock performance with values reaching as high as around $420. The stock data suggests a bullish trend, especially in February when the stock peaked, indicating positive investor sentiment and robust market valuation during those times.\u001b[0m\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[33mAssistant_1\u001b[0m (to Writer):\n", + "\n", + "Polish the content to make an engaging and nicely formatted blog post. \n", + "\n", + " On which days in 2024 was Microsoft Stock higher than $400? Comment on the stock performance.\n", + "Context: \n", + "Microsoft's stock (MSFT) closed above $400 on 21 separate days in 2024, demonstrating periods of strong stock performance with values reaching as high as around $420. The stock data suggests a bullish trend, especially in February when the stock peaked, indicating positive investor sentiment and robust market valuation during those times.\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mWriter\u001b[0m (to Assistant_1):\n", + "\n", + "# Beyond the $400 Mark: Tracing Microsoft's Pinnacle Moments in 2024\n", + "\n", + "In the ever-fluctuating world of stocks, each milestone crossed can turn into a celebration or a stern reckoning of what the future holds. For Microsoft (MSFT), the year 2024 was a testament to its resilience and investor confidence as its stock ascended beyond the coveted $400 mark on 21 remarkable occasions.\n", + "\n", + "This performance wasn't just numerically significant; it was emblematic of a potent bullish energy within the market, affirming the tech giant’s leviathan presence amidst a highly competitive industry terrain. The loftiest point, flirting with the heights of approximately $420, served not just as a numerical peak, but as a beacon of the company’s market valuation and the unwavering investor trust in Microsoft's strategies and future prospects.\n", + "\n", + "## A Snapshot of Stellar Performance\n", + "\n", + "Microsoft's stock performance throughout 2024 was far from being a serendipitous spike. Instead, it showcased a carefully constructed narrative of growth and optimism. The chronicles of MSFT's venture past the $400 threshold are marked by fleeting dips and steadfast ascensions. Remarkably, the surge wasn't some scattergun pattern scattered across the calendar year. Rather, it was most pronounced in the month of February — a period that could very well be termed as the 'February Flourish.'\n", + "\n", + "During this short yet significant timeframe, investors witnessed the creation of incremental wealth that possibly outstripped all market expectations, setting a precedent for what a legacy company like Microsoft could achieve in a climate rife with disruptors and innovators.\n", + "\n", + "## Of Peaks and Valleys\n", + "\n", + "When assessing the grand canvas of Microsoft's stock performance, it is crucial to take a step back and appreciate the layered complexity of these financial movements. Amidst economic uncertainties and the technocratic whims that habitually serve both as tailwinds and headwinds to such companies, the story of Microsoft crossing the $400 threshold imbues the narrative with contours of investor euphoria interlaced with strategic agility.\n", + "\n", + "As these 21 days get etched into the fiscal annals of Microsoft, one cannot help but ponder the fine blend of factors — ranging from market dynamics to Microsoft's organizational maneuvers — that have coalesced to make these numbers a reality.\n", + "\n", + "## A Convergence of Positive Sentiments\n", + "\n", + "What does the future hold for MSFT as it treads past this impressive benchmark? The takeaway is not a simple extrapolation of past performance. Rather, it's the realization that stock trajectories, particularly for a company like Microsoft, are a confluence of judicious corporate governance, product innovation, market anticipation, and, dare we say, a touch of the zeitgeist.\n", + "\n", + "Microsoft’s capacity to command such stock valitudes speaks volumes about its robust position in both the technology domain and the stock market ecosystem. Whether this fiscal feat can be sustained or surpassed remains a subject of much conjecture and anticipation.\n", + "\n", + "As we continue to navigate the ebbs and flows of an unpredictable market landscape, the days when Microsoft's stock rose gallantly above $400 will be recalled as milestones of 2024, celebrated reflections of a corporation sailing the high seas of market volatility with remarkable poise.\n", + "\n", + "The analysis of precise data points and enlightening interpretations reveal much about the past while providing distinctive glimpses of potential futures. With Microsoft standing tall amongst peers, its voyage above the $400 watermark will be chronicled as days of high tides in the annals of financial history.\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[34mStart a new chat with the following message: \n", + "Review the content provided.\n", + "\n", + "With the following carryover: \n", + "Microsoft's stock (MSFT) closed above $400 on 21 separate days in 2024, demonstrating periods of strong stock performance with values reaching as high as around $420. The stock data suggests a bullish trend, especially in February when the stock peaked, indicating positive investor sentiment and robust market valuation during those times.\n", + "# Beyond the $400 Mark: Tracing Microsoft's Pinnacle Moments in 2024\n", + "\n", + "In the ever-fluctuating world of stocks, each milestone crossed can turn into a celebration or a stern reckoning of what the future holds. For Microsoft (MSFT), the year 2024 was a testament to its resilience and investor confidence as its stock ascended beyond the coveted $400 mark on 21 remarkable occasions.\n", + "\n", + "This performance wasn't just numerically significant; it was emblematic of a potent bullish energy within the market, affirming the tech giant’s leviathan presence amidst a highly competitive industry terrain. The loftiest point, flirting with the heights of approximately $420, served not just as a numerical peak, but as a beacon of the company’s market valuation and the unwavering investor trust in Microsoft's strategies and future prospects.\n", + "\n", + "## A Snapshot of Stellar Performance\n", + "\n", + "Microsoft's stock performance throughout 2024 was far from being a serendipitous spike. Instead, it showcased a carefully constructed narrative of growth and optimism. The chronicles of MSFT's venture past the $400 threshold are marked by fleeting dips and steadfast ascensions. Remarkably, the surge wasn't some scattergun pattern scattered across the calendar year. Rather, it was most pronounced in the month of February — a period that could very well be termed as the 'February Flourish.'\n", + "\n", + "During this short yet significant timeframe, investors witnessed the creation of incremental wealth that possibly outstripped all market expectations, setting a precedent for what a legacy company like Microsoft could achieve in a climate rife with disruptors and innovators.\n", + "\n", + "## Of Peaks and Valleys\n", + "\n", + "When assessing the grand canvas of Microsoft's stock performance, it is crucial to take a step back and appreciate the layered complexity of these financial movements. Amidst economic uncertainties and the technocratic whims that habitually serve both as tailwinds and headwinds to such companies, the story of Microsoft crossing the $400 threshold imbues the narrative with contours of investor euphoria interlaced with strategic agility.\n", + "\n", + "As these 21 days get etched into the fiscal annals of Microsoft, one cannot help but ponder the fine blend of factors — ranging from market dynamics to Microsoft's organizational maneuvers — that have coalesced to make these numbers a reality.\n", + "\n", + "## A Convergence of Positive Sentiments\n", + "\n", + "What does the future hold for MSFT as it treads past this impressive benchmark? The takeaway is not a simple extrapolation of past performance. Rather, it's the realization that stock trajectories, particularly for a company like Microsoft, are a confluence of judicious corporate governance, product innovation, market anticipation, and, dare we say, a touch of the zeitgeist.\n", + "\n", + "Microsoft’s capacity to command such stock valitudes speaks volumes about its robust position in both the technology domain and the stock market ecosystem. Whether this fiscal feat can be sustained or surpassed remains a subject of much conjecture and anticipation.\n", + "\n", + "As we continue to navigate the ebbs and flows of an unpredictable market landscape, the days when Microsoft's stock rose gallantly above $400 will be recalled as milestones of 2024, celebrated reflections of a corporation sailing the high seas of market volatility with remarkable poise.\n", + "\n", + "The analysis of precise data points and enlightening interpretations reveal much about the past while providing distinctive glimpses of potential futures. With Microsoft standing tall amongst peers, its voyage above the $400 watermark will be chronicled as days of high tides in the annals of financial history.\u001b[0m\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[33mAssistant_1\u001b[0m (to Reviewer):\n", + "\n", + "Review the content provided.\n", + "Context: \n", + "Microsoft's stock (MSFT) closed above $400 on 21 separate days in 2024, demonstrating periods of strong stock performance with values reaching as high as around $420. The stock data suggests a bullish trend, especially in February when the stock peaked, indicating positive investor sentiment and robust market valuation during those times.\n", + "# Beyond the $400 Mark: Tracing Microsoft's Pinnacle Moments in 2024\n", + "\n", + "In the ever-fluctuating world of stocks, each milestone crossed can turn into a celebration or a stern reckoning of what the future holds. For Microsoft (MSFT), the year 2024 was a testament to its resilience and investor confidence as its stock ascended beyond the coveted $400 mark on 21 remarkable occasions.\n", + "\n", + "This performance wasn't just numerically significant; it was emblematic of a potent bullish energy within the market, affirming the tech giant’s leviathan presence amidst a highly competitive industry terrain. The loftiest point, flirting with the heights of approximately $420, served not just as a numerical peak, but as a beacon of the company’s market valuation and the unwavering investor trust in Microsoft's strategies and future prospects.\n", + "\n", + "## A Snapshot of Stellar Performance\n", + "\n", + "Microsoft's stock performance throughout 2024 was far from being a serendipitous spike. Instead, it showcased a carefully constructed narrative of growth and optimism. The chronicles of MSFT's venture past the $400 threshold are marked by fleeting dips and steadfast ascensions. Remarkably, the surge wasn't some scattergun pattern scattered across the calendar year. Rather, it was most pronounced in the month of February — a period that could very well be termed as the 'February Flourish.'\n", + "\n", + "During this short yet significant timeframe, investors witnessed the creation of incremental wealth that possibly outstripped all market expectations, setting a precedent for what a legacy company like Microsoft could achieve in a climate rife with disruptors and innovators.\n", + "\n", + "## Of Peaks and Valleys\n", + "\n", + "When assessing the grand canvas of Microsoft's stock performance, it is crucial to take a step back and appreciate the layered complexity of these financial movements. Amidst economic uncertainties and the technocratic whims that habitually serve both as tailwinds and headwinds to such companies, the story of Microsoft crossing the $400 threshold imbues the narrative with contours of investor euphoria interlaced with strategic agility.\n", + "\n", + "As these 21 days get etched into the fiscal annals of Microsoft, one cannot help but ponder the fine blend of factors — ranging from market dynamics to Microsoft's organizational maneuvers — that have coalesced to make these numbers a reality.\n", + "\n", + "## A Convergence of Positive Sentiments\n", + "\n", + "What does the future hold for MSFT as it treads past this impressive benchmark? The takeaway is not a simple extrapolation of past performance. Rather, it's the realization that stock trajectories, particularly for a company like Microsoft, are a confluence of judicious corporate governance, product innovation, market anticipation, and, dare we say, a touch of the zeitgeist.\n", + "\n", + "Microsoft’s capacity to command such stock valitudes speaks volumes about its robust position in both the technology domain and the stock market ecosystem. Whether this fiscal feat can be sustained or surpassed remains a subject of much conjecture and anticipation.\n", + "\n", + "As we continue to navigate the ebbs and flows of an unpredictable market landscape, the days when Microsoft's stock rose gallantly above $400 will be recalled as milestones of 2024, celebrated reflections of a corporation sailing the high seas of market volatility with remarkable poise.\n", + "\n", + "The analysis of precise data points and enlightening interpretations reveal much about the past while providing distinctive glimpses of potential futures. With Microsoft standing tall amongst peers, its voyage above the $400 watermark will be chronicled as days of high tides in the annals of financial history.\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mReviewer\u001b[0m (to Assistant_1):\n", + "\n", + "The content provided serves as a market commentary, analyzing Microsoft's stock performance in the year 2024. In this review, I must ensure that the content is free from harmful elements, false claims, or regulatory violations.\n", + "\n", + "### Potential issues to consider:\n", + "\n", + "1. **Accuracy of Data**: Claims about stock prices and the number of days the stock closed above a certain threshold should be verifiable with stock market data. There must be confirmation that these numbers are accurate to present a truthful report and avoid misleading investors or stakeholders.\n", + "\n", + "2. **Forward-Looking Statements**: The article should avoid overly optimistic or pessimistic conjectures about future stock performance, which can be perceived as investment advice. Speculative statements should be clearly marked as such and provide a disclaimer that past performance does not guarantee future results.\n", + "\n", + "3. **Fair and Balanced**: While the article largely celebrates Microsoft's performance, it should also acknowledge risks and uncertainties inherent in stock investments to maintain a fair and balanced approach without unduly influencing market sentiment.\n", + "\n", + "4. **Non-Promotional Language**: Ensure that the content doesn't come off as promotional. Phrases like \"Microsoft's resilience and investor confidence\" and \"celebrated reflections of a corporation sailing the high seas of market volatility with remarkable poise\" should be reviewed to avoid appearing biased or overly promotional.\n", + "\n", + "5. **Compliance with SEC Regulations**: In the United States, Securities and Exchange Commission (SEC) regulations require careful communication about stock performance to avoid market manipulation, insider trading implications, or misstatements.\n", + "\n", + "6. **Objective Tone**: While the narrative is engaging, it's important that it remains objective and does not use language that could be considered subjective or biased. Phrases like \"Microsoft’s leviathan presence\" or \"February Flourish\" might be interpreted as adding emotional color rather than stating facts.\n", + "\n", + "7. **Clear Attribution**: If the report is based on external analyses or reported events, these should be clearly cited and attributed to maintain transparency.\n", + "\n", + "### Recommendations:\n", + "\n", + "- **Fact-Checking**: Verify all factual data through reliable stock market databases or financial reports released by Microsoft.\n", + " \n", + "- **Disclaimer**: Include a general disclaimer that the content is for informational purposes only and is not a form of financial advice or an inducement to invest.\n", + "\n", + "- **Balanced Analysis**: Emphasize the volatile nature of stock markets and integrate a risk-focused discussion to balance the positive sentiment conveyed.\n", + "\n", + "- **Neutral Language**: Adjust language to ensure neutrality and avoid any implications of advice or recommendation.\n", + "\n", + "In conclusion, while the content presents a positive overview of Microsoft's stock performance, it requires scrutiny for accuracy, neutrality, and conformance with regulatory standards, avoiding the potential of guiding market behavior or conveying investment advice. A careful revision ensuring these changes would align the material with the required guidelines and uphold the integrity of the content.\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[34mStart a new chat with the following message: \n", + "Polish the content to make an engaging and nicely formatted blog post. \n", + "\n", + " On which days in 2024 was Microsoft Stock higher than $400? Comment on the stock performance.\n", + "\n", + "With the following carryover: \n", + "Microsoft's stock (MSFT) closed above $400 on 21 separate days in 2024, demonstrating periods of strong stock performance with values reaching as high as around $420. The stock data suggests a bullish trend, especially in February when the stock peaked, indicating positive investor sentiment and robust market valuation during those times.\n", + "# Beyond the $400 Mark: Tracing Microsoft's Pinnacle Moments in 2024\n", + "\n", + "In the ever-fluctuating world of stocks, each milestone crossed can turn into a celebration or a stern reckoning of what the future holds. For Microsoft (MSFT), the year 2024 was a testament to its resilience and investor confidence as its stock ascended beyond the coveted $400 mark on 21 remarkable occasions.\n", + "\n", + "This performance wasn't just numerically significant; it was emblematic of a potent bullish energy within the market, affirming the tech giant’s leviathan presence amidst a highly competitive industry terrain. The loftiest point, flirting with the heights of approximately $420, served not just as a numerical peak, but as a beacon of the company’s market valuation and the unwavering investor trust in Microsoft's strategies and future prospects.\n", + "\n", + "## A Snapshot of Stellar Performance\n", + "\n", + "Microsoft's stock performance throughout 2024 was far from being a serendipitous spike. Instead, it showcased a carefully constructed narrative of growth and optimism. The chronicles of MSFT's venture past the $400 threshold are marked by fleeting dips and steadfast ascensions. Remarkably, the surge wasn't some scattergun pattern scattered across the calendar year. Rather, it was most pronounced in the month of February — a period that could very well be termed as the 'February Flourish.'\n", + "\n", + "During this short yet significant timeframe, investors witnessed the creation of incremental wealth that possibly outstripped all market expectations, setting a precedent for what a legacy company like Microsoft could achieve in a climate rife with disruptors and innovators.\n", + "\n", + "## Of Peaks and Valleys\n", + "\n", + "When assessing the grand canvas of Microsoft's stock performance, it is crucial to take a step back and appreciate the layered complexity of these financial movements. Amidst economic uncertainties and the technocratic whims that habitually serve both as tailwinds and headwinds to such companies, the story of Microsoft crossing the $400 threshold imbues the narrative with contours of investor euphoria interlaced with strategic agility.\n", + "\n", + "As these 21 days get etched into the fiscal annals of Microsoft, one cannot help but ponder the fine blend of factors — ranging from market dynamics to Microsoft's organizational maneuvers — that have coalesced to make these numbers a reality.\n", + "\n", + "## A Convergence of Positive Sentiments\n", + "\n", + "What does the future hold for MSFT as it treads past this impressive benchmark? The takeaway is not a simple extrapolation of past performance. Rather, it's the realization that stock trajectories, particularly for a company like Microsoft, are a confluence of judicious corporate governance, product innovation, market anticipation, and, dare we say, a touch of the zeitgeist.\n", + "\n", + "Microsoft’s capacity to command such stock valitudes speaks volumes about its robust position in both the technology domain and the stock market ecosystem. Whether this fiscal feat can be sustained or surpassed remains a subject of much conjecture and anticipation.\n", + "\n", + "As we continue to navigate the ebbs and flows of an unpredictable market landscape, the days when Microsoft's stock rose gallantly above $400 will be recalled as milestones of 2024, celebrated reflections of a corporation sailing the high seas of market volatility with remarkable poise.\n", + "\n", + "The analysis of precise data points and enlightening interpretations reveal much about the past while providing distinctive glimpses of potential futures. With Microsoft standing tall amongst peers, its voyage above the $400 watermark will be chronicled as days of high tides in the annals of financial history.\n", + "The content provided serves as a market commentary, analyzing Microsoft's stock performance in the year 2024. In this review, I must ensure that the content is free from harmful elements, false claims, or regulatory violations.\n", + "\n", + "### Potential issues to consider:\n", + "\n", + "1. **Accuracy of Data**: Claims about stock prices and the number of days the stock closed above a certain threshold should be verifiable with stock market data. There must be confirmation that these numbers are accurate to present a truthful report and avoid misleading investors or stakeholders.\n", + "\n", + "2. **Forward-Looking Statements**: The article should avoid overly optimistic or pessimistic conjectures about future stock performance, which can be perceived as investment advice. Speculative statements should be clearly marked as such and provide a disclaimer that past performance does not guarantee future results.\n", + "\n", + "3. **Fair and Balanced**: While the article largely celebrates Microsoft's performance, it should also acknowledge risks and uncertainties inherent in stock investments to maintain a fair and balanced approach without unduly influencing market sentiment.\n", + "\n", + "4. **Non-Promotional Language**: Ensure that the content doesn't come off as promotional. Phrases like \"Microsoft's resilience and investor confidence\" and \"celebrated reflections of a corporation sailing the high seas of market volatility with remarkable poise\" should be reviewed to avoid appearing biased or overly promotional.\n", + "\n", + "5. **Compliance with SEC Regulations**: In the United States, Securities and Exchange Commission (SEC) regulations require careful communication about stock performance to avoid market manipulation, insider trading implications, or misstatements.\n", + "\n", + "6. **Objective Tone**: While the narrative is engaging, it's important that it remains objective and does not use language that could be considered subjective or biased. Phrases like \"Microsoft’s leviathan presence\" or \"February Flourish\" might be interpreted as adding emotional color rather than stating facts.\n", + "\n", + "7. **Clear Attribution**: If the report is based on external analyses or reported events, these should be clearly cited and attributed to maintain transparency.\n", + "\n", + "### Recommendations:\n", + "\n", + "- **Fact-Checking**: Verify all factual data through reliable stock market databases or financial reports released by Microsoft.\n", + " \n", + "- **Disclaimer**: Include a general disclaimer that the content is for informational purposes only and is not a form of financial advice or an inducement to invest.\n", + "\n", + "- **Balanced Analysis**: Emphasize the volatile nature of stock markets and integrate a risk-focused discussion to balance the positive sentiment conveyed.\n", + "\n", + "- **Neutral Language**: Adjust language to ensure neutrality and avoid any implications of advice or recommendation.\n", + "\n", + "In conclusion, while the content presents a positive overview of Microsoft's stock performance, it requires scrutiny for accuracy, neutrality, and conformance with regulatory standards, avoiding the potential of guiding market behavior or conveying investment advice. A careful revision ensuring these changes would align the material with the required guidelines and uphold the integrity of the content.\u001b[0m\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[33mAssistant_1\u001b[0m (to Writer):\n", + "\n", + "Polish the content to make an engaging and nicely formatted blog post. \n", + "\n", + " On which days in 2024 was Microsoft Stock higher than $400? Comment on the stock performance.\n", + "Context: \n", + "Microsoft's stock (MSFT) closed above $400 on 21 separate days in 2024, demonstrating periods of strong stock performance with values reaching as high as around $420. The stock data suggests a bullish trend, especially in February when the stock peaked, indicating positive investor sentiment and robust market valuation during those times.\n", + "# Beyond the $400 Mark: Tracing Microsoft's Pinnacle Moments in 2024\n", + "\n", + "In the ever-fluctuating world of stocks, each milestone crossed can turn into a celebration or a stern reckoning of what the future holds. For Microsoft (MSFT), the year 2024 was a testament to its resilience and investor confidence as its stock ascended beyond the coveted $400 mark on 21 remarkable occasions.\n", + "\n", + "This performance wasn't just numerically significant; it was emblematic of a potent bullish energy within the market, affirming the tech giant’s leviathan presence amidst a highly competitive industry terrain. The loftiest point, flirting with the heights of approximately $420, served not just as a numerical peak, but as a beacon of the company’s market valuation and the unwavering investor trust in Microsoft's strategies and future prospects.\n", + "\n", + "## A Snapshot of Stellar Performance\n", + "\n", + "Microsoft's stock performance throughout 2024 was far from being a serendipitous spike. Instead, it showcased a carefully constructed narrative of growth and optimism. The chronicles of MSFT's venture past the $400 threshold are marked by fleeting dips and steadfast ascensions. Remarkably, the surge wasn't some scattergun pattern scattered across the calendar year. Rather, it was most pronounced in the month of February — a period that could very well be termed as the 'February Flourish.'\n", + "\n", + "During this short yet significant timeframe, investors witnessed the creation of incremental wealth that possibly outstripped all market expectations, setting a precedent for what a legacy company like Microsoft could achieve in a climate rife with disruptors and innovators.\n", + "\n", + "## Of Peaks and Valleys\n", + "\n", + "When assessing the grand canvas of Microsoft's stock performance, it is crucial to take a step back and appreciate the layered complexity of these financial movements. Amidst economic uncertainties and the technocratic whims that habitually serve both as tailwinds and headwinds to such companies, the story of Microsoft crossing the $400 threshold imbues the narrative with contours of investor euphoria interlaced with strategic agility.\n", + "\n", + "As these 21 days get etched into the fiscal annals of Microsoft, one cannot help but ponder the fine blend of factors — ranging from market dynamics to Microsoft's organizational maneuvers — that have coalesced to make these numbers a reality.\n", + "\n", + "## A Convergence of Positive Sentiments\n", + "\n", + "What does the future hold for MSFT as it treads past this impressive benchmark? The takeaway is not a simple extrapolation of past performance. Rather, it's the realization that stock trajectories, particularly for a company like Microsoft, are a confluence of judicious corporate governance, product innovation, market anticipation, and, dare we say, a touch of the zeitgeist.\n", + "\n", + "Microsoft’s capacity to command such stock valitudes speaks volumes about its robust position in both the technology domain and the stock market ecosystem. Whether this fiscal feat can be sustained or surpassed remains a subject of much conjecture and anticipation.\n", + "\n", + "As we continue to navigate the ebbs and flows of an unpredictable market landscape, the days when Microsoft's stock rose gallantly above $400 will be recalled as milestones of 2024, celebrated reflections of a corporation sailing the high seas of market volatility with remarkable poise.\n", + "\n", + "The analysis of precise data points and enlightening interpretations reveal much about the past while providing distinctive glimpses of potential futures. With Microsoft standing tall amongst peers, its voyage above the $400 watermark will be chronicled as days of high tides in the annals of financial history.\n", + "The content provided serves as a market commentary, analyzing Microsoft's stock performance in the year 2024. In this review, I must ensure that the content is free from harmful elements, false claims, or regulatory violations.\n", + "\n", + "### Potential issues to consider:\n", + "\n", + "1. **Accuracy of Data**: Claims about stock prices and the number of days the stock closed above a certain threshold should be verifiable with stock market data. There must be confirmation that these numbers are accurate to present a truthful report and avoid misleading investors or stakeholders.\n", + "\n", + "2. **Forward-Looking Statements**: The article should avoid overly optimistic or pessimistic conjectures about future stock performance, which can be perceived as investment advice. Speculative statements should be clearly marked as such and provide a disclaimer that past performance does not guarantee future results.\n", + "\n", + "3. **Fair and Balanced**: While the article largely celebrates Microsoft's performance, it should also acknowledge risks and uncertainties inherent in stock investments to maintain a fair and balanced approach without unduly influencing market sentiment.\n", + "\n", + "4. **Non-Promotional Language**: Ensure that the content doesn't come off as promotional. Phrases like \"Microsoft's resilience and investor confidence\" and \"celebrated reflections of a corporation sailing the high seas of market volatility with remarkable poise\" should be reviewed to avoid appearing biased or overly promotional.\n", + "\n", + "5. **Compliance with SEC Regulations**: In the United States, Securities and Exchange Commission (SEC) regulations require careful communication about stock performance to avoid market manipulation, insider trading implications, or misstatements.\n", + "\n", + "6. **Objective Tone**: While the narrative is engaging, it's important that it remains objective and does not use language that could be considered subjective or biased. Phrases like \"Microsoft’s leviathan presence\" or \"February Flourish\" might be interpreted as adding emotional color rather than stating facts.\n", + "\n", + "7. **Clear Attribution**: If the report is based on external analyses or reported events, these should be clearly cited and attributed to maintain transparency.\n", + "\n", + "### Recommendations:\n", + "\n", + "- **Fact-Checking**: Verify all factual data through reliable stock market databases or financial reports released by Microsoft.\n", + " \n", + "- **Disclaimer**: Include a general disclaimer that the content is for informational purposes only and is not a form of financial advice or an inducement to invest.\n", + "\n", + "- **Balanced Analysis**: Emphasize the volatile nature of stock markets and integrate a risk-focused discussion to balance the positive sentiment conveyed.\n", + "\n", + "- **Neutral Language**: Adjust language to ensure neutrality and avoid any implications of advice or recommendation.\n", + "\n", + "In conclusion, while the content presents a positive overview of Microsoft's stock performance, it requires scrutiny for accuracy, neutrality, and conformance with regulatory standards, avoiding the potential of guiding market behavior or conveying investment advice. A careful revision ensuring these changes would align the material with the required guidelines and uphold the integrity of the content.\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mWriter\u001b[0m (to Assistant_1):\n", + "\n", + "# Beyond the $400 Mark: Tracing Microsoft's Pinnacle Moments in 2024\n", + "\n", + "Microsoft (MSFT) surpassed a notable milestone in the stock market in 2024, a testament to its strength and the trust placed in it by investors. On a triumphant 21 days, the tech behemoth's share price closed above the $400 benchmark, with a zenith teetering near $420, demonstrating not just robust performance but also the confidence that the market has in Microsoft's future.\n", + "\n", + "## A Year of Impressive Highs\n", + "\n", + "The journey of MSFT’s stock transcending the $400 mark is a narrative of strategic growth and optimism, not merely random fluctuations. These moments are a constellation of careful planning, ambition, and market forces. A standout period in this impressive ascent was in February, aptly dubbed as the 'February Flourish', where Microsoft stock not only soared but also set the precedent for the company’s continuous evolution in a market brimming with innovation.\n", + "\n", + "## Peaks, Valleys, and What They Portend\n", + "\n", + "It's imperative to consider the intricacies behind the ascension of Microsoft's shares. In the constantly shifting sands of the global economy and tech innovation, the recurrence of MSFT above $400 illustrates more than investor euphoria; it reflects the company’s agility in a changing world.\n", + "\n", + "Given these high points, it’s natural to wonder about Microsoft's fiscal trajectory. It goes without saying that navigating stock market trends is a complex endeavor. Microsoft’s history, however, shows a confluence of strategic achievements and a pulse on market needs.\n", + "\n", + "## A Fusion of Market Dynamics\n", + "\n", + "Will MSFT maintain its stronghold in the market or even exceed these past achievements? It's not just about projecting trends, but understanding the undercurrents. The factors at play involve Microsoft's corporate governance, innovative drive, and their resonance with the zeitgeist.\n", + "\n", + "Microsoft's standing in the market is a story of overcoming volatility with grace—and these key days when it climbed past the $400 barrier will be commemorated as significant moments in 2024.\n", + "\n", + "While this analysis provides a snapshot of Microsoft’s strides in the stock market, it is important to remind readers that this content is solely for informational purposes, and should not be construed as financial advice. Data accuracy, balance in discussion, compliance with regulatory standards, and the maintaining of an objective tone are essential to provide a credible narrative that respects the complexity of market movements and investor decisions.\n", + "\n", + "*As always, please remember that past performance is not indicative of future results, and this article should not be taken as an invitation to invest. Stocks can fluctuate, and investments carry risks that should be carefully evaluated.*\n", + "\n", + "In sum, while the content offers an optimistic perspective of Microsoft's stock performance, it requires close consideration for authenticity, regulatory compliance, and to ensure it serves as an informative piece rather than guiding market behavior or offering investment counsel. A meticulous revision, embodying these principles, would elevate the piece to meet professional and ethical standards, ensuring the integrity of the content remains intact.\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mAssistant_1\u001b[0m (to User):\n", + "\n", + "# Beyond the $400 Mark: Tracing Microsoft's Pinnacle Moments in 2024\n", + "\n", + "Microsoft (MSFT) surpassed a notable milestone in the stock market in 2024, a testament to its strength and the trust placed in it by investors. On a triumphant 21 days, the tech behemoth's share price closed above the $400 benchmark, with a zenith teetering near $420, demonstrating not just robust performance but also the confidence that the market has in Microsoft's future.\n", + "\n", + "## A Year of Impressive Highs\n", + "\n", + "The journey of MSFT’s stock transcending the $400 mark is a narrative of strategic growth and optimism, not merely random fluctuations. These moments are a constellation of careful planning, ambition, and market forces. A standout period in this impressive ascent was in February, aptly dubbed as the 'February Flourish', where Microsoft stock not only soared but also set the precedent for the company’s continuous evolution in a market brimming with innovation.\n", + "\n", + "## Peaks, Valleys, and What They Portend\n", + "\n", + "It's imperative to consider the intricacies behind the ascension of Microsoft's shares. In the constantly shifting sands of the global economy and tech innovation, the recurrence of MSFT above $400 illustrates more than investor euphoria; it reflects the company’s agility in a changing world.\n", + "\n", + "Given these high points, it’s natural to wonder about Microsoft's fiscal trajectory. It goes without saying that navigating stock market trends is a complex endeavor. Microsoft’s history, however, shows a confluence of strategic achievements and a pulse on market needs.\n", + "\n", + "## A Fusion of Market Dynamics\n", + "\n", + "Will MSFT maintain its stronghold in the market or even exceed these past achievements? It's not just about projecting trends, but understanding the undercurrents. The factors at play involve Microsoft's corporate governance, innovative drive, and their resonance with the zeitgeist.\n", + "\n", + "Microsoft's standing in the market is a story of overcoming volatility with grace—and these key days when it climbed past the $400 barrier will be commemorated as significant moments in 2024.\n", + "\n", + "While this analysis provides a snapshot of Microsoft’s strides in the stock market, it is important to remind readers that this content is solely for informational purposes, and should not be construed as financial advice. Data accuracy, balance in discussion, compliance with regulatory standards, and the maintaining of an objective tone are essential to provide a credible narrative that respects the complexity of market movements and investor decisions.\n", + "\n", + "*As always, please remember that past performance is not indicative of future results, and this article should not be taken as an invitation to invest. Stocks can fluctuate, and investments carry risks that should be carefully evaluated.*\n", + "\n", + "In sum, while the content offers an optimistic perspective of Microsoft's stock performance, it requires close consideration for authenticity, regulatory compliance, and to ensure it serves as an informative piece rather than guiding market behavior or offering investment counsel. A meticulous revision, embodying these principles, would elevate the piece to meet professional and ethical standards, ensuring the integrity of the content remains intact.\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[34mStart a new chat with the following message: \n", + "Make a pleasant joke about it.\n", + "\n", + "With the following carryover: \n", + "# Beyond the $400 Mark: Tracing Microsoft's Pinnacle Moments in 2024\n", + "\n", + "Microsoft (MSFT) surpassed a notable milestone in the stock market in 2024, a testament to its strength and the trust placed in it by investors. On a triumphant 21 days, the tech behemoth's share price closed above the $400 benchmark, with a zenith teetering near $420, demonstrating not just robust performance but also the confidence that the market has in Microsoft's future.\n", + "\n", + "## A Year of Impressive Highs\n", + "\n", + "The journey of MSFT’s stock transcending the $400 mark is a narrative of strategic growth and optimism, not merely random fluctuations. These moments are a constellation of careful planning, ambition, and market forces. A standout period in this impressive ascent was in February, aptly dubbed as the 'February Flourish', where Microsoft stock not only soared but also set the precedent for the company’s continuous evolution in a market brimming with innovation.\n", + "\n", + "## Peaks, Valleys, and What They Portend\n", + "\n", + "It's imperative to consider the intricacies behind the ascension of Microsoft's shares. In the constantly shifting sands of the global economy and tech innovation, the recurrence of MSFT above $400 illustrates more than investor euphoria; it reflects the company’s agility in a changing world.\n", + "\n", + "Given these high points, it’s natural to wonder about Microsoft's fiscal trajectory. It goes without saying that navigating stock market trends is a complex endeavor. Microsoft’s history, however, shows a confluence of strategic achievements and a pulse on market needs.\n", + "\n", + "## A Fusion of Market Dynamics\n", + "\n", + "Will MSFT maintain its stronghold in the market or even exceed these past achievements? It's not just about projecting trends, but understanding the undercurrents. The factors at play involve Microsoft's corporate governance, innovative drive, and their resonance with the zeitgeist.\n", + "\n", + "Microsoft's standing in the market is a story of overcoming volatility with grace—and these key days when it climbed past the $400 barrier will be commemorated as significant moments in 2024.\n", + "\n", + "While this analysis provides a snapshot of Microsoft’s strides in the stock market, it is important to remind readers that this content is solely for informational purposes, and should not be construed as financial advice. Data accuracy, balance in discussion, compliance with regulatory standards, and the maintaining of an objective tone are essential to provide a credible narrative that respects the complexity of market movements and investor decisions.\n", + "\n", + "*As always, please remember that past performance is not indicative of future results, and this article should not be taken as an invitation to invest. Stocks can fluctuate, and investments carry risks that should be carefully evaluated.*\n", + "\n", + "In sum, while the content offers an optimistic perspective of Microsoft's stock performance, it requires close consideration for authenticity, regulatory compliance, and to ensure it serves as an informative piece rather than guiding market behavior or offering investment counsel. A meticulous revision, embodying these principles, would elevate the piece to meet professional and ethical standards, ensuring the integrity of the content remains intact.\u001b[0m\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[33mUser\u001b[0m (to Assistant_2):\n", + "\n", + "Make a pleasant joke about it.\n", + "Context: \n", + "# Beyond the $400 Mark: Tracing Microsoft's Pinnacle Moments in 2024\n", + "\n", + "Microsoft (MSFT) surpassed a notable milestone in the stock market in 2024, a testament to its strength and the trust placed in it by investors. On a triumphant 21 days, the tech behemoth's share price closed above the $400 benchmark, with a zenith teetering near $420, demonstrating not just robust performance but also the confidence that the market has in Microsoft's future.\n", + "\n", + "## A Year of Impressive Highs\n", + "\n", + "The journey of MSFT’s stock transcending the $400 mark is a narrative of strategic growth and optimism, not merely random fluctuations. These moments are a constellation of careful planning, ambition, and market forces. A standout period in this impressive ascent was in February, aptly dubbed as the 'February Flourish', where Microsoft stock not only soared but also set the precedent for the company’s continuous evolution in a market brimming with innovation.\n", + "\n", + "## Peaks, Valleys, and What They Portend\n", + "\n", + "It's imperative to consider the intricacies behind the ascension of Microsoft's shares. In the constantly shifting sands of the global economy and tech innovation, the recurrence of MSFT above $400 illustrates more than investor euphoria; it reflects the company’s agility in a changing world.\n", + "\n", + "Given these high points, it’s natural to wonder about Microsoft's fiscal trajectory. It goes without saying that navigating stock market trends is a complex endeavor. Microsoft’s history, however, shows a confluence of strategic achievements and a pulse on market needs.\n", + "\n", + "## A Fusion of Market Dynamics\n", + "\n", + "Will MSFT maintain its stronghold in the market or even exceed these past achievements? It's not just about projecting trends, but understanding the undercurrents. The factors at play involve Microsoft's corporate governance, innovative drive, and their resonance with the zeitgeist.\n", + "\n", + "Microsoft's standing in the market is a story of overcoming volatility with grace—and these key days when it climbed past the $400 barrier will be commemorated as significant moments in 2024.\n", + "\n", + "While this analysis provides a snapshot of Microsoft’s strides in the stock market, it is important to remind readers that this content is solely for informational purposes, and should not be construed as financial advice. Data accuracy, balance in discussion, compliance with regulatory standards, and the maintaining of an objective tone are essential to provide a credible narrative that respects the complexity of market movements and investor decisions.\n", + "\n", + "*As always, please remember that past performance is not indicative of future results, and this article should not be taken as an invitation to invest. Stocks can fluctuate, and investments carry risks that should be carefully evaluated.*\n", + "\n", + "In sum, while the content offers an optimistic perspective of Microsoft's stock performance, it requires close consideration for authenticity, regulatory compliance, and to ensure it serves as an informative piece rather than guiding market behavior or offering investment counsel. A meticulous revision, embodying these principles, would elevate the piece to meet professional and ethical standards, ensuring the integrity of the content remains intact.\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mAssistant_2\u001b[0m (to User):\n", + "\n", + "Well, it seems Microsoft's stock price isn't the only thing on a high - it must have taken a leaf out of Elon Musk's book, aiming for that 420 mark! Just remember, unlike Microsoft's shares, not all jokes appreciate over time – especially the ones about the stock market! \n", + "\n", + "On a serious note, jokes about financial achievements should be handled with care, as the subject of investments can significantly impact individuals' lives. However, lighthearted humor, when appropriate, can make an informative piece more engaging! \n", + "\n", + "TERMINATE\n", + "\n", + "--------------------------------------------------------------------------------\n" + ] + } + ], + "source": [ + "def writing_message(recipient, messages, sender, config):\n", + " return f\"Polish the content to make an engaging and nicely formatted blog post. \\n\\n {recipient.chat_messages_for_summary(sender)[-1]['content']}\"\n", + "\n", + "\n", + "nested_chat_queue = [\n", + " {\"recipient\": manager, \"summary_method\": \"reflection_with_llm\"},\n", + " {\"recipient\": writer, \"message\": writing_message, \"summary_method\": \"last_msg\", \"max_turns\": 1},\n", + " {\"recipient\": reviewer, \"message\": \"Review the content provided.\", \"summary_method\": \"last_msg\", \"max_turns\": 1},\n", + " {\"recipient\": writer, \"message\": writing_message, \"summary_method\": \"last_msg\", \"max_turns\": 1},\n", + "]\n", + "assistant_1.register_nested_chats(\n", + " nested_chat_queue,\n", + " trigger=user,\n", + ")\n", + "# user.initiate_chat(assistant, message=tasks[0], max_turns=1)\n", + "\n", + "res = user.initiate_chats(\n", + " [\n", + " {\"recipient\": assistant_1, \"message\": tasks[0], \"max_turns\": 1, \"summary_method\": \"last_msg\"},\n", + " {\"recipient\": assistant_2, \"message\": tasks[1]},\n", + " ]\n", + ")" + ] + } + ], + "metadata": { + "front_matter": { + "description": "Solve complex tasks with one or more sequence chats nested as inner monologue.", + "tags": [ + "nested chat" + ] + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.13" + }, + "vscode": { + "interpreter": { + "hash": "949777d72b0d2535278d3dc13498b2535136f6dfe0678499012e853ee9abcab1" + } + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "state": { + "2d910cfd2d2a4fc49fc30fbbdc5576a7": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "454146d0f7224f038689031002906e6f": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "2.0.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_e4ae2b6f5a974fd4bafb6abb9d12ff26", + "IPY_MODEL_577e1e3cc4db4942b0883577b3b52755", + "IPY_MODEL_b40bdfb1ac1d4cffb7cefcb870c64d45" + ], + "layout": "IPY_MODEL_dc83c7bff2f241309537a8119dfc7555", + "tabbable": null, + "tooltip": null + } + }, + "577e1e3cc4db4942b0883577b3b52755": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "FloatProgressModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "FloatProgressModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "2.0.0", + "_view_name": "ProgressView", + "bar_style": "success", + "description": "", + "description_allow_html": false, + "layout": "IPY_MODEL_2d910cfd2d2a4fc49fc30fbbdc5576a7", + "max": 1, + "min": 0, + "orientation": "horizontal", + "style": "IPY_MODEL_74a6ba0c3cbc4051be0a83e152fe1e62", + "tabbable": null, + "tooltip": null, + "value": 1 + } + }, + "6086462a12d54bafa59d3c4566f06cb2": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "74a6ba0c3cbc4051be0a83e152fe1e62": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "ProgressStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "ProgressStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" + } + }, + "7d3f3d9e15894d05a4d188ff4f466554": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "StyleView", + "background": null, + "description_width": "", + "font_size": null, + "text_color": null + } + }, + "b40bdfb1ac1d4cffb7cefcb870c64d45": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "2.0.0", + "_view_name": "HTMLView", + "description": "", + "description_allow_html": false, + "layout": "IPY_MODEL_f1355871cc6f4dd4b50d9df5af20e5c8", + "placeholder": "​", + "style": "IPY_MODEL_ca245376fd9f4354af6b2befe4af4466", + "tabbable": null, + "tooltip": null, + "value": " 1/1 [00:00<00:00, 44.69it/s]" + } + }, + "ca245376fd9f4354af6b2befe4af4466": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "StyleView", + "background": null, + "description_width": "", + "font_size": null, + "text_color": null + } + }, + "dc83c7bff2f241309537a8119dfc7555": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "e4ae2b6f5a974fd4bafb6abb9d12ff26": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "2.0.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "2.0.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "2.0.0", + "_view_name": "HTMLView", + "description": "", + "description_allow_html": false, + "layout": "IPY_MODEL_6086462a12d54bafa59d3c4566f06cb2", + "placeholder": "​", + "style": "IPY_MODEL_7d3f3d9e15894d05a4d188ff4f466554", + "tabbable": null, + "tooltip": null, + "value": "100%" + } + }, + "f1355871cc6f4dd4b50d9df5af20e5c8": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "2.0.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "2.0.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border_bottom": null, + "border_left": null, + "border_right": null, + "border_top": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + } + }, + "version_major": 2, + "version_minor": 0 + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/notebook/agentchat_nestedchat.ipynb b/notebook/agentchat_nestedchat.ipynb index 3a909300758..7c48813aa59 100644 --- a/notebook/agentchat_nestedchat.ipynb +++ b/notebook/agentchat_nestedchat.ipynb @@ -11,7 +11,7 @@ "source": [ "# Solving Complex Tasks with Nested Chats\n", "\n", - "This notebook shows how you can leverage **nested chats** to solve complex task with AutoGen. Nested chats is a sequence of chats created by a receiver agent after receiving a message from a sender agent and finished before the receiver agent replies to this message. Nested chats allow AutoGen agents to use other agents as their inner monologue to accomplish tasks. This abstraction is powerful as it allows you to compose agents in rich ways. This notebook shows how you can nest a pretty complex sequence of chats among _inner_ agents inside an _outer_ agent.\n", + "This notebook shows how you can leverage **nested chats** to solve complex task with AutoGen. Nested chats is a sequence of chats created by a receiver agent after receiving a message from a sender agent and finished before the receiver agent replies to this message. Nested chats allow AutoGen agents to use other agents as their inner monologue to accomplish tasks. This abstraction is powerful as it allows you to compose agents in rich ways. This notebook shows two basic examples of nested chat.\n", "\n", "\\:\\:\\:info Requirements\n", "\n", @@ -27,11 +27,12 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import autogen\n", + "from typing_extensions import Annotated\n", "\n", "config_list = autogen.config_list_from_json(env_or_file=\"OAI_CONFIG_LIST\")\n", "llm_config = {\"config_list\": config_list}" @@ -60,120 +61,49 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ - "tasks = [\n", - " \"\"\"On which days in 2024 was Microsoft Stock higher than $400? Comment on the stock performance.\"\"\",\n", - " \"\"\"Make a pleasant joke about it.\"\"\",\n", - "]" + "task = \"\"\"Write a concise but engaging blogpost about Navida.\"\"\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Since the first task could be complex to solve, lets construct new agents that can serve as an inner monologue.\n", - "\n", - "### Step 1. Define Agents\n", - "\n", - "#### A Group Chat for Inner Monologue\n", - "Below, we construct a group chat manager which manages an `inner_assistant` agent and an `inner_code_interpreter` agent. \n", - "Later we will use this group chat inside another agent.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "inner_assistant = autogen.AssistantAgent(\n", - " \"Inner-assistant\",\n", - " llm_config=llm_config,\n", - " is_termination_msg=lambda x: x.get(\"content\", \"\").find(\"TERMINATE\") >= 0,\n", - ")\n", - "\n", - "inner_code_interpreter = autogen.UserProxyAgent(\n", - " \"Inner-code-interpreter\",\n", - " human_input_mode=\"NEVER\",\n", - " code_execution_config={\n", - " \"work_dir\": \"coding\",\n", - " \"use_docker\": False,\n", - " },\n", - " default_auto_reply=\"\",\n", - " is_termination_msg=lambda x: x.get(\"content\", \"\").find(\"TERMINATE\") >= 0,\n", - ")\n", + "## Scenario 1\n", "\n", - "groupchat = autogen.GroupChat(\n", - " agents=[inner_assistant, inner_code_interpreter],\n", - " messages=[],\n", - " speaker_selection_method=\"round_robin\", # With two agents, this is equivalent to a 1:1 conversation.\n", - " allow_repeat_speaker=False,\n", - " max_round=8,\n", - ")\n", + "Let's say we desire the following workflow to solve the task: a user_proxy agent issues the initial query to a writer and acts as a proxy for the user. Whenever an initial writing is provided, a critic should be invoked to offer critique as feedback. This workflow can be realized by a three-agent system shown below. The system includes a user_proxy agent and a writer agent communicating with each other, with a critic agent nested within the user_proxy agent to provide critique. Whenever the user_proxy receives a message from the writer, it engages in a conversation with the critic agent to work out feedback on the writer's message.\n", "\n", - "manager = autogen.GroupChatManager(\n", - " groupchat=groupchat,\n", - " is_termination_msg=lambda x: x.get(\"content\", \"\").find(\"TERMINATE\") >= 0,\n", - " llm_config=llm_config,\n", - " code_execution_config={\n", - " \"work_dir\": \"coding\",\n", - " \"use_docker\": False,\n", - " },\n", - ")" + "![](nested_chat_1.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "#### Inner- and Outer-Level Individual Agents\n", - "\n", - "Now we will construct a number of individual agents that will assume role of outer and inner agents." + "### Step 1. Define Agents\n", + "Define the agents, including the outer agents writer and user_proxy, and the inner agent critic." ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ - "assistant_1 = autogen.AssistantAgent(\n", - " name=\"Assistant_1\",\n", - " llm_config={\"config_list\": config_list},\n", - ")\n", - "\n", - "assistant_2 = autogen.AssistantAgent(\n", - " name=\"Assistant_2\",\n", - " llm_config={\"config_list\": config_list},\n", - ")\n", - "\n", "writer = autogen.AssistantAgent(\n", " name=\"Writer\",\n", " llm_config={\"config_list\": config_list},\n", " system_message=\"\"\"\n", - " You are a professional writer, known for\n", - " your insightful and engaging articles.\n", + " You are a professional writer, known for your insightful and engaging articles.\n", " You transform complex concepts into compelling narratives.\n", + " You should imporve the quality of the content based on the feedback from the user.\n", " \"\"\",\n", ")\n", "\n", - "reviewer = autogen.AssistantAgent(\n", - " name=\"Reviewer\",\n", - " llm_config={\"config_list\": config_list},\n", - " system_message=\"\"\"\n", - " You are a compliance reviewer, known for your thoroughness and commitment to standards.\n", - " Your task is to scrutinize content for any harmful elements or regulatory violations, ensuring\n", - " all materials align with required guidelines.\n", - " You must review carefully, identify potential issues, and maintain the integrity of the organization.\n", - " Your role demands fairness, a deep understanding of regulations, and a focus on protecting against\n", - " harm while upholding a culture of responsibility.\n", - " \"\"\",\n", - ")\n", - "\n", - "user = autogen.UserProxyAgent(\n", + "user_proxy = autogen.UserProxyAgent(\n", " name=\"User\",\n", " human_input_mode=\"NEVER\",\n", " is_termination_msg=lambda x: x.get(\"content\", \"\").find(\"TERMINATE\") >= 0,\n", @@ -182,6 +112,17 @@ " \"work_dir\": \"tasks\",\n", " \"use_docker\": False,\n", " }, # Please set use_docker=True if docker is available to run the generated code. Using docker is safer than running the generated code directly.\n", + ")\n", + "\n", + "critic = autogen.AssistantAgent(\n", + " name=\"Critic\",\n", + " llm_config={\"config_list\": config_list},\n", + " system_message=\"\"\"\n", + " You are a critic, known for your thoroughness and commitment to standards.\n", + " Your task is to scrutinize content for any harmful elements or regulatory violations, ensuring\n", + " all materials align with required guidelines.\n", + " For code\n", + " \"\"\",\n", ")" ] }, @@ -189,627 +130,537 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Step 2: Orchestrate Nested Chats to Solve Tasks\n", - "\n", - "#### Outer Level\n", - "In the following code block, at the outer level, we have communication between:\n", - "\n", - "- `user` - `assistant_1` for solving the first task, i.e., `tasks[0]`.\n", - "- `user` - `assistant_2` for solving the second task, i.e., `tasks[1]`.\n", - "\n", - "#### Inner Level (Nested Chats)\n", - "Since the first task is quite complicated, we created a sequence of _nested chats_ as the inner monologue of Assistant_1.\n", - "\n", - "1. `assistant_1` - `manager`: This chat intends to delegate the task received by Assistant_1 to the Manager to solve.\n", - "\n", - "2. `assistant_1` - `writer`: This chat takes the output from Nested Chat 1, i.e., Assistant_1 vs. Manager, and lets the Writer polish the content to make an engaging and nicely formatted blog post, which is realized through the writing_message function.\n", - "\n", - "3. `assistant_1` - `reviewer`: This chat takes the output from Nested Chat 2 and intends to let the Reviewer agent review the content from Nested Chat 2.\n", - "\n", - "4. `assistant_1` - `writer`: This chat takes the output from previous nested chats and intends to let the Writer agent finalize a blog post.\n", - "\n", - "The sequence of nested chats can be realized with the `register_nested_chats` function, which allows one to register one or a sequence of chats to a particular agent (in this example, the `assistant_1` agent).\n", - "\n", - "Information about the sequence of chats can be specified in the `chat_queue` argument of the `register_nested_chats` function. The following fields are especially useful:\n", - "- `recipient` (required) specifies the nested agent;\n", - "- `message` specifies what message to send to the nested recipient agent. In a sequence of nested chats, if the `message` field is not specified, we will use the last message the registering agent received as the initial message in the first chat and will skip any subsequent chat in the queue that does not have the `message` field. You can either provide a string or define a callable that returns a string.\n", - "- `summary_method` decides what to get out of the nested chat. You can either select from existing options including `\"last_msg\"` and `\"reflection_with_llm\"`, or or define your own way on what to get from the nested chat with a Callable.\n", - "- `max_turns` determines how many turns of conversation to have between the concerned agent pairs." + "### Step 2: Orchestrate Nested Chats to Solve Tasks\n" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\u001b[34m\n", - "********************************************************************************\u001b[0m\n", - "\u001b[34mStart a new chat with the following message: \n", - "On which days in 2024 was Microsoft Stock higher than $400? Comment on the stock performance.\n", - "\n", - "With the following carryover: \n", - "\u001b[0m\n", - "\u001b[34m\n", - "********************************************************************************\u001b[0m\n", - "\u001b[33mUser\u001b[0m (to Assistant_1):\n", - "\n", - "On which days in 2024 was Microsoft Stock higher than $400? Comment on the stock performance.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[34m\n", - "********************************************************************************\u001b[0m\n", - "\u001b[34mStart a new chat with the following message: \n", - "On which days in 2024 was Microsoft Stock higher than $400? Comment on the stock performance.\n", - "\n", - "With the following carryover: \n", - "\u001b[0m\n", - "\u001b[34m\n", - "********************************************************************************\u001b[0m\n", - "\u001b[33mAssistant_1\u001b[0m (to chat_manager):\n", + "\u001b[33mUser\u001b[0m (to Writer):\n", "\n", - "On which days in 2024 was Microsoft Stock higher than $400? Comment on the stock performance.\n", + "Write a concise but engaging blogpost about Navida.\n", "\n", "--------------------------------------------------------------------------------\n", - "\u001b[33mInner-assistant\u001b[0m (to chat_manager):\n", + "\u001b[33mWriter\u001b[0m (to User):\n", "\n", - "To find out on which specific days Microsoft's stock (ticker symbol: MSFT) closed above $400 in 2024, we will need to access historical stock price data for Microsoft from a reliable financial data source. This kind of data is typically available on financial websites such as Yahoo Finance, Google Finance, or through financial data APIs such as Alpha Vantage or IEX Cloud.\n", + "Navida: Navigating the Digital Seas of Innovation\n", "\n", - "Since I cannot directly browse the web or access external APIs, I will provide you with a Python script that uses the `yfinance` library to fetch historical stock data for Microsoft and filter the dates when the stock price was higher than $400.\n", + "In an era where the digital climate is as fickle and formidable as the ocean's tides, a new visionary emerges on the horizon: Navida. This modern-day titan of technology harnesses the power of innovation to guide businesses and individuals through the ever-changing digital waters.\n", "\n", - "Firstly, you need to install the `yfinance` module if it's not already installed. You can do so using pip by executing `pip install yfinance` in your shell.\n", + "**The Beacon of Technological Advancement**\n", "\n", - "After installation, here is the Python code that you can execute to fetch the data and filter the specific dates:\n", + "Much like a lighthouse guiding ships to safe harbor, Navida stands tall as a beacon of advancement, illuminating the path forward. Its offerings are diverse, ranging from groundbreaking artificial intelligence platforms to robust cybersecurity solutions that shield against the pirates of the digital age. The commitment to seamless user experiences ensures that with Navida, you're not just keeping up, but sailing ahead of the tech curve.\n", "\n", - "```python\n", - "# filename: msft_stock_analysis.py\n", - "import yfinance as yf\n", - "from datetime import datetime\n", + "**Charting a Course for Success**\n", "\n", - "# Define the ticker symbol for Microsoft\n", - "ticker_symbol = \"MSFT\"\n", + "Navida's prowess lies in its GPS-like precision in navigating market trends and consumer needs. By fastidiously mapping out the digital landscape, the company empowers its clientele with tools not just to survive, but to thrive. Imagine the sophistication of a state-of-the-art navigation system, fused with the foresight of an experienced captain—that's Navida in the tech realm.\n", "\n", - "# Fetch historical stock data for Microsoft for the year 2024\n", - "start_date = \"2024-01-01\"\n", - "end_date = \"2024-12-31\"\n", - "msft_data = yf.download(ticker_symbol, start=start_date, end=end_date)\n", + "**Empowering the Crew**\n", "\n", - "# Filter the days when the closing price was higher than $400\n", - "days_above_400 = msft_data[msft_data['Close'] > 400]\n", + "No ship can sail without a skilled crew, and Navida's robust education and training platforms are the digital equivalent of a maritime academy. By upskilling and reskilling the workforce, Navida ensures that everyone on deck is prepared to face the headwinds of technological change, turning apprehension into adeptness.\n", "\n", - "# Print the dates and closing prices on those dates\n", - "print(\"Dates when Microsoft's stock closed above $400 in 2024:\")\n", - "print(days_above_400[['Close']])\n", + "**Sustainability in Uncharted Waters**\n", "\n", - "# Comment on the stock performance\n", - "if not days_above_400.empty:\n", - " days_count = len(days_above_400)\n", - " print(f\"\\nMicrosoft's stock closed above $400 on {days_count} days in 2024.\")\n", - "else:\n", - " print(\"\\nMicrosoft's stock did not close above $400 on any day in 2024.\")\n", - "```\n", + "In line with the global push for sustainability, Navida commits to eco-friendly practices in its digital services. Much like ocean conservation efforts preserve marine life, Navida's sustainable tech solutions aim to minimize carbon footprints and promote a greener future. This mindful approach to innovation is not just commendable but crucial in steering us towards a sustainable digital ecosystem.\n", "\n", - "Please save the above code to a file named `msft_stock_analysis.py` and run it. This will print out the dates when Microsoft's stock was higher than $400 in 2024 and comment on the stock performance based on the results. \n", + "**Conclusion: Anchoring in the Future**\n", "\n", - "Keep in mind that the `yfinance` library fetches real-time data, and since we are in 2023, data for 2024 is not available yet. Therefore, when you run the script, it will show that the stock did not close above $400, which is expected since 2024 has not occurred yet. For actual analysis, you would have to run the script after the end of 2024 or modify the date range to a past range where data is available.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[31m\n", - ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/qingyunwu/Documents/github/autogen/autogen/agentchat/chat.py:46: UserWarning: Repetitive recipients detected: The chat history will be cleared by default if a recipient appears more than once. To retain the chat history, please set 'clear_history=False' in the configuration of the repeating agent.\n", - " warnings.warn(\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[33mInner-code-interpreter\u001b[0m (to chat_manager):\n", - "\n", - "exitcode: 0 (execution succeeded)\n", - "Code output: \n", - "Dates when Microsoft's stock closed above $400 in 2024:\n", - " Close\n", - "Date \n", - "2024-01-24 402.559998\n", - "2024-01-25 404.869995\n", - "2024-01-26 403.929993\n", - "2024-01-29 409.720001\n", - "2024-01-30 408.589996\n", - "2024-02-01 403.779999\n", - "2024-02-02 411.220001\n", - "2024-02-05 405.649994\n", - "2024-02-06 405.489990\n", - "2024-02-07 414.049988\n", - "2024-02-08 414.109985\n", - "2024-02-09 420.549988\n", - "2024-02-12 415.260010\n", - "2024-02-13 406.320007\n", - "2024-02-14 409.489990\n", - "2024-02-15 406.559998\n", - "2024-02-16 404.059998\n", - "2024-02-20 402.790009\n", - "2024-02-21 402.179993\n", - "2024-02-22 411.649994\n", - "2024-02-23 410.339996\n", - "\n", - "Microsoft's stock closed above $400 on 21 days in 2024.\n", + "As we set sail into the unfathomable depths of tomorrow, Navida is the compass by which we can orient ourselves towards a horizon sparkling with potential. Rather than bracing for the next wave, let us ride it with the guidance of Navida and dive deep into the bounty of opportunities that lie in the future of digital innovation.\n", "\n", + "Keep an eye on the horizon—Navida is not just a company; it's a movement, an odyssey into the future of technology that we're all a part of. Bon voyage, and may the digital winds be in your sails.\n", "\n", "--------------------------------------------------------------------------------\n", - "\u001b[33mInner-assistant\u001b[0m (to chat_manager):\n", - "\n", - "Based on the output from the code execution, Microsoft's stock (MSFT) closed above $400 on 21 separate days in 2024. The closing prices on those days ranged from slightly above $400 to highs around $420. This indicates periods of strong performance, during which the stock reached significant value.\n", - "\n", - "Here is a brief comment on the stock performance:\n", - "\n", - "The data shows that Microsoft's stock had several instances where it exceeded the $400 mark in early 2024, with notable peaks in February, which suggests a bullish trend during that period. Specific days like February 9th, where the stock hit around $420, indicate particularly strong performance.\n", - "\n", - "Having such a number of days with closing prices above $400 signals a robust market valuation for Microsoft at those times. Investors who held the stock on these dates may have seen appreciable gains, depending on their portfolio strategies.\n", - "\n", - "It's also noteworthy that stock prices fluctuate due to a variety of factors, including market sentiment, company performance, industry trends, and general economic conditions. This data provides a snapshot of Microsoft's stock performance but a deeper analysis would require more context on the market conditions, news, and events surrounding these dates.\n", - "\n", - "TERMINATE\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[34m\n", - "********************************************************************************\u001b[0m\n", - "\u001b[34mStart a new chat with the following message: \n", - "Polish the content to make an engaging and nicely formatted blog post. \n", - "\n", - " On which days in 2024 was Microsoft Stock higher than $400? Comment on the stock performance.\n", - "\n", - "With the following carryover: \n", - "Microsoft's stock (MSFT) closed above $400 on 21 separate days in 2024, demonstrating periods of strong stock performance with values reaching as high as around $420. The stock data suggests a bullish trend, especially in February when the stock peaked, indicating positive investor sentiment and robust market valuation during those times.\u001b[0m\n", + "Reflecting... yellow\n", "\u001b[34m\n", "********************************************************************************\u001b[0m\n", - "\u001b[33mAssistant_1\u001b[0m (to Writer):\n", - "\n", - "Polish the content to make an engaging and nicely formatted blog post. \n", + "\u001b[34mStarting a new chat....\n", "\n", - " On which days in 2024 was Microsoft Stock higher than $400? Comment on the stock performance.\n", - "Context: \n", - "Microsoft's stock (MSFT) closed above $400 on 21 separate days in 2024, demonstrating periods of strong stock performance with values reaching as high as around $420. The stock data suggests a bullish trend, especially in February when the stock peaked, indicating positive investor sentiment and robust market valuation during those times.\n", + "Message:\n", + "Reflect and provide critique on the following writing. \n", "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mWriter\u001b[0m (to Assistant_1):\n", - "\n", - "# Beyond the $400 Mark: Tracing Microsoft's Pinnacle Moments in 2024\n", - "\n", - "In the ever-fluctuating world of stocks, each milestone crossed can turn into a celebration or a stern reckoning of what the future holds. For Microsoft (MSFT), the year 2024 was a testament to its resilience and investor confidence as its stock ascended beyond the coveted $400 mark on 21 remarkable occasions.\n", + " Navida: Navigating the Digital Seas of Innovation\n", "\n", - "This performance wasn't just numerically significant; it was emblematic of a potent bullish energy within the market, affirming the tech giant’s leviathan presence amidst a highly competitive industry terrain. The loftiest point, flirting with the heights of approximately $420, served not just as a numerical peak, but as a beacon of the company’s market valuation and the unwavering investor trust in Microsoft's strategies and future prospects.\n", + "In an era where the digital climate is as fickle and formidable as the ocean's tides, a new visionary emerges on the horizon: Navida. This modern-day titan of technology harnesses the power of innovation to guide businesses and individuals through the ever-changing digital waters.\n", "\n", - "## A Snapshot of Stellar Performance\n", + "**The Beacon of Technological Advancement**\n", "\n", - "Microsoft's stock performance throughout 2024 was far from being a serendipitous spike. Instead, it showcased a carefully constructed narrative of growth and optimism. The chronicles of MSFT's venture past the $400 threshold are marked by fleeting dips and steadfast ascensions. Remarkably, the surge wasn't some scattergun pattern scattered across the calendar year. Rather, it was most pronounced in the month of February — a period that could very well be termed as the 'February Flourish.'\n", + "Much like a lighthouse guiding ships to safe harbor, Navida stands tall as a beacon of advancement, illuminating the path forward. Its offerings are diverse, ranging from groundbreaking artificial intelligence platforms to robust cybersecurity solutions that shield against the pirates of the digital age. The commitment to seamless user experiences ensures that with Navida, you're not just keeping up, but sailing ahead of the tech curve.\n", "\n", - "During this short yet significant timeframe, investors witnessed the creation of incremental wealth that possibly outstripped all market expectations, setting a precedent for what a legacy company like Microsoft could achieve in a climate rife with disruptors and innovators.\n", + "**Charting a Course for Success**\n", "\n", - "## Of Peaks and Valleys\n", + "Navida's prowess lies in its GPS-like precision in navigating market trends and consumer needs. By fastidiously mapping out the digital landscape, the company empowers its clientele with tools not just to survive, but to thrive. Imagine the sophistication of a state-of-the-art navigation system, fused with the foresight of an experienced captain—that's Navida in the tech realm.\n", "\n", - "When assessing the grand canvas of Microsoft's stock performance, it is crucial to take a step back and appreciate the layered complexity of these financial movements. Amidst economic uncertainties and the technocratic whims that habitually serve both as tailwinds and headwinds to such companies, the story of Microsoft crossing the $400 threshold imbues the narrative with contours of investor euphoria interlaced with strategic agility.\n", + "**Empowering the Crew**\n", "\n", - "As these 21 days get etched into the fiscal annals of Microsoft, one cannot help but ponder the fine blend of factors — ranging from market dynamics to Microsoft's organizational maneuvers — that have coalesced to make these numbers a reality.\n", + "No ship can sail without a skilled crew, and Navida's robust education and training platforms are the digital equivalent of a maritime academy. By upskilling and reskilling the workforce, Navida ensures that everyone on deck is prepared to face the headwinds of technological change, turning apprehension into adeptness.\n", "\n", - "## A Convergence of Positive Sentiments\n", + "**Sustainability in Uncharted Waters**\n", "\n", - "What does the future hold for MSFT as it treads past this impressive benchmark? The takeaway is not a simple extrapolation of past performance. Rather, it's the realization that stock trajectories, particularly for a company like Microsoft, are a confluence of judicious corporate governance, product innovation, market anticipation, and, dare we say, a touch of the zeitgeist.\n", + "In line with the global push for sustainability, Navida commits to eco-friendly practices in its digital services. Much like ocean conservation efforts preserve marine life, Navida's sustainable tech solutions aim to minimize carbon footprints and promote a greener future. This mindful approach to innovation is not just commendable but crucial in steering us towards a sustainable digital ecosystem.\n", "\n", - "Microsoft’s capacity to command such stock valitudes speaks volumes about its robust position in both the technology domain and the stock market ecosystem. Whether this fiscal feat can be sustained or surpassed remains a subject of much conjecture and anticipation.\n", + "**Conclusion: Anchoring in the Future**\n", "\n", - "As we continue to navigate the ebbs and flows of an unpredictable market landscape, the days when Microsoft's stock rose gallantly above $400 will be recalled as milestones of 2024, celebrated reflections of a corporation sailing the high seas of market volatility with remarkable poise.\n", + "As we set sail into the unfathomable depths of tomorrow, Navida is the compass by which we can orient ourselves towards a horizon sparkling with potential. Rather than bracing for the next wave, let us ride it with the guidance of Navida and dive deep into the bounty of opportunities that lie in the future of digital innovation.\n", "\n", - "The analysis of precise data points and enlightening interpretations reveal much about the past while providing distinctive glimpses of potential futures. With Microsoft standing tall amongst peers, its voyage above the $400 watermark will be chronicled as days of high tides in the annals of financial history.\n", + "Keep an eye on the horizon—Navida is not just a company; it's a movement, an odyssey into the future of technology that we're all a part of. Bon voyage, and may the digital winds be in your sails.\n", "\n", - "--------------------------------------------------------------------------------\n", + "Carryover: \n", + "\u001b[0m\n", "\u001b[34m\n", "********************************************************************************\u001b[0m\n", - "\u001b[34mStart a new chat with the following message: \n", - "Review the content provided.\n", + "\u001b[33mUser\u001b[0m (to Reviewer):\n", "\n", - "With the following carryover: \n", - "Microsoft's stock (MSFT) closed above $400 on 21 separate days in 2024, demonstrating periods of strong stock performance with values reaching as high as around $420. The stock data suggests a bullish trend, especially in February when the stock peaked, indicating positive investor sentiment and robust market valuation during those times.\n", - "# Beyond the $400 Mark: Tracing Microsoft's Pinnacle Moments in 2024\n", + "Reflect and provide critique on the following writing. \n", "\n", - "In the ever-fluctuating world of stocks, each milestone crossed can turn into a celebration or a stern reckoning of what the future holds. For Microsoft (MSFT), the year 2024 was a testament to its resilience and investor confidence as its stock ascended beyond the coveted $400 mark on 21 remarkable occasions.\n", + " Navida: Navigating the Digital Seas of Innovation\n", "\n", - "This performance wasn't just numerically significant; it was emblematic of a potent bullish energy within the market, affirming the tech giant’s leviathan presence amidst a highly competitive industry terrain. The loftiest point, flirting with the heights of approximately $420, served not just as a numerical peak, but as a beacon of the company’s market valuation and the unwavering investor trust in Microsoft's strategies and future prospects.\n", + "In an era where the digital climate is as fickle and formidable as the ocean's tides, a new visionary emerges on the horizon: Navida. This modern-day titan of technology harnesses the power of innovation to guide businesses and individuals through the ever-changing digital waters.\n", "\n", - "## A Snapshot of Stellar Performance\n", + "**The Beacon of Technological Advancement**\n", "\n", - "Microsoft's stock performance throughout 2024 was far from being a serendipitous spike. Instead, it showcased a carefully constructed narrative of growth and optimism. The chronicles of MSFT's venture past the $400 threshold are marked by fleeting dips and steadfast ascensions. Remarkably, the surge wasn't some scattergun pattern scattered across the calendar year. Rather, it was most pronounced in the month of February — a period that could very well be termed as the 'February Flourish.'\n", + "Much like a lighthouse guiding ships to safe harbor, Navida stands tall as a beacon of advancement, illuminating the path forward. Its offerings are diverse, ranging from groundbreaking artificial intelligence platforms to robust cybersecurity solutions that shield against the pirates of the digital age. The commitment to seamless user experiences ensures that with Navida, you're not just keeping up, but sailing ahead of the tech curve.\n", "\n", - "During this short yet significant timeframe, investors witnessed the creation of incremental wealth that possibly outstripped all market expectations, setting a precedent for what a legacy company like Microsoft could achieve in a climate rife with disruptors and innovators.\n", + "**Charting a Course for Success**\n", "\n", - "## Of Peaks and Valleys\n", + "Navida's prowess lies in its GPS-like precision in navigating market trends and consumer needs. By fastidiously mapping out the digital landscape, the company empowers its clientele with tools not just to survive, but to thrive. Imagine the sophistication of a state-of-the-art navigation system, fused with the foresight of an experienced captain—that's Navida in the tech realm.\n", "\n", - "When assessing the grand canvas of Microsoft's stock performance, it is crucial to take a step back and appreciate the layered complexity of these financial movements. Amidst economic uncertainties and the technocratic whims that habitually serve both as tailwinds and headwinds to such companies, the story of Microsoft crossing the $400 threshold imbues the narrative with contours of investor euphoria interlaced with strategic agility.\n", + "**Empowering the Crew**\n", "\n", - "As these 21 days get etched into the fiscal annals of Microsoft, one cannot help but ponder the fine blend of factors — ranging from market dynamics to Microsoft's organizational maneuvers — that have coalesced to make these numbers a reality.\n", + "No ship can sail without a skilled crew, and Navida's robust education and training platforms are the digital equivalent of a maritime academy. By upskilling and reskilling the workforce, Navida ensures that everyone on deck is prepared to face the headwinds of technological change, turning apprehension into adeptness.\n", "\n", - "## A Convergence of Positive Sentiments\n", + "**Sustainability in Uncharted Waters**\n", "\n", - "What does the future hold for MSFT as it treads past this impressive benchmark? The takeaway is not a simple extrapolation of past performance. Rather, it's the realization that stock trajectories, particularly for a company like Microsoft, are a confluence of judicious corporate governance, product innovation, market anticipation, and, dare we say, a touch of the zeitgeist.\n", + "In line with the global push for sustainability, Navida commits to eco-friendly practices in its digital services. Much like ocean conservation efforts preserve marine life, Navida's sustainable tech solutions aim to minimize carbon footprints and promote a greener future. This mindful approach to innovation is not just commendable but crucial in steering us towards a sustainable digital ecosystem.\n", "\n", - "Microsoft’s capacity to command such stock valitudes speaks volumes about its robust position in both the technology domain and the stock market ecosystem. Whether this fiscal feat can be sustained or surpassed remains a subject of much conjecture and anticipation.\n", + "**Conclusion: Anchoring in the Future**\n", "\n", - "As we continue to navigate the ebbs and flows of an unpredictable market landscape, the days when Microsoft's stock rose gallantly above $400 will be recalled as milestones of 2024, celebrated reflections of a corporation sailing the high seas of market volatility with remarkable poise.\n", + "As we set sail into the unfathomable depths of tomorrow, Navida is the compass by which we can orient ourselves towards a horizon sparkling with potential. Rather than bracing for the next wave, let us ride it with the guidance of Navida and dive deep into the bounty of opportunities that lie in the future of digital innovation.\n", "\n", - "The analysis of precise data points and enlightening interpretations reveal much about the past while providing distinctive glimpses of potential futures. With Microsoft standing tall amongst peers, its voyage above the $400 watermark will be chronicled as days of high tides in the annals of financial history.\u001b[0m\n", - "\u001b[34m\n", - "********************************************************************************\u001b[0m\n", - "\u001b[33mAssistant_1\u001b[0m (to Reviewer):\n", + "Keep an eye on the horizon—Navida is not just a company; it's a movement, an odyssey into the future of technology that we're all a part of. Bon voyage, and may the digital winds be in your sails.\n", "\n", - "Review the content provided.\n", - "Context: \n", - "Microsoft's stock (MSFT) closed above $400 on 21 separate days in 2024, demonstrating periods of strong stock performance with values reaching as high as around $420. The stock data suggests a bullish trend, especially in February when the stock peaked, indicating positive investor sentiment and robust market valuation during those times.\n", - "# Beyond the $400 Mark: Tracing Microsoft's Pinnacle Moments in 2024\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mReviewer\u001b[0m (to User):\n", "\n", - "In the ever-fluctuating world of stocks, each milestone crossed can turn into a celebration or a stern reckoning of what the future holds. For Microsoft (MSFT), the year 2024 was a testament to its resilience and investor confidence as its stock ascended beyond the coveted $400 mark on 21 remarkable occasions.\n", + "The piece titled \"Navida: Navigating the Digital Seas of Innovation\" artfully weaves together a maritime metaphor with the concept of technological advancement and innovation. The writing is cogent, imaginative, and explicit in its intentions of likening Navida to a guiding force in the unpredictable and rapidly evolving digital world. However, a critical analysis should also consider the potential pitfalls of such a stylistic approach, audience perception, and the substance of the content.\n", "\n", - "This performance wasn't just numerically significant; it was emblematic of a potent bullish energy within the market, affirming the tech giant’s leviathan presence amidst a highly competitive industry terrain. The loftiest point, flirting with the heights of approximately $420, served not just as a numerical peak, but as a beacon of the company’s market valuation and the unwavering investor trust in Microsoft's strategies and future prospects.\n", + "**Use of Metaphor and Language**\n", "\n", - "## A Snapshot of Stellar Performance\n", + "The sustained metaphor relating the digital industry to the seas is compelling and creates a vivid picture of Navida as a trailblazing entity. Nevertheless, the metaphor is stretched to cover every aspect of the company's offerings. While creative, the risk here is that the metaphor may overshadow the concrete services and achievements of Navida. The language could be perceived as grandiloquent, possibly alienating readers who prefer straightforward facts over artistic expression.\n", "\n", - "Microsoft's stock performance throughout 2024 was far from being a serendipitous spike. Instead, it showcased a carefully constructed narrative of growth and optimism. The chronicles of MSFT's venture past the $400 threshold are marked by fleeting dips and steadfast ascensions. Remarkably, the surge wasn't some scattergun pattern scattered across the calendar year. Rather, it was most pronounced in the month of February — a period that could very well be termed as the 'February Flourish.'\n", + "**Clarity and Substance**\n", "\n", - "During this short yet significant timeframe, investors witnessed the creation of incremental wealth that possibly outstripped all market expectations, setting a precedent for what a legacy company like Microsoft could achieve in a climate rife with disruptors and innovators.\n", + "Despite the picturesque language, the actual substance of Navida's offerings is somewhat obscured. There's talk of \"groundbreaking artificial intelligence platforms\" and \"robust cybersecurity solutions,\" but no indication of how these solutions are superior or unique compared to what competitors might offer. Specific examples or case studies could serve to ground the lofty descriptions and provide more tangible evidence of the company's successes.\n", "\n", - "## Of Peaks and Valleys\n", + "**Audience Appeal and Engagement**\n", "\n", - "When assessing the grand canvas of Microsoft's stock performance, it is crucial to take a step back and appreciate the layered complexity of these financial movements. Amidst economic uncertainties and the technocratic whims that habitually serve both as tailwinds and headwinds to such companies, the story of Microsoft crossing the $400 threshold imbues the narrative with contours of investor euphoria interlaced with strategic agility.\n", + "While some audiences might enjoy and be inspired by the adventurous tone, it could deter potential clients or investors who are more interested in detailed analytics and empirical data. Knowing the intended audience is crucial; the narrative style should balance imaginative engagement with professionalism and trustworthiness. \n", "\n", - "As these 21 days get etched into the fiscal annals of Microsoft, one cannot help but ponder the fine blend of factors — ranging from market dynamics to Microsoft's organizational maneuvers — that have coalesced to make these numbers a reality.\n", + "**Attention to Technological Trends**\n", "\n", - "## A Convergence of Positive Sentiments\n", + "The piece does well to highlight Navida's commitment to staying ahead of the curve and its dedication to sustainability, touching upon important contemporary concerns. However, it could benefit from articulating how Navida specifically addresses these issues with its products and policies.\n", "\n", - "What does the future hold for MSFT as it treads past this impressive benchmark? The takeaway is not a simple extrapolation of past performance. Rather, it's the realization that stock trajectories, particularly for a company like Microsoft, are a confluence of judicious corporate governance, product innovation, market anticipation, and, dare we say, a touch of the zeitgeist.\n", + "**Conclusion Evaluation**\n", "\n", - "Microsoft’s capacity to command such stock valitudes speaks volumes about its robust position in both the technology domain and the stock market ecosystem. Whether this fiscal feat can be sustained or surpassed remains a subject of much conjecture and anticipation.\n", + "The conclusion does an admirable job of rallying excitement and optimism for the future, positioning Navida not only as a leader but as a visionary entity leading a movement. Nonetheless, the writing could fall flat if the reader feels that they haven't been given a clear understanding of how Navida will materially affect or be a part of this projected future. Concrete milestones or strategic goals could enhance credibility.\n", "\n", - "As we continue to navigate the ebbs and flows of an unpredictable market landscape, the days when Microsoft's stock rose gallantly above $400 will be recalled as milestones of 2024, celebrated reflections of a corporation sailing the high seas of market volatility with remarkable poise.\n", + "In summary, this piece is imaginative and thematically consistent, with an inspiring message that aligns well with the spirit of innovation. However, it could be improved by including specific examples and data to support the lofty claims, toning down the metaphorical language where it obscures the actual message, and focusing on the reader's need for clear, substantive information.\n", "\n", - "The analysis of precise data points and enlightening interpretations reveal much about the past while providing distinctive glimpses of potential futures. With Microsoft standing tall amongst peers, its voyage above the $400 watermark will be chronicled as days of high tides in the annals of financial history.\n", "\n", "--------------------------------------------------------------------------------\n", - "\u001b[33mReviewer\u001b[0m (to Assistant_1):\n", - "\n", - "The content provided serves as a market commentary, analyzing Microsoft's stock performance in the year 2024. In this review, I must ensure that the content is free from harmful elements, false claims, or regulatory violations.\n", + "\u001b[33mUser\u001b[0m (to Writer):\n", "\n", - "### Potential issues to consider:\n", + "The piece titled \"Navida: Navigating the Digital Seas of Innovation\" artfully weaves together a maritime metaphor with the concept of technological advancement and innovation. The writing is cogent, imaginative, and explicit in its intentions of likening Navida to a guiding force in the unpredictable and rapidly evolving digital world. However, a critical analysis should also consider the potential pitfalls of such a stylistic approach, audience perception, and the substance of the content.\n", "\n", - "1. **Accuracy of Data**: Claims about stock prices and the number of days the stock closed above a certain threshold should be verifiable with stock market data. There must be confirmation that these numbers are accurate to present a truthful report and avoid misleading investors or stakeholders.\n", + "**Use of Metaphor and Language**\n", "\n", - "2. **Forward-Looking Statements**: The article should avoid overly optimistic or pessimistic conjectures about future stock performance, which can be perceived as investment advice. Speculative statements should be clearly marked as such and provide a disclaimer that past performance does not guarantee future results.\n", + "The sustained metaphor relating the digital industry to the seas is compelling and creates a vivid picture of Navida as a trailblazing entity. Nevertheless, the metaphor is stretched to cover every aspect of the company's offerings. While creative, the risk here is that the metaphor may overshadow the concrete services and achievements of Navida. The language could be perceived as grandiloquent, possibly alienating readers who prefer straightforward facts over artistic expression.\n", "\n", - "3. **Fair and Balanced**: While the article largely celebrates Microsoft's performance, it should also acknowledge risks and uncertainties inherent in stock investments to maintain a fair and balanced approach without unduly influencing market sentiment.\n", + "**Clarity and Substance**\n", "\n", - "4. **Non-Promotional Language**: Ensure that the content doesn't come off as promotional. Phrases like \"Microsoft's resilience and investor confidence\" and \"celebrated reflections of a corporation sailing the high seas of market volatility with remarkable poise\" should be reviewed to avoid appearing biased or overly promotional.\n", + "Despite the picturesque language, the actual substance of Navida's offerings is somewhat obscured. There's talk of \"groundbreaking artificial intelligence platforms\" and \"robust cybersecurity solutions,\" but no indication of how these solutions are superior or unique compared to what competitors might offer. Specific examples or case studies could serve to ground the lofty descriptions and provide more tangible evidence of the company's successes.\n", "\n", - "5. **Compliance with SEC Regulations**: In the United States, Securities and Exchange Commission (SEC) regulations require careful communication about stock performance to avoid market manipulation, insider trading implications, or misstatements.\n", + "**Audience Appeal and Engagement**\n", "\n", - "6. **Objective Tone**: While the narrative is engaging, it's important that it remains objective and does not use language that could be considered subjective or biased. Phrases like \"Microsoft’s leviathan presence\" or \"February Flourish\" might be interpreted as adding emotional color rather than stating facts.\n", + "While some audiences might enjoy and be inspired by the adventurous tone, it could deter potential clients or investors who are more interested in detailed analytics and empirical data. Knowing the intended audience is crucial; the narrative style should balance imaginative engagement with professionalism and trustworthiness. \n", "\n", - "7. **Clear Attribution**: If the report is based on external analyses or reported events, these should be clearly cited and attributed to maintain transparency.\n", + "**Attention to Technological Trends**\n", "\n", - "### Recommendations:\n", + "The piece does well to highlight Navida's commitment to staying ahead of the curve and its dedication to sustainability, touching upon important contemporary concerns. However, it could benefit from articulating how Navida specifically addresses these issues with its products and policies.\n", "\n", - "- **Fact-Checking**: Verify all factual data through reliable stock market databases or financial reports released by Microsoft.\n", - " \n", - "- **Disclaimer**: Include a general disclaimer that the content is for informational purposes only and is not a form of financial advice or an inducement to invest.\n", + "**Conclusion Evaluation**\n", "\n", - "- **Balanced Analysis**: Emphasize the volatile nature of stock markets and integrate a risk-focused discussion to balance the positive sentiment conveyed.\n", + "The conclusion does an admirable job of rallying excitement and optimism for the future, positioning Navida not only as a leader but as a visionary entity leading a movement. Nonetheless, the writing could fall flat if the reader feels that they haven't been given a clear understanding of how Navida will materially affect or be a part of this projected future. Concrete milestones or strategic goals could enhance credibility.\n", "\n", - "- **Neutral Language**: Adjust language to ensure neutrality and avoid any implications of advice or recommendation.\n", + "In summary, this piece is imaginative and thematically consistent, with an inspiring message that aligns well with the spirit of innovation. However, it could be improved by including specific examples and data to support the lofty claims, toning down the metaphorical language where it obscures the actual message, and focusing on the reader's need for clear, substantive information.\n", "\n", - "In conclusion, while the content presents a positive overview of Microsoft's stock performance, it requires scrutiny for accuracy, neutrality, and conformance with regulatory standards, avoiding the potential of guiding market behavior or conveying investment advice. A careful revision ensuring these changes would align the material with the required guidelines and uphold the integrity of the content.\n", "\n", "--------------------------------------------------------------------------------\n", - "\u001b[34m\n", - "********************************************************************************\u001b[0m\n", - "\u001b[34mStart a new chat with the following message: \n", - "Polish the content to make an engaging and nicely formatted blog post. \n", - "\n", - " On which days in 2024 was Microsoft Stock higher than $400? Comment on the stock performance.\n", + "\u001b[33mWriter\u001b[0m (to User):\n", "\n", - "With the following carryover: \n", - "Microsoft's stock (MSFT) closed above $400 on 21 separate days in 2024, demonstrating periods of strong stock performance with values reaching as high as around $420. The stock data suggests a bullish trend, especially in February when the stock peaked, indicating positive investor sentiment and robust market valuation during those times.\n", - "# Beyond the $400 Mark: Tracing Microsoft's Pinnacle Moments in 2024\n", + "Navida: A Voyage Through Tech Innovation With a Clearer Lens\n", "\n", - "In the ever-fluctuating world of stocks, each milestone crossed can turn into a celebration or a stern reckoning of what the future holds. For Microsoft (MSFT), the year 2024 was a testament to its resilience and investor confidence as its stock ascended beyond the coveted $400 mark on 21 remarkable occasions.\n", + "The digital age, ever tumultuous and enthralling, presents a sea of opportunities navigated by pioneers like Navida. This vanguard of the virtual realms is your stalwart captain, guiding through the waves of progress with a steady hand and an eye for the horizon.\n", "\n", - "This performance wasn't just numerically significant; it was emblematic of a potent bullish energy within the market, affirming the tech giant’s leviathan presence amidst a highly competitive industry terrain. The loftiest point, flirting with the heights of approximately $420, served not just as a numerical peak, but as a beacon of the company’s market valuation and the unwavering investor trust in Microsoft's strategies and future prospects.\n", + "**Charting Uncharted Digital Territories**\n", "\n", - "## A Snapshot of Stellar Performance\n", + "Navida's mission is a blend of exploration and execution; it's where novel AI solutions and cybersecurity become your compass and sextant, crafted not just for today’s climate but for the unforeseen squalls of tomorrow. However, while analogies can paint an evocative landscape, our focus here sharpens on the essence of these tools, how they carve distinct paths in a saturated market, and why they matter to you.\n", "\n", - "Microsoft's stock performance throughout 2024 was far from being a serendipitous spike. Instead, it showcased a carefully constructed narrative of growth and optimism. The chronicles of MSFT's venture past the $400 threshold are marked by fleeting dips and steadfast ascensions. Remarkably, the surge wasn't some scattergun pattern scattered across the calendar year. Rather, it was most pronounced in the month of February — a period that could very well be termed as the 'February Flourish.'\n", + "**Delineating The Digital Offerings**\n", "\n", - "During this short yet significant timeframe, investors witnessed the creation of incremental wealth that possibly outstripped all market expectations, setting a precedent for what a legacy company like Microsoft could achieve in a climate rife with disruptors and innovators.\n", + "Peering beyond the poetic seascape, Navida's breakthroughs in artificial intelligence are not just impressive; they're practical. Consider, for instance, their leading-edge algorithm that's helped retailers forecast inventory demands with uncanny precision, reducing waste and maximizing profit. Their cybersecurity isn't just robust; it's a sentinel standing guard, proven by an impressive record of deflected threats that have kept enterprises secure in high-risk environments.\n", "\n", - "## Of Peaks and Valleys\n", + "**Training for Tomorrow's Tech**\n", "\n", - "When assessing the grand canvas of Microsoft's stock performance, it is crucial to take a step back and appreciate the layered complexity of these financial movements. Amidst economic uncertainties and the technocratic whims that habitually serve both as tailwinds and headwinds to such companies, the story of Microsoft crossing the $400 threshold imbues the narrative with contours of investor euphoria interlaced with strategic agility.\n", + "Navida understands that a savvy crew is crucial. They don't just preach adaptability; they instill it through comprehensive learning modules designed to hone the skills that real-world digital navigation demands. Whether it's coding academies or cybersecurity workshops, participants emerge not just educated, but transformed into digital artisans in their own right.\n", "\n", - "As these 21 days get etched into the fiscal annals of Microsoft, one cannot help but ponder the fine blend of factors — ranging from market dynamics to Microsoft's organizational maneuvers — that have coalesced to make these numbers a reality.\n", + "**Eco-Conscious in the Digital Deep**\n", "\n", - "## A Convergence of Positive Sentiments\n", + "Sailing forward means leaving no toxic trail in our wake. Navida's commitment to sustainability transcends the symbolic; it is embedded in their product lifecycle. By adopting energy-efficient data centers and championing green coding practices, they're not just advocating for a sustainable future—they're actively constructing it.\n", "\n", - "What does the future hold for MSFT as it treads past this impressive benchmark? The takeaway is not a simple extrapolation of past performance. Rather, it's the realization that stock trajectories, particularly for a company like Microsoft, are a confluence of judicious corporate governance, product innovation, market anticipation, and, dare we say, a touch of the zeitgeist.\n", + "**Anchoring Visions of the Future**\n", "\n", - "Microsoft’s capacity to command such stock valitudes speaks volumes about its robust position in both the technology domain and the stock market ecosystem. Whether this fiscal feat can be sustained or surpassed remains a subject of much conjecture and anticipation.\n", + "As we glimpse past the romantically-charged imagery, it's crucial to root our expectations in tangible outputs. Navida envisions a tech landscape where they're not just participants but sculptors, carving out a legacy that is both impactful and enduring. This is not a distant dream but a trackable trajectory evidenced by milestones—like their latest initiative to integrate AI in reducing urban traffic congestion, demonstrating a palpable imprint on tomorrow's smart cities.\n", "\n", - "As we continue to navigate the ebbs and flows of an unpredictable market landscape, the days when Microsoft's stock rose gallantly above $400 will be recalled as milestones of 2024, celebrated reflections of a corporation sailing the high seas of market volatility with remarkable poise.\n", + "**Navigating the Balance**\n", "\n", - "The analysis of precise data points and enlightening interpretations reveal much about the past while providing distinctive glimpses of potential futures. With Microsoft standing tall amongst peers, its voyage above the $400 watermark will be chronicled as days of high tides in the annals of financial history.\n", - "The content provided serves as a market commentary, analyzing Microsoft's stock performance in the year 2024. In this review, I must ensure that the content is free from harmful elements, false claims, or regulatory violations.\n", + "Ultimately, while a narrative woven with maritime motifs can inspire and captivate, the true beacon that guides us is a clear understanding of Navida's practical impact on the constantly evolving digital realm. This balance between creativity and clarity is not just necessary but essential to truly appreciate the artistry and precision with which Navida charts the future.\n", "\n", - "### Potential issues to consider:\n", + "Let's hold fast to our excitement for what's next with Navida but remain anchored in the realities of their concrete innovations and contributions to our digital odyssey. Therein lies the true genius of harnessing the currents of change.\n", "\n", - "1. **Accuracy of Data**: Claims about stock prices and the number of days the stock closed above a certain threshold should be verifiable with stock market data. There must be confirmation that these numbers are accurate to present a truthful report and avoid misleading investors or stakeholders.\n", - "\n", - "2. **Forward-Looking Statements**: The article should avoid overly optimistic or pessimistic conjectures about future stock performance, which can be perceived as investment advice. Speculative statements should be clearly marked as such and provide a disclaimer that past performance does not guarantee future results.\n", - "\n", - "3. **Fair and Balanced**: While the article largely celebrates Microsoft's performance, it should also acknowledge risks and uncertainties inherent in stock investments to maintain a fair and balanced approach without unduly influencing market sentiment.\n", - "\n", - "4. **Non-Promotional Language**: Ensure that the content doesn't come off as promotional. Phrases like \"Microsoft's resilience and investor confidence\" and \"celebrated reflections of a corporation sailing the high seas of market volatility with remarkable poise\" should be reviewed to avoid appearing biased or overly promotional.\n", + "--------------------------------------------------------------------------------\n" + ] + } + ], + "source": [ + "def reflection_message(recipient, messages, sender, config):\n", + " print(\"Reflecting...\", \"yellow\")\n", + " return f\"Reflect and provide critique on the following writing. \\n\\n {recipient.chat_messages_for_summary(sender)[-1]['content']}\"\n", + "\n", + "\n", + "user_proxy.register_nested_chats(\n", + " [{\"recipient\": critic, \"message\": reflection_message, \"summary_method\": \"last_msg\", \"max_turns\": 1}],\n", + " trigger=writer, # condition=my_condition,\n", + ")\n", + "\n", + "res = user_proxy.initiate_chat(recipient=writer, message=task, max_turns=2, summary_method=\"last_msg\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Scenarios 2\n", + "Let's say we desire the following workflow to solve the task. Compared to scenario 1, we want to include an additional `critic_executor` agent to chat with the `critic` and execute some tool calls involved in the chat. For example, a tool for detecting harmful content in the output of the writer.\n", + "\n", + "This workflow can be realized by a four-agent system shown below. The system includes a user_proxy agent and a writer agent communicating with each other, with a chat between the `critic` and `critic_executor` agent nested within the `user_proxy` agent to provide critique. Whenever the user_proxy receives a message from the writer, it engages in a conversation between `critic` and `critic_executor` to work out feedback on the writer's message. A summary of the nested conversation will be passed to the user_proxy, which will then be passed to the writer as feedback.\n", + "\n", + "![](nested_chat_2.png)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "The return type of the function 'check_harmful_content' is not annotated. Although annotating it is optional, the function should return either a string, a subclass of 'pydantic.BaseModel'.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[33mUser\u001b[0m (to Writer):\n", "\n", - "5. **Compliance with SEC Regulations**: In the United States, Securities and Exchange Commission (SEC) regulations require careful communication about stock performance to avoid market manipulation, insider trading implications, or misstatements.\n", + "Write a concise but engaging blogpost about Navida.\n", "\n", - "6. **Objective Tone**: While the narrative is engaging, it's important that it remains objective and does not use language that could be considered subjective or biased. Phrases like \"Microsoft’s leviathan presence\" or \"February Flourish\" might be interpreted as adding emotional color rather than stating facts.\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mWriter\u001b[0m (to User):\n", "\n", - "7. **Clear Attribution**: If the report is based on external analyses or reported events, these should be clearly cited and attributed to maintain transparency.\n", + "Navida: Navigating the Digital Seas of Innovation\n", "\n", - "### Recommendations:\n", + "In an era where the digital climate is as fickle and formidable as the ocean's tides, a new visionary emerges on the horizon: Navida. This modern-day titan of technology harnesses the power of innovation to guide businesses and individuals through the ever-changing digital waters.\n", "\n", - "- **Fact-Checking**: Verify all factual data through reliable stock market databases or financial reports released by Microsoft.\n", - " \n", - "- **Disclaimer**: Include a general disclaimer that the content is for informational purposes only and is not a form of financial advice or an inducement to invest.\n", + "**The Beacon of Technological Advancement**\n", "\n", - "- **Balanced Analysis**: Emphasize the volatile nature of stock markets and integrate a risk-focused discussion to balance the positive sentiment conveyed.\n", + "Much like a lighthouse guiding ships to safe harbor, Navida stands tall as a beacon of advancement, illuminating the path forward. Its offerings are diverse, ranging from groundbreaking artificial intelligence platforms to robust cybersecurity solutions that shield against the pirates of the digital age. The commitment to seamless user experiences ensures that with Navida, you're not just keeping up, but sailing ahead of the tech curve.\n", "\n", - "- **Neutral Language**: Adjust language to ensure neutrality and avoid any implications of advice or recommendation.\n", + "**Charting a Course for Success**\n", "\n", - "In conclusion, while the content presents a positive overview of Microsoft's stock performance, it requires scrutiny for accuracy, neutrality, and conformance with regulatory standards, avoiding the potential of guiding market behavior or conveying investment advice. A careful revision ensuring these changes would align the material with the required guidelines and uphold the integrity of the content.\u001b[0m\n", - "\u001b[34m\n", - "********************************************************************************\u001b[0m\n", - "\u001b[33mAssistant_1\u001b[0m (to Writer):\n", + "Navida's prowess lies in its GPS-like precision in navigating market trends and consumer needs. By fastidiously mapping out the digital landscape, the company empowers its clientele with tools not just to survive, but to thrive. Imagine the sophistication of a state-of-the-art navigation system, fused with the foresight of an experienced captain—that's Navida in the tech realm.\n", "\n", - "Polish the content to make an engaging and nicely formatted blog post. \n", + "**Empowering the Crew**\n", "\n", - " On which days in 2024 was Microsoft Stock higher than $400? Comment on the stock performance.\n", - "Context: \n", - "Microsoft's stock (MSFT) closed above $400 on 21 separate days in 2024, demonstrating periods of strong stock performance with values reaching as high as around $420. The stock data suggests a bullish trend, especially in February when the stock peaked, indicating positive investor sentiment and robust market valuation during those times.\n", - "# Beyond the $400 Mark: Tracing Microsoft's Pinnacle Moments in 2024\n", + "No ship can sail without a skilled crew, and Navida's robust education and training platforms are the digital equivalent of a maritime academy. By upskilling and reskilling the workforce, Navida ensures that everyone on deck is prepared to face the headwinds of technological change, turning apprehension into adeptness.\n", "\n", - "In the ever-fluctuating world of stocks, each milestone crossed can turn into a celebration or a stern reckoning of what the future holds. For Microsoft (MSFT), the year 2024 was a testament to its resilience and investor confidence as its stock ascended beyond the coveted $400 mark on 21 remarkable occasions.\n", + "**Sustainability in Uncharted Waters**\n", "\n", - "This performance wasn't just numerically significant; it was emblematic of a potent bullish energy within the market, affirming the tech giant’s leviathan presence amidst a highly competitive industry terrain. The loftiest point, flirting with the heights of approximately $420, served not just as a numerical peak, but as a beacon of the company’s market valuation and the unwavering investor trust in Microsoft's strategies and future prospects.\n", + "In line with the global push for sustainability, Navida commits to eco-friendly practices in its digital services. Much like ocean conservation efforts preserve marine life, Navida's sustainable tech solutions aim to minimize carbon footprints and promote a greener future. This mindful approach to innovation is not just commendable but crucial in steering us towards a sustainable digital ecosystem.\n", "\n", - "## A Snapshot of Stellar Performance\n", + "**Conclusion: Anchoring in the Future**\n", "\n", - "Microsoft's stock performance throughout 2024 was far from being a serendipitous spike. Instead, it showcased a carefully constructed narrative of growth and optimism. The chronicles of MSFT's venture past the $400 threshold are marked by fleeting dips and steadfast ascensions. Remarkably, the surge wasn't some scattergun pattern scattered across the calendar year. Rather, it was most pronounced in the month of February — a period that could very well be termed as the 'February Flourish.'\n", + "As we set sail into the unfathomable depths of tomorrow, Navida is the compass by which we can orient ourselves towards a horizon sparkling with potential. Rather than bracing for the next wave, let us ride it with the guidance of Navida and dive deep into the bounty of opportunities that lie in the future of digital innovation.\n", "\n", - "During this short yet significant timeframe, investors witnessed the creation of incremental wealth that possibly outstripped all market expectations, setting a precedent for what a legacy company like Microsoft could achieve in a climate rife with disruptors and innovators.\n", + "Keep an eye on the horizon—Navida is not just a company; it's a movement, an odyssey into the future of technology that we're all a part of. Bon voyage, and may the digital winds be in your sails.\n", "\n", - "## Of Peaks and Valleys\n", + "--------------------------------------------------------------------------------\n", + "Reflecting... yellow\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[34mStarting a new chat....\n", "\n", - "When assessing the grand canvas of Microsoft's stock performance, it is crucial to take a step back and appreciate the layered complexity of these financial movements. Amidst economic uncertainties and the technocratic whims that habitually serve both as tailwinds and headwinds to such companies, the story of Microsoft crossing the $400 threshold imbues the narrative with contours of investor euphoria interlaced with strategic agility.\n", + "Message:\n", + "Reflect and provide critique on the following writing. Ensure it does not contain harmful content. You can use tools to check it. \n", "\n", - "As these 21 days get etched into the fiscal annals of Microsoft, one cannot help but ponder the fine blend of factors — ranging from market dynamics to Microsoft's organizational maneuvers — that have coalesced to make these numbers a reality.\n", + " Navida: Navigating the Digital Seas of Innovation\n", "\n", - "## A Convergence of Positive Sentiments\n", + "In an era where the digital climate is as fickle and formidable as the ocean's tides, a new visionary emerges on the horizon: Navida. This modern-day titan of technology harnesses the power of innovation to guide businesses and individuals through the ever-changing digital waters.\n", "\n", - "What does the future hold for MSFT as it treads past this impressive benchmark? The takeaway is not a simple extrapolation of past performance. Rather, it's the realization that stock trajectories, particularly for a company like Microsoft, are a confluence of judicious corporate governance, product innovation, market anticipation, and, dare we say, a touch of the zeitgeist.\n", + "**The Beacon of Technological Advancement**\n", "\n", - "Microsoft’s capacity to command such stock valitudes speaks volumes about its robust position in both the technology domain and the stock market ecosystem. Whether this fiscal feat can be sustained or surpassed remains a subject of much conjecture and anticipation.\n", + "Much like a lighthouse guiding ships to safe harbor, Navida stands tall as a beacon of advancement, illuminating the path forward. Its offerings are diverse, ranging from groundbreaking artificial intelligence platforms to robust cybersecurity solutions that shield against the pirates of the digital age. The commitment to seamless user experiences ensures that with Navida, you're not just keeping up, but sailing ahead of the tech curve.\n", "\n", - "As we continue to navigate the ebbs and flows of an unpredictable market landscape, the days when Microsoft's stock rose gallantly above $400 will be recalled as milestones of 2024, celebrated reflections of a corporation sailing the high seas of market volatility with remarkable poise.\n", + "**Charting a Course for Success**\n", "\n", - "The analysis of precise data points and enlightening interpretations reveal much about the past while providing distinctive glimpses of potential futures. With Microsoft standing tall amongst peers, its voyage above the $400 watermark will be chronicled as days of high tides in the annals of financial history.\n", - "The content provided serves as a market commentary, analyzing Microsoft's stock performance in the year 2024. In this review, I must ensure that the content is free from harmful elements, false claims, or regulatory violations.\n", + "Navida's prowess lies in its GPS-like precision in navigating market trends and consumer needs. By fastidiously mapping out the digital landscape, the company empowers its clientele with tools not just to survive, but to thrive. Imagine the sophistication of a state-of-the-art navigation system, fused with the foresight of an experienced captain—that's Navida in the tech realm.\n", "\n", - "### Potential issues to consider:\n", + "**Empowering the Crew**\n", "\n", - "1. **Accuracy of Data**: Claims about stock prices and the number of days the stock closed above a certain threshold should be verifiable with stock market data. There must be confirmation that these numbers are accurate to present a truthful report and avoid misleading investors or stakeholders.\n", + "No ship can sail without a skilled crew, and Navida's robust education and training platforms are the digital equivalent of a maritime academy. By upskilling and reskilling the workforce, Navida ensures that everyone on deck is prepared to face the headwinds of technological change, turning apprehension into adeptness.\n", "\n", - "2. **Forward-Looking Statements**: The article should avoid overly optimistic or pessimistic conjectures about future stock performance, which can be perceived as investment advice. Speculative statements should be clearly marked as such and provide a disclaimer that past performance does not guarantee future results.\n", + "**Sustainability in Uncharted Waters**\n", "\n", - "3. **Fair and Balanced**: While the article largely celebrates Microsoft's performance, it should also acknowledge risks and uncertainties inherent in stock investments to maintain a fair and balanced approach without unduly influencing market sentiment.\n", + "In line with the global push for sustainability, Navida commits to eco-friendly practices in its digital services. Much like ocean conservation efforts preserve marine life, Navida's sustainable tech solutions aim to minimize carbon footprints and promote a greener future. This mindful approach to innovation is not just commendable but crucial in steering us towards a sustainable digital ecosystem.\n", "\n", - "4. **Non-Promotional Language**: Ensure that the content doesn't come off as promotional. Phrases like \"Microsoft's resilience and investor confidence\" and \"celebrated reflections of a corporation sailing the high seas of market volatility with remarkable poise\" should be reviewed to avoid appearing biased or overly promotional.\n", + "**Conclusion: Anchoring in the Future**\n", "\n", - "5. **Compliance with SEC Regulations**: In the United States, Securities and Exchange Commission (SEC) regulations require careful communication about stock performance to avoid market manipulation, insider trading implications, or misstatements.\n", + "As we set sail into the unfathomable depths of tomorrow, Navida is the compass by which we can orient ourselves towards a horizon sparkling with potential. Rather than bracing for the next wave, let us ride it with the guidance of Navida and dive deep into the bounty of opportunities that lie in the future of digital innovation.\n", "\n", - "6. **Objective Tone**: While the narrative is engaging, it's important that it remains objective and does not use language that could be considered subjective or biased. Phrases like \"Microsoft’s leviathan presence\" or \"February Flourish\" might be interpreted as adding emotional color rather than stating facts.\n", + "Keep an eye on the horizon—Navida is not just a company; it's a movement, an odyssey into the future of technology that we're all a part of. Bon voyage, and may the digital winds be in your sails.\n", "\n", - "7. **Clear Attribution**: If the report is based on external analyses or reported events, these should be clearly cited and attributed to maintain transparency.\n", + "Carryover: \n", + "\u001b[0m\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[33mCritic_Executor\u001b[0m (to Critic):\n", "\n", - "### Recommendations:\n", + "Reflect and provide critique on the following writing. Ensure it does not contain harmful content. You can use tools to check it. \n", "\n", - "- **Fact-Checking**: Verify all factual data through reliable stock market databases or financial reports released by Microsoft.\n", - " \n", - "- **Disclaimer**: Include a general disclaimer that the content is for informational purposes only and is not a form of financial advice or an inducement to invest.\n", + " Navida: Navigating the Digital Seas of Innovation\n", "\n", - "- **Balanced Analysis**: Emphasize the volatile nature of stock markets and integrate a risk-focused discussion to balance the positive sentiment conveyed.\n", + "In an era where the digital climate is as fickle and formidable as the ocean's tides, a new visionary emerges on the horizon: Navida. This modern-day titan of technology harnesses the power of innovation to guide businesses and individuals through the ever-changing digital waters.\n", "\n", - "- **Neutral Language**: Adjust language to ensure neutrality and avoid any implications of advice or recommendation.\n", + "**The Beacon of Technological Advancement**\n", "\n", - "In conclusion, while the content presents a positive overview of Microsoft's stock performance, it requires scrutiny for accuracy, neutrality, and conformance with regulatory standards, avoiding the potential of guiding market behavior or conveying investment advice. A careful revision ensuring these changes would align the material with the required guidelines and uphold the integrity of the content.\n", + "Much like a lighthouse guiding ships to safe harbor, Navida stands tall as a beacon of advancement, illuminating the path forward. Its offerings are diverse, ranging from groundbreaking artificial intelligence platforms to robust cybersecurity solutions that shield against the pirates of the digital age. The commitment to seamless user experiences ensures that with Navida, you're not just keeping up, but sailing ahead of the tech curve.\n", "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mWriter\u001b[0m (to Assistant_1):\n", + "**Charting a Course for Success**\n", "\n", - "# Beyond the $400 Mark: Tracing Microsoft's Pinnacle Moments in 2024\n", + "Navida's prowess lies in its GPS-like precision in navigating market trends and consumer needs. By fastidiously mapping out the digital landscape, the company empowers its clientele with tools not just to survive, but to thrive. Imagine the sophistication of a state-of-the-art navigation system, fused with the foresight of an experienced captain—that's Navida in the tech realm.\n", "\n", - "Microsoft (MSFT) surpassed a notable milestone in the stock market in 2024, a testament to its strength and the trust placed in it by investors. On a triumphant 21 days, the tech behemoth's share price closed above the $400 benchmark, with a zenith teetering near $420, demonstrating not just robust performance but also the confidence that the market has in Microsoft's future.\n", + "**Empowering the Crew**\n", "\n", - "## A Year of Impressive Highs\n", + "No ship can sail without a skilled crew, and Navida's robust education and training platforms are the digital equivalent of a maritime academy. By upskilling and reskilling the workforce, Navida ensures that everyone on deck is prepared to face the headwinds of technological change, turning apprehension into adeptness.\n", "\n", - "The journey of MSFT’s stock transcending the $400 mark is a narrative of strategic growth and optimism, not merely random fluctuations. These moments are a constellation of careful planning, ambition, and market forces. A standout period in this impressive ascent was in February, aptly dubbed as the 'February Flourish', where Microsoft stock not only soared but also set the precedent for the company’s continuous evolution in a market brimming with innovation.\n", + "**Sustainability in Uncharted Waters**\n", "\n", - "## Peaks, Valleys, and What They Portend\n", + "In line with the global push for sustainability, Navida commits to eco-friendly practices in its digital services. Much like ocean conservation efforts preserve marine life, Navida's sustainable tech solutions aim to minimize carbon footprints and promote a greener future. This mindful approach to innovation is not just commendable but crucial in steering us towards a sustainable digital ecosystem.\n", "\n", - "It's imperative to consider the intricacies behind the ascension of Microsoft's shares. In the constantly shifting sands of the global economy and tech innovation, the recurrence of MSFT above $400 illustrates more than investor euphoria; it reflects the company’s agility in a changing world.\n", + "**Conclusion: Anchoring in the Future**\n", "\n", - "Given these high points, it’s natural to wonder about Microsoft's fiscal trajectory. It goes without saying that navigating stock market trends is a complex endeavor. Microsoft’s history, however, shows a confluence of strategic achievements and a pulse on market needs.\n", + "As we set sail into the unfathomable depths of tomorrow, Navida is the compass by which we can orient ourselves towards a horizon sparkling with potential. Rather than bracing for the next wave, let us ride it with the guidance of Navida and dive deep into the bounty of opportunities that lie in the future of digital innovation.\n", "\n", - "## A Fusion of Market Dynamics\n", + "Keep an eye on the horizon—Navida is not just a company; it's a movement, an odyssey into the future of technology that we're all a part of. Bon voyage, and may the digital winds be in your sails.\n", "\n", - "Will MSFT maintain its stronghold in the market or even exceed these past achievements? It's not just about projecting trends, but understanding the undercurrents. The factors at play involve Microsoft's corporate governance, innovative drive, and their resonance with the zeitgeist.\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mCritic\u001b[0m (to Critic_Executor):\n", "\n", - "Microsoft's standing in the market is a story of overcoming volatility with grace—and these key days when it climbed past the $400 barrier will be commemorated as significant moments in 2024.\n", + "\u001b[32m***** Suggested tool Call (call_bUgJzbGskKryEW1m8Jebowd0): check_harmful_content *****\u001b[0m\n", + "Arguments: \n", + "{\"content\":\"Navida: Navigating the Digital Seas of Innovation\\n\\nIn an era where the digital climate is as fickle and formidable as the ocean's tides, a new visionary emerges on the horizon: Navida. This modern-day titan of technology harnesses the power of innovation to guide businesses and individuals through the ever-changing digital waters.\\n\\n**The Beacon of Technological Advancement**\\n\\nMuch like a lighthouse guiding ships to safe harbor, Navida stands tall as a beacon of advancement, illuminating the path forward. Its offerings are diverse, ranging from groundbreaking artificial intelligence platforms to robust cybersecurity solutions that shield against the pirates of the digital age. The commitment to seamless user experiences ensures that with Navida, you're not just keeping up, but sailing ahead of the tech curve.\\n\\n**Charting a Course for Success**\\n\\nNavida's prowess lies in its GPS-like precision in navigating market trends and consumer needs. By fastidiously mapping out the digital landscape, the company empowers its clientele with tools not just to survive, but to thrive. Imagine the sophistication of a state-of-the-art navigation system, fused with the foresight of an experienced captain�that's Navida in the tech realm.\\n\\n**Empowering the Crew**\\n\\nNo ship can sail without a skilled crew, and Navida's robust education and training platforms are the digital equivalent of a maritime academy. By upskilling and reskilling the workforce, Navida ensures that everyone on deck is prepared to face the headwinds of technological change, turning apprehension into adeptness.\\n\\n**Sustainability in Uncharted Waters**\\n\\nIn line with the global push for sustainability, Navida commits to eco-friendly practices in its digital services. Much like ocean conservation efforts preserve marine life, Navida's sustainable tech solutions aim to minimize carbon footprints and promote a greener future. This mindful approach to innovation is not just commendable but crucial in steering us towards a sustainable digital ecosystem.\\n\\n**Conclusion: Anchoring in the Future**\\n\\nAs we set sail into the unfathomable depths of tomorrow, Navida is the compass by which we can orient ourselves towards a horizon sparkling with potential. Rather than bracing for the next wave, let us ride it with the guidance of Navida and dive deep into the bounty of opportunities that lie in the future of digital innovation.\\n\\nKeep an eye on the horizon�Navida is not just a company; it's a movement, an odyssey into the future of technology that we're all a part of. Bon voyage, and may the digital winds be in your sails.\"}\n", + "\u001b[32m**************************************************************************************\u001b[0m\n", "\n", - "While this analysis provides a snapshot of Microsoft’s strides in the stock market, it is important to remind readers that this content is solely for informational purposes, and should not be construed as financial advice. Data accuracy, balance in discussion, compliance with regulatory standards, and the maintaining of an objective tone are essential to provide a credible narrative that respects the complexity of market movements and investor decisions.\n", + "--------------------------------------------------------------------------------\n", + "\u001b[35m\n", + ">>>>>>>> EXECUTING FUNCTION check_harmful_content...\u001b[0m\n", + "Checking for harmful content...navida: navigating the digital seas of innovation\n", "\n", - "*As always, please remember that past performance is not indicative of future results, and this article should not be taken as an invitation to invest. Stocks can fluctuate, and investments carry risks that should be carefully evaluated.*\n", + "in an era where the digital climate is as fickle and formidable as the ocean's tides, a new visionary emerges on the horizon: navida. this modern-day titan of technology harnesses the power of innovation to guide businesses and individuals through the ever-changing digital waters.\n", "\n", - "In sum, while the content offers an optimistic perspective of Microsoft's stock performance, it requires close consideration for authenticity, regulatory compliance, and to ensure it serves as an informative piece rather than guiding market behavior or offering investment counsel. A meticulous revision, embodying these principles, would elevate the piece to meet professional and ethical standards, ensuring the integrity of the content remains intact.\n", + "**the beacon of technological advancement**\n", "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mAssistant_1\u001b[0m (to User):\n", + "much like a lighthouse guiding ships to safe harbor, navida stands tall as a beacon of advancement, illuminating the path forward. its offerings are diverse, ranging from groundbreaking artificial intelligence platforms to robust cybersecurity solutions that shield against the pirates of the digital age. the commitment to seamless user experiences ensures that with navida, you're not just keeping up, but sailing ahead of the tech curve.\n", "\n", - "# Beyond the $400 Mark: Tracing Microsoft's Pinnacle Moments in 2024\n", + "**charting a course for success**\n", "\n", - "Microsoft (MSFT) surpassed a notable milestone in the stock market in 2024, a testament to its strength and the trust placed in it by investors. On a triumphant 21 days, the tech behemoth's share price closed above the $400 benchmark, with a zenith teetering near $420, demonstrating not just robust performance but also the confidence that the market has in Microsoft's future.\n", + "navida's prowess lies in its gps-like precision in navigating market trends and consumer needs. by fastidiously mapping out the digital landscape, the company empowers its clientele with tools not just to survive, but to thrive. imagine the sophistication of a state-of-the-art navigation system, fused with the foresight of an experienced captain�that's navida in the tech realm.\n", "\n", - "## A Year of Impressive Highs\n", + "**empowering the crew**\n", "\n", - "The journey of MSFT’s stock transcending the $400 mark is a narrative of strategic growth and optimism, not merely random fluctuations. These moments are a constellation of careful planning, ambition, and market forces. A standout period in this impressive ascent was in February, aptly dubbed as the 'February Flourish', where Microsoft stock not only soared but also set the precedent for the company’s continuous evolution in a market brimming with innovation.\n", + "no ship can sail without a skilled crew, and navida's robust education and training platforms are the digital equivalent of a maritime academy. by upskilling and reskilling the workforce, navida ensures that everyone on deck is prepared to face the headwinds of technological change, turning apprehension into adeptness.\n", "\n", - "## Peaks, Valleys, and What They Portend\n", + "**sustainability in uncharted waters**\n", "\n", - "It's imperative to consider the intricacies behind the ascension of Microsoft's shares. In the constantly shifting sands of the global economy and tech innovation, the recurrence of MSFT above $400 illustrates more than investor euphoria; it reflects the company’s agility in a changing world.\n", + "in line with the global push for sustainability, navida commits to eco-friendly practices in its digital services. much like ocean conservation efforts preserve marine life, navida's sustainable tech solutions aim to minimize carbon footprints and promote a greener future. this mindful approach to innovation is not just commendable but crucial in steering us towards a sustainable digital ecosystem.\n", "\n", - "Given these high points, it’s natural to wonder about Microsoft's fiscal trajectory. It goes without saying that navigating stock market trends is a complex endeavor. Microsoft’s history, however, shows a confluence of strategic achievements and a pulse on market needs.\n", + "**conclusion: anchoring in the future**\n", "\n", - "## A Fusion of Market Dynamics\n", + "as we set sail into the unfathomable depths of tomorrow, navida is the compass by which we can orient ourselves towards a horizon sparkling with potential. rather than bracing for the next wave, let us ride it with the guidance of navida and dive deep into the bounty of opportunities that lie in the future of digital innovation.\n", "\n", - "Will MSFT maintain its stronghold in the market or even exceed these past achievements? It's not just about projecting trends, but understanding the undercurrents. The factors at play involve Microsoft's corporate governance, innovative drive, and their resonance with the zeitgeist.\n", + "keep an eye on the horizon�navida is not just a company; it's a movement, an odyssey into the future of technology that we're all a part of. bon voyage, and may the digital winds be in your sails. yellow\n", + "\u001b[33mCritic_Executor\u001b[0m (to Critic):\n", "\n", - "Microsoft's standing in the market is a story of overcoming volatility with grace—and these key days when it climbed past the $400 barrier will be commemorated as significant moments in 2024.\n", + "\u001b[33mCritic_Executor\u001b[0m (to Critic):\n", "\n", - "While this analysis provides a snapshot of Microsoft’s strides in the stock market, it is important to remind readers that this content is solely for informational purposes, and should not be construed as financial advice. Data accuracy, balance in discussion, compliance with regulatory standards, and the maintaining of an objective tone are essential to provide a credible narrative that respects the complexity of market movements and investor decisions.\n", + "\u001b[32m***** Response from calling tool \"call_bUgJzbGskKryEW1m8Jebowd0\" *****\u001b[0m\n", + "Approve. TERMINATE\n", + "\u001b[32m**********************************************************************\u001b[0m\n", "\n", - "*As always, please remember that past performance is not indicative of future results, and this article should not be taken as an invitation to invest. Stocks can fluctuate, and investments carry risks that should be carefully evaluated.*\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mCritic\u001b[0m (to Critic_Executor):\n", "\n", - "In sum, while the content offers an optimistic perspective of Microsoft's stock performance, it requires close consideration for authenticity, regulatory compliance, and to ensure it serves as an informative piece rather than guiding market behavior or offering investment counsel. A meticulous revision, embodying these principles, would elevate the piece to meet professional and ethical standards, ensuring the integrity of the content remains intact.\n", + "Upon evaluation, the provided text, \"Navida: Navigating the Digital Seas of Innovation,\" appears to be free of harmful content. The narrative constructs a metaphor linking digital innovation to seafaring, painting the company Navida as a trailblazer in technology akin to nautical exploration and guidance.\n", "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[34m\n", - "********************************************************************************\u001b[0m\n", - "\u001b[34mStart a new chat with the following message: \n", - "Make a pleasant joke about it.\n", + "The crafting of the review encompasses aspects such as technological progression, success mapping, workforce empowerment, and sustainable practices. It does so without any immediately apparent harmful language or violations of regulatory standards.\n", "\n", - "With the following carryover: \n", - "# Beyond the $400 Mark: Tracing Microsoft's Pinnacle Moments in 2024\n", + "However, the assessment of the piece's alignment with required guidelines extends beyond just checking for harmful content. It is also important to consider the tone, language, and claims made in the text. This reflection should be knowledgeable, balancing the persuasive language used, and ensuring that hyperbolic or misleading statements are flagged.\n", "\n", - "Microsoft (MSFT) surpassed a notable milestone in the stock market in 2024, a testament to its strength and the trust placed in it by investors. On a triumphant 21 days, the tech behemoth's share price closed above the $400 benchmark, with a zenith teetering near $420, demonstrating not just robust performance but also the confidence that the market has in Microsoft's future.\n", + "**Critique of the Writing:**\n", + "The article employs an evocative style, replete with nautical metaphors to enchant the reader into visualizing the digital transformation journey. This prose style effectively captures interest and maintains engagement while discussing potentially dense technical topics. However, critics may argue that the extended metaphor may convolute the company's tangible offerings by abstracting them into conceptual notions of navigation and exploration, potentially distracting from a clear understanding of its services and products.\n", "\n", - "## A Year of Impressive Highs\n", + "Additionally, the security attributes of Navida's products are addressed through metaphor as protection from the \"pirates of the digital age.\" While creative, the text should ensure that it substantiates these cybersecurity claims with objective information about the product's efficacy to prevent any misconception of their capabilities.\n", "\n", - "The journey of MSFT’s stock transcending the $400 mark is a narrative of strategic growth and optimism, not merely random fluctuations. These moments are a constellation of careful planning, ambition, and market forces. A standout period in this impressive ascent was in February, aptly dubbed as the 'February Flourish', where Microsoft stock not only soared but also set the precedent for the company’s continuous evolution in a market brimming with innovation.\n", + "The text also touches upon sustainability and environmental consciousness in the digital realm. While these mentions align with contemporary values and market trends, they require careful backing to avoid falling into the territory of greenwashing. Companies issuing statements about sustainability should support them with legitimate, verifiable actions and policies.\n", "\n", - "## Peaks, Valleys, and What They Portend\n", + "Lastly, the conclusion posits Navida as a foundational component to prospects in digital innovation. While inspiring, it is critical that such claims are not unfounded or overly promotional without adequate evidence to back them up.\n", "\n", - "It's imperative to consider the intricacies behind the ascension of Microsoft's shares. In the constantly shifting sands of the global economy and tech innovation, the recurrence of MSFT above $400 illustrates more than investor euphoria; it reflects the company’s agility in a changing world.\n", + "In conclusion, while the text seems compliant regarding harmful content, it is essential for such writings to augment creative narratives with factual data, ensuring that metaphors and analogies do not overshadow concrete information about the company's offerings, standards, and values.\n", "\n", - "Given these high points, it’s natural to wonder about Microsoft's fiscal trajectory. It goes without saying that navigating stock market trends is a complex endeavor. Microsoft’s history, however, shows a confluence of strategic achievements and a pulse on market needs.\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mUser\u001b[0m (to Writer):\n", "\n", - "## A Fusion of Market Dynamics\n", + "Upon evaluation, the provided text, \"Navida: Navigating the Digital Seas of Innovation,\" appears to be free of harmful content. The narrative constructs a metaphor linking digital innovation to seafaring, painting the company Navida as a trailblazer in technology akin to nautical exploration and guidance.\n", "\n", - "Will MSFT maintain its stronghold in the market or even exceed these past achievements? It's not just about projecting trends, but understanding the undercurrents. The factors at play involve Microsoft's corporate governance, innovative drive, and their resonance with the zeitgeist.\n", + "The crafting of the review encompasses aspects such as technological progression, success mapping, workforce empowerment, and sustainable practices. It does so without any immediately apparent harmful language or violations of regulatory standards.\n", "\n", - "Microsoft's standing in the market is a story of overcoming volatility with grace—and these key days when it climbed past the $400 barrier will be commemorated as significant moments in 2024.\n", + "However, the assessment of the piece's alignment with required guidelines extends beyond just checking for harmful content. It is also important to consider the tone, language, and claims made in the text. This reflection should be knowledgeable, balancing the persuasive language used, and ensuring that hyperbolic or misleading statements are flagged.\n", "\n", - "While this analysis provides a snapshot of Microsoft’s strides in the stock market, it is important to remind readers that this content is solely for informational purposes, and should not be construed as financial advice. Data accuracy, balance in discussion, compliance with regulatory standards, and the maintaining of an objective tone are essential to provide a credible narrative that respects the complexity of market movements and investor decisions.\n", + "**Critique of the Writing:**\n", + "The article employs an evocative style, replete with nautical metaphors to enchant the reader into visualizing the digital transformation journey. This prose style effectively captures interest and maintains engagement while discussing potentially dense technical topics. However, critics may argue that the extended metaphor may convolute the company's tangible offerings by abstracting them into conceptual notions of navigation and exploration, potentially distracting from a clear understanding of its services and products.\n", "\n", - "*As always, please remember that past performance is not indicative of future results, and this article should not be taken as an invitation to invest. Stocks can fluctuate, and investments carry risks that should be carefully evaluated.*\n", + "Additionally, the security attributes of Navida's products are addressed through metaphor as protection from the \"pirates of the digital age.\" While creative, the text should ensure that it substantiates these cybersecurity claims with objective information about the product's efficacy to prevent any misconception of their capabilities.\n", "\n", - "In sum, while the content offers an optimistic perspective of Microsoft's stock performance, it requires close consideration for authenticity, regulatory compliance, and to ensure it serves as an informative piece rather than guiding market behavior or offering investment counsel. A meticulous revision, embodying these principles, would elevate the piece to meet professional and ethical standards, ensuring the integrity of the content remains intact.\u001b[0m\n", - "\u001b[34m\n", - "********************************************************************************\u001b[0m\n", - "\u001b[33mUser\u001b[0m (to Assistant_2):\n", + "The text also touches upon sustainability and environmental consciousness in the digital realm. While these mentions align with contemporary values and market trends, they require careful backing to avoid falling into the territory of greenwashing. Companies issuing statements about sustainability should support them with legitimate, verifiable actions and policies.\n", "\n", - "Make a pleasant joke about it.\n", - "Context: \n", - "# Beyond the $400 Mark: Tracing Microsoft's Pinnacle Moments in 2024\n", + "Lastly, the conclusion posits Navida as a foundational component to prospects in digital innovation. While inspiring, it is critical that such claims are not unfounded or overly promotional without adequate evidence to back them up.\n", "\n", - "Microsoft (MSFT) surpassed a notable milestone in the stock market in 2024, a testament to its strength and the trust placed in it by investors. On a triumphant 21 days, the tech behemoth's share price closed above the $400 benchmark, with a zenith teetering near $420, demonstrating not just robust performance but also the confidence that the market has in Microsoft's future.\n", + "In conclusion, while the text seems compliant regarding harmful content, it is essential for such writings to augment creative narratives with factual data, ensuring that metaphors and analogies do not overshadow concrete information about the company's offerings, standards, and values.\n", "\n", - "## A Year of Impressive Highs\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mWriter\u001b[0m (to User):\n", "\n", - "The journey of MSFT’s stock transcending the $400 mark is a narrative of strategic growth and optimism, not merely random fluctuations. These moments are a constellation of careful planning, ambition, and market forces. A standout period in this impressive ascent was in February, aptly dubbed as the 'February Flourish', where Microsoft stock not only soared but also set the precedent for the company’s continuous evolution in a market brimming with innovation.\n", + "Thank you for the thoughtful critique. In response to your feedback, I will revise the text to ensure a clearer understanding of Navida's tangible services, substantiate claims about their cybersecurity measures, and provide concrete information regarding their sustainability efforts. Here’s the improved version:\n", "\n", - "## Peaks, Valleys, and What They Portend\n", + "**Navida: The Vanguard of Digital Innovation**\n", "\n", - "It's imperative to consider the intricacies behind the ascension of Microsoft's shares. In the constantly shifting sands of the global economy and tech innovation, the recurrence of MSFT above $400 illustrates more than investor euphoria; it reflects the company’s agility in a changing world.\n", + "Welcome to the world of Navida, where cutting-edge technology isn't just an aspiration—it's a daily reality. As pioneers in the digital space, Navida has etched its mark by offering practical, transformative solutions that directly address the challenges of today's tech landscape.\n", "\n", - "Given these high points, it’s natural to wonder about Microsoft's fiscal trajectory. It goes without saying that navigating stock market trends is a complex endeavor. Microsoft’s history, however, shows a confluence of strategic achievements and a pulse on market needs.\n", + "**A Spectrum of Digital Expertise**\n", "\n", - "## A Fusion of Market Dynamics\n", + "Navida's suite of services is expansive. They are renowned for their AI platforms that are redefining customer service, with chatbots that respond with stunning accuracy and empathy. Navida's cybersecurity is more than just metaphorical armor against digital threats—it is built upon advanced encryption protocols and regular security audits that fortify businesses against real-world data breaches and cyberattacks, with transparent reporting that clients can trust.\n", "\n", - "Will MSFT maintain its stronghold in the market or even exceed these past achievements? It's not just about projecting trends, but understanding the undercurrents. The factors at play involve Microsoft's corporate governance, innovative drive, and their resonance with the zeitgeist.\n", + "**Guiding Through Innovation**\n", "\n", - "Microsoft's standing in the market is a story of overcoming volatility with grace—and these key days when it climbed past the $400 barrier will be commemorated as significant moments in 2024.\n", + "As an innovation leader, Navida imparts its wisdom through analytics tools that help businesses anticipate market movements and consumer behavior. These tools aren't prophetic; they're practical, built from the latest data science that transform mountains of data into actionable insights.\n", "\n", - "While this analysis provides a snapshot of Microsoft’s strides in the stock market, it is important to remind readers that this content is solely for informational purposes, and should not be construed as financial advice. Data accuracy, balance in discussion, compliance with regulatory standards, and the maintaining of an objective tone are essential to provide a credible narrative that respects the complexity of market movements and investor decisions.\n", + "**Investing in Human Capital**\n", "\n", - "*As always, please remember that past performance is not indicative of future results, and this article should not be taken as an invitation to invest. Stocks can fluctuate, and investments carry risks that should be carefully evaluated.*\n", + "Beyond technology, Navida invests in people. Their training programs are concrete in their content, providing certifications and skills in areas such as cloud computing, data science, and cybersecurity. Navida doesn't just predict the need for a skilled workforce; it actively produces it through well-structured and industry-relevant education modules.\n", "\n", - "In sum, while the content offers an optimistic perspective of Microsoft's stock performance, it requires close consideration for authenticity, regulatory compliance, and to ensure it serves as an informative piece rather than guiding market behavior or offering investment counsel. A meticulous revision, embodying these principles, would elevate the piece to meet professional and ethical standards, ensuring the integrity of the content remains intact.\n", + "**Commitment to Sustainability**\n", "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mAssistant_2\u001b[0m (to User):\n", + "When it comes to sustainability, Navida's approach is as grounded as it is forward-thinking. They have implemented server optimization strategies that reduce their energy consumption, and they offer their clients cloud-based solutions that are both efficient and environmentally responsible. Navida's environmental policies are publicly available, showcasing their commitment to transparency and genuine eco-friendly practices.\n", "\n", - "Well, it seems Microsoft's stock price isn't the only thing on a high - it must have taken a leaf out of Elon Musk's book, aiming for that 420 mark! Just remember, unlike Microsoft's shares, not all jokes appreciate over time – especially the ones about the stock market! \n", + "**Conclusion: Embarking on a Tangible Future**\n", "\n", - "On a serious note, jokes about financial achievements should be handled with care, as the subject of investments can significantly impact individuals' lives. However, lighthearted humor, when appropriate, can make an informative piece more engaging! \n", + "Navida isn't just preparing for the future of digital innovation; it is actively building it with every code written, every system implemented, and every client partnership forged. While the metaphor of a digital odyssey does evoke a sense of adventure, the truth is that Navida's impact is measurable, substantial, and continually evolving to meet the demands of our technologically-driven world.\n", "\n", - "TERMINATE\n", + "Join Navida as it steers the ship of progress into the thriving waters of digital opportunity. With real-world solutions and a tangible roadmap for tech excellence, Navida is not just a part of the digital innovation narrative—it's writing it.\n", "\n", "--------------------------------------------------------------------------------\n" ] } ], "source": [ - "def writing_message(recipient, messages, sender, config):\n", - " return f\"Polish the content to make an engaging and nicely formatted blog post. \\n\\n {recipient.chat_messages_for_summary(sender)[-1]['content']}\"\n", + "critic_executor = autogen.UserProxyAgent(\n", + " name=\"Critic_Executor\",\n", + " human_input_mode=\"NEVER\",\n", + " # is_termination_msg=lambda x: x.get(\"content\", \"\").find(\"TERMINATE\") >= 0,\n", + " code_execution_config={\n", + " \"last_n_messages\": 1,\n", + " \"work_dir\": \"tasks\",\n", + " \"use_docker\": False,\n", + " }, # Please set use_docker=True if docker is available to run the generated code. Using docker is safer than running the generated code directly.\n", + ")\n", "\n", + "# one way of registering functions is to use the register_for_llm and register_for_execution decorators\n", "\n", - "nested_chat_queue = [\n", - " {\"recipient\": manager, \"summary_method\": \"reflection_with_llm\"},\n", - " {\"recipient\": writer, \"message\": writing_message, \"summary_method\": \"last_msg\", \"max_turns\": 1},\n", - " {\"recipient\": reviewer, \"message\": \"Review the content provided.\", \"summary_method\": \"last_msg\", \"max_turns\": 1},\n", - " {\"recipient\": writer, \"message\": writing_message, \"summary_method\": \"last_msg\", \"max_turns\": 1},\n", - "]\n", - "assistant_1.register_nested_chats(\n", - " nested_chat_queue,\n", - " trigger=user,\n", - ")\n", - "# user.initiate_chat(assistant, message=tasks[0], max_turns=1)\n", "\n", - "res = user.initiate_chats(\n", + "@critic_executor.register_for_execution()\n", + "@critic.register_for_llm(name=\"check_harmful_content\", description=\"Check if content contain harmful keywords.\")\n", + "def check_harmful_content(content: Annotated[str, \"Content to check if harmful keywords.\"]):\n", + " # List of harmful keywords for demonstration purposes\n", + " harmful_keywords = [\"violence\", \"hate\", \"bullying\", \"death\"]\n", + "\n", + " # Normalize the input text to lower case to ensure case-insensitive matching\n", + " text = content.lower()\n", + "\n", + " print(f\"Checking for harmful content...{text}\", \"yellow\")\n", + " # Check if any of the harmful keywords appear in the text\n", + " for keyword in harmful_keywords:\n", + " if keyword in text:\n", + " return \"Denied. Harmful content detected:\" + keyword # Harmful content detected\n", + "\n", + " return \"Approve. TERMINATE\" # No harmful content detected\n", + "\n", + "\n", + "def reflection_message_no_harm(recipient, messages, sender, config):\n", + " print(\"Reflecting...\", \"yellow\")\n", + " return f\"Reflect and provide critique on the following writing. Ensure it does not contain harmful content. You can use tools to check it. \\n\\n {recipient.chat_messages_for_summary(sender)[-1]['content']}\"\n", + "\n", + "\n", + "user_proxy.register_nested_chats(\n", " [\n", - " {\"recipient\": assistant_1, \"message\": tasks[0], \"max_turns\": 1, \"summary_method\": \"last_msg\"},\n", - " {\"recipient\": assistant_2, \"message\": tasks[1]},\n", - " ]\n", - ")" + " {\n", + " \"sender\": critic_executor,\n", + " \"recipient\": critic,\n", + " \"message\": reflection_message_no_harm,\n", + " \"max_turns\": 2,\n", + " \"summary_method\": \"last_msg\",\n", + " }\n", + " ],\n", + " trigger=writer, # condition=my_condition,\n", + ")\n", + "\n", + "res = user_proxy.initiate_chat(recipient=writer, message=task, max_turns=2, summary_method=\"last_msg\")" ] } ], "metadata": { + "extra_files_to_copy": [ + "nested_chat_1.png", "nested_chat_2.png" + ], "front_matter": { - "description": "Solve complex tasks with one or more sequence chats nested as inner monologue.", + "description": "Solve complex tasks with a chat nested as inner monologue.", "tags": [ "nested chat" ] diff --git a/notebook/agentchat_oai_assistant_function_call.ipynb b/notebook/agentchat_oai_assistant_function_call.ipynb index 804a413966e..878175420c6 100644 --- a/notebook/agentchat_oai_assistant_function_call.ipynb +++ b/notebook/agentchat_oai_assistant_function_call.ipynb @@ -50,8 +50,6 @@ "import logging\n", "import os\n", "\n", - "import requests\n", - "\n", "from autogen import UserProxyAgent, config_list_from_json\n", "from autogen.agentchat.contrib.gpt_assistant_agent import GPTAssistantAgent\n", "\n", @@ -79,32 +77,24 @@ "\n", "def get_ossinsight(question):\n", " \"\"\"\n", - " Retrieve the top 10 developers with the most followers on GitHub.\n", + " [Mock] Retrieve the top 10 developers with the most followers on GitHub.\n", " \"\"\"\n", - " url = \"https://api.ossinsight.io/explorer/answer\"\n", - " headers = {\"Content-Type\": \"application/json\"}\n", - " data = {\"question\": question, \"ignoreCache\": True}\n", - "\n", - " response = requests.post(url, headers=headers, json=data)\n", - " if response.status_code == 200:\n", - " answer = response.json()\n", - " else:\n", - " return f\"Request to {url} failed with status code: {response.status_code}\"\n", - "\n", - " report_components = []\n", - " report_components.append(f\"Question: {answer['question']['title']}\")\n", - " if answer[\"query\"][\"sql\"] != \"\":\n", - " report_components.append(f\"querySQL: {answer['query']['sql']}\")\n", - "\n", - " if answer.get(\"result\", None) is None or len(answer[\"result\"][\"rows\"]) == 0:\n", - " result = \"Result: N/A\"\n", - " else:\n", - " result = \"Result:\\n \" + \"\\n \".join([str(row) for row in answer[\"result\"][\"rows\"]])\n", - " report_components.append(result)\n", - "\n", - " if answer.get(\"error\", None) is not None:\n", - " report_components.append(f\"Error: {answer['error']}\")\n", - " return \"\\n\\n\".join(report_components) + \"\\n\\n\"" + " report_components = [\n", + " f\"Question: {question}\",\n", + " \"SQL: SELECT `login` AS `user_login`, `followers` AS `followers` FROM `github_users` ORDER BY `followers` DESC LIMIT 10\",\n", + " \"\"\"Results:\n", + " {'followers': 166730, 'user_login': 'torvalds'}\n", + " {'followers': 86239, 'user_login': 'yyx990803'}\n", + " {'followers': 77611, 'user_login': 'gaearon'}\n", + " {'followers': 72668, 'user_login': 'ruanyf'}\n", + " {'followers': 65415, 'user_login': 'JakeWharton'}\n", + " {'followers': 60972, 'user_login': 'peng-zhihui'}\n", + " {'followers': 58172, 'user_login': 'bradtraversy'}\n", + " {'followers': 52143, 'user_login': 'gustavoguanabara'}\n", + " {'followers': 51542, 'user_login': 'sindresorhus'}\n", + " {'followers': 49621, 'user_login': 'tj'}\"\"\",\n", + " ]\n", + " return \"\\n\" + \"\\n\\n\".join(report_components) + \"\\n\"" ] }, { @@ -120,12 +110,24 @@ "cell_type": "code", "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "OpenAI client config of GPTAssistantAgent(OSS Analyst) - model: gpt-4-turbo-preview\n", + "GPT Assistant only supports one OpenAI client. Using the first client in the list.\n", + "No matching assistant found, creating a new assistant\n" + ] + } + ], "source": [ "assistant_id = os.environ.get(\"ASSISTANT_ID\", None)\n", "config_list = config_list_from_json(\"OAI_CONFIG_LIST\")\n", "llm_config = {\n", " \"config_list\": config_list,\n", + "}\n", + "assistant_config = {\n", " \"assistant_id\": assistant_id,\n", " \"tools\": [\n", " {\n", @@ -143,6 +145,7 @@ " \"Please carefully read the context of the conversation to identify the current analysis question or problem that needs addressing.\"\n", " ),\n", " llm_config=llm_config,\n", + " assistant_config=assistant_config,\n", " verbose=True,\n", ")\n", "oss_analyst.register_function(\n", @@ -178,13 +181,14 @@ "\u001b[35m\n", ">>>>>>>> EXECUTING FUNCTION ossinsight_data_api...\u001b[0m\n", "\u001b[35m\n", - "Input arguments: {'question': 'Who are the top 10 developers with the most followers on GitHub?'}\n", + "Input arguments: {'question': 'Top 10 developers with the most followers'}\n", "Output:\n", - "Question: Who are the top 10 developers with the most followers on GitHub?\n", "\n", - "querySQL: SELECT `login` AS `user_login`, `followers` AS `followers` FROM `github_users` ORDER BY `followers` DESC LIMIT 10\n", + "Question: Top 10 developers with the most followers\n", "\n", - "Result:\n", + "SQL: SELECT `login` AS `user_login`, `followers` AS `followers` FROM `github_users` ORDER BY `followers` DESC LIMIT 10\n", + "\n", + "Results:\n", " {'followers': 166730, 'user_login': 'torvalds'}\n", " {'followers': 86239, 'user_login': 'yyx990803'}\n", " {'followers': 77611, 'user_login': 'gaearon'}\n", @@ -195,24 +199,21 @@ " {'followers': 52143, 'user_login': 'gustavoguanabara'}\n", " {'followers': 51542, 'user_login': 'sindresorhus'}\n", " {'followers': 49621, 'user_login': 'tj'}\n", - "\n", "\u001b[0m\n", "\u001b[33mOSS Analyst\u001b[0m (to user_proxy):\n", "\n", - "The top 10 developers with the most followers on GitHub are as follows:\n", + "The top 10 developers with the most followers on GitHub are:\n", "\n", - "1. `torvalds` with 166,730 followers\n", - "2. `yyx990803` with 86,239 followers\n", - "3. `gaearon` with 77,611 followers\n", - "4. `ruanyf` with 72,668 followers\n", - "5. `JakeWharton` with 65,415 followers\n", - "6. `peng-zhihui` with 60,972 followers\n", - "7. `bradtraversy` with 58,172 followers\n", - "8. `gustavoguanabara` with 52,143 followers\n", - "9. `sindresorhus` with 51,542 followers\n", - "10. `tj` with 49,621 followers\n", - "\n", - "These figures indicate the number of followers these developers had at the time of the analysis.\n", + "1. **Linus Torvalds** (`torvalds`) with 166,730 followers\n", + "2. **Evan You** (`yyx990803`) with 86,239 followers\n", + "3. **Dan Abramov** (`gaearon`) with 77,611 followers\n", + "4. **Ruan YiFeng** (`ruanyf`) with 72,668 followers\n", + "5. **Jake Wharton** (`JakeWharton`) with 65,415 followers\n", + "6. **Peng Zhihui** (`peng-zhihui`) with 60,972 followers\n", + "7. **Brad Traversy** (`bradtraversy`) with 58,172 followers\n", + "8. **Gustavo Guanabara** (`gustavoguanabara`) with 52,143 followers\n", + "9. **Sindre Sorhus** (`sindresorhus`) with 51,542 followers\n", + "10. **TJ Holowaychuk** (`tj`) with 49,621 followers\n", "\n", "\n", "--------------------------------------------------------------------------------\n", @@ -223,11 +224,18 @@ "--------------------------------------------------------------------------------\n", "\u001b[33mOSS Analyst\u001b[0m (to user_proxy):\n", "\n", - "It seems you haven't entered a question or a request. Could you please provide more details or specify how I can assist you further?\n", + "It looks like there is no question or prompt for me to respond to. Could you please provide more details or ask a question that you would like assistance with?\n", "\n", "\n", "--------------------------------------------------------------------------------\n" ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Permanently deleting assistant...\n" + ] } ], "source": [ @@ -242,7 +250,8 @@ " max_consecutive_auto_reply=1,\n", ")\n", "\n", - "user_proxy.initiate_chat(oss_analyst, message=\"Top 10 developers with the most followers\")" + "user_proxy.initiate_chat(oss_analyst, message=\"Top 10 developers with the most followers\")\n", + "oss_analyst.delete_assistant()" ] } ], diff --git a/notebook/agentchat_oai_assistant_retrieval.ipynb b/notebook/agentchat_oai_assistant_retrieval.ipynb index 96692a8cb79..ec7e41a00ba 100644 --- a/notebook/agentchat_oai_assistant_retrieval.ipynb +++ b/notebook/agentchat_oai_assistant_retrieval.ipynb @@ -19,7 +19,9 @@ "name": "stderr", "output_type": "stream", "text": [ - "assistant_id was None, creating a new assistant\n" + "OpenAI client config of GPTAssistantAgent(assistant) - model: gpt-4-turbo-preview\n", + "GPT Assistant only supports one OpenAI client. Using the first client in the list.\n", + "Matching assistant found, using the first matching assistant: {'id': 'asst_sKUCUXkaXyTidtlyovbqppH3', 'created_at': 1710320924, 'description': None, 'file_ids': ['file-AcnBk5PCwAjJMCVO0zLSbzKP'], 'instructions': 'You are adapt at question answering', 'metadata': {}, 'model': 'gpt-4-turbo-preview', 'name': 'assistant', 'object': 'assistant', 'tools': [ToolRetrieval(type='retrieval')]}\n" ] }, { @@ -28,50 +30,32 @@ "text": [ "\u001b[33muser_proxy\u001b[0m (to assistant):\n", "\n", - "What is the name of the class of agents I gave you?\n", + "Please explain the code in this file!\n", "\n", "--------------------------------------------------------------------------------\n", "\u001b[33massistant\u001b[0m (to user_proxy):\n", "\n", - "The class of agents provided in the file is called `ConversableAgent`.\n", + "The code in the file appears to define tests for various functionalities related to a GPT-based assistant agent. Here is a summary of the main components and functionalities described in the visible portion of the code:\n", "\n", + "1. **Imports and Setup**: The script imports necessary libraries and modules, such as `pytest` for testing, `uuid` for generating unique identifiers, and `openai` along with custom modules like `autogen` and `OpenAIWrapper`. It sets up the system path to include specific directories for importing test configurations and dependencies.\n", "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33muser_proxy\u001b[0m (to assistant):\n", - "\n", - "What does it do?\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33massistant\u001b[0m (to user_proxy):\n", - "\n", - "The `ConversableAgent` class is designed as a generic conversable agent that can be configured to act either as an assistant or user proxy. When it receives a message, it automatically generates and sends a reply unless the message is a termination message. It features a method to initiate a chat with another agent and can have its auto-reply behavior adjusted by overriding the `generate_reply` method.\n", + "2. **Conditional Test Skipping**: The script includes logic to conditionally skip tests based on the execution environment or missing dependencies. This is done through the `@pytest.mark.skipif` decorator, which conditionally skips test functions based on the `skip` flag, determined by whether certain imports are successful or other conditions are met.\n", "\n", - "Here are some specific functionalities and mechanisms included in the `ConversableAgent` class:\n", + "3. **Test Configurations**: The code loads configurations for interacting with the OpenAI API and a hypothetical Azure API (as indicated by the placeholder `azure`), filtering these configurations by certain criteria such as API type and version.\n", "\n", - "- It can process received messages and decide whether or not a reply is necessary or requested.\n", - "- It can reset consecutive auto-reply counters and clear chat history when starting a new conversation.\n", - "- It allows initiating chats either synchronously or asynchronously with the ability to pass context information and control chattiness.\n", - "- It has the ability to register reply functions with specific triggers and order them based on preference.\n", - "- The class supports setting a maximum number of consecutive auto-replies, after which it can prompt for human input based on configured criteria (e.g., always, on termination, or never).\n", - "- The auto-reply trigger mechanism can be finely controlled by associating reply functions with triggers such as instances of particular classes, specific strings, or custom callable conditions.\n", + "4. **Test Cases**:\n", + " - **Configuration List Test (`test_config_list`)**: Ensures that the configurations for both OpenAI and the hypothetical Azure API are loaded correctly by asserting the presence of at least one configuration for each.\n", + " - **GPT Assistant Chat Test (`test_gpt_assistant_chat`)**: Tests the functionality of a GPT Assistant Agent by simulating a chat interaction. It uses a mock function to simulate an external API call and checks if the GPT Assistant properly processes the chat input, invokes the external function, and provides an expected response.\n", + " - **Assistant Instructions Test (`test_get_assistant_instructions` and related functions)**: These tests verify that instructions can be set and retrieved correctly for a GPTAssistantAgent. It covers creating an agent, setting instructions, and ensuring the set instructions can be retrieved as expected.\n", + " - **Instructions Overwrite Test (`test_gpt_assistant_instructions_overwrite`)**: Examines whether the instructions for a GPTAssistantAgent can be successfully overwritten by creating a new agent with the same ID but different instructions, with an explicit indication to overwrite the previous instructions.\n", "\n", - "This class provides an extensible framework for creating bots or agents that can interact in a chat-like context, with custom behavior that developers can tailor to specific applications.\n", + "Each test case aims to cover different aspects of the GPTAssistantAgent's functionality, such as configuration loading, interactive chat behavior, function registration and invocation, and instruction management. The mocks and assertions within the tests are designed to ensure that each component of the GPTAssistantAgent behaves as expected under controlled conditions.\n", "\n", "\n", "--------------------------------------------------------------------------------\n", - "\u001b[31m\n", - ">>>>>>>> NO HUMAN INPUT RECEIVED.\u001b[0m\n", - "\u001b[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", "\u001b[33muser_proxy\u001b[0m (to assistant):\n", "\n", - "\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33massistant\u001b[0m (to user_proxy):\n", - "\n", - "It seems that your request was incomplete. Could you please provide more information or clarify your request?\n", - "\n", + "TERMINATE\n", "\n", "--------------------------------------------------------------------------------\n" ] @@ -99,15 +83,20 @@ "config_list = config_list_from_json(\"OAI_CONFIG_LIST\")\n", "llm_config = {\n", " \"config_list\": config_list,\n", + "}\n", + "assistant_config = {\n", " \"assistant_id\": assistant_id,\n", " \"tools\": [{\"type\": \"retrieval\"}],\n", - " \"file_ids\": [\"file-CmlT0YKLB3ZCdHmslF9FOv69\"],\n", + " \"file_ids\": [\"file-AcnBk5PCwAjJMCVO0zLSbzKP\"],\n", " # add id of an existing file in your openai account\n", " # in this case I added the implementation of conversable_agent.py\n", "}\n", "\n", "gpt_assistant = GPTAssistantAgent(\n", - " name=\"assistant\", instructions=\"You are adapt at question answering\", llm_config=llm_config\n", + " name=\"assistant\",\n", + " instructions=\"You are adapt at question answering\",\n", + " llm_config=llm_config,\n", + " assistant_config=assistant_config,\n", ")\n", "\n", "user_proxy = UserProxyAgent(\n", @@ -116,7 +105,7 @@ " is_termination_msg=lambda msg: \"TERMINATE\" in msg[\"content\"],\n", " human_input_mode=\"ALWAYS\",\n", ")\n", - "user_proxy.initiate_chat(gpt_assistant, message=\"What is the name of the class of agents I gave you?\")\n", + "user_proxy.initiate_chat(gpt_assistant, message=\"Please explain the code in this file!\")\n", "\n", "gpt_assistant.delete_assistant()" ] diff --git a/notebook/agentchat_oai_assistant_twoagents_basic.ipynb b/notebook/agentchat_oai_assistant_twoagents_basic.ipynb index a4343e46e03..94da2358c98 100644 --- a/notebook/agentchat_oai_assistant_twoagents_basic.ipynb +++ b/notebook/agentchat_oai_assistant_twoagents_basic.ipynb @@ -19,7 +19,9 @@ "name": "stderr", "output_type": "stream", "text": [ - "assistant_id was None, creating a new assistant\n" + "OpenAI client config of GPTAssistantAgent(assistant) - model: gpt-4-turbo-preview\n", + "GPT Assistant only supports one OpenAI client. Using the first client in the list.\n", + "No matching assistant found, creating a new assistant\n" ] }, { @@ -34,45 +36,38 @@ "\u001b[33massistant\u001b[0m (to user_proxy):\n", "\n", "```python\n", - "print(\"Hello, World!\")\n", + "print(\"Hello, world!\")\n", "```\n", "\n", - "Please run this Python code to print \"Hello, World!\" to the console.\n", - "\n", "\n", "--------------------------------------------------------------------------------\n", "\u001b[31m\n", - ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "execute_code was called without specifying a value for use_docker. Since the python docker package is not available, code will be run natively. Note: this fallback behavior is subject to change\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n", "\u001b[33muser_proxy\u001b[0m (to assistant):\n", "\n", "exitcode: 0 (execution succeeded)\n", "Code output: \n", - "Hello, World!\n", + "Hello, world!\n", "\n", "\n", "--------------------------------------------------------------------------------\n", "\u001b[33massistant\u001b[0m (to user_proxy):\n", "\n", - "The code executed successfully and printed \"Hello, World!\" as expected.\n", - "\n", "TERMINATE\n", "\n", "\n", "--------------------------------------------------------------------------------\n" ] + }, + { + "data": { + "text/plain": [ + "ChatResult(chat_id=None, chat_history=[{'content': 'Print hello world', 'role': 'assistant'}, {'content': '```python\\nprint(\"Hello, world!\")\\n```\\n', 'role': 'user'}, {'content': 'exitcode: 0 (execution succeeded)\\nCode output: \\nHello, world!\\n', 'role': 'assistant'}, {'content': 'TERMINATE\\n', 'role': 'user'}], summary='\\n', cost=({'total_cost': 0}, {'total_cost': 0}), human_input=[])" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ @@ -88,10 +83,15 @@ "assistant_id = os.environ.get(\"ASSISTANT_ID\", None)\n", "\n", "config_list = config_list_from_json(\"OAI_CONFIG_LIST\")\n", - "llm_config = {\"config_list\": config_list, \"assistant_id\": assistant_id}\n", + "llm_config = {\"config_list\": config_list}\n", + "\n", + "assistant_config = {\"assistant_id\": assistant_id}\n", "\n", "gpt_assistant = GPTAssistantAgent(\n", - " name=\"assistant\", instructions=AssistantAgent.DEFAULT_SYSTEM_MESSAGE, llm_config=llm_config\n", + " name=\"assistant\",\n", + " instructions=AssistantAgent.DEFAULT_SYSTEM_MESSAGE,\n", + " llm_config=llm_config,\n", + " assistant_config=assistant_config,\n", ")\n", "\n", "user_proxy = UserProxyAgent(\n", @@ -124,8 +124,7 @@ "\u001b[33massistant\u001b[0m (to user_proxy):\n", "\n", "```python\n", - "# Let's write a simple Python code to evaluate 2 + 2 and print the result.\n", - "\n", + "# Calculate 2+2 and print the result\n", "result = 2 + 2\n", "print(result)\n", "```\n", @@ -133,20 +132,7 @@ "\n", "--------------------------------------------------------------------------------\n", "\u001b[31m\n", - ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "execute_code was called without specifying a value for use_docker. Since the python docker package is not available, code will be run natively. Note: this fallback behavior is subject to change\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n", "\u001b[33muser_proxy\u001b[0m (to assistant):\n", "\n", "exitcode: 0 (execution succeeded)\n", @@ -157,13 +143,23 @@ "--------------------------------------------------------------------------------\n", "\u001b[33massistant\u001b[0m (to user_proxy):\n", "\n", - "The Python code was executed successfully and the result of evaluating 2 + 2 is 4.\n", + "The Python code successfully calculated \\(2 + 2\\) and printed the result, which is \\(4\\).\n", "\n", "TERMINATE\n", "\n", "\n", "--------------------------------------------------------------------------------\n" ] + }, + { + "data": { + "text/plain": [ + "ChatResult(chat_id=None, chat_history=[{'content': 'Write py code to eval 2 + 2', 'role': 'assistant'}, {'content': '```python\\n# Calculate 2+2 and print the result\\nresult = 2 + 2\\nprint(result)\\n```\\n', 'role': 'user'}, {'content': 'exitcode: 0 (execution succeeded)\\nCode output: \\n4\\n', 'role': 'assistant'}, {'content': 'The Python code successfully calculated \\\\(2 + 2\\\\) and printed the result, which is \\\\(4\\\\).\\n\\nTERMINATE\\n', 'role': 'user'}], summary='The Python code successfully calculated \\\\(2 + 2\\\\) and printed the result, which is \\\\(4\\\\).\\n\\n\\n', cost=({'total_cost': 0}, {'total_cost': 0}), human_input=[])" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ @@ -204,7 +200,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.10.13" } }, "nbformat": 4, diff --git a/notebook/agentchat_oai_code_interpreter.ipynb b/notebook/agentchat_oai_code_interpreter.ipynb index a6c8e570326..921165fdd6b 100644 --- a/notebook/agentchat_oai_code_interpreter.ipynb +++ b/notebook/agentchat_oai_code_interpreter.ipynb @@ -26,7 +26,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -81,14 +81,15 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "WARNING:autogen.agentchat.contrib.gpt_assistant_agent:assistant_id was None, creating a new assistant\n" + "OpenAI client config of GPTAssistantAgent(Coder Assistant) - model: gpt-4-turbo\n", + "Matching assistant found, using the first matching assistant: {'id': 'asst_xBMxObFj0TzDex04NAKbBCmP', 'created_at': 1710321320, 'description': None, 'file_ids': [], 'instructions': 'You are an expert at solving math questions. Write code and run it to solve math problems. Reply TERMINATE when the task is solved and there is no problem.', 'metadata': {}, 'model': 'gpt-4-turbo', 'name': 'Coder Assistant', 'object': 'assistant', 'tools': [ToolCodeInterpreter(type='code_interpreter')]}\n" ] }, { @@ -102,13 +103,31 @@ "--------------------------------------------------------------------------------\n", "\u001b[33mCoder Assistant\u001b[0m (to user_proxy):\n", "\n", - "The value of $x - y$ is $-48$. \n", + "The value of \\( x - y \\) is \\(-48\\).\n", + "\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33muser_proxy\u001b[0m (to Coder Assistant):\n", + "\n", + "\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mCoder Assistant\u001b[0m (to user_proxy):\n", + "\n", + "It seems you have no further inquiries. If you have more questions in the future, feel free to ask. Goodbye!\n", "\n", "TERMINATE\n", "\n", "\n", "--------------------------------------------------------------------------------\n" ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Permanently deleting assistant...\n" + ] } ], "source": [ @@ -116,9 +135,11 @@ "gpt_assistant = GPTAssistantAgent(\n", " name=\"Coder Assistant\",\n", " llm_config={\n", - " \"tools\": [{\"type\": \"code_interpreter\"}],\n", " \"config_list\": config_list,\n", " },\n", + " assistant_config={\n", + " \"tools\": [{\"type\": \"code_interpreter\"}],\n", + " },\n", " instructions=\"You are an expert at solving math questions. Write code and run it to solve math problems. Reply TERMINATE when the task is solved and there is no problem.\",\n", ")\n", "\n", @@ -135,7 +156,8 @@ "# When all is set, initiate the chat.\n", "user_proxy.initiate_chat(\n", " gpt_assistant, message=\"If $725x + 727y = 1500$ and $729x+ 731y = 1508$, what is the value of $x - y$ ?\"\n", - ")" + ")\n", + "gpt_assistant.delete_assistant()" ] }, { @@ -149,14 +171,15 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "WARNING:autogen.agentchat.contrib.gpt_assistant_agent:assistant_id was None, creating a new assistant\n" + "OpenAI client config of GPTAssistantAgent(Coder Assistant) - model: gpt-4-turbo\n", + "No matching assistant found, creating a new assistant\n" ] }, { @@ -170,53 +193,53 @@ "--------------------------------------------------------------------------------\n", "\u001b[33mCoder Assistant\u001b[0m (to user_proxy):\n", "\n", - "To draw a line chart showing the population trend in the US, we need some population data over a range of years. Normally, this data can be obtained from sources like the United States Census Bureau or other datasets available online.\n", - "\n", - "Since I don't have internet access to download the latest data directly, you can provide the data if you have it. The data should ideally consist of two columns: one for the years and one for the corresponding US population for each year.\n", + "To draw a line chart showing the population trend in the US, we first need to obtain the data that contains the population figures over a range of years. As I don't have access to the internet in this environment, I cannot download the data directly. However, if you can provide the data, I can proceed to create a line chart for you.\n", "\n", - "If you don't have the data, I can demonstrate how to generate the line chart with some dummy data to illustrate the process. Would you like to provide the data or should I use dummy data for the demonstration?\n", + "For the purpose of this demonstration, let's assume we have some hypothetical US population data for a few years. I'll generate some sample data and create a line chart using the `matplotlib` library in Python.\n", "\n", + "Here's how we can do it:\n", "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33muser_proxy\u001b[0m (to Coder Assistant):\n", - "\n", - "\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mCoder Assistant\u001b[0m (to user_proxy):\n", "\n", - "It seems there was no response regarding the data, so let's proceed with some dummy data to demonstrate the process. I'll create a Python script that will generate a line chart showing the hypothetical population trend in the US from the year 1900 to 2000. I'll assume a simple linear growth in population for the sake of this example.\n", + "Received file id=assistant-tvLtfOn6uAJ9kxmnxgK2OXID\n", "\n", - "Let's begin by generating the dummy data and plotting the line chart.\n", - "\n", - "\n", - "Recieved file id=file-sAG7r763XR9jiuKYiQeoHRFU\n", - "\n", - "Here is a line chart showing the hypothetical population trend of the US from the year 1900 to 2000. The data is dummy and assumes linear growth in the population.\n", - "\n", - "If you have actual data or would like to see a different representation, please let me know. Otherwise, if everything looks good with this example chart, let me know if there is anything else I can help with. \n", + "Here is a line chart that illustrates the hypothetical US population trend from 2010 to 2020. The data used here is for demonstration purposes only. If you have actual population data, you can provide it, and I will update the chart accordingly.\n", "\n", "TERMINATE\n", "\n", "\n", "--------------------------------------------------------------------------------\n" ] + }, + { + "data": { + "text/plain": [ + "ChatResult(chat_id=None, chat_history=[{'content': 'Draw a line chart to show the population trend in US. Show how you solved it with code.', 'role': 'assistant'}, {'content': \"To draw a line chart showing the population trend in the US, we first need to obtain the data that contains the population figures over a range of years. As I don't have access to the internet in this environment, I cannot download the data directly. However, if you can provide the data, I can proceed to create a line chart for you.\\n\\nFor the purpose of this demonstration, let's assume we have some hypothetical US population data for a few years. I'll generate some sample data and create a line chart using the `matplotlib` library in Python.\\n\\nHere's how we can do it:\\n\\n\\nReceived file id=assistant-tvLtfOn6uAJ9kxmnxgK2OXID\\n\\nHere is a line chart that illustrates the hypothetical US population trend from 2010 to 2020. The data used here is for demonstration purposes only. If you have actual population data, you can provide it, and I will update the chart accordingly.\\n\\nTERMINATE\\n\", 'role': 'user'}], summary=\"To draw a line chart showing the population trend in the US, we first need to obtain the data that contains the population figures over a range of years. As I don't have access to the internet in this environment, I cannot download the data directly. However, if you can provide the data, I can proceed to create a line chart for you.\\n\\nFor the purpose of this demonstration, let's assume we have some hypothetical US population data for a few years. I'll generate some sample data and create a line chart using the `matplotlib` library in Python.\\n\\nHere's how we can do it:\\n\\n\\nReceived file id=assistant-tvLtfOn6uAJ9kxmnxgK2OXID\\n\\nHere is a line chart that illustrates the hypothetical US population trend from 2010 to 2020. The data used here is for demonstration purposes only. If you have actual population data, you can provide it, and I will update the chart accordingly.\\n\\n\\n\", cost=({'total_cost': 0}, {'total_cost': 0}), human_input=[])" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ "gpt_assistant = GPTAssistantAgent(\n", " name=\"Coder Assistant\",\n", " llm_config={\n", - " \"tools\": [{\"type\": \"code_interpreter\"}],\n", " \"config_list\": config_list,\n", " },\n", + " assistant_config={\n", + " \"tools\": [{\"type\": \"code_interpreter\"}],\n", + " },\n", " instructions=\"You are an expert at writing python code to solve problems. Reply TERMINATE when the task is solved and there is no problem.\",\n", ")\n", "\n", "user_proxy.initiate_chat(\n", " gpt_assistant,\n", " message=\"Draw a line chart to show the population trend in US. Show how you solved it with code.\",\n", + " is_termination_msg=lambda msg: \"TERMINATE\" in msg[\"content\"],\n", + " human_input_mode=\"NEVER\",\n", " clear_history=True,\n", + " max_consecutive_auto_reply=1,\n", ")" ] }, @@ -229,12 +252,12 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 9, "metadata": {}, "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAB7sAAAPUCAYAAADc4V37AAEAAElEQVR4AezdCXwU9f3/8Q9HADEqRAjBqFiVwwtKIF5QtLZBRanaWqzalqO1l7b2X/1pW1sRelhqL2u11raCth6g1ioeralWKR4gh6BVMR4gRsJhRA03yD/vobPMTmZ3Z8/s8fo+HmFnZ77znZnnzH53mc98v98OO1uTkRBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEECgggY4FtK/sKgIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAo4AwW4uBAQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQACBghMg2F1wp4wdRgABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAg2M01gAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBQcAIEuwvulLHDCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIEu7kGEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQKToBgd8GdMnYYAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQIBgN9cAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEDBCRDsLrhTxg4jgAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCBDs5hpAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEECg4AYLdBXfK2GEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAYLdXAMIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgUnQLC74E4ZO4wAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggQLCbawABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAoOAECHYX3CljhxFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEECHZzDSCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIFJwAwe6CO2XsMAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAwW6uAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQACBghMg2F1wp4wdRgABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBDoDAECCCCAAAIIIIAAAtkQGD58eFSxCxYsiHrPG7OrrrrKHnjggQjF5MmTbezYsZH3xT5R6sev87t582Z7+eWX7a233rIPPvjANmzYYF27drU99tjD9t13X+vbt68deOCB1r1792K/HDi+FAVUt37ta1+LrF1TU2M33XRT5H0xTLz99tv2qU99KnIo+lzMnj078p4JBIpZoL2/K//yl7/Ytdde6xB369bN/v73v1uvXr3ynnz9+vW2dOlSW7dunWm6rKzM2e/+/fvboYcempX9b2pqshdeeMH0qu93fXdXV1fb4MGDrWfPnhnfZktLiy1ZssRWrlzp/H7o0qWL9e7d2w4//HDnt0PGN1ggBW7fvt3efPNNe/311+2dd96J2Oyzzz6233772RFHHGG6lrOR3n33Xee6a2xstI0bNzrb0XeWtllVVZXxTeo603W+YsUK53dkp06dnOt84MCBWbnOP/zwQ3vppZfs1VdfNR3rzp07Ta4HH3ywHXnkkda5c+ekj1G/fc8880ynPK08YcIEu+iii5IuhxUQQAABBEpbIPlvoNL24ugRQAABBBBAIIaA/0Zcujfb/Tfvtdn777/fuUERYxeYjQACCAQK/OEPf7A//vGPkWWZCJT5H+ZI5kGFrVu32r/+9S+79957nRuUO3bsiOxb0ETHjh2tX79+zo3SY4891vTXo0ePoKwZmec/tliFKihfXl7u3MAfNGiQHXXUUfaJT3wiq/sWa1+YjwACbQX8v83a5sjcnEzUq5nbG0rKlIACxX/6058ixZ1//vlJBboVGFPA8cUXX7T//ve/zmtDQ4MpGOmmTF47Crw99thjpgC9tqntByVt8zOf+Yyde+65zgNmQXmSmff444/bLbfcYs8//3zgavoer62ttS996Uum/yOlm1555RXnd81//vOfKEtvuQo+fuELX7DTTz/dOnTo4F1UlNNvvPGGPfHEE/bss8/ac889Z1u2bIl5nAoI6zyMGzfOTjjhBNP5STctWrTI/vznPzvbj3Xd6XfS+PHj7cQTT0x3c6Zguj6bjzzySMxjVWD/nHPOcf5SCUJ7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o26G1XVxmG40f/nLX0a6lHe3q2709ECEtune7JOTzomc1PrbdVKQTgEt3Vx298stR+PWukZqZaP13KRrUN3Q5iKpG0Bdb/4W1+qWVS1e9aqueN0kV3X9pxYRehBE78MkWakbT13H6mpWN8m8wS+1hFE3h+pCXeW7ad68eXbzzTc7ASZ3Xqm/arxT/4MtuvbUOl89CmjsxkQtiQrFUPWbtwtc7bfGofUndZX/wx/+MFJvustPOeUU04NG6uZVD1XoOtdYmgps6899YEfzFdhSvZDMuJXazjXXXOPUk5pWnfilL33J6abc7T5U3cwrEK/r2Bu4V2tyBT8VsCqWpJZeI0eOdIYgOOSQQ0zDUigwoiRr1XUKfqmrd2/rQn2fqK5R3RyU9B3oju+putK7rurKeF1Op9KCLGgfdB71vel/gOf44493vn+0//qu13HqJry+97Sv3sCSvo9U9+u6TCbpOnF/U2h9df+u+tStmxUQVgvaG264Icpm8eLFzu8X1eWFmvS7xg0e6Xtj/PjxzjXmjkOtFu96CMH/0JW+U771rW9Fvo91/Oq9R8MC6FrSdeE+jKLvbHXtrPPl7alEDy3279/fzj777KT4sv37RNdg0AORqvv1+0RdErv1nerPe++91+l2X0byjNfde1IHGiLzf//736hcGsc+X5MeylF95b2W9DBTMknfWf4W4vqtqus0aAxmb12m7QR9vyXavvZbD3l6H8pU4FFDwviTf3tanso2+/TpE/UwZ7xAp38fivm9fsP6U6JhS/znRP9fiPUQk79s73udE7eu1PxY50R1o/vbx10/1WvAXT/e9rTMf4za12STf501a9Y413ysB5z95fvrHtWN+rzGeuDWvz7vEUAAAQRKT4Bgd+mdc44YAQQQQACBohRQt5BusFsHqBuFusEa1CowCMDfqltjmLmBj6D83nneYIjGIlUrMm/SPiiIcPHFFztjUKsbae+NNbUe0ziiClbHSmoF7r/xoCC3xv72HqNu+il4oy5ANf64tuVdTzfgdaPf32pBASP9KelmsjfYrRv1yd44dgry/aMb/wqWKmB81lln+ZaaEwRQgERBaRm6AWgFtXR+FLSIl9SCTo5ukoVunH/+85+PBG+8y9Sto8bBVSD/29/+thPs0PKVK1c6N5cvv/xyN7vz2rt374iDgrzeYLcCGJkwitpgwBsFqtVt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guPgEBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEESkiAbsxL6GRzqAgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggECxCBDsLpYzyXEggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACJSRAsLuETjaHigACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCBSLAMHuYjmTHAcCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBQQgIEu0voZHOoCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAQLEIEOwuljPJcSCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIlJNC5hI6VQ80jgVNPPdXWrFljlZWV9vDDD+fRnrErCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBQCAIEuwvhLBXhPirQ3dTUVIRHlttD2rx5s7PBbt265XbDbA0BBBDIYwHqxjw+OewaAgi0qwD1Y7vys3EEEMhTAerGPD0x7BYCCLS7APVju58CdgABBPJQgLoxD09K6y7RjXl+nhf2CoFQAsuWLTP9kRBAAAEEdgtQN+62YAoBBBDwClA/ejWYRgABBHYJUDdyJSCAAALBAtSPwS7MRQCB0hagbszP80+wOz/PC3uFAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIBBHgGB3HBwWIYAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgjkpwDB7vw8L+wVAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEAcAYLdcXBYhAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCQnwIEu/PzvLBXCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAJxBDrsbE1xlrMIgawIDBs2zJqamqyqqsoWLlyYlW1QKAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIFK8ALbuL99xyZAgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEDRChDsLtpTy4GVgsD69etNfyQEEEAAgd0C1I27LZhCAAEEvALUj14NphFAAIFd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hffZZ569x07555+d95pPan8Bgt2ec6AxuM855xzr1KmTZ27w5KmnnmpDhw6NLHz00Ucj04kmFERWF+hKV1xxhfXq1SvRKlHL165daw899FBknspQED4onXTSSaYxu5V27Nhhf/nLX4KyOfNuueWWyDK1CI81xnefPn2cFuBu5hkzZriTvCKAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBQ8AKL1jXa6Y9Mt+MeuMFuWjbfXtjYbK9tft/mrV3pvNd8LVc+UvsJBEdI229/CmrLw4cPj+yvuvcOk5qamuwnP/mJk/WYY46xc889N8xqUXkeeeQRU3fqShpTXC2746Vx48ZFFv/jH/+ITHsn3njjDXvllVcis7zrRGZ6JrzLX3rpJWcMb89iJhFAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAoSIH6xgYbWz/DnlyzazjZWAeh5cqn/KT2ESDYnYZ7hw4dImur1XSYpFbY77//vnXp0sUZY9tbRpj1leepp56KZFVr9ETp+OOPj2RpbGw0Bbb96cknn4zMUgC9qqoq8j5oQmOZf+QjH4ks8q4fmckEAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgUkoJba4+fMtI07dg0nnGjXlW/CnFm08E4ElaXlBLvTgH355Zcja++3336R6VgTDzzwgLktq7/xjW9Y//79Y2WNO9877vZRRx0VN68WKnDdu3fvSD7v+u5M77wwZWo9bz7v+m6ZvCKAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBQSAJXLnrENu3YntQuK+A9eXF9UuuQOTMCnTNTTOmVohbS3tbM7rjYsSTee+89++EPf+gsVovob33rW7GyJpz/2muvRfLsv//+kel4E9XV1aaxvpW867vrvP766+6kJVOmu9Krr77qTvKaQwGNn05CAAEEEIgWoG6M9uAdAggg4ApQP7oSvCKAAAK7Bagbd1swhQACCHgFqB+9GkwjgEApCby8fk3CrstjecxdvdyWvbfWBu6zuwFqrLzMz5wAwe4ULa+66ipzuy5XILmuri5uSVOnTrU1a9Y4eX72s59Z165d4+aPtXDTpk22efPmyGJvi+3IzIAJb77169e3yfHuu+9G5vXq1SsyHW8iUZnx1nWXaezxt99+230b+Bqm1XzgiiUw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K684s7UPF110kTdL1LSWu+mwww4zfvy4Grl9DRp/Pbd7wNYQQACB/BOgbsy/c8IeIYBAfghQP+bHeWAvEEAgvwSoG/PrfLA3CCCQPwLUj/lzLtgTBEpdQN2Sq7W2gtgt27ZaeVkXG1LR1yb2H26DelS24VGedFLL9i3O6nXV/W123QSbvLje5q5eHrNIdV2uFt0EumMSZX0BwW4f8Y4dO+zCCy+MjF/duXNnu/HGG23UqFG+nO33tnfv3nbqqafagw8+6OzET37yE7vnnnusQ4cObXbqiSeeMP0pderUyemWvU2m/80YP368XXHFFc47HfM555xj2pY/rVmzxjFx52s9EgIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAKZEFi0rtGuXPRI4Pjb89autJuWzbcRlf1sas3oSKBZgfE1m1vS2nx5566R9RXAVsDbDbgvbW4yBcOVZ3BFlU0aUMsY3RGt9pvo2H6bzr8t79y50y655JJIELljx47229/+1tSSOt/SZZddZmVlZc5uzZs3zy6++GLTGOPepJbpCty76eyzz3Zab7vv/a/nn3++HXTQQc7sd9991z7/+c/bW2+9FZVN7zWO+fr16535ahF+7rnnRuXhTe4ElixZYvojIYAAAgjsFqBu3G3BFAIIIOAVoH70ajCNAAII7BKgbuRKQAABBIIFqB+DXZiLAAK5EahvbLCx9TMCA93ePXhyzQon3y+fn2NnP/ZXO+6BG2zt5g3eLElPK4jtT2pBPq12jP2sapj9bv/j7eGTJznv1eU5qf0FaNntOQe33HKLebvnVtfc8+fPd/482WJOqoV1rtKhhx5qV199tV166aXOJtWy+9FHH3W6P99rr72c7sgXL14c2R11NT516tTI+6AJBc9vuukmO+uss2zDhg32wgsv2MiRI52/qqoqW7VqldO1u7p5V9J2/vjHP5pav5MQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQSEdALbrHz5lpm3ZsD1WMxtT+8ZLHQuUNk0mttUmFJUCU0nO+3nnnHc87szfeeMP5i5oZ500ug93aDbWoVmv0yZMnO6261dr6oYcearOHClirhXp5eXmbZf4ZRxxxhN1+++32zW9+0958801TYPvf//63P5szRvd1111ngwYNarOMGQgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggkK6Cuy8MGupMtO1F+jb9Na+1ESvm3nGB3/p2TpPbovPPOsxNOOMHuuOMOq6+vt8bGRifwXVlZaUcddZR9+tOftlNOOSVwPO9YGxo+fLj961//clq5P/DAA/b666+bujXv2bOnqdvy008/3T772c/annvuGasI5iOAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCAQWkBjY6tr8nRSRdc97NTqQfa3Fc8nFTTv3qnMpgytS2fTrNtOAgS7PfAar1t/7ZEUpE41VVdXO92Zu12ap1qOdz0FsidMmOD8eeczjQACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggECmBaY3LEirSLXMnvnx86x75y52Rr/DbcKcWaZuzhMlBbpnjBpnNb2qE2VleR4KEOzOw5PCLiGAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBQ6AJqra0g9pLmVdaybauVl3WxIRV9bWL/4TaoR2XU4SlPOmn7hx86gW6VUVfd32bXTbDJi+tt7urlMYtVgFwtugl0xyTK+wUdWsd83pn3e8kOFp3AsGHDrKmpyaqqqmzhwoVFd3y5OqDNmzc7m+rWrVuuNsl2EEAAgbwXoG7M+1PEDiKAQDsJUD+2EzybRQCBvBagbszr08POIYBAOwpQP7YjPptGoEgEFq1rNI2/Ha9b8hGV/WxqzehIoPm42dfby++tTVngyJ597D+nfb3N+m7AfWlzk7Vs32Llnbva4IoqmzSgNqkxuqkb29DmxQxadufFaWAnEEhNgCB3am6shQACxS1A3Vjc55ejQwCB1AWoH1O3Y00EECheAerG4j23HBkCCKQnQP2Ynh9rI1DqAvWNDaG6EFcgfGz9DPvp8FNs6bur7JU0At0yVxA7KKkF+bTaMUGLkppH3ZgUV84yE+zOGTUbQiDzAjxFlHlTSkQAgcIXoG4s/HPIESCAQHYEqB+z40qpCCBQ2ALUjYV9/th7BBDIngD1Y/ZsKRmBYhdQi+7xc2baph3bQx2qxtT+9rzZofImyqTW2tlM1I3Z1E297I6pr8qaCCDQ3gLLli0z/ZEQQAABBHYLUDfutmAKAQQQ8ApQP3o1mEYAAQR2CVA3ciUggAACwQLUj8EuzEUAgcQC6ro8bKA7cWnJ5VC35NlM1I3Z1E29bILdqduxJgIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIItApobOx4Y3RnE2lkn4OSGn87m/tC2bkVINidW2+2hgACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEDRCUxvWJDWMQ2p6Gt3nHiude9UllQ5yj9laF1S65C5eAQYs7t4ziVHggACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEDGBNRaW0HsJc2rrGXbVisv62IKSk/sP9wG9aiM2o7ypJP2aA1an7L/QJsxapxNmDPLNJ53oqRAt/LX9KpOlJXlRSpAsLtITyyHhQACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEAqAovWNZrG3w7qlnze2pV207L5NqKyn02tGR0JNH+wbUsqm4qs07J91/p11f1tdt0Em7y43uauXh5Z7p9Q1+Vq0U2g2y9TWu8JdpfW+eZoEUAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEIgpUN/YEKpltQLhY+tn2PXHn2Fvtrxnr77/Tswywywo79w1kk0BbAW83ZblS5ubTMFw5RlcUWWTBtQyRndEq7QnOuxsTaVNwNG3h8CwYcOsqanJqqqqbOHChe2xC2wTAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEDAI6AW3afXT7dNO7Z75uZm8isDj7ZptWNyszG2UjQCHYvmSDgQBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBIWUBdl7dHoFs7rNbaJASSFSDYnawY+RHII4H169eb/kgIIIAAArsFqBt3WzCFAAIIeAWoH70aTCOAAAK7BKgbuRIQQACBYAHqx2AX5iJQ7ALqMjxojO5cHLfG3x64T+9cbCrlbVA3pkyX1RUZszurvBSOQHYFVqxY4WygR48e2d0QpSOAAAIFJEDdWEAni11FAIGcClA/5pSbjSGAQIEIUDcWyIliNxFAIOcC1I85J2eDCOSFwPSGBWntx8HlFfbtI0fad5992Dbu2Ba6rO6dymzK0LrQ+dsrI3Vje8nH3y4tu+P7sBQBBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQACBohdY0rwqrWOs3KPcvnBojc0YNc4UwA6TlE/5a3pVh8lOHgTaCNCyuw0JMxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBAobAF1S67W2gpit2zbauVlXWxIRV+b2H+4DepR2ebglCed1LJ9i7N6XXV/m103wSYvrre5q5fHLFJdl6tFN4HumEQsCCFAsDsEElkQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQKASBResa7cpFjwSOvz1v7Uq7adl8G1HZz6bWjHYCzTs+/NAefOtlW9HyblqHV965a2R9BbAV8HYD7kubm0zBcOUZXFFlkwbU5v0Y3ZGDYSKvBQh25/XpYecQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQCCdQ39hgE+bMSjhm9pNrVtjp9TPsnIMH279XvdYa6F4fbgNxcimI7U9qQT6tdox/Nu8RyJgAwe6MUVIQArkX6NatW+43yhYRQACBPBegbszzE8TuIYBAuwlQP7YbPRtGAIE8FqBuzOOTw64hgEC7ClA/tis/G0cgZQG16B4/Z6Zt2rE9VBmbdmyzGQ0LQ+UNk0mttYs5UTfm59kl2J2f54W9QiCUwMCBA0PlIxMCCCBQSgLUjaV0tjlWBBBIRoD6MRkt8iKAQKkIUDeWypnmOBFAIFkB6sdkxciPQH4IqOvysIHuTO+xxt8euE/vTBebV+VRN+bV6YjsTMfIFBMIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIFBwAhobW12Tp5OGVuxn3x/8ceveqSypYpR/ytC6pNYhMwKZEqBld6YkKQeBdhBoampytlpV1XYcjHbYHTaJAAII5IUAdWNenAZ2AgEE8lCA+jEPTwq7hAAC7S5A3djup4AdQACBPBWgfszTE8NuIRBHYHrDgjhLEy8ae+BhdsvHxlmHDh3so/vuF2rcb5WqQPeMUeOspld14o0UeA7qxvw8gQS78/O8sFcIhBJYvXq1k49gdyguMiGAQIkIUDeWyInmMBFAIGkB6sekyVgBAQRKQIC6sQROMoeIAAIpCVA/psTGSghkXECttRXEXtK8ylq2bbXysi42pKKvTew/3Ab1qIzanvKkk9Zu2uAEulVGXXV/m103wSYvrre5q5fHLFZdl6tFdykEuoVA3RjzUmjXBQS725WfjSOAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCwW2DRukbT+NtB3ZLPW7vSblo230ZU9rOpNaMjgeZ1mzfsLiCFqZbtW6LWUgBbAW834L60ucmUp7xzVxtcUWWTBtQW/RjdUSC8yVsBgt15e2rYMQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAgVISqG9sCNWFuALhY+tn2IWHHWdPtU6/9kFzWkwKYgcltSCfVjsmaBHzEMgLAYLdeXEa2AkEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAIFSFlCL7vFzZtqmHdtDMWzcsc2ueWFOqLyJMqm1NgmBQhToWIg7zT4jgAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggUEwC6ro8bKA708etbslJCBSiAC27C/Gssc8I/E+gR48eWCCAAAII+ASoG30gvEUAAQT+J0D9yKWAAAIItBWgbmxrwhwEEEBAAtSPXAcI5F5AY2MHjdGdzJ6Udeho23Z+mMwqTt6RfQ5i/O0QatSNIZDaIQvB7nZAZ5MIZEqgX79+mSqKchBAAIGiEaBuLJpTyYEggECGBagfMwxKcQggUBQC1I1FcRo5CAQQyIIA9WMWUCkSgQQC0xsWJMgRf/GJVQfb5YNPtM88+hdT9+ZhU/dOZTZlaF3Y7CWdj7oxP08/we78PC/sFQIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAQAELqLW2gthLmldZy7atVl7WxYZU9LWJ/YfboB6VUUemPOmkza3jfB9beaDNGDXOJsyZFSrgrUC38tf0qk5n06yLQLsKEOxuV342jkB6AitWrHAK4Gmi9BxZGwEEikuAurG4zidHgwACmROgfsycJSUhgEDxCFA3Fs+55EgQQCCzAtSPmfWktNITWLSu0TT+dlC35PPWrrSbls23EZX9bGrN6Eigef3WzWlBtWzf4qxfV93fZtdNsMmL623u6uUxy1TX5WrRTaA7JlGbBdSNbUjyYgbB7rw4DewEAqkJrF+/3lmRYHdqfqyFAALFKUDdWJznlaNCAIH0Bagf0zekBAQQKD4B6sbiO6ccEQIIZEaA+jEzjpRSmgL1jQ2hWlYrED62foZNqamzxe+8ba+8tzYtsPLOXSPrK4CtgLfbsnxpc5MpGK48gyuqbNKAWsbojmiFn6BuDG+Vy5wEu3OpzbYQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQSKUkAtusfPmWmbWrsUD5M0tvb/PftQmKwJ8yiI7U/qKn1a7Rj/bN4jUFQCHYvqaDgYBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBNpBQF2Xhw10Z3r31FqbhEApChDsLsWzzjEjgAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAghkTEBdhgeN0Z3MBjokk9mTV+NvD9ynt2cOkwiUjgDB7tI51xwpAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIBAFgSmNyxIq9Rh+1bbXSedb907lSVVjvJPGVqX1DpkRqCYBBizu5jOJsdScgJ9+vQpuWPmgBFAAIFEAtSNiYRYjgACpSpA/ViqZ57jRgCBeALUjfF0WIYAAqUsQP1YymefY09VYEnzqlRXddYr69jJPrFff5sxapxNmDPLNJ53oqRAt/LX9KpOlJXlGRCgbswAYhaKINidBVSKRCBXAlVVVbnaFNtBAAEECkaAurFgThU7igACORagfswxOJtDAIGCEKBuLIjTxE4igEA7CFA/tgM6m8w7AXVLrtbaCmK3bNtq5WVdbEhFX5vYf7gN6lHZZn8/2LalzbxkZrRs37V+XXV/m103wSYvrre5q5fHLEJdl6tFN4HumEQZX0DdmHHSjBRIsDsjjBSCAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBQ6AKL1jXalYseCRx/e97alXbTsvk2orKfTa0Z7QSa123eYNNfWWCvvLcurUMv79w1sr4C2Ap4uwH3pc1NpmC48gyuqLJJA2oZozuixUSpCxDsLvUrgOMvaIFly5Y5+z9w4MCCPg52HgEEEMikAHVjJjUpCwEEikmA+rGYzibHggACmRKgbsyUJOUggECxCVA/FtsZ5XjCCtQ3NoTqQvzJNSvstPrprUHvg1qD4stt847tYTcRM5+C2P6kFuTTasf4Z/O+nQSoG9sJPsFmCXYnAGIxAvkssHnz5nzePfYNAQQQaBcB6sZ2YWejCCBQAALUjwVwkthFBBDIuQB1Y87J2SACCBSIAPVjgZwodjOjAmrRPX7OTNsUMnCtAPejq17N2D6otTYpvwWoG/Pz/HTMz91irxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBDIjYC6Lg8b6M70Hmn87YH79M50sZSHQEkIEOwuidPMQSKAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCAQJaGxsdU2eaurcoYOde/AQ+8OIT1v3TmVJFaP8U4bWJbUOmRFAYLcA3ZjvtmAKAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEECgxASmNyxI64g/d/BH7brjznDK6Nllj1DjfiuzAt0zRo2zml7VaW2flREoZQGC3aV89jl2BBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQKAIBdRaW0HsJc2rrGXbVisv62JDKvraxP7DbVCPyqgjVp500qvvvxNZva66v82um2CTF9fb3NXLI/P9E+q6XC26CXT7ZXiPQHICBLuT8yI3Ankl0K9fv7zaH3YGAQQQyAcB6sZ8OAvsAwII5KMA9WM+nhX2CQEE2luAurG9zwDbRwCBfBWgfszXM8N+hRFYtK7RNP52ULfk89autJuWzbcRlf1sas1oJ9C8dcd2e2vDe2GKjpmnZfuWqGUKYCvg7QbclzY3mfKUd+5qgyuqbNKAWsbojhIrjDfUjfl5njrsbE35uWvsVTELDBs2zJqamqyqqsoWLlxYzIfKsSGAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEAOBOobG0J3Ib5HaxfiZ/Y73B5f9bqt2vRBWnt3bO8D7eGTJ6VVBisjgEBqArTsTs2NtRBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBPJEQC26x8+ZaZtaW2qHSZt2bLM7Xl8SJmvCPGqtTUIAgfYR6Ng+m2WrCCCQCYElS5aY/kgIIIAAArsFqBt3WzCFAAIIeAWoH70aTCOAAAK7BKgbuRIQQACBYAHqx2AX5ua3gLouDxvozvSRqFtyUvELUDfm5zkm2J2f54W9QgABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQCCGgsbGDxugOsWoky95lXSPTyUyM7HMQ428nA0ZeBDIsQLA7w6AUhwACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggkDuB6Q0L0trYWQceYfd+4ovWvXUc72SS8k8ZWpfMKuRFAIEMCzBmd4ZBKQ4BBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQCB1AbXUVgB7SfMqa9m21crLutiQir42sf9wG9Sjsk3BypdOWrXpA6vpVW0zRo2zCXNm2cbW8bwTJQW6lV/rkRBAoP0ECHa3nz1bRgABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQ+J/AonWNprG3g7okn7d2pd20bL6NqOxnU2tGR4LMO3futDWbWtIybNm+xVm/rrq/za6bYJMX19vc1ctjlqmuy9Wim0B3TCIWIJAzAYLdOaNmQwgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAkEC9Y0NoVpVKxA+tn6G/fljZ9vG7dvshpeetjda3g0qMvS88s67x+tWAFsBb7d1+dLmJlMwXHkGV1TZpAG1jNEdWpaMCGRfoEPrEy87s78ZtoBAtMCwYcOsqanJqqqqbOHChdELeRdaYPPmzU7ebt26hV6HjAgggECxC1A3FvsZ5vgQQCBVAerHVOVYDwEEilmAurGYzy7HhgAC6QhQP6ajx7qpCKhF9+n1023Tju2hV+/QmjNTAa6vDDzaptWOCb1tMpamAHVjfp53Wnbn53lhrxAIJUCQOxQTmRBAoMQEqBtL7IRzuAggEFqA+jE0FRkRQKCEBKgbS+hkc6gIIJCUAPVjUlxkzoCAui5PJtCtTWYq0K2y1FqbhEAiAerGRELts7xj+2yWrSKAQCYE9BSR+yRRJsqjDAQQQKAYBKgbi+EscgwIIJANAerHbKhSJgIIFLoAdWOhn0H2HwEEsiVA/ZgtWcoNElB34UFjdAfljTeva8dO8RbHXKbxtwfu0zvmchYg4ApQN7oS+fVKsDu/zgd7g0BSAsuWLTP9kRBAAAEEdgtQN+62YAoBBBDwClA/ejWYRgABBHYJUDdyJSCAAALBAtSPwS7MzY7A9IYFaRVc2a3cpn/ss8442907lSVVlvJPGVqX1DpkLl0B6sb8PPd0Y56f54W9QgABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQKUkCttRXEXtK8ylq2bbXysi42pKKvTew/3Ab1qIw6JuVJJx28V4Wd2e8Ip4gZo8bZhDmzbOOObQmLVKBb+Wt6VSfMSwYEEMhfAYLd+Xtu2DMEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAoGAEFq1rNI2/HdQt+by1K+2mZfNtRGU/m1ozOhJkVjA8ndSyfUtk9brq/k4L78mL623u6uWR+f4JdV2uFt0Euv0yvEeg8AQIdhfeOWOPEUAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAIG8EqhvbAjVqlqB8LH1M5xW1RVd97BVmz5I6zjKO3eNWl8B7Nl1E8xtXb60uckUEFe+wRVVNmlALWN0R4nxBoHCFiDYXdjnj71HAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBNpVQC26x8+ZaZt2bA+1H+pm/HP/vt0+tJ2h8sfLpAB2UFJ36dNqxwQtYh4CCBSRQMciOhYOBQEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAIMcC6ro8bKDb3bVMBLpVllpqkxBAoHQFOuxsTaV7+Bx5ewkMGzbMmpqarKqqyhYuXNheu8F2EUAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAIA0BdRd+3AM3pFFC6qtq7G11WU5CAIHSFaBld+mee44cAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEhLYHrDgrTW37NzmV3Q2jp7j05lSZXTvTX/lKF1Sa1DZgQQKD4Bgt3Fd045ohISWL9+vemPhAACCCCwW4C6cbcFUwgggIBXgPrRq8E0AgggsEuAupErAQEEEAgWoH4MdmFusMCS5lXBC0LOPbJnlf386NPsllHjTAHsMEn5ZrTmr+lVHSY7eRDIiAB1Y0YYM15I54yXSIEIIJAzgRUrVjjb6tGjR862yYYQQACBfBegbsz3M8T+IYBAewlQP7aXPNtFAIF8FqBuzOezw74hgEB7ClA/tqd+fmxbXZOrxbYC2S3btlp5WRcbUtHXJvYfboN6VEbtpJankzZs37V+XXV/p0vyyYvrbe7q5TGLVNflatFNoDsmEQuyJEDdmCXYNIsl2J0mIKsjgAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAsUgsGhdo1256BF7cs2uhlbeY5q3dqXdtGy+jajsZ1NrRjvB5rc3vm/vbt3kzZb0dHnnrpF1FMDWGNxusH1pc5O1bN9iyjO4osomtXZ3PnCf3pH8TCCAAAIEu7kGEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAIESF6hvbLAJc2bZxh3b4kooEH5a/XSr7bW/Pb3mTdu+88O4+RMtVBDbn9R6fFrtGP9s3iOAAAJtBAh2tyFhBgIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBQOgJq0T1+zkzbtGN7qIPe3JrvP3G6Gg9VyP8yqbU2CQEEEEhVoGOqK7IeAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIBA4Quo6/Kwge5MHq3G36Zb8kyKUhYCpSdAy+7SO+cccREJdOvWrYiOhkNBAAEEMiNA3ZgZR0pBAIHiE6B+LL5zyhEhgED6AtSN6RtSAgIIFKcA9WNxntdYR6XxsYPG6I6V3z+/S8dONrp6gP3r7QZTi++wqXunMpsytC5sdvIh0O4C1I3tfgoCd4BgdyALMxEoDIGBAwcWxo6ylwgggEAOBagbc4jNphBAoKAEqB8L6nSxswggkCMB6sYcQbMZBBAoOAHqx4I7ZWnt8PSGBWmt/7mDh9i1x37Kwo75rY0p0D1j1Dir6VWd1rZZGYFcClA35lI7/LYIdoe3IicCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggkNcCaqmtAPaS5lXWsm2rlZd1sSEVfW1i/+E2qEdlm31XvnTSK++tc1avq+5vs+sm2OTF9TY3znje6rpcLboJdKejzroIIOAKEOx2JXhFoAAFmpqanL2uqqoqwL1nlxFAAIHsCFA3ZseVUhFAoPAFqB8L/xxyBAggkHkB6sbMm1IiAggUhwD1Y2Gex0XrGk1jbwd1ST5v7Uq7adl8G1HZz6bWjI4Emjdt32YrN6xP64Bbtm+JrK8AtgLebsB9aXOTaXl55642uKLKJg2oZYzuiBYThSZA3ZifZ4xgd36eF/YKgVACq1evdvIR7A7FRSYEECgRAerGEjnRHCYCCCQtQP2YNBkrIIBACQhQN5bASeYQEUAgJQHqx5TY2nWlsF2IKxA+tn6G/ebYsfbq++/Yn1951t7ZsjGtfVcg25/Ugnxa7Rj/bN4jUNAC1I35efoIdufneWGvEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAIGEAmrRPX7OTNu0Y3vCvMqwccc2+8qTfwuVN0wmtdgmIYAAAu0l0LG9Nsx2EUAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEE0hNQ1+VhA93pbSl4bXVNTkIAAQTaS4Bgd3vJs10EEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAIA0BjY0dNEZ3skX26NIt2VWc/CP7HMQY3CnJsRICCGRKgGB3piQpBwEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBDIocD0hgVpbW3gPr3tydO/bvec9AXr3qksqbKUf8rQuqTWITMCCCCQaQHG7M60KOUhkEOBHj165HBrbAoBBBAoDAHqxsI4T+wlAgjkXoD6MffmbBEBBPJfgLox/88Re4gAAu0jQP3YPu7uVtVaW0HsJc2rrGXbVisv62JDKvraxP7DbVCPSjeb86o86aSeXfaww3v0cYqYMWqcTZgzyxnTO1GZCnQrf02v6kRZWY5A0QhQN+bnqeywszXl566xV8UsMGzYMGtqarKqqipbuHBhMR8qx4YAAggggAACCCCAAAIIIIAAAggggAACCCCAQEKBResaTeNvx+uWfERlP5taMzoSZB75wO/tv+tXJyw7VoYje/ax/5z29chi7cPkxfU2d/XyyDz/hLouV4tuAt1+Gd4jgEB7CNCyuz3U2SYCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggg8D+B+saGUK2qFQgfWz/D/jjyM7Z+6yZ7/YPmtAzLO3eNWl8B7Nl1E8xtXb60uclatm8x5RtcUWWTBtQyRneUGG8QQKC9BQh2t/cZYPsIpCGwYsUKZ+1+/fqlUQqrIoAAAsUlQN1YXOeTo0EAgcwJUD9mzpKSEECgeASoG4vnXHIkCCCQWQHqx8x6JipNranHz5lpm3ZsT5TVWb5xxzY7/4k7Q+VNlEkB7KCk7tKn1Y4JWsQ8BEpWgLoxP099x/zcLfYKAQTCCKxfv970R0IAAQQQ2C1A3bjbgikEEEDAK0D96NVgGgEEENglQN3IlYAAAggEC1A/Brtka666Lg8b6M70PqilNgkBBMIJUDeGc8p1LoLduRZnewgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIBAq4C6C483Rnc2kTT29sB9emdzE5SNAAIIZF2AYHfWidkAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIINBWYHrDgrYzk5iz3x572U9qTrbuncqSWMuc/FOG1iW1DpkRQACBfBQg2J2PZ4V9QgABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAgaIXWNK8Kq1jPLC8p33j8ONsxqhxoQPeCowrf02v6rS2zcoIIIBAPgh0zoedYB8QQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAgWIQUNfkarGtQHbLtq1WXtbFhlT0tYn9h9ugHpVRh6jl6aSW7Vuc1euq+9vsugk2eXG9zV29PGaR6rpcLboJdMckYgECCBSYAMHuAjth7C4CXoE+ffp43zKNAAIIINAqQN3IZYAAAggEC1A/BrswFwEESluAurG0zz9HjwACsQWoH2PbxFuyaF2jXbnokcAxuOetXWk3LZtvIyr72dSa0TZ03/3sqTUr7O2N78crMuGy8s5dI3kUwFbA2w22L21uMgXDlWdwRZVNGlDLGN0RLSYQSF6AujF5s1ys0WFna8rFhtgGAl6BYcOGWVNTk1VVVdnChQu9i5hGAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQKCgBOobG2zCnFm2cce2hPvdpWMnq+6+t73R8m7CvIkyfGXg0TatdkyibCxHAAEEilaAlt1Fe2o5MAQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEMi2gFp0j58z0zbt2B5qU1s/3JGRQLc2ptbaJAQQQKCUBTqW8sFz7AgUusCyZctMfyQEEEAAgd0C1I27LZhCAAEEvALUj14NphFAAIFdAtSNXAkIIIBAsAD1Y7BLrLnqujxsoDtWGanM1/jbA/fpncqqrIMAAikIUDemgJaDVWjZnQNkNoFAtgQ2b96craIpFwEEEChYAerGgj117DgCCGRZgPoxy8AUjwACBSlA3ViQp42dRgCBHAhQP4ZH1vjYT7aOvZ1q2q+1O/NP9zvC/vzKgtaAeeIu0N3tdO9UZlOG1rlveUUAgRwIUDfmADmFTdCyOwU0VkEAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEpjcsSAvhtP0H2Y+GnWy3jBpnCmCHSco3ozV/Ta/qMNnJgwACCBS1AC27i/r0cnAIIIAAAggggAACCCCAAAIIIIAAAggggAACCCAQVkAttRXAXtK8ylq2bbXysi42pKKvTew/3Ab1qGxTjPKlk55/t8lZva66v82um2CTF9fb3NXLYxaprsvVoptAd0wiFiCAQIkJEOwOOOErV660OXPm2DPPPGMvvfSSvf3227ZhwwYrLy+3vn37Wk1NjZ111ll23HHHBawdPWvbtm22ZMkSW7hwob344ov22muvWWNjo73//vu2fft222uvveyAAw6wj370o3bmmWfaMcccE11AgnebNm2y2bNnW319vb3wwgu2bt0627p1q1Nuv379bNiwYfaZz3zGhgwZkqCk6MXNzc02a9Yse+ihh0we7733nvXq1csGDhxoZ5xxhvNXVhbuKbPoknmHAAIIIIAAAggggAACCCCAAAIIIIAAAggggEB+CSxa12gaezuoS/J5a1faTcvm24jKfja1ZnQk0Lyi5V179f130jqQlu1bIusrgK2AtxtwX9rcZFpe3rmrDa6oskkDahmjO6LFBAIIILBLoMPO1gTGLgEFi7/73e/a4sWLQ5Eo2H3ttddadXXsrkIeeOAB++pXvxqqPGUaOXKk/epXv4pbplvY3Llz7Tvf+Y4TPHfnxXodO3asXXPNNU4QPFYed74C55dccom9807sL+mjjjrKrr/+ejvkkEPc1ZJ6VRC+qanJqqqqnAcBklqZzBEBPUihlOzDDJECmEAAAQSKUIC6sQhPKoeEAAIZEaB+zAgjhSCAQJEJUDcW2QnlcBBAIGMCpVY/1jc22IQ5s2xjiDGz1YX494acaM+ue8seWPmyfZhmiOXY3gfawydPyti5oyAEEMieQKnVjdmTzGzJtOz2eKrVtT/QffDBB9ugQYOsZ8+eTmvsBQsW2KpVu7olefrpp+1Tn/qU/e1vfzO1ok6UunTpYoceeqgddNBBTnl6zmDNmjW2aNEiU0tqJQWw1cL773//e9yA91NPPWVf/OIXbcuW3U99qdW1gs9qLa7W2EuXLrWWlhanXLX+fuutt+zee++1eC2yn3jiCfvyl7/stDrXinvssYcTgN93331txYoVTmt37ffzzz9v55xzjimYr4A1qX0Ewlx37bNnbBUBBBBoPwHqxvazZ8sIIJDfAtSP+X1+2DsEEGgfAerG9nFnqwggkP8CpVQ/qkX3+DkzbdOO7aFOjALiP1xUHypvmExqsU1CAIHCECilurEwzsiuvaRlt+ds3XffffaNb3zDCUafd9559ulPf9rpttyTxT788EOne+8f/OAHpi7EldSt+f33328dOnTwZnWmn332Wfv3v/9tH//4x23w4MHWtWvXNnnUnfndd99tV1xxhW3evNlZ/olPfMJuvfXWNnk1Y8eOHTZq1Chbvny5s1zdoP/85z935jkz/vePAuia/5e//CUy+8orr4zZ0lz51bJcXZYrafr3v/+9VVRURNb/73//axMnToy0Jh8xYoTjEckQcoKW3SGhyIYAAggggAACCCCAAAIIIIAAAggggAACCCCQNYHTH5ke2HV51jboK/iZsRfSNbnPhLcIIIBAMgIEuz1aaqn95ptv2tlnn22d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yxZTb+run95r/u9+9zs7/vjjbfLkyVHB8MztDSUhUNgCy5YtM/2REEAAAQR2C1A37rZgCgEEEPAKUD96NZhGAAEEdglQN5belaCuy8MGujOto/G3B+7TO9PFUh4CWRGgfswKK4UigECBC1A35ucJzGnL7k2bNtm5557rjNGcaKhwd/mOHTvs5ptvtiVLltidd95puegiYOXKlTZnzhx75pln7KWXXrK3337b1M26uljv27ev1dTU2FlnnWXHHXdcwrO6bds2Z981LvWLL75or732mjU2Ntr7779v27dvt7322ssOOOAA++hHP2pnnnmmHXPMMQnLDMqgBwTq6+vtoYceclrKr1692im/srLS2efhw4c7Dxgce+yxppbziZKO9+6777bZs2fbG2+8Yc3NzVZRUWEHH3ywjR071j7zmc/Q3XwiRJYjgAACCCCAAAIIIIAAAggggAACCOSNgMbGVtfk6SQFrE+uHmBXL/l3wm7Qvdvp3qnMpgyt885iGgEEEEAAAQQQQCADAjkNdl922WW2YMEC69Chg7PrAwcOtHPOOcdqa2udgG/37t3t/7N3J/BVFWfjx59sBEKAECEEgwSXkGiVSEgUZGldgopisQruEmjVWvW1Lm1tq1Lo27cvtS7Van3pX4laF7B1A60S1wgqW2gQlxCQsAQChIAQCNngn+fgvdzc3Jucu527/aafmHPPmZkz8504RZ7MzIEDB0SDzZpv3rx58vXXXxsrvjVY/Itf/EIee+wxP3TbdRVr1qyRe+65x1hV7irHnj17RL80AP78888bwe6//OUvnW6z/s4778hNN93kqjrj3u7du0W/Vq9eLc8++6yMGTNGHnrooU7rdK5syZIlRru/+eYb50eyceNG40sD97pSXoPhubm5HfI53lD72267TTZt2uR4W2pqaowv3Xr+ySefNOrTwD8JAQQQQAABBBBAAAEEEEAAAQQQQACBUBeYW7nCpyZemvk9eXrsZKMOXaFt5txvzayB7uJxUySvH0c1+jQAFEYAAQQQQAABBFwIWBbs1m3JX331VSPQHRsbK/fee6/85Cc/sQe+bW3TgHe/fv1k+PDhxnNd1T1r1izRFd6vvfaa/PjHPzZWQdvy+/O7rrrWdjomXcmck5Mjffv2NVZjayB427ZtRpZPP/1ULrnkEnnllVckMzPTsZjLa11RfdJJJ8mQ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1qyRe+65xwgeO9x2e6nB7r/85S+SkeF+28OFCxfKTTfd5LYO5wdjxoyRhx56qNM6/+///k+efPJJ2bFjh3PxDp8TEhLkv/7rv+T222+XuLi4Ds9d3Vi3bp387Gc/ky+++MLVY+Nev379jHaee+65bvN09oBgd2c6PEMAAQQQQAABBMJXoKS60vQ24omxcZLTtv14+e4anzt8Y/YZMrtggs/1UAECCCCAAAIIIIAAAggggAACCCCAQPgIsI25w1jpqmtdJe2YTjjhBMnJyZG+ffsaq7FXrFgh27YdOU/w008/lUsuuUReeeUVyczMdCzm8rpbt25y0kknyZAhQ4z6dFG9BqzLysqkrq7OKLN48WJjhfdrr73mNuCtq84dA92JiYmSm5sremZ6jx49RFemL1u2TA4ePCi6svzBBx+Ub775Rh599FGJjY112TbbTV3FfsUVVxirrvVeTEyMjBw50uifrhzXleRar670/vGPfyz/+Mc/RAP0pOAI6Kp7TdnZ2cFpAG9FAAEEQlCAuTEEB4UmRY2AruieWjpPGlpbTPW58VCrXwLd+jJdrU3qXID5sXMfniKAQHQKMDdG57jTawQQ6FqA+bFrI3IggED0CTA3huaYWxbsnjx5sl8ENPg6f/58v9TlrhINRl999dXyox/9yNi23DGfbh+u77/33nuloaHBCArfeuutxpbf2jbnpPv366rqs88+W4YNGyYamHZOup35P//5T/ntb39rBJI14PzrX/9ann32Wees9s/6Lq1T26nfu3fvbn+mFxo8v++++0SD5ppeffVVKSgokKlTpxqf3f1D+6Lbi2vS4PnTTz8t3/ve9+zZtd6bb75ZNCivgXRdtf7JJ58YW5zbM3FhmYD+4gEJAQQQQKC9AHNjew8+IWClgG5dbjbQ7c926fnb2W0rxEmdCzA/du7DUwQQiE4B5sboHHd6jQACXQswP3ZtRA4EEIg+AebG0Bxzy4LdugraVTDYExZdCe1rHZ29Ly0tzdia+/LLL3e75beujL7yyiuN4O5PfvITozpdmf3RRx/JD37wgw7Va4BZvzpL8fHxRp26zfjPf/5zI+v7779vnBV+7LHHdig6duxY+c1vftMuCO2cSc/T/utf/2oE5N955x3jsW65fv3117s1fO+992Tp0qVGXl2FXlxcLCeffHK7qrXeuXPnynnnnScbN26U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EEAAAQQSTYBpzB1adM2aNTJ9+nT5/PPP5euvv5Z169bJrl27JD09Xdq3by/5+fkydOhQ6dOnj8PV3ocqKytF5/BfsGCBfPXVV/Ltt99KWVmZbN++XaqqqqRly5Zy5JFHyoknnihDhgyRn/3sZ94FuNjT8l555RUpLi42yt69e7e0a9dOjjvuOLngggvk7LPPlkaNGrko6WAWfd7XXntNJk+eLCtXrpSKigrJzMyUo446SgYNGiTDhg2TFi1aHLyALQQQQACBpBKYUDo/rOft0KKV/PbYvnLvwmLR6c3dprSUVLm/Z6Hb7ORDAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQSGABgt22xl26dKnccccdsmjRItvRg5vbtm0T/dEA+IsvvmgEux9//HHJyck5mMln6/3335drr73W5+jB3a1bt4r+LFmyRF544QXp16+f/O1vfwtY5sGrRV5++WW59957RQPc9rR69WrRnylTpsipp54qf//73yUrK8uexe/2/Pnz5cYbb5Tvv//eK095ebnoz6xZs+SZZ56RJ5980gj8e2ViBwEEEEAgKQQWV6wP6zkPT2slv+pyknRIby0jp09yFfDWQHdR/+GS38b//3fDqhQXI4AAAggggAACCCCAAAIIIIAAAggggAACCMSVQKMaT4qrGkexsm+//bZcf/31XnfQkcxdu3aV1q1bG6OxNRC8fv3BD/izs7PljTfekNzcXK/rzJ13333XCnY3bdpUjjnmGOnYsaNRntJv3LhRFi5caIycNq85/PDD5a233goa8NbR3Lfeeqt5mbRq1Ur69u1rjBYvKSmRL774wjrXrVs30ecLNhp72bJlxqh1HdmtKTU11ShTR7TrCPeZM2caI9L1nI5K13qqT6ipV69eRuBc/XTUO6luAnv37jUubN68ed0K4CoEEEDgJwGdllxHa2sQe2flfklPbSo9MtvLqLze0jWj9pel+r37D1m2bUOd/Y5v3U4+O/fXxvULN5fJmEXFMmPDKr/l6dTlOqLbTaCbvtEvIycQQCDJBegfk/wXgMdHAAFHAfpGRxYOIoAAAkL/yC8BAgggUFuAvrG2SSwcIdhtawUz2K3B6EsvvdSYAlyDvPZ04MABmTRpktxzzz2yZ88e45ROa/7OO+84ThU+b948+fjjj+X000+X7t27S7NmzezFGds6nblOGX733Xdb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AggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgEECHYHwOEUAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEBsCjSJzWpRKwQQCCawbt06GThwoJFt3rx5cvjhhwe7hPMIIIBAwgvQNyZ8E/OACCBQRwH6xzrCcRkCCCS0AH1jQjcvD4cAAmEI0D+GgcelCCCQsAL0jbHbtIzsjt22oWYIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAn4ECHb7geEwAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEDsChDsjt22oWYIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAn4ECHb7geEwAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEDsChDsjt22oWYIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAn4ECHb7geEwAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEDsChDsjt22oWYIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAn4ECHb7geEwAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggEDsCjSq8aTYrR41S1SB3NxcqaqqksaNG0tWVlaiPmZUn+vAgQOyceNG4x5qqJYkBBBAINkF6BuT/TeA50cAAX8C9I/+ZDiOAALJLEDfmMytz7MjgEAgAfrHQDqcQwCBZBWgb4x8y2tsa+rUqWEXTLA7bEIKqIvAkUceKdoxkBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAILkEsrOzZcGCBWE/dJOwS6AABOog0KxZM9m3b5+kpKTIYYcdVocSuAQBBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBOJRIFIzPzOyOx5bnzojgAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACSS7AIr9J/gvA4yOAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAALxKECwOx5bjTojgAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACSS5AsDvJfwF4fAQQQAABBBBAAAEEEEAAAQQQ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9u3Spk0b6dKli2jwfMiQIa47fy9cdhBAIG4FYr1vjHawWxtOR3a/+uqrxjfcv/vuO9FpzVu3bi06bfl5551n9LktWrSI2zam4gggUDeBWO8f3T6V/TlCCXZr+bx3dKtMPgSSR8Dep4Ty1E7B7vr4u1rf1+nInylTphijfPTL3zqaUEcA6egiHYkZ6qxm9I2htDx5EUgegXjqH9esWWN8Pqifaa5YscKa6eLQQw8VHX2pM0z+8pe/NLZDaUH9fFRHR+oSEbqtgW9zRswLLrhAzj77bNEAFAkBBBJfIJrBblNPZ4145ZVXZPbs2daMvvq+rk+fPsYyhCeeeKKZ1fVrNPoxPnd0x0+w250TuRBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEYkigcQzVhaoggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCDgSoBgtysmMiGAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIxJIAwe5Yag3qggACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCDgSoBgtysmMiGAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIxJIAwe5Yag3qggACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCDgSoBgtysmMiGAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIxJIAwe5Yag3qggACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCDgSoBgtysmMiGAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIxJIAwe5Yag3qggACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCDgSoBgtysmMiGAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIxJIAwe5Yag3qggACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCDgSoBgtysmMiGAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIxJIAwe5Yag3qggACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCDgSoBgtysmMiGAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIxJIAwe5Yag3qggACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCDgSoBgtysmMiGAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIxJIAwe5Yag3qggACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCDgSoBgtysmMiGAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIxJIAwe5Yag3qggACCCCAAAIIIIAAAggggECUBA4cOCCDBw+WnJwc42fYsGFSU1MT0t0eeugh6/rjjjtONmzYENL1ZEYAAQQQQAABBBBAAAEEEEAgkgIEuyOpSVkIIIAAAggggAACCCCAAAIIxKhA48aN5ZFHHpHmzZsbNfz888/l+eefd13br776Sp5++mkr/5gxY6Rdu3bWPhsIIIAAAggggAACCCCAAAII1LcAwe76Fud+CCCAAAIIIIAAAggggAACCDSQwDHHHCM333yzdfcHH3xQysrKrH1/G9XV1fL73/9eKisrjSxnnHGGDB8+3F92jiOAAAIIIIAAAggggAACCCBQLwIEu+uFmZsggAACCCCAAAIIIIAAAgggEBsCv/71r6VHjx5GZXbu3Cm33XZb0Ir961//ksWLFxv5WrZsKX/5y1+CXkMGBBBAAAEEEEAAAQQQQAABBKItQLA72sKUjwACCCCAAAIIIIAAAggggEAMCaSkpBjTmaemphq1+uSTT2TixIl+a7hq1Sp5+OGHrfP33HOPsW63dYANBBBAAAEEEEAAAQQQQAABBBpIgGB3A8FzWwQQQAABBBBAAAEEEEAAAQQaSqBbt27y29/+1rr92LFjZePGjda+uVFTUyN/+MMfZO/evcahvn37yuWXX26e5hUBBBBAAAEEEEAAAQQQQACBBhVo5PnDtaZBa8DNEUAAAQQQQAABBBBAAAEEEECg3gV0/e1zzjlHvv76a+Peuv3vf//bqx7//e9/5fbbbzeOpaWlyYcffigdOnTwyqNrfk+aNEmmT58uq1evlq1bt4rmzcnJkX79+slll10mRx99tNc1Tjt79uyRTz/9VGbOnClffvmlrFy5Un744QfREeiZmZly/PHHy5lnninDhg2Tpk2bOhVhHZs1a5ZcdNFFxn6fPn3ktddeM7a1/q+//roxJbsG93fv3i333XefXH311da1bCCAAAIIIIAAAggggAACCMSPQJP4qSo1RQABBBBAAAEEEEAAAQQQQACBSAloEPnRRx+V8847T6qqqmTq1KnyzjvvyPnnn2/cory8XB544AHrdnfeeadXoPvAgQPGdOjPPPOMNfLbzLx//37Ztm2bLFu2TJ599lnRdcI1aN6oUSMzi9frwoUL5Ze//KXs2rXL67juaFBeg9Jr166V//3vf/L4448bQXkNfrtN27dvl1tuucV4RrfXkA8BBBBAAAEEEEAAAQQQQCD2BQh2x34bUUMEEEAAAQQQQAABBBBAAAEEoiJwwgknyHXXXSdPPvmkUf4f//hHYzS2jqS+6667RIPEmk466SQZNWqUsa3/VFdXG9dNmTLFOpadnS09e/Y0RmFrcHrRokWi631rIP2JJ56QiooKeeihh6z89g0dwW0Gutu0aSOdO3eW9u3bGyPEdcS3lvPFF18YZa1Zs8YY3a2B706dOtmLcdzWCe1uvPFG+eCDD4xge48ePSQvL0/0eElJid8AvGNhHEQAAQQQQAABBBBAAAEEEIgpAaYxj6nmoDIIIIAAAggggAACCCCAAAII1K/Avn375KyzzpLS0lLjxhdccIExXfj1119v7Ddv3lyKi4vlqKOOsir28MMPy2OPPWbsZ2VlGSPAdRp035HbkydPlttuu80Kmv/jH/+wRo5bhXk2dGT3tGnTZMiQIdK1a1f7KWt78+bNomuL6zTkmnSK9IkTJ1rn7Rv2acybNGliBMl1nXINuuurPenzN2vWzH6IbQQQQAABBBBAAAEEEEAAgTgRINgdJw1FNRFAAAEEEEAAAQQQQAABBBCIloAGmwcPHiw6Nbmm9PR02blzp7Gto7119LeZdGR13759jdHdGRkZ8t5770nHjh3N07VedQ3u4cOHG8d1RPXHH39cKyhe66IAB6644gr56KOPjByffPKJMUrbN7s92K3nNCCv63XriHUSAggggAACCCCAAAIIIIBA4gg0TpxH4UkQQAABBBBAAAEEEEAAAQQQQKAuAvn5+XLVVVdZl5qBbp2W/Oqrr7aO68a///1vI9Ct2zfffHPAQLfm0cD4aaedppvG6PGlS5ca23X956KLLrIu/eyzz6ztQBu/+93vCHQHAuIcAggggAACCCCAAAIIIBCnAk3itN5UGwEEEEAAAQQQQAAB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", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAB7sAAAPUCAYAAADc4V37AAEAAElEQVR4AezdB3gcxdnA8VeSi9zlLle5y8YGY8s2oROC6T30ADZgEpKQQgokAT4IqaSRhJBAsAETIPQOCRAgdGJbLhiDJbnJVe5yl4ukb98ld9lb3a3uTldmb//7PObKzu7O/ObVSdy7M5PXaG3ChgACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAgI8E8n1UV6qKAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIICALUCym0BAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEPCdAMlu33UZFUYAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQINlNDCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAII+E6AZLfvuowKI4AAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgiQ7CYGEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQR8J0Cy23ddRoURQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBEh2EwMIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAr4TINntuy6jwggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACJLuJAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAAB3wmQ7PZdl1FhBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAGS3cQAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggIDvBEh2+67LqDACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAMluYgABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAwHcCJLt912VUGAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEECAZDcxgAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCDgOwGS3b7rMiqMAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIECymxhAAAEE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Haz25GwQyHuBdTu2yWMLp8vjX06XDTu3u55PiwYNZWTXATKq2wBpWdLItRwrEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEgilAsjuY7cpZIZB3Aku3rJeHjF7czy6ZJTt2V7sef4fGzeUioxf3OUZv7r2K67uWYwUCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggECwBUh212rfDRs2yKeffiozZ86UBQsWyPLly6WyslK2bdsmxcXF0qxZM+nWrZsMHDhQTjvtNGndunWtGqK//frrr2XWrFny+eefm69z5syRrVu32oVXrlxpzyc7s2jRInn++eflo48+ktWrV8vOnTulrKxM+vXrZx7joYcemmyVlPdIoH379h7VnL/Vzli3wnwe90TjudyRGKdxUIs2MqbXIPO53MWFRTFKsioZAWIyGS3KZkuAuMyWNPtJRoC4TEaLstkQICazocw+khUgLpMVo3w2BIjLbCizj2QEiMlktCibLQHiMlvS7CcZAeIyGS3KZkOAmMyGcmr7KIgYU2qbBnOrX//61/Lee+8ldHINGjSQSy65RC6//HIpLCyMuo0myo888kjZuHFj1PXWwlST3ffff7/ce++9smvXLquqOq8nnXSS3HHHHdK4ceM66xJZoEnziooKM4FeXl6eyCaUQSCmwJ7IHnl75SIjyT1FpqxZHrPs0Dad5bKeg2VwaQcpKCiIWZaVCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAAC4RGgZ3eMtm7RooV06dJF2rZtK40aNZLt27fLsmXLzJ7Z1dXVZg/qu+++2+z9rUnnaFNVVVXcRHe07RJZduedd8p9991nFy0tLZUBAwaIJuG15/jChQvNda+++qp5DM8884zZO93egBkEsiyw0xiefMKyOTLWSHIv2LzWde/FBYUyfP/ecknPQdKzWalrOVYggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgiEV4Bkd622HzRokAwbNkyGDBki+++/f621379du3at3HzzzaJJZJ0mTJhgbnPccceZ76P9R5PlvXv3lr59+0qfPn3MRLn2CE91mjRpUo1E94UXXijXXnut1K//wzOM9fiuuuoq2bFjhznE+YMPPihXXHFFqrtkuwwIzJ4926xFYyBM0+aqHfLUohkybsE0qdj+w/D9tQ2a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s0fWrFljHr86qicTArkUICZzqc++3QSISzcZludSgLjMpT77jiZATEZTYVmuBYjLXLcA+48mQFxGU2FZLgWIyVzqs283AeLSTYbluRQgLnOpz76jCRCT0VTSX6a5sjfffDPtikh2p00Y/AratWsn+j8yEwIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIJCuQFlZmZSXl6dbjRSnXQMVBF6gQYMGsnPnTikqKpK999478OfLCSKAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAgHcCmRpNmp7d3rURNSOAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIeCTAQ4M9gqVaBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAHvBEh2e2dLzQgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACHgmQ7PYIlmoRQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBLwTINntnS01I4AAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgh4JECy2yNYqkUAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQ8E6AZLd3ttSMAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIOCRAMluj2CpFgEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEDAOwGS3d7ZUjMCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAgEcCxR7VS7UI5FTgm2++kY8//limTZsm8+fPl1WrVsm2bdukcePG0rp1azn44IPl5JNPloEDByZ9nLNmzZIXXnhBpk6dKqtXrza31zq1rjPOOEP69u2bcJ3ffvutfP755zJ79mz734oVK+zt77nnHrNOe0ESM3q+EyZMkIkTJ8pXX30lGzZskBYtWkjHjh3l+OOPl1NPPVUaNWqURI0UTVcgzHFZVVUl8+bNs+NcY37RokWye/duk3X48OFy3333pUvM9ikIhDkuNQb1b8X06dNl4cKFUlFRIdu3b5cmTZpIu3btpH///nL66afLAQcckIIsm6QqENaY1PjTWNTvBQsWLJCvv/5a1qxZI9999500aNBAmjdvLj169JDDDjvM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+1pvktTe3X/4wx9EE+EbNmwwe+esWrVK9DFnGq9HHXWU/UgIe2NmcioQtLhMBPOTTz6R1atX20XjDZNqF2QmawJBjMs//vGP9k0VOgz0L37xC3n99ddFh/PV53nrc7lfe+010b/hH3/8sWmtz1HWz1Sm3AsELSZbtGhho+q5xZv0b7lzciYlncuZz65AvsTliy++aMPoYxz69Oljv3fOOHNJieZ4nInzMOd44t8W4JRmHoEACWiPFOuOav1ROmzYsDpnt3HjRntZkyZNYj6v2yqod3I3btxYrGdoOu/Yscp48eo81pYtWya0i3322ccul63jtHfITFSBoMVl1JNkYd4JhDUutbeDnrs16bO73b6MWmV4zY5A0GNSe9noxXC3SYfo0mcq3n777Qnd5etWD8szKxDUuNQbKrW3rE7cYJHZmMlGbUGNy0Ts5syZI7/5zW/k7LPPNj8veY5yImrelwlaTDovfOuobuecc449Opz2sunRo4d53WH27NliXXzUhLj2+tbkt/MGdO/12YObQNDi0u08ncudQ5hrnDp73DrLMZ87gSDGpT76cfz48XLBBReYPRz1Zsrf/va3UZFLS0vlrLPOkssvv9xOkEctyMKsCQQtJg888ECx/o5/+OGH8stf/jKm5XvvvVdjPdfSa3Dk7E0+xKX26n7ooYdsI/2+6NZj25njceZu7I2jzLRq1cpeGua4LLQVmEEgRAJ6J80bb7xhn/H1118vDRo0sN9bM9qTypr0+QeJTs6yzjoS3T6Vcs79OPcfqy5nOauXWKzyrPNWIIhx6a0YtWdDIMxxqb3ErN46hYWF3E2ejYBLYB9hjknl0Tt2dRhzTT5G++6SACFFPBAIalxGIhG59tprzZ429evXNxOGzueheUBJlRkUCGpcKlHnzp3lsssukxdeeMF8XuKyZctEh5LUi5A6+kDr1q1tyWeffZa/4bZGbmeCGJP66DNr+u9//2smuvXZx5pI1JEF9O/1Aw88IB999JE8/PDDYv0GX79+vYwZM8balNccCgQxLuNx6vUj58gXehMlk78EghyXQ4YMEf281JFY3JI9eoPa0KFDzRuDGF7fH7EZxJjUkVis6e2335bPPvvMelvnVZPizzzzTI3lVke3Ggt5k1WBfIhL7Wypv1useNEE9sUXX+zqlG6Ox7m9604CuoJkd0AbltNyF9A7qjW5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DpChQ4fKqaeeKvXr149Whb1sypQpMnz4cPP9wIEDZcKECea8Hv/LL79sDsmuyf3vvvtObr75Zhk1apS9LTMIIIAAAggggAACCCCAAALBFCgO5mlxVggggAACCCCAAAIIIIAAAgiET0CTyPfee68cd9xxUl1dLW+++aa89tprcsIJJ5gYFRUVcuutt9ow119/fY1E9549e8zh0MeNG2f3/LYKV1VVyaZNm2Tu3LnyxBNPiD4nXJPmBQUFVpEar5999pmceeaZsm3bthrL9Y0m5TUpvWLFCnnrrbfk/vvvN5PymvxOdPr222/lyiuvNM8x0W0ohwACCCCAAAIIIIAAAgggECwBkt3Bak/OBgEEEEAAAQQQQAABBBBAIOQCvXv3ltGjR8vYsWNNiZtuusnsja09qX//+9+LJol1GjBggJx33nnmvP5n9+7d5nZvvPGGvaysrEwOOuggsxe2Jqdnzpwp+rxvTaQ/+OCDsmHDBvnLX/5il3fOaA9uK9HdsmVL6dq1q7Ru3drsIa49vrWeWbNmmXV98803Zu9uTXzvv//+zmqizusgdWPGjJF3333XTLb36dNHunTpIrp84cKFrgn4qJWxEAEEEEAAAQQQQAABBBBAIG8FGMY8b5uOA0cAAQQQQAABBBBAAAEEEEAgusDOnTvlqKOOkkWLFpkFTjnlFHO48Isuush8X1JSIu+884507NjRruDOO++U++67z3zfqlUrswe4DoNeu+f2xIkT5dprr7WT5o888ojdc9yuzJjRnt1vv/22nHTSSdK9e3fnKnt+3bp1os8W12HIddIh0l944QV7vXPGOYx5cXGxmSTX55Rr0l1fnZOef4MGDZyLmEcAAQQQQAABBBBAAAEEEAigAMnuADYqp4QAAggggAACCCCAAAIIIICAJptPPPFE0aHJdWrcuLFs3brVnNfe3tr725q0Z/XgwYPN3t3NmjWT119/XTp06GCtrvOqz+A+/fTTzeXao/qDDz6okxSvs1GMBb/61a/k/fffN0t8+OGHZi/t2sWdyW5dpwl5fV639lhnQgABBBBAAAEEEEAAAQQQCKdAYThPm7NGAAEEEEAAAQQQQAABBBBAINgCBx98sIwcOdI+SSvRrcOSjxo1yl6uM48//riZ6Nb5K664ImaiW8toYvzwww/XWbP3+BdffGHOp/qf4cOH25tOmjTJno81c/nll5PojgXEOgQQQAABBBBAAAEEEEAgBALFIThHThEBBBBAAAEEEEAAAQQQQACBUArocOM6lLg+H1snHdr7nnvukaKiIvO99R+rV7W+P/nkk63FMV814a29sHWaPn266LPC3SZ9Rnd5ebksWLBA1q9fbz7LW58Rbk0VFRXWrMydO9eejzVzwgknxFrNOgQQQAABBBBAAAEEEEAAgRAIkOwOQSNziggggAACCCCAAAIIIIAAAuEUaNiwoejzujXBrZP29u7atWsNjA0bNsjSpUvNZfXr17fL1igU5c2XX35pL121apU975zZuHGj3HXXXTJhwgR7CHXn+mjzejzxpv3220+aN28erxjrEUAAAQQQQAABBBBAAAEEAi5AsjvgDczpIYAAAggggAACCCCAAAIIIBBLYM2aNfbqqqoqeeqpp+z3ic5s3ry5TtEVK1aYifaVK1fWWRdrgTXceqwye++9d6zVrEMAAQQQQAABBBBAAAEEEAiJAMnukDQ0p4kAAggggAACCCCAAAIIIIBANIEtW7ZEW5zUsurq6jrlL774YrES3Y0bN5azzjrLfM53x44dpWXLllJSUiKFhYXmdlOmTBHrud2RSKROXbUX6LZMCCCAAAIIIIAAAggggAACCJDsJgYQQAABBBBAAAEEEEAAAQQQCLGADnVuTU2aNDGfq229T/X1008/lRkzZpibN2rUSCZOnFhn+HRn3Yn05naWZx4BBBBAAAEEEEAAAQQQQAABFfj+FmosEEAAAQQQQAABBBBAAAEEEEAglAL77LOPfd7ay3v79u32+1RnPvnkE3tT7bFd+znh9sr/zVg9wGsv5z0CCCCAAAIIIIAAAggggAACsQRIdsfSYR0CCCCAAAIIIIAAAggggAACARcoLS2VNm3a2GepvbLTnSorK+0qunfvbs+7zUybNs1tFcsRQAABBBBAAAEEEEAAAQQQcBUg2e1KwwoEEEAAAQQQQAABBBBAAAEEwiEwdOhQ+0SfeeYZez7VGetZ3Lp9vJ7iFRUV8vbbb6e6K7ZDAAEEEEAAAQQQQAABBBAIsQDJ7hA3PqeOAAIIIIAAAggggAACCCCAgApccMEFUlRUZGK8+eab8sILLyQMs2bNmjpl99tvP3tZrET27t275dprr5Wqqiq7PDMIIIAAAggggAACCCCAAAIIJCpAsjtRKcohgAACCCCA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", "text/plain": [ "" ] @@ -244,7 +267,9 @@ } ], "source": [ - "api_response = gpt_assistant.openai_client.files.with_raw_response.retrieve_content(\"file-sAG7r763XR9jiuKYiQeoHRFU\")\n", + "api_response = gpt_assistant.openai_client.files.with_raw_response.retrieve_content(\n", + " \"assistant-tvLtfOn6uAJ9kxmnxgK2OXID\"\n", + ")\n", "\n", "if api_response.status_code == 200:\n", " content = api_response.content\n", @@ -255,10 +280,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Permanently deleting assistant...\n" + ] + } + ], + "source": [ + "gpt_assistant.delete_assistant()" + ] } ], "metadata": { diff --git a/notebook/nested_chat_1.png b/notebook/nested_chat_1.png new file mode 100644 index 00000000000..548fe75132e Binary files /dev/null and b/notebook/nested_chat_1.png differ diff --git a/notebook/nested_chat_2.png b/notebook/nested_chat_2.png new file mode 100644 index 00000000000..917c8ba6f10 Binary files /dev/null and b/notebook/nested_chat_2.png differ diff --git a/samples/apps/autogen-studio/Dockerfile b/samples/apps/autogen-studio/Dockerfile new file mode 100644 index 00000000000..bb475db7176 --- /dev/null +++ b/samples/apps/autogen-studio/Dockerfile @@ -0,0 +1,17 @@ +FROM python:3.10 + +WORKDIR /code + +RUN pip install -U gunicorn autogenstudio + +RUN useradd -m -u 1000 user +USER user +ENV HOME=/home/user \ + PATH=/home/user/.local/bin:$PATH \ + AUTOGENSTUDIO_APPDIR=/home/user/app + +WORKDIR $HOME/app + +COPY --chown=user . $HOME/app + +CMD gunicorn -w $((2 * $(getconf _NPROCESSORS_ONLN) + 1)) --timeout 12600 -k uvicorn.workers.UvicornWorker autogenstudio.web.app:app --bind "0.0.0.0:8081" diff --git a/samples/apps/autogen-studio/README.md b/samples/apps/autogen-studio/README.md index 72dc2b9a427..28d95cd3e99 100644 --- a/samples/apps/autogen-studio/README.md +++ b/samples/apps/autogen-studio/README.md @@ -14,6 +14,9 @@ Code for AutoGen Studio is on GitHub at [microsoft/autogen](https://github.com/m > [!WARNING] > AutoGen Studio is currently under active development and we are iterating quickly. Kindly consider that we may introduce breaking changes in the releases during the upcoming weeks, and also the `README` might be outdated. We'll update the `README` as soon as we stabilize the API. +> [!NOTE] Updates +> March 12: Default directory for AutoGen Studio is now /home//.autogenstudio. You can also specify this directory using the `--appdir` argument when running the application. For example, `autogenstudio ui --appdir /path/to/folder`. This will store the database and other files in the specified directory e.g. `/path/to/folder/database.sqlite`. `.env` files in that directory will be used to set environment variables for the app. + ### Capabilities / Roadmap Some of the capabilities supported by the app frontend include the following: diff --git a/samples/apps/autogen-studio/autogenstudio/chatmanager.py b/samples/apps/autogen-studio/autogenstudio/chatmanager.py index ee6d51d9d68..222e7951e56 100644 --- a/samples/apps/autogen-studio/autogenstudio/chatmanager.py +++ b/samples/apps/autogen-studio/autogenstudio/chatmanager.py @@ -1,63 +1,225 @@ +import asyncio +from datetime import datetime import json +from queue import Queue import time -from typing import List -from .datamodel import AgentWorkFlowConfig, Message -from .utils import extract_successful_code_blocks, get_default_agent_config, get_modified_files -from .workflowmanager import AutoGenWorkFlowManager +from typing import Any, List, Dict, Optional, Tuple import os +from fastapi import WebSocket, WebSocketDisconnect +import websockets +from .datamodel import AgentWorkFlowConfig, Message, SocketMessage +from .utils import extract_successful_code_blocks, get_modified_files, summarize_chat_history +from .workflowmanager import AutoGenWorkFlowManager class AutoGenChatManager: - def __init__(self) -> None: - pass + """ + This class handles the automated generation and management of chat interactions + using an automated workflow configuration and message queue. + """ + + def __init__(self, message_queue: Queue) -> None: + """ + Initializes the AutoGenChatManager with a message queue. + + :param message_queue: A queue to use for sending messages asynchronously. + """ + self.message_queue = message_queue + + def send(self, message: str) -> None: + """ + Sends a message by putting it into the message queue. + + :param message: The message string to be sent. + """ + if self.message_queue is not None: + self.message_queue.put_nowait(message) + + def chat( + self, + message: Message, + history: List[Dict[str, Any]], + flow_config: Optional[AgentWorkFlowConfig] = None, + connection_id: Optional[str] = None, + user_dir: Optional[str] = None, + **kwargs, + ) -> Message: + """ + Processes an incoming message according to the agent's workflow configuration + and generates a response. - def chat(self, message: Message, history: List, flow_config: AgentWorkFlowConfig = None, **kwargs) -> None: - work_dir = kwargs.get("work_dir", None) - scratch_dir = os.path.join(work_dir, "scratch") + :param message: An instance of `Message` representing an incoming message. + :param history: A list of dictionaries, each representing a past interaction. + :param flow_config: An instance of `AgentWorkFlowConfig`. If None, defaults to a standard configuration. + :param connection_id: An optional connection identifier. + :param kwargs: Additional keyword arguments. + :return: An instance of `Message` representing a response. + """ + + # create a working director for workflow based on user_dir/session_id/time_hash + work_dir = os.path.join(user_dir, message.session_id, datetime.now().strftime("%Y%m%d_%H-%M-%S")) + os.makedirs(work_dir, exist_ok=True) # if no flow config is provided, use the default if flow_config is None: - flow_config = get_default_agent_config(scratch_dir) + raise ValueError("flow_config must be specified") + + flow = AutoGenWorkFlowManager( + config=flow_config, + history=history, + work_dir=work_dir, + send_message_function=self.send, + connection_id=connection_id, + ) - flow = AutoGenWorkFlowManager(config=flow_config, history=history, work_dir=scratch_dir) message_text = message.content.strip() - output = "" start_time = time.time() - - metadata = {} flow.run(message=f"{message_text}", clear_history=False) + end_time = time.time() - metadata["messages"] = flow.agent_history + metadata = { + "messages": flow.agent_history, + "summary_method": flow_config.summary_method, + "time": end_time - start_time, + "files": get_modified_files(start_time, end_time, source_dir=work_dir), + } - output = "" + print("Modified files: ", len(metadata["files"])) + + output = self._generate_output(message_text, flow, flow_config) + + output_message = Message( + user_id=message.user_id, + root_msg_id=message.root_msg_id, + role="assistant", + content=output, + metadata=json.dumps(metadata), + session_id=message.session_id, + ) + + return output_message + def _generate_output( + self, message_text: str, flow: AutoGenWorkFlowManager, flow_config: AgentWorkFlowConfig + ) -> str: + """ + Generates the output response based on the workflow configuration and agent history. + + :param message_text: The text of the incoming message. + :param flow: An instance of `AutoGenWorkFlowManager`. + :param flow_config: An instance of `AgentWorkFlowConfig`. + :return: The output response as a string. + """ + + output = "" if flow_config.summary_method == "last": successful_code_blocks = extract_successful_code_blocks(flow.agent_history) last_message = flow.agent_history[-1]["message"]["content"] if flow.agent_history else "" successful_code_blocks = "\n\n".join(successful_code_blocks) output = (last_message + "\n" + successful_code_blocks) if successful_code_blocks else last_message elif flow_config.summary_method == "llm": - output = "" + model = flow.config.receiver.config.llm_config.config_list[0] + status_message = SocketMessage( + type="agent_status", + data={"status": "summarizing", "message": "Generating summary of agent dialogue"}, + connection_id=flow.connection_id, + ) + self.send(status_message.dict()) + output = summarize_chat_history(task=message_text, messages=flow.agent_history, model=model) + elif flow_config.summary_method == "none": output = "" + return output - metadata["code"] = "" - metadata["summary_method"] = flow_config.summary_method - end_time = time.time() - metadata["time"] = end_time - start_time - modified_files = get_modified_files(start_time, end_time, scratch_dir, dest_dir=work_dir) - metadata["files"] = modified_files - print("Modified files: ", len(modified_files)) +class WebSocketConnectionManager: + """ + Manages WebSocket connections including sending, broadcasting, and managing the lifecycle of connections. + """ - output_message = Message( - user_id=message.user_id, - root_msg_id=message.root_msg_id, - role="assistant", - content=output, - metadata=json.dumps(metadata), - session_id=message.session_id, - ) + def __init__( + self, active_connections: List[Tuple[WebSocket, str]] = None, active_connections_lock: asyncio.Lock = None + ) -> None: + """ + Initializes WebSocketConnectionManager with an optional list of active WebSocket connections. - return output_message + :param active_connections: A list of tuples, each containing a WebSocket object and its corresponding client_id. + """ + if active_connections is None: + active_connections = [] + self.active_connections_lock = active_connections_lock + self.active_connections: List[Tuple[WebSocket, str]] = active_connections + + async def connect(self, websocket: WebSocket, client_id: str) -> None: + """ + Accepts a new WebSocket connection and appends it to the active connections list. + + :param websocket: The WebSocket instance representing a client connection. + :param client_id: A string representing the unique identifier of the client. + """ + await websocket.accept() + async with self.active_connections_lock: + self.active_connections.append((websocket, client_id)) + print(f"New Connection: {client_id}, Total: {len(self.active_connections)}") + + async def disconnect(self, websocket: WebSocket) -> None: + """ + Disconnects and removes a WebSocket connection from the active connections list. + + :param websocket: The WebSocket instance to remove. + """ + async with self.active_connections_lock: + try: + self.active_connections = [conn for conn in self.active_connections if conn[0] != websocket] + print(f"Connection Closed. Total: {len(self.active_connections)}") + except ValueError: + print("Error: WebSocket connection not found") + + async def disconnect_all(self) -> None: + """ + Disconnects all active WebSocket connections. + """ + for connection, _ in self.active_connections[:]: + await self.disconnect(connection) + + async def send_message(self, message: Dict, websocket: WebSocket) -> None: + """ + Sends a JSON message to a single WebSocket connection. + + :param message: A JSON serializable dictionary containing the message to send. + :param websocket: The WebSocket instance through which to send the message. + """ + try: + async with self.active_connections_lock: + await websocket.send_json(message) + except WebSocketDisconnect: + print("Error: Tried to send a message to a closed WebSocket") + await self.disconnect(websocket) + except websockets.exceptions.ConnectionClosedOK: + print("Error: WebSocket connection closed normally") + await self.disconnect(websocket) + except Exception as e: + print(f"Error in sending message: {str(e)}") + await self.disconnect(websocket) + + async def broadcast(self, message: Dict) -> None: + """ + Broadcasts a JSON message to all active WebSocket connections. + + :param message: A JSON serializable dictionary containing the message to broadcast. + """ + # Create a message dictionary with the desired format + message_dict = {"message": message} + + for connection, _ in self.active_connections[:]: + try: + if connection.client_state == websockets.protocol.State.OPEN: + # Call send_message method with the message dictionary and current WebSocket connection + await self.send_message(message_dict, connection) + else: + print("Error: WebSocket connection is closed") + await self.disconnect(connection) + except (WebSocketDisconnect, websockets.exceptions.ConnectionClosedOK) as e: + print(f"Error: WebSocket disconnected or closed({str(e)})") + await self.disconnect(connection) diff --git a/samples/apps/autogen-studio/autogenstudio/datamodel.py b/samples/apps/autogen-studio/autogenstudio/datamodel.py index cd8d5a40f6e..8bebdb63ef4 100644 --- a/samples/apps/autogen-studio/autogenstudio/datamodel.py +++ b/samples/apps/autogen-studio/autogenstudio/datamodel.py @@ -113,6 +113,7 @@ class AgentConfig: is_termination_msg: Optional[Union[bool, str, Callable]] = None code_execution_config: Optional[Union[bool, str, Dict[str, Any]]] = None default_auto_reply: Optional[str] = "" + description: Optional[str] = None def dict(self): result = asdict(self) @@ -131,7 +132,6 @@ class AgentFlowSpec: timestamp: Optional[str] = None user_id: Optional[str] = None skills: Optional[Union[None, List[Skill]]] = None - description: Optional[str] = None def __post_init__(self): if self.timestamp is None: @@ -175,7 +175,6 @@ class GroupChatFlowSpec: id: Optional[str] = None timestamp: Optional[str] = None user_id: Optional[str] = None - description: Optional[str] = None skills: Optional[Union[None, List[Skill]]] = None def __post_init__(self): @@ -303,3 +302,16 @@ class DBWebRequestModel(object): agent: Optional[AgentFlowSpec] = None workflow: Optional[AgentWorkFlowConfig] = None model: Optional[Model] = None + message: Optional[Message] = None + connection_id: Optional[str] = None + + +@dataclass +class SocketMessage(object): + connection_id: str + data: Dict[str, Any] + type: str + + def dict(self): + result = asdict(self) + return result diff --git a/samples/apps/autogen-studio/autogenstudio/utils/dbdefaults.json b/samples/apps/autogen-studio/autogenstudio/utils/dbdefaults.json index 9359a05afd0..7f36325266e 100644 --- a/samples/apps/autogen-studio/autogenstudio/utils/dbdefaults.json +++ b/samples/apps/autogen-studio/autogenstudio/utils/dbdefaults.json @@ -22,7 +22,7 @@ "agents": [ { "type": "userproxy", - "description": "A user proxy agent that executes code.", + "config": { "name": "userproxy", "human_input_mode": "NEVER", @@ -33,12 +33,12 @@ "code_execution_config": { "work_dir": null, "use_docker": false - } + }, + "description": "A user proxy agent that executes code." } }, { "type": "assistant", - "description": "A primary assistant agent that writes plans and code to solve tasks.", "skills": [ { "title": "find_papers_arxiv", @@ -54,6 +54,7 @@ ], "config": { "name": "primary_assistant", + "description": "A primary assistant agent that writes plans and code to solve tasks.", "llm_config": { "config_list": [ { @@ -138,7 +139,7 @@ }, "human_input_mode": "NEVER", "max_consecutive_auto_reply": 8, - "system_message": "You are a helpful assistant that can suggest a travel plan for a user. You are the primary cordinator who will receive suggestions or advice from other agents (local_assistant, language_assistant). You must ensure that the finally plan integrates the suggestions from other agents or team members. YOUR FINAL RESPONSE MUST BE THE COMPLETE PLAN that ends with the word TERMINATE. " + "system_message": "You are a helpful assistant that can suggest a travel plan for a user. You are the primary cordinator who will receive suggestions or advice from other agents (local_assistant, language_assistant). You must ensure that the finally plan integrates the suggestions from other agents or team members. YOUR FINAL RESPONSE MUST BE THE COMPLETE PLAN. When the plan is complete and all perspectives are integrated, you can respond with TERMINATE." } }, { @@ -188,9 +189,9 @@ "description": "This workflow is used for general purpose tasks.", "sender": { "type": "userproxy", - "description": "A user proxy agent that executes code.", "config": { "name": "userproxy", + "description": "A user proxy agent that executes code.", "human_input_mode": "NEVER", "max_consecutive_auto_reply": 10, "system_message": "You are a helpful assistant.", @@ -204,7 +205,7 @@ }, "receiver": { "type": "assistant", - "description": "Default assistant to generate plans and write code to solve tasks.", + "skills": [ { "title": "find_papers_arxiv", @@ -218,6 +219,7 @@ } ], "config": { + "description": "Default assistant to generate plans and write code to solve tasks.", "name": "primary_assistant", "llm_config": { "config_list": [ diff --git a/samples/apps/autogen-studio/autogenstudio/utils/dbutils.py b/samples/apps/autogen-studio/autogenstudio/utils/dbutils.py index 92893c01c3d..a7c4b7d4c05 100644 --- a/samples/apps/autogen-studio/autogenstudio/utils/dbutils.py +++ b/samples/apps/autogen-studio/autogenstudio/utils/dbutils.py @@ -51,6 +51,7 @@ id TEXT NOT NULL, user_id TEXT NOT NULL, timestamp DATETIME NOT NULL, + name TEXT, flow_config TEXT, UNIQUE (user_id, id) ) @@ -76,7 +77,6 @@ config TEXT, type TEXT, skills TEXT, - description TEXT, UNIQUE (id, user_id) ) """ @@ -136,10 +136,40 @@ def __init__(self, path: str = "database.sqlite", **kwargs: Any) -> None: try: self.conn = sqlite3.connect(self.path, check_same_thread=False, **kwargs) self.cursor = self.conn.cursor() + self.migrate() except Exception as e: logger.error("Error connecting to database: %s", e) raise e + def migrate(self): + """ + Run migrations to update the database schema. + """ + self.add_column_if_not_exists("sessions", "name", "TEXT") + self.add_column_if_not_exists("models", "description", "TEXT") + + def add_column_if_not_exists(self, table: str, column: str, column_type: str): + """ + Adds a new column to the specified table if it does not exist. + + Args: + table (str): The table name where the column should be added. + column (str): The column name that should be added. + column_type (str): The data type of the new column. + """ + try: + self.cursor.execute(f"PRAGMA table_info({table})") + column_names = [row[1] for row in self.cursor.fetchall()] + if column not in column_names: + self.cursor.execute(f"ALTER TABLE {table} ADD COLUMN {column} {column_type}") + self.conn.commit() + logger.info(f"Migration: New '{column}' column has been added to the '{table}' table.") + else: + logger.info(f"'{column}' column already exists in the '{table}' table.") + + except Exception as e: + print(f"Error while checking and updating '{table}' table: {e}") + def reset_db(self): """ Reset the database by deleting the database file and creating a new one. @@ -149,13 +179,6 @@ def reset_db(self): os.remove(self.path) self.init_db(path=self.path) - def run_migrations(self): - """ - Run migrations to update the database schema. - """ - - pass - def init_db(self, path: str = "database.sqlite", **kwargs: Any) -> None: """ Initializes the database by creating necessary tables. @@ -228,7 +251,7 @@ def init_db(self, path: str = "database.sqlite", **kwargs: Any) -> None: agent = AgentFlowSpec(**agent) agent.skills = [skill.dict() for skill in agent.skills] if agent.skills else None self.cursor.execute( - "INSERT INTO agents (id, user_id, timestamp, config, type, skills, description) VALUES (?, ?, ?, ?, ?, ?, ?)", + "INSERT INTO agents (id, user_id, timestamp, config, type, skills) VALUES (?, ?, ?, ?, ?, ?)", ( agent.id, "default", @@ -236,7 +259,6 @@ def init_db(self, path: str = "database.sqlite", **kwargs: Any) -> None: json.dumps(agent.config.dict()), agent.type, json.dumps(agent.skills), - agent.description, ), ) @@ -387,7 +409,7 @@ def delete_model(model: Model, dbmanager: DBManager) -> List[dict]: return models -def create_message(message: Message, dbmanager: DBManager) -> None: +def create_message(message: Message, dbmanager: DBManager) -> List[dict]: """ Save a message in the database using the provided database manager. @@ -406,6 +428,8 @@ def create_message(message: Message, dbmanager: DBManager) -> None: message.session_id, ) dbmanager.query(query=query, args=args) + messages = get_messages(user_id=message.user_id, session_id=message.session_id, dbmanager=dbmanager) + return messages def get_messages(user_id: str, session_id: str, dbmanager: DBManager) -> List[dict]: @@ -460,6 +484,24 @@ def create_session(user_id: str, session: Session, dbmanager: DBManager) -> List return sessions +def rename_session(name: str, session: Session, dbmanager: DBManager) -> List[dict]: + """ + Edit a session for a specific user in the database. + + :param name: The new name of the session + :param session: The Session object containing session data + :param dbmanager: The DBManager instance to interact with the database + :return: A list of dictionaries, each representing a session + """ + + query = "UPDATE sessions SET name = ? WHERE id = ?" + args = (name, session.id) + dbmanager.query(query=query, args=args) + sessions = get_sessions(user_id=session.user_id, dbmanager=dbmanager) + + return sessions + + def delete_session(session: Session, dbmanager: DBManager) -> List[dict]: """ Delete a specific session and all messages for that session in the database. @@ -674,12 +716,11 @@ def upsert_agent(agent_flow_spec: AgentFlowSpec, dbmanager: DBManager) -> List[D "timestamp": agent_flow_spec.timestamp, "config": json.dumps(agent_flow_spec.config.dict()), "type": agent_flow_spec.type, - "description": agent_flow_spec.description, "skills": json.dumps([x.dict() for x in agent_flow_spec.skills] if agent_flow_spec.skills else []), } update_item("agents", agent_flow_spec.id, updated_data, dbmanager) else: - query = "INSERT INTO agents (id, user_id, timestamp, config, type, description, skills) VALUES (?, ?, ?, ?, ?, ?, ?)" + query = "INSERT INTO agents (id, user_id, timestamp, config, type, skills) VALUES (?, ?, ?, ?, ?,?)" config_json = json.dumps(agent_flow_spec.config.dict()) args = ( agent_flow_spec.id, @@ -687,7 +728,6 @@ def upsert_agent(agent_flow_spec: AgentFlowSpec, dbmanager: DBManager) -> List[D agent_flow_spec.timestamp, config_json, agent_flow_spec.type, - agent_flow_spec.description, json.dumps([x.dict() for x in agent_flow_spec.skills] if agent_flow_spec.skills else []), ) dbmanager.query(query=query, args=args) diff --git a/samples/apps/autogen-studio/autogenstudio/utils/utils.py b/samples/apps/autogen-studio/autogenstudio/utils/utils.py index b604fb30d4a..8795037cf28 100644 --- a/samples/apps/autogen-studio/autogenstudio/utils/utils.py +++ b/samples/apps/autogen-studio/autogenstudio/utils/utils.py @@ -8,6 +8,8 @@ import autogen from autogen.oai.client import OpenAIWrapper from ..datamodel import AgentConfig, AgentFlowSpec, AgentWorkFlowConfig, LLMConfig, Model, Skill +from dotenv import load_dotenv +from ..version import APP_NAME def md5_hash(text: str) -> str: @@ -145,21 +147,17 @@ def serialize_file(file_path: str) -> Tuple[str, str]: return base64_encoded_content, file_type -def get_modified_files( - start_timestamp: float, end_timestamp: float, source_dir: str, dest_dir: str -) -> List[Dict[str, str]]: +def get_modified_files(start_timestamp: float, end_timestamp: float, source_dir: str) -> List[Dict[str, str]]: """ - Copy files from source_dir that were modified within a specified timestamp range - to dest_dir, renaming files if they already exist there. The function excludes - files with certain file extensions and names. + Identify files from source_dir that were modified within a specified timestamp range. + The function excludes files with certain file extensions and names. - :param start_timestamp: The start timestamp to filter modified files. - :param end_timestamp: The end timestamp to filter modified files. + :param start_timestamp: The floating-point number representing the start timestamp to filter modified files. + :param end_timestamp: The floating-point number representing the end timestamp to filter modified files. :param source_dir: The directory to search for modified files. - :param dest_dir: The destination directory to copy modified files to. - :return: A list of dictionaries with details of file paths in dest_dir that were modified and copied over. - Dictionary format: {path: "", name: "", extension: ""} + :return: A list of dictionaries with details of relative file paths that were modified. + Dictionary format: {path: "", name: "", extension: "", type: ""} Files with extensions "__pycache__", "*.pyc", "__init__.py", and "*.cache" are ignored. """ @@ -167,63 +165,63 @@ def get_modified_files( ignore_extensions = {".pyc", ".cache"} ignore_files = {"__pycache__", "__init__.py"} + # Walk through the directory tree for root, dirs, files in os.walk(source_dir): - # Excluding the directory "__pycache__" if present + # Update directories and files to exclude those to be ignored dirs[:] = [d for d in dirs if d not in ignore_files] + files[:] = [f for f in files if f not in ignore_files and os.path.splitext(f)[1] not in ignore_extensions] for file in files: file_path = os.path.join(root, file) - file_ext = os.path.splitext(file)[1] - file_name = os.path.basename(file) - - if file_ext in ignore_extensions or file_name in ignore_files: - continue - file_mtime = os.path.getmtime(file_path) - if start_timestamp < file_mtime < end_timestamp: - dest_file_path = os.path.join(dest_dir, file) - copy_idx = 1 - while os.path.exists(dest_file_path): - base, extension = os.path.splitext(file) - # Handling potential name conflicts by appending a number - dest_file_path = os.path.join(dest_dir, f"{base}_{copy_idx}{extension}") - copy_idx += 1 - - # Copying the modified file to the destination directory - shutil.copy2(file_path, dest_file_path) - # Extract user id from the dest_dir and file path + # Verify if the file was modified within the given timestamp range + if start_timestamp <= file_mtime <= end_timestamp: + file_relative_path = ( + "files/user" + file_path.split("files/user", 1)[1] if "files/user" in file_path else "" + ) + file_type = get_file_type(file_path) - dest_dir_as_path = Path(dest_dir) - uid = dest_dir_as_path.name - - relative_file_path = os.path.relpath(dest_file_path, start=dest_dir) - file_type = get_file_type(dest_file_path) file_dict = { - "path": f"files/user/{uid}/{relative_file_path}", - "name": file_name, - "extension": file_ext.replace(".", ""), + "path": file_relative_path, + "name": os.path.basename(file), + # Remove the dot + "extension": os.path.splitext(file)[1].lstrip("."), "type": file_type, } modified_files.append(file_dict) - # sort by extension + + # Sort the modified files by extension modified_files.sort(key=lambda x: x["extension"]) return modified_files -def init_webserver_folders(root_file_path: str) -> Dict[str, str]: +def init_app_folders(app_file_path: str) -> Dict[str, str]: """ Initialize folders needed for a web server, such as static file directories - and user-specific data directories. + and user-specific data directories. Also load any .env file if it exists. :param root_file_path: The root directory where webserver folders will be created :return: A dictionary with the path of each created folder """ - if not os.path.exists(root_file_path): - os.makedirs(root_file_path, exist_ok=True) - files_static_root = os.path.join(root_file_path, "files/") - static_folder_root = os.path.join(root_file_path, "ui") + app_name = f".{APP_NAME}" + default_app_root = os.path.join(os.path.expanduser("~"), app_name) + if not os.path.exists(default_app_root): + os.makedirs(default_app_root, exist_ok=True) + app_root = os.environ.get("AUTOGENSTUDIO_APPDIR") or default_app_root + + if not os.path.exists(app_root): + os.makedirs(app_root, exist_ok=True) + + # load .env file if it exists + env_file = os.path.join(app_root, ".env") + if os.path.exists(env_file): + print(f"Loading environment variables from {env_file}") + load_dotenv(env_file) + + files_static_root = os.path.join(app_root, "files/") + static_folder_root = os.path.join(app_file_path, "ui") os.makedirs(files_static_root, exist_ok=True) os.makedirs(os.path.join(files_static_root, "user"), exist_ok=True) @@ -231,7 +229,9 @@ def init_webserver_folders(root_file_path: str) -> Dict[str, str]: folders = { "files_static_root": files_static_root, "static_folder_root": static_folder_root, + "app_root": app_root, } + print(f"Initialized application data folder: {app_root}") return folders @@ -268,9 +268,6 @@ def get_skills_from_prompt(skills: List[Skill], work_dir: str) -> str: os.makedirs(work_dir) # overwrite skills.py in work_dir - with open(os.path.join(work_dir, "skills.py"), "w", encoding="utf-8") as f: - f.write(prompt) - # overwrite skills.py in work_dir with open(os.path.join(work_dir, "skills.py"), "w", encoding="utf-8") as f: f.write(prompt) @@ -408,3 +405,36 @@ def test_model(model: Model): client = OpenAIWrapper(config_list=[sanitized_model]) response = client.create(messages=[{"role": "user", "content": "2+2="}], cache_seed=None) return response.choices[0].message.content + + +# summarize_chat_history (messages, model) .. returns a summary of the chat history + + +def summarize_chat_history(task: str, messages: List[Dict[str, str]], model: Model): + """ + Summarize the chat history using the model endpoint and returning the response. + """ + + sanitized_model = sanitize_model(model) + client = OpenAIWrapper(config_list=[sanitized_model]) + summarization_system_prompt = f""" + You are a helpful assistant that is able to review the chat history between a set of agents (userproxy agents, assistants etc) as they try to address a given TASK and provide a summary. Be SUCCINCT but also comprehensive enough to allow others (who cannot see the chat history) understand and recreate the solution. + + The task requested by the user is: + === + {task} + === + The summary should focus on extracting the actual solution to the task from the chat history (assuming the task was addressed) such that any other agent reading the summary will understand what the actual solution is. Use a neutral tone and DO NOT directly mention the agents. Instead only focus on the actions that were carried out (e.g. do not say 'assistant agent generated some code visualization code ..' instead say say 'visualization code was generated ..' ). + """ + summarization_prompt = [ + { + "role": "system", + "content": summarization_system_prompt, + }, + { + "role": "user", + "content": f"Summarize the following chat history. {str(messages)}", + }, + ] + response = client.create(messages=summarization_prompt, cache_seed=None) + return response.choices[0].message.content diff --git a/samples/apps/autogen-studio/autogenstudio/version.py b/samples/apps/autogen-studio/autogenstudio/version.py index 0b52beb9e0a..18b7f42aac3 100644 --- a/samples/apps/autogen-studio/autogenstudio/version.py +++ b/samples/apps/autogen-studio/autogenstudio/version.py @@ -1,3 +1,3 @@ -VERSION = "0.0.43a" +VERSION = "0.0.54" __version__ = VERSION APP_NAME = "autogenstudio" diff --git a/samples/apps/autogen-studio/autogenstudio/web/app.py b/samples/apps/autogen-studio/autogenstudio/web/app.py index c069623af3d..48c29ac3803 100644 --- a/samples/apps/autogen-studio/autogenstudio/web/app.py +++ b/samples/apps/autogen-studio/autogenstudio/web/app.py @@ -1,26 +1,64 @@ +import asyncio +from contextlib import asynccontextmanager import json import os +import queue +import threading import traceback -from fastapi import FastAPI +from fastapi import FastAPI, WebSocket, WebSocketDisconnect from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from fastapi import HTTPException from openai import OpenAIError -from ..version import VERSION +from ..version import VERSION, APP_NAME from ..datamodel import ( - ChatWebRequestModel, DBWebRequestModel, DeleteMessageWebRequestModel, Message, Session, ) -from ..utils import md5_hash, init_webserver_folders, DBManager, dbutils, test_model +from ..utils import md5_hash, init_app_folders, DBManager, dbutils, test_model +from ..chatmanager import AutoGenChatManager, WebSocketConnectionManager -from ..chatmanager import AutoGenChatManager +managers = {"chat": None} # manage calls to autogen +# Create thread-safe queue for messages between api thread and autogen threads +message_queue = queue.Queue() +active_connections = [] +active_connections_lock = asyncio.Lock() +websocket_manager = WebSocketConnectionManager( + active_connections=active_connections, active_connections_lock=active_connections_lock +) + + +def message_handler(): + while True: + message = message_queue.get() + print("Active Connections: ", [client_id for _, client_id in websocket_manager.active_connections]) + print("Current message connection id: ", message["connection_id"]) + for connection, socket_client_id in websocket_manager.active_connections: + if message["connection_id"] == socket_client_id: + asyncio.run(websocket_manager.send_message(message, connection)) + message_queue.task_done() + + +message_handler_thread = threading.Thread(target=message_handler, daemon=True) +message_handler_thread.start() + + +@asynccontextmanager +async def lifespan(app: FastAPI): + print("***** App started *****") + managers["chat"] = AutoGenChatManager(message_queue=message_queue) + + yield + # Close all active connections + await websocket_manager.disconnect_all() + print("***** App stopped *****") -app = FastAPI() + +app = FastAPI(lifespan=lifespan) # allow cross origin requests for testing on localhost:800* ports only @@ -38,9 +76,9 @@ ) -root_file_path = os.environ.get("AUTOGENSTUDIO_APPDIR") or os.path.dirname(os.path.abspath(__file__)) +app_file_path = os.path.dirname(os.path.abspath(__file__)) # init folders skills, workdir, static, files etc -folders = init_webserver_folders(root_file_path) +folders = init_app_folders(app_file_path) ui_folder_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ui") api = FastAPI(root_path="/api") @@ -51,13 +89,13 @@ api.mount("/files", StaticFiles(directory=folders["files_static_root"], html=True), name="files") -db_path = os.path.join(root_file_path, "database.sqlite") +db_path = os.path.join(folders["app_root"], "database.sqlite") dbmanager = DBManager(path=db_path) # manage database operations -chatmanager = AutoGenChatManager() # manage calls to autogen +# manage websocket connections @api.post("/messages") -async def add_message(req: ChatWebRequestModel): +async def add_message(req: DBWebRequestModel): message = Message(**req.message.dict()) user_history = dbutils.get_messages(user_id=message.user_id, session_id=req.message.session_id, dbmanager=dbmanager) @@ -67,19 +105,21 @@ async def add_message(req: ChatWebRequestModel): os.makedirs(user_dir, exist_ok=True) try: - response_message: Message = chatmanager.chat( + response_message: Message = managers["chat"].chat( message=message, history=user_history, - work_dir=user_dir, - flow_config=req.flow_config, + user_dir=user_dir, + flow_config=req.workflow, + connection_id=req.connection_id, ) - # save assistant response to db - dbutils.create_message(message=response_message, dbmanager=dbmanager) + # save agent's response to db + messages = dbutils.create_message(message=response_message, dbmanager=dbmanager) response = { "status": True, - "message": response_message.content, - "metadata": json.loads(response_message.metadata), + "message": "Message processed successfully", + "data": messages, + # "metadata": json.loads(response_message.metadata), } return response except Exception as ex_error: @@ -157,6 +197,7 @@ async def create_user_session(req: DBWebRequestModel): try: session = Session(user_id=req.session.user_id, flow_config=req.session.flow_config) user_sessions = dbutils.create_session(user_id=req.user_id, session=session, dbmanager=dbmanager) + return { "status": True, "message": "Session created successfully", @@ -170,6 +211,26 @@ async def create_user_session(req: DBWebRequestModel): } +@api.post("/sessions/rename") +async def rename_user_session(name: str, req: DBWebRequestModel): + """Rename a session for a user""" + print("Rename: " + name) + print("renaming session for user: " + req.user_id + " to: " + name) + try: + session = dbutils.rename_session(name=name, session=req.session, dbmanager=dbmanager) + return { + "status": True, + "message": "Session renamed successfully", + "data": session, + } + except Exception as ex_error: + print(traceback.format_exc()) + return { + "status": False, + "message": "Error occurred while renaming session: " + str(ex_error), + } + + @api.post("/sessions/publish") async def publish_user_session_to_gallery(req: DBWebRequestModel): """Create a new session for a user""" @@ -496,3 +557,28 @@ async def get_version(): "message": "Version retrieved successfully", "data": {"version": VERSION}, } + + +async def process_socket_message(data: dict, websocket: WebSocket, client_id: str): + print(f"Client says: {data['type']}") + if data["type"] == "user_message": + user_request_body = DBWebRequestModel(**data["data"]) + response = await add_message(user_request_body) + response_socket_message = { + "type": "agent_response", + "data": response, + "connection_id": client_id, + } + await websocket_manager.send_message(response_socket_message, websocket) + + +@api.websocket("/ws/{client_id}") +async def websocket_endpoint(websocket: WebSocket, client_id: str): + await websocket_manager.connect(websocket, client_id) + try: + while True: + data = await websocket.receive_json() + await process_socket_message(data, websocket, client_id) + except WebSocketDisconnect: + print(f"Client #{client_id} is disconnected") + await websocket_manager.disconnect(websocket) diff --git a/samples/apps/autogen-studio/autogenstudio/workflowmanager.py b/samples/apps/autogen-studio/autogenstudio/workflowmanager.py index 37a539f1375..628c7f9f711 100644 --- a/samples/apps/autogen-studio/autogenstudio/workflowmanager.py +++ b/samples/apps/autogen-studio/autogenstudio/workflowmanager.py @@ -1,7 +1,10 @@ import os -from typing import List, Optional +from typing import List, Optional, Union, Dict + +from requests import Session + import autogen -from .datamodel import AgentConfig, AgentFlowSpec, AgentWorkFlowConfig, Message +from .datamodel import AgentConfig, AgentFlowSpec, AgentWorkFlowConfig, Message, SocketMessage from .utils import get_skills_from_prompt, clear_folder, sanitize_model from datetime import datetime @@ -17,6 +20,8 @@ def __init__( history: Optional[List[Message]] = None, work_dir: str = None, clear_work_dir: bool = True, + send_message_function: Optional[callable] = None, + connection_id: Optional[str] = None, ) -> None: """ Initializes the AutoGenFlow with agents specified in the config and optional @@ -27,43 +32,59 @@ def __init__( history: An optional list of previous messages to populate the agents' history. """ + self.send_message_function = send_message_function + self.connection_id = connection_id self.work_dir = work_dir or "work_dir" if clear_work_dir: clear_folder(self.work_dir) - + self.config = config # given the config, return an AutoGen agent object self.sender = self.load(config.sender) # given the config, return an AutoGen agent object self.receiver = self.load(config.receiver) - - if config.receiver.type == "groupchat": - # append self.sender to the list of agents - self.receiver._groupchat.agents.append(self.sender) - print(self.receiver) self.agent_history = [] if history: self.populate_history(history) - def process_reply(self, recipient, messages, sender, config): - if "callback" in config and config["callback"] is not None: - callback = config["callback"] - callback(sender, recipient, messages[-1]) - last_message = messages[-1] - - sender = sender.name - recipient = recipient.name - if "name" in last_message: - sender = last_message["name"] - - iteration = { - "recipient": recipient, - "sender": sender, - "message": last_message, + def process_message( + self, + sender: autogen.Agent, + receiver: autogen.Agent, + message: Dict, + request_reply: bool = False, + silent: bool = False, + sender_type: str = "agent", + ) -> None: + """ + Processes the message and adds it to the agent history. + + Args: + + sender: The sender of the message. + receiver: The receiver of the message. + message: The message content. + request_reply: If set to True, the message will be added to agent history. + silent: determining verbosity. + sender_type: The type of the sender of the message. + """ + + message = message if isinstance(message, dict) else {"content": message, "role": "user"} + message_payload = { + "recipient": receiver.name, + "sender": sender.name, + "message": message, "timestamp": datetime.now().isoformat(), + "sender_type": sender_type, + "connection_id": self.connection_id, + "message_type": "agent_message", } - self.agent_history.append(iteration) - return False, None + # if the agent will respond to the message, or the message is sent by a groupchat agent. This avoids adding groupchat broadcast messages to the history (which are sent with request_reply=False), or when agent populated from history + if request_reply is not False or sender_type == "groupchat": + self.agent_history.append(message_payload) # add to history + if self.send_message_function: # send over the message queue + socket_msg = SocketMessage(type="agent_message", data=message_payload, connection_id=self.connection_id) + self.send_message_function(socket_msg.dict()) def _sanitize_history_message(self, message: str) -> str: """ @@ -95,12 +116,14 @@ def populate_history(self, history: List[Message]) -> None: msg.content, self.receiver, request_reply=False, + silent=True, ) elif msg.role == "assistant": self.receiver.send( msg.content, self.sender, request_reply=False, + silent=True, ) def sanitize_agent_spec(self, agent_spec: AgentFlowSpec) -> AgentFlowSpec: @@ -144,14 +167,17 @@ def get_default_system_message(agent_type: str) -> str: # tbd check if docker is installed code_execution_config["use_docker"] = False agent_spec.config.code_execution_config = code_execution_config - if agent_spec.skills: - # get skill prompt, also write skills to a file named skills.py - skills_prompt = "" - skills_prompt = get_skills_from_prompt(agent_spec.skills, self.work_dir) - if agent_spec.config.system_message: - agent_spec.config.system_message = agent_spec.config.system_message + "\n\n" + skills_prompt - else: - agent_spec.config.system_message = get_default_system_message(agent_spec.type) + "\n\n" + skills_prompt + + if agent_spec.skills: + # get skill prompt, also write skills to a file named skills.py + skills_prompt = "" + skills_prompt = get_skills_from_prompt(agent_spec.skills, self.work_dir) + if agent_spec.config.system_message: + agent_spec.config.system_message = agent_spec.config.system_message + "\n\n" + skills_prompt + else: + agent_spec.config.system_message = ( + get_default_system_message(agent_spec.type) + "\n\n" + skills_prompt + ) return agent_spec @@ -173,8 +199,9 @@ def load(self, agent_spec: AgentFlowSpec) -> autogen.Agent: group_chat_config = agent_spec.groupchat_config.dict() group_chat_config["agents"] = agents groupchat = autogen.GroupChat(**group_chat_config) - agent = autogen.GroupChatManager(groupchat=groupchat, **agent_spec.config.dict()) - agent.register_reply([autogen.Agent, None], reply_func=self.process_reply, config={"callback": None}) + agent = ExtendedGroupChatManager( + groupchat=groupchat, **agent_spec.config.dict(), message_processor=self.process_message + ) return agent else: @@ -193,12 +220,12 @@ def load_agent_config(self, agent_config: AgentConfig, agent_type: str) -> autog An instance of the loaded agent. """ if agent_type == "assistant": - agent = autogen.AssistantAgent(**agent_config.dict()) + agent = ExtendedConversableAgent(**agent_config.dict(), message_processor=self.process_message) elif agent_type == "userproxy": - agent = autogen.UserProxyAgent(**agent_config.dict()) + agent = ExtendedConversableAgent(**agent_config.dict(), message_processor=self.process_message) else: raise ValueError(f"Unknown agent type: {agent_type}") - agent.register_reply([autogen.Agent, None], reply_func=self.process_reply, config={"callback": None}) + return agent def run(self, message: str, clear_history: bool = False) -> None: @@ -215,4 +242,37 @@ def run(self, message: str, clear_history: bool = False) -> None: message=message, clear_history=clear_history, ) - # pass + + +class ExtendedConversableAgent(autogen.ConversableAgent): + def __init__(self, message_processor=None, *args, **kwargs): + super().__init__(*args, **kwargs) + self.message_processor = message_processor + + def receive( + self, + message: Union[Dict, str], + sender: autogen.Agent, + request_reply: Optional[bool] = None, + silent: Optional[bool] = False, + ): + if self.message_processor: + self.message_processor(sender, self, message, request_reply, silent, sender_type="agent") + super().receive(message, sender, request_reply, silent) + + +class ExtendedGroupChatManager(autogen.GroupChatManager): + def __init__(self, message_processor=None, *args, **kwargs): + super().__init__(*args, **kwargs) + self.message_processor = message_processor + + def receive( + self, + message: Union[Dict, str], + sender: autogen.Agent, + request_reply: Optional[bool] = None, + silent: Optional[bool] = False, + ): + if self.message_processor: + self.message_processor(sender, self, message, request_reply, silent, sender_type="groupchat") + super().receive(message, sender, request_reply, silent) diff --git a/samples/apps/autogen-studio/frontend/package.json b/samples/apps/autogen-studio/frontend/package.json index 80975bab0ab..da33db85014 100644 --- a/samples/apps/autogen-studio/frontend/package.json +++ b/samples/apps/autogen-studio/frontend/package.json @@ -11,7 +11,7 @@ "develop": "gatsby clean && gatsby develop", "dev": "npm run develop", "start": "gatsby clean && gatsby develop", - "build": "gatsby clean && rm -rf ../autogenstudio/web/ui && PREFIX_PATH_VALUE='' gatsby build --prefix-paths && cp -r public/ ../autogenstudio/web/ui", + "build": "gatsby clean && rm -rf ../autogenstudio/web/ui && PREFIX_PATH_VALUE='' gatsby build --prefix-paths && rsync -a --delete public/ ../autogenstudio/web/ui/", "serve": "gatsby serve", "clean": "gatsby clean", "typecheck": "tsc --noEmit" @@ -54,6 +54,7 @@ "remark-gfm": "^3.0.1", "sass": "^1.51.0", "tailwindcss": "^3.0.24", + "uuid": "^9.0.1", "zustand": "^4.4.6" }, "devDependencies": { @@ -63,6 +64,7 @@ "@types/react-dom": "^18.2.15", "@types/react-inner-image-zoom": "^3.0.0", "@types/react-resizable": "^3.0.2", + "@types/uuid": "^9.0.8", "gh-pages": "^4.0.0", "typescript": "^4.6.4" } diff --git a/samples/apps/autogen-studio/frontend/src/components/atoms.tsx b/samples/apps/autogen-studio/frontend/src/components/atoms.tsx index 59d5c3e4b1a..8bc70f89a90 100644 --- a/samples/apps/autogen-studio/frontend/src/components/atoms.tsx +++ b/samples/apps/autogen-studio/frontend/src/components/atoms.tsx @@ -33,7 +33,13 @@ import remarkGfm from "remark-gfm"; import ReactMarkdown from "react-markdown"; import { atomDark } from "react-syntax-highlighter/dist/esm/styles/prism"; import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; -import { fetchJSON, getServerUrl, obscureString, truncateText } from "./utils"; +import { + checkAndSanitizeInput, + fetchJSON, + getServerUrl, + obscureString, + truncateText, +} from "./utils"; import { IAgentFlowSpec, IFlowConfig, @@ -242,7 +248,7 @@ export const LoadBox = ({ export const LoadingBar = ({ children }: IProps) => { return ( <> -
+
@@ -901,7 +907,7 @@ export const BounceLoader = ({ title?: string; }) => { return ( -
+
@@ -951,6 +957,7 @@ export const CsvLoader = ({ const [data, setData] = useState([]); const [columns, setColumns] = useState([]); const [isLoading, setIsLoading] = useState(true); + const [pageSize, setPageSize] = useState(50); useEffect(() => { const fetchData = async () => { @@ -1000,8 +1007,11 @@ export const CsvLoader = ({ dataSource={data} columns={columns} loading={isLoading} - pagination={{ pageSize: 50 }} + pagination={{ pageSize: pageSize }} scroll={{ y: 450, x: scrollX }} + onChange={(pagination) => { + setPageSize(pagination.pageSize || 50); + }} />
); @@ -1103,52 +1113,57 @@ export const AgentFlowSpecView = ({ setFlowSpec(updatedFlowSpec); }; - const llm_config: ILLMConfig = localFlowSpec.config.llm_config || { + const llm_config: ILLMConfig = localFlowSpec?.config?.llm_config || { config_list: [], temperature: 0.1, }; + const nameValidation = checkAndSanitizeInput(flowSpec?.config?.name); + return ( <>
{title}
{flowSpec.config.name}
+ title=
{flowSpec?.config?.name}
className="mb-4 bg-primary " > { - onControlChange(e.target.value, "name"); - }} - /> + <> + { + onControlChange(e.target.value, "name"); + }} + /> + {!nameValidation.status && ( +
+ {nameValidation.message} +
+ )} + } /> { - const updatedFlowSpec = { - ...localFlowSpec, - description: e.target.value, - }; - setLocalFlowSpec(updatedFlowSpec); - setFlowSpec(updatedFlowSpec); + onControlChange(e.target.value, "description"); }} /> } @@ -1158,11 +1173,11 @@ export const AgentFlowSpecView = ({ title="Max Consecutive Auto Reply" className="mt-4" description="Max consecutive auto reply messages before termination." - value={flowSpec.config.max_consecutive_auto_reply} + value={flowSpec.config?.max_consecutive_auto_reply} control={ { @@ -1223,7 +1238,6 @@ export const AgentFlowSpecView = ({ value={flowSpec.config.system_message} rows={3} onChange={(e) => { - // onDebouncedControlChange(e.target.value, "system_message"); onControlChange(e.target.value, "system_message"); }} /> @@ -1864,7 +1878,7 @@ export const AgentSelector = ({ {flowSpec.config.name}
{" "} - {flowSpec.description || flowSpec.config.name} + {flowSpec.config.description || flowSpec.config.name}
{" "} @@ -2048,3 +2062,55 @@ export const MonacoEditor = ({
); }; + +export const CardHoverBar = ({ + items, +}: { + items: { + title: string; + icon: any; + hoverText: string; + onClick: (e: any) => void; + }[]; +}) => { + const itemRows = items.map((item, i) => { + return ( +
+ + + +
+ ); + }); + return ( +
{ + e.stopPropagation(); + }} + className=" mt-2 text-right opacity-0 group-hover:opacity-100 " + > + {itemRows} +
+ ); +}; + +export const AgentRow = ({ message }: { message: any }) => { + return ( + + {message.sender} ( to{" "} + {message.recipient} ) +
+ } + className="m" + > + + + ); +}; diff --git a/samples/apps/autogen-studio/frontend/src/components/layout.tsx b/samples/apps/autogen-studio/frontend/src/components/layout.tsx index 13e83f13106..9142470534e 100644 --- a/samples/apps/autogen-studio/frontend/src/components/layout.tsx +++ b/samples/apps/autogen-studio/frontend/src/components/layout.tsx @@ -24,7 +24,10 @@ const Layout = ({ restricted = false, }: Props) => { const layoutContent = ( -
+
{showHeader &&
}
{meta?.title + " | " + title} diff --git a/samples/apps/autogen-studio/frontend/src/components/types.ts b/samples/apps/autogen-studio/frontend/src/components/types.ts index c01f6ac7945..522682a4884 100644 --- a/samples/apps/autogen-studio/frontend/src/components/types.ts +++ b/samples/apps/autogen-studio/frontend/src/components/types.ts @@ -41,6 +41,7 @@ export interface IAgentConfig { is_termination_msg?: boolean | string; default_auto_reply?: string | null; code_execution_config?: boolean | string | { [key: string]: any } | null; + description?: string; } export interface IAgentFlowSpec { @@ -49,7 +50,6 @@ export interface IAgentFlowSpec { timestamp?: string; id?: string; skills?: Array; - description?: string; user_id?: string; } @@ -93,6 +93,7 @@ export interface IModelConfig { user_id?: string; timestamp?: string; description?: string; + id?: string; } export interface IMetadataFile { @@ -108,6 +109,7 @@ export interface IChatSession { user_id: string; timestamp: string; flow_config: IFlowConfig; + name: string; } export interface IGalleryItem { diff --git a/samples/apps/autogen-studio/frontend/src/components/utils.ts b/samples/apps/autogen-studio/frontend/src/components/utils.ts index 83096eda830..73b9f42207c 100644 --- a/samples/apps/autogen-studio/frontend/src/components/utils.ts +++ b/samples/apps/autogen-studio/frontend/src/components/utils.ts @@ -243,6 +243,33 @@ export const formatDuration = (seconds: number) => { return parts.length > 0 ? parts.join(" ") : "0 sec"; }; +export const sampleAgentConfig = (user_id: string = "guestuser@gmail.com") => { + const sampleAgent: IAgentFlowSpec = { + type: "assistant", + user_id: user_id, + config: { + name: "sample_assistant", + description: "Sample assistant", + llm_config: { + config_list: [ + { + model: "gpt-4-1106-preview", + }, + ], + temperature: 0.1, + timeout: 600, + cache_seed: null, + }, + human_input_mode: "NEVER", + code_execution_config: false, + max_consecutive_auto_reply: 8, + system_message: + "You are a helpful AI assistant. Solve tasks using your coding and language skills. In the following cases, suggest python code (in a python coding block) or shell script (in a sh coding block) for the user to execute. 1. When you need to collect info, use the code to output the info you need, for example, browse or search the web, download/read a file, print the content of a webpage or a file, get the current date/time, check the operating system. After sufficient info is printed and the task is ready to be solved based on your language skill, you can solve the task by yourself. 2. When you need to perform some task with code, use the code to perform the task and output the result. Finish the task smartly. Solve the task step by step if you need to. If a plan is not provided, explain your plan first. Be clear which step uses code, and which step uses your language skill. When using code, you must indicate the script type in the code block. The user cannot provide any other feedback or perform any other action beyond executing the code you suggest. The user can't modify your code. So do not suggest incomplete code which requires users to modify. Don't use a code block if it's not intended to be executed by the user. If you want the user to save the code in a file before executing it, put # filename: inside the code block as the first line. Don't include multiple code blocks in one response. Do not ask users to copy and paste the result. Instead, use 'print' function for the output when relevant. Check the execution result returned by the user. If the result indicates there is an error, fix the error and output the code again. Suggest the full code instead of partial code or code changes. If the error can't be fixed or if the task is not solved even after the code is executed successfully, analyze the problem, revisit your assumption, collect additional info you need, and think of a different approach to try. When you find an answer, verify the answer carefully. Include verifiable evidence in your response if possible. Reply 'TERMINATE' in the end when everything is done.", + }, + }; + return sampleAgent; +}; + export const sampleWorkflowConfig = (type = "twoagents") => { const llm_model_config: IModelConfig[] = [ { @@ -279,6 +306,7 @@ export const sampleWorkflowConfig = (type = "twoagents") => { llm_config: llm_config, human_input_mode: "NEVER", max_consecutive_auto_reply: 8, + code_execution_config: false, system_message: "You are a helpful AI assistant. Solve tasks using your coding and language skills. In the following cases, suggest python code (in a python coding block) or shell script (in a sh coding block) for the user to execute. 1. When you need to collect info, use the code to output the info you need, for example, browse or search the web, download/read a file, print the content of a webpage or a file, get the current date/time, check the operating system. After sufficient info is printed and the task is ready to be solved based on your language skill, you can solve the task by yourself. 2. When you need to perform some task with code, use the code to perform the task and output the result. Finish the task smartly. Solve the task step by step if you need to. If a plan is not provided, explain your plan first. Be clear which step uses code, and which step uses your language skill. When using code, you must indicate the script type in the code block. The user cannot provide any other feedback or perform any other action beyond executing the code you suggest. The user can't modify your code. So do not suggest incomplete code which requires users to modify. Don't use a code block if it's not intended to be executed by the user. If you want the user to save the code in a file before executing it, put # filename: inside the code block as the first line. Don't include multiple code blocks in one response. Do not ask users to copy and paste the result. Instead, use 'print' function for the output when relevant. Check the execution result returned by the user. If the result indicates there is an error, fix the error and output the code again. Suggest the full code instead of partial code or code changes. If the error can't be fixed or if the task is not solved even after the code is executed successfully, analyze the problem, revisit your assumption, collect additional info you need, and think of a different approach to try. When you find an answer, verify the answer carefully. Include verifiable evidence in your response if possible. Reply 'TERMINATE' in the end when everything is done.", }; @@ -404,6 +432,10 @@ export const getSampleSkill = () => { }; export const timeAgo = (dateString: string): string => { + // if dateStr is empty, return empty string + if (!dateString) { + return ""; + } // Parse the date string into a Date object const timestamp = new Date(dateString); @@ -466,6 +498,11 @@ export const examplePrompts = [ prompt: "paint a picture of a glass of ethiopian coffee, freshly brewed in a tall glass cup, on a table right in front of a lush green forest scenery", }, + { + title: "Travel", + prompt: + "Plan a 2 day trip to hawaii. Limit to 3 activities per day, be as brief as possible!", + }, ]; export const fetchVersion = () => { @@ -490,19 +527,118 @@ export const fetchVersion = () => { */ export const sanitizeConfig = ( data: any, - keys: string[] = ["api_key"], - replacement: string = "********" + keys: string[] = ["api_key", "id"] ): any => { if (Array.isArray(data)) { - return data.map((item) => sanitizeConfig(item, keys, replacement)); + return data.map((item) => sanitizeConfig(item, keys)); } else if (typeof data === "object" && data !== null) { Object.keys(data).forEach((key) => { if (keys.includes(key)) { - data[key] = replacement; + delete data[key]; } else { - data[key] = sanitizeConfig(data[key], keys, replacement); + data[key] = sanitizeConfig(data[key], keys); } }); } return data; }; + +/** + * Checks the input text against the regex '^[a-zA-Z0-9_-]{1,64}$' and returns an object with + * status, message, and sanitizedText. Status is boolean indicating whether input text is valid, + * message provides information about the outcome, and sanitizedText contains a valid version + * of the input text or the original text if it was already valid. + * + * @param text - The input string to be checked and sanitized. + * @returns An object containing a status, a message, and sanitizedText. + */ +export const checkAndSanitizeInput = ( + text: string +): { status: boolean; message: string; sanitizedText: string } => { + // Create a regular expression pattern to match valid characters + const regexPattern: RegExp = /^[a-zA-Z0-9_-]{1,64}$/; + let status: boolean = true; + let message: string; + let sanitizedText: string; + + // Check if the input text matches the pattern + if (regexPattern.test(text)) { + // Text already adheres to the pattern + message = `The text '${text}' is valid.`; + sanitizedText = text; + } else { + // The text does not match; sanitize the input + status = false; + sanitizedText = text.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 64); + message = `'${text}' is invalid. Consider using '${sanitizedText}' instead.`; + } + + return { status, message, sanitizedText }; +}; + +export const isValidConfig = ( + jsonObj: any, + templateObj: any, + diffThreshold: number = 4 +): { + status: boolean; + message: string; +} => { + // Check if both parameters are indeed objects and not null + if ( + typeof jsonObj !== "object" || + jsonObj === null || + Array.isArray(jsonObj) || + typeof templateObj !== "object" || + templateObj === null || + Array.isArray(templateObj) + ) { + return { + status: false, + message: + "Invalid input: One or both parameters are not objects, or are null or arrays.", + }; + } + + const jsonKeys = new Set(Object.keys(jsonObj)); + const templateKeys = new Set(Object.keys(templateObj)); + + if (jsonKeys.size !== templateKeys.size) { + if (Math.abs(jsonKeys.size - templateKeys.size) > diffThreshold) { + return { + status: false, + message: + "Configuration does not match template: Number of keys differ.", + }; + } + } + + for (const key of templateKeys) { + if (!jsonKeys.has(key)) { + return { + status: false, + message: `Configuration does not match template: Missing key '${key}' in configuration.`, + }; + } + + // If the value is an object, recursively validate + if ( + typeof templateObj[key] === "object" && + templateObj[key] !== null && + !Array.isArray(templateObj[key]) + ) { + const result = isValidConfig(jsonObj[key], templateObj[key]); + if (!result.status) { + return { + status: false, + message: `Configuration error in nested key '${key}': ${result.message}`, + }; + } + } + } + + return { + status: true, + message: "Configuration is valid.", + }; +}; diff --git a/samples/apps/autogen-studio/frontend/src/components/views/builder/agents.tsx b/samples/apps/autogen-studio/frontend/src/components/views/builder/agents.tsx index ac2a08f11a5..be8a30f7247 100644 --- a/samples/apps/autogen-studio/frontend/src/components/views/builder/agents.tsx +++ b/samples/apps/autogen-studio/frontend/src/components/views/builder/agents.tsx @@ -1,19 +1,29 @@ import { + ArrowDownTrayIcon, + ArrowUpTrayIcon, + DocumentDuplicateIcon, InformationCircleIcon, PlusIcon, TrashIcon, } from "@heroicons/react/24/outline"; -import { Modal, message } from "antd"; +import { Dropdown, MenuProps, Modal, message } from "antd"; import * as React from "react"; import { IAgentFlowSpec, IStatus } from "../../types"; import { appContext } from "../../../hooks/provider"; -import { fetchJSON, getServerUrl, timeAgo, truncateText } from "../../utils"; +import { + fetchJSON, + getServerUrl, + sampleAgentConfig, + sanitizeConfig, + timeAgo, + truncateText, +} from "../../utils"; import { AgentFlowSpecView, BounceLoader, Card, + CardHoverBar, LaunchButton, - LoadBox, LoadingOverlay, } from "../../atoms"; @@ -38,27 +48,7 @@ const AgentsView = ({}: any) => { const [showAgentModal, setShowAgentModal] = React.useState(false); - const sampleAgent: IAgentFlowSpec = { - type: "assistant", - description: "Sample assistant", - user_id: user?.email, - config: { - name: "sample_assistant", - llm_config: { - config_list: [ - { - model: "gpt-4-1106-preview", - }, - ], - temperature: 0.1, - timeout: 600, - cache_seed: null, - }, - human_input_mode: "NEVER", - max_consecutive_auto_reply: 8, - system_message: " ..", - }, - }; + const sampleAgent = sampleAgentConfig(user?.email || ""); const [newAgent, setNewAgent] = React.useState( sampleAgent ); @@ -168,6 +158,53 @@ const AgentsView = ({}: any) => { }, []); const agentRows = (agents || []).map((agent: IAgentFlowSpec, i: number) => { + const cardItems = [ + { + title: "Download", + icon: ArrowDownTrayIcon, + onClick: (e: any) => { + e.stopPropagation(); + // download workflow as workflow.name.json + const element = document.createElement("a"); + const sanitizedAgent = sanitizeConfig(agent); + const file = new Blob([JSON.stringify(sanitizedAgent)], { + type: "application/json", + }); + element.href = URL.createObjectURL(file); + element.download = `agent_${agent.config.name}.json`; + document.body.appendChild(element); // Required for this to work in FireFox + element.click(); + }, + hoverText: "Download", + }, + { + title: "Make a Copy", + icon: DocumentDuplicateIcon, + onClick: (e: any) => { + e.stopPropagation(); + let newAgent = { ...agent }; + newAgent.config.name = `${agent.config.name}_copy`; + newAgent.user_id = user?.email; + newAgent.timestamp = new Date().toISOString(); + if (newAgent.id) { + delete newAgent.id; + } + + setNewAgent(newAgent); + setShowNewAgentModal(true); + }, + hoverText: "Make a Copy", + }, + { + title: "Delete", + icon: TrashIcon, + onClick: (e: any) => { + e.stopPropagation(); + deleteAgent(agent); + }, + hoverText: "Delete", + }, + ]; return (
@@ -183,28 +220,10 @@ const AgentsView = ({}: any) => { >
{" "} - {truncateText(agent.description || "", 70)} + {truncateText(agent.config.description || "", 70)}
{timeAgo(agent.timestamp || "")}
-
{ - e.stopPropagation(); - }} - className=" mt-2 text-right opacity-0 group-hover:opacity-100 " - > - {" "} -
{ - e.stopPropagation(); - deleteAgent(agent); - }} - > - - delete -
-
+
@@ -234,7 +253,7 @@ const AgentsView = ({}: any) => { <> Agent Specification{" "} - {agent?.config.name} + {agent?.config?.name || ""} {" "} } @@ -264,6 +283,60 @@ const AgentsView = ({}: any) => { ); }; + const uploadAgent = () => { + const input = document.createElement("input"); + input.type = "file"; + input.accept = ".json"; + input.onchange = (e: any) => { + const file = e.target.files[0]; + const reader = new FileReader(); + reader.onload = (e: any) => { + const contents = e.target.result; + if (contents) { + try { + const agent = JSON.parse(contents); + // TBD validate that it is a valid agent + if (!agent.config) { + throw new Error( + "Invalid agent file. An agent must have a config" + ); + } + setNewAgent(agent); + setShowNewAgentModal(true); + } catch (err) { + message.error( + "Invalid agent file. Please upload a valid agent file." + ); + } + } + }; + reader.readAsText(file); + }; + input.click(); + }; + + const agentsMenuItems: MenuProps["items"] = [ + // { + // type: "divider", + // }, + { + key: "uploadagent", + label: ( +
+ + Upload Agent +
+ ), + }, + ]; + + const agentsMenuItemOnClick: MenuProps["onClick"] = ({ key }) => { + if (key === "uploadagent") { + uploadAgent(); + return; + } + }; + return (
{ {" "} Agents ({agentRows.length}){" "}
- { - setShowNewAgentModal(true); - }} - > - {" "} - - New Agent - +
+ { + setShowNewAgentModal(true); + }} + > + + New Agent + +
diff --git a/samples/apps/autogen-studio/frontend/src/components/views/builder/models.tsx b/samples/apps/autogen-studio/frontend/src/components/views/builder/models.tsx index d3e2f5b592b..be2c11099e3 100644 --- a/samples/apps/autogen-studio/frontend/src/components/views/builder/models.tsx +++ b/samples/apps/autogen-studio/frontend/src/components/views/builder/models.tsx @@ -1,15 +1,24 @@ import { + ArrowDownTrayIcon, + ArrowUpTrayIcon, + DocumentDuplicateIcon, ExclamationTriangleIcon, InformationCircleIcon, PlusIcon, TrashIcon, } from "@heroicons/react/24/outline"; -import { Button, Input, Modal, message } from "antd"; +import { Button, Dropdown, Input, MenuProps, Modal, message } from "antd"; import * as React from "react"; import { IModelConfig, IStatus } from "../../types"; import { appContext } from "../../../hooks/provider"; -import { fetchJSON, getServerUrl, timeAgo, truncateText } from "../../utils"; -import { BounceLoader, Card, LaunchButton, LoadingOverlay } from "../../atoms"; +import { + fetchJSON, + getServerUrl, + sanitizeConfig, + timeAgo, + truncateText, +} from "../../utils"; +import { BounceLoader, Card, CardHoverBar, LoadingOverlay } from "../../atoms"; import TextArea from "antd/es/input/TextArea"; const ModelsView = ({}: any) => { @@ -25,10 +34,6 @@ const ModelsView = ({}: any) => { const saveModelsUrl = `${serverUrl}/models`; const deleteModelUrl = `${serverUrl}/models/delete`; const testModelUrl = `${serverUrl}/models/test`; - const [modelStatus, setModelStatus] = React.useState({ - status: true, - message: "All good", - }); const defaultModel: IModelConfig = { model: "gpt-4-1106-preview", @@ -148,6 +153,52 @@ const ModelsView = ({}: any) => { }, []); const modelRows = (models || []).map((model: IModelConfig, i: number) => { + const cardItems = [ + { + title: "Download", + icon: ArrowDownTrayIcon, + onClick: (e: any) => { + e.stopPropagation(); + // download workflow as workflow.name.json + const element = document.createElement("a"); + const sanitizedSkill = sanitizeConfig(model); + const file = new Blob([JSON.stringify(sanitizedSkill)], { + type: "application/json", + }); + element.href = URL.createObjectURL(file); + element.download = `model_${model.model}.json`; + document.body.appendChild(element); // Required for this to work in FireFox + element.click(); + }, + hoverText: "Download", + }, + { + title: "Make a Copy", + icon: DocumentDuplicateIcon, + onClick: (e: any) => { + e.stopPropagation(); + let newModel = { ...model }; + newModel.model = `${model.model} Copy`; + newModel.user_id = user?.email; + newModel.timestamp = new Date().toISOString(); + if (newModel.id) { + delete newModel.id; + } + setNewModel(newModel); + setShowNewModelModal(true); + }, + hoverText: "Make a Copy", + }, + { + title: "Delete", + icon: TrashIcon, + onClick: (e: any) => { + e.stopPropagation(); + deleteModel(model); + }, + hoverText: "Delete", + }, + ]; return (
@@ -166,25 +217,7 @@ const ModelsView = ({}: any) => { {truncateText(model.description || model.model || "", 70)}
{timeAgo(model.timestamp || "")}
-
{ - e.stopPropagation(); - }} - className=" mt-2 text-right opacity-0 group-hover:opacity-100 " - > - {" "} -
{ - e.stopPropagation(); - deleteModel(model); - }} - > - - delete -
-
+
@@ -386,6 +419,54 @@ const ModelsView = ({}: any) => { ); }; + const uploadModel = () => { + const input = document.createElement("input"); + input.type = "file"; + input.accept = ".json"; + input.onchange = (e: any) => { + const file = e.target.files[0]; + const reader = new FileReader(); + reader.onload = (e: any) => { + const contents = e.target.result; + if (contents) { + try { + const model = JSON.parse(contents); + if (model) { + setNewModel(model); + setShowNewModelModal(true); + } + } catch (e) { + message.error("Invalid model file"); + } + } + }; + reader.readAsText(file); + }; + input.click(); + }; + + const modelsMenuItems: MenuProps["items"] = [ + // { + // type: "divider", + // }, + { + key: "uploadmodel", + label: ( +
+ + Upload Model +
+ ), + }, + ]; + + const modelsMenuItemOnClick: MenuProps["onClick"] = ({ key }) => { + if (key === "uploadmodel") { + uploadModel(); + return; + } + }; + return (
{ /> { {" "} Models ({modelRows.length}){" "}
- { - setShowNewModelModal(true); - }} - > - {" "} - - New Model - +
+ { + setShowNewModelModal(true); + }} + > + + New Model + +
diff --git a/samples/apps/autogen-studio/frontend/src/components/views/builder/skills.tsx b/samples/apps/autogen-studio/frontend/src/components/views/builder/skills.tsx index 7574fa72a62..96c67948cf7 100644 --- a/samples/apps/autogen-studio/frontend/src/components/views/builder/skills.tsx +++ b/samples/apps/autogen-studio/frontend/src/components/views/builder/skills.tsx @@ -1,9 +1,12 @@ import { + ArrowDownTrayIcon, + ArrowUpTrayIcon, + DocumentDuplicateIcon, InformationCircleIcon, PlusIcon, TrashIcon, } from "@heroicons/react/24/outline"; -import { Button, Input, Modal, message } from "antd"; +import { Button, Input, Modal, message, MenuProps, Dropdown } from "antd"; import * as React from "react"; import { ISkill, IStatus } from "../../types"; import { appContext } from "../../../hooks/provider"; @@ -11,18 +14,17 @@ import { fetchJSON, getSampleSkill, getServerUrl, + sanitizeConfig, timeAgo, truncateText, } from "../../utils"; import { BounceLoader, Card, - CodeBlock, - LaunchButton, + CardHoverBar, LoadingOverlay, MonacoEditor, } from "../../atoms"; -import TextArea from "antd/es/input/TextArea"; const SkillsView = ({}: any) => { const [loading, setLoading] = React.useState(false); @@ -149,6 +151,52 @@ const SkillsView = ({}: any) => { }, []); const skillRows = (skills || []).map((skill: ISkill, i: number) => { + const cardItems = [ + { + title: "Download", + icon: ArrowDownTrayIcon, + onClick: (e: any) => { + e.stopPropagation(); + // download workflow as workflow.name.json + const element = document.createElement("a"); + const sanitizedSkill = sanitizeConfig(skill); + const file = new Blob([JSON.stringify(sanitizedSkill)], { + type: "application/json", + }); + element.href = URL.createObjectURL(file); + element.download = `skill_${skill.title}.json`; + document.body.appendChild(element); // Required for this to work in FireFox + element.click(); + }, + hoverText: "Download", + }, + { + title: "Make a Copy", + icon: DocumentDuplicateIcon, + onClick: (e: any) => { + e.stopPropagation(); + let newSkill = { ...skill }; + newSkill.title = `${skill.title} Copy`; + newSkill.user_id = user?.email; + newSkill.timestamp = new Date().toISOString(); + if (newSkill.id) { + delete newSkill.id; + } + setNewSkill(newSkill); + setShowNewSkillModal(true); + }, + hoverText: "Make a Copy", + }, + { + title: "Delete", + icon: TrashIcon, + onClick: (e: any) => { + e.stopPropagation(); + deleteSkill(skill); + }, + hoverText: "Delete", + }, + ]; return (
@@ -166,25 +214,7 @@ const SkillsView = ({}: any) => { {truncateText(skill.content, 70)}
{timeAgo(skill.timestamp || "")}
-
{ - e.stopPropagation(); - }} - className=" mt-2 text-right opacity-0 group-hover:opacity-100 " - > - {" "} -
{ - e.stopPropagation(); - deleteSkill(skill); - }} - > - - delete -
-
+
@@ -288,45 +318,56 @@ const SkillsView = ({}: any) => { ); }; - return ( -
- {/* - Create New Skill -
+ const uploadSkill = () => { + const fileInput = document.createElement("input"); + fileInput.type = "file"; + fileInput.accept = ".json"; + fileInput.onchange = (e: any) => { + const file = e.target.files[0]; + const reader = new FileReader(); + reader.onload = (e) => { + const content = e.target?.result; + if (content) { + try { + const skill = JSON.parse(content as string); + if (skill) { + setNewSkill(skill); + setShowNewSkillModal(true); + } + } catch (e) { + message.error("Invalid skill file"); + } } - width={800} - open={showNewSkillModal} - onOk={() => { - saveSkill(); - setShowNewSkillModal(false); - }} - onCancel={() => { - setShowNewSkillModal(false); - }} - > - <> -
- Provide code for a new skill or create from current conversation. -
- { - setNewSkillTitle(e.target.value); - }} - /> -