diff --git a/ROADMAP.md b/ROADMAP.md index d81a0374..2f971ced 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -9,7 +9,7 @@ Core features improve the library itself to cater wider range of functionalities | Name | Description | Status | Release version | |------|-------------|--------|-----------------| |Linear Router|A router that lets you build agents or teams that execute linearly or sequentially. The current router supervisor works in a hierarchical way where all the children report to one parent| In progress | 0.0.3| -|Reflexion| Reflection lets you build a component that can make the AI retrospectively look at the current output and retry or work again on the task at hand| Yet to start| 0.0.3| +|Reflection| Reflection lets you build a component that can make the AI retrospectively look at the current output and retry or work again on the task at hand| Yet to start| 0.0.3| |Output formatter| Ability to templatize output format using pydantic| Yet to start| 0.0.4| |LLM Extensibilty| Ability to different LLMs across different agents and teams| Yet to start| 0.0.4| |Auto-Query RAG| Ability to make metadata query within the agentic, which can automatically add metadata while rag query runs, like timestamp or other data|Yet to start|TBD| diff --git a/examples/agent_of_flo_ai.ipynb b/examples/agent_of_flo_ai.ipynb index ede50487..78979e23 100644 --- a/examples/agent_of_flo_ai.ipynb +++ b/examples/agent_of_flo_ai.ipynb @@ -14,30 +14,25 @@ "\n", "2. LLM Agents (`kind: llm`): These agents are simply an LLM which can answer any questions asked to it. The agents dont except tools. If tool is passed to an agent of type llm, they are ignored.\n", "\n", - "3. Tool LLM (`kind: tool`): These agents are just tools or functions that can be executed on the current state. Within the tool will be given the current state as the input, meaning the history of what happened in the flo until now" + "3. Tool Agents (`kind: tool`): These agents are just tools or functions that can be executed on the current state. Within the tool will be given the current state as the input, meaning the history of what happened in the flo until now\n", + "\n", + "4. Reflection Agents (`kind: reflection`): These agents can help in reflecting on the current answer and retrying an exisitng flow. This is useful when you want to re-evaluate an answer with better model for example.\n", + "\n", + "5. Delegator Agent (`kind: delegator`): These agents can delegate to any other agent with the workflow based on a prompt. For example you want to delegate to different agents based on the user question" ] }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 6, "metadata": {}, "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Log level -> INFO\n", - "Log level -> INFO\n", - "Log level -> INFO\n" - ] - }, { "data": { "text/plain": [ "True" ] }, - "execution_count": 1, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -63,31 +58,16 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2024-09-21 12:58:25,784 - SESSION - INFO - New FloSession created with ID: 9b56b8e0-bc8f-4c4c-b8a7-4a9695a7c97a\n", - "2024-09-21 12:58:25,785 - SESSION - INFO - Tool 'InternetSearchTool' registered for session 9b56b8e0-bc8f-4c4c-b8a7-4a9695a7c97a\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Log level -> ERROR\n" - ] - }, { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 6, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } @@ -98,12 +78,8 @@ "\n", "llm = ChatOpenAI(temperature=0, model_name='gpt-4o-mini')\n", "\n", - "# Create custom FloLangchainLogger\n", - "# custom_langchainlog_handler = FloLangchainLogger(\"CustomFloCallback\", \"DEBUG\")\n", - "\n", "session = FloSession(\n", " llm, \n", - " # custom_langchainlog_handler=custom_langchainlog_handler,\n", " log_level=\"ERROR\"\n", ")\n", "\n", @@ -126,7 +102,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -146,90 +122,45 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2024-09-21 12:58:31,259 - BUILDER - INFO - Building Flo instance from YAML\n", - "2024-09-21 12:58:31,265 - COMMON - INFO - Flo instance created for session 9b56b8e0-bc8f-4c4c-b8a7-4a9695a7c97a\n", - "2024-09-21 12:58:31,266 - COMMON - INFO - Invoking query for session 9b56b8e0-bc8f-4c4c-b8a7-4a9695a7c97a: Whats the whether in california\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", - "\u001b[32;1m\u001b[1;3m\n", - "Invoking: `tavily_search_results_json` with `{'query': 'California weather October 2023'}`\n", - "\n", - "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[{'url': 'https://www.weatherapi.com/', 'content': \"{'location': {'name': 'California City', 'region': 'California', 'country': 'United States of America', 'lat': 35.13, 'lon': -117.99, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1726903691, 'localtime': '2024-09-21 00:28'}, 'current': {'last_updated_epoch': 1726902900, 'last_updated': '2024-09-21 00:15', 'temp_c': 16.8, 'temp_f': 62.2, 'is_day': 0, 'condition': {'text': 'Clear', 'icon': '//cdn.weatherapi.com/weather/64x64/night/113.png', 'code': 1000}, 'wind_mph': 4.5, 'wind_kph': 7.2, 'wind_degree': 264, 'wind_dir': 'W', 'pressure_mb': 1011.0, 'pressure_in': 29.86, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 64, 'cloud': 0, 'feelslike_c': 16.8, 'feelslike_f': 62.2, 'windchill_c': 15.6, 'windchill_f': 60.0, 'heatindex_c': 15.8, 'heatindex_f': 60.5, 'dewpoint_c': 10.1, 'dewpoint_f': 50.2, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 1.0, 'gust_mph': 7.8, 'gust_kph': 12.5}}\"}, {'url': 'https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023', 'content': 'Weather reports from October 2023 in Los Angeles, California, USA with highs and lows. Sep 17-18. Sign in. News. News Home; Astronomy News; Time Zone News; Calendar & Holiday News; Newsletter; Live events. ... High & Low Weather Summary for October 2023 Temperature Humidity Pressure; High: 92 °F (Oct 5, 11:53 am) 100% (Oct 7, 9:02 am) 30.11 ...'}, {'url': 'https://www.meteoprog.com/weather/California-california/month/october/', 'content': 'California (United States) weather in October 2023 ☀️ Accurate weather forecast for California in October ⛅ Detailed forecast By month Current temperature \"near me\" Weather news ⊳ Widget of weather ⊳ Water temperature | METEOPROG'}, {'url': 'https://weatherspark.com/h/m/1828/2023/10/Historical-Weather-in-October-2023-in-Anaheim-California-United-States', 'content': 'October 2023 Weather History in Anaheim California, United States This report shows the past weather for Anaheim, providing a weather history for October 2023. It features all historical weather data series we have available, including the Anaheim temperature history for October 2023. Anaheim Temperature History October 2023 Hourly Temperature in October 2023 in Anaheim Cloud Cover in October 2023 in Anaheim Daily Precipitation in October 2023 in Anaheim Observed Weather in October 2023 in Anaheim Hours of Daylight and Twilight in October 2023 in Anaheim Solar Elevation and Azimuth in October 2023 in Anaheim Oct 2023 Humidity Comfort Levels in October 2023 in Anaheim Wind Speed in October 2023 in Anaheim Hourly Wind Speed in October 2023 in Anaheim'}, {'url': 'https://world-weather.info/forecast/usa/los_angeles/october-2023/', 'content': 'Extended weather forecast in Los Angeles. Hourly Week 10 days 14 days 30 days Year. Detailed ⚡ Los Angeles Weather Forecast for October 2023 - day/night 🌡️ temperatures, precipitations - World-Weather.info.'}]\u001b[0m\u001b[32;1m\u001b[1;3mThe current weather in California is as follows:\n", - "\n", - "- **Location**: California City\n", - "- **Temperature**: 16.8°C (62.2°F)\n", - "- **Condition**: Clear\n", - "- **Wind**: 4.5 mph (7.2 kph) from the west\n", - "- **Humidity**: 64%\n", - "- **Visibility**: 16 km (9 miles)\n", - "\n", - "For more detailed weather information, you can check the following resources:\n", - "- [Weather API](https://www.weatherapi.com/)\n", - "- [Time and Date - Los Angeles Weather](https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023)\n", - "- [Meteoprog - California Weather](https://www.meteoprog.com/weather/California-california/month/october/)\n", - "- [Weather Spark - Anaheim Weather History](https://weatherspark.com/h/m/1828/2023/10/Historical-Weather-in-October-2023-in-Anaheim-California-United-States)\n", - "\n", - "If you need specific information about a particular city in California, let me know!\u001b[0m\n", - "\n", - "\u001b[1m> Finished chain.\u001b[0m\n" + "2024-09-22 13:22:31,840 - BUILDER - INFO - Building Flo instance from YAML\n", + "2024-09-22 13:22:31,846 - COMMON - INFO - Flo instance created for session e7f22b4d-7380-4d00-97c9-5267a468468a\n" ] }, { "data": { + "image/jpeg": "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", "text/plain": [ - "{'messages': [HumanMessage(content='Whats the whether in california')],\n", - " 'output': 'The current weather in California is as follows:\\n\\n- **Location**: California City\\n- **Temperature**: 16.8°C (62.2°F)\\n- **Condition**: Clear\\n- **Wind**: 4.5 mph (7.2 kph) from the west\\n- **Humidity**: 64%\\n- **Visibility**: 16 km (9 miles)\\n\\nFor more detailed weather information, you can check the following resources:\\n- [Weather API](https://www.weatherapi.com/)\\n- [Time and Date - Los Angeles Weather](https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023)\\n- [Meteoprog - California Weather](https://www.meteoprog.com/weather/California-california/month/october/)\\n- [Weather Spark - Anaheim Weather History](https://weatherspark.com/h/m/1828/2023/10/Historical-Weather-in-October-2023-in-Anaheim-California-United-States)\\n\\nIf you need specific information about a particular city in California, let me know!'}" + "" ] }, - "execution_count": 8, "metadata": {}, - "output_type": "execute_result" + "output_type": "display_data" } ], "source": [ + "from IPython.display import Image, display\n", "flo = Flo.build(session, simple_weather_checking_agent,log_level=\"DEBUG\")\n", "\n", - "flo.invoke(\"Whats the whether in california\")" + "flo.draw()" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2024-09-20 00:38:07,862 - BUILDER - INFO - Building Flo instance from YAML\n", - "2024-09-20 00:38:07,870 - COMMON - INFO - Flo instance created for session dd5c4a4c-4390-46bc-945d-eb9474e63702\n", - "2024-09-20 00:38:07,872 - COMMON - INFO - Invoking query for session dd5c4a4c-4390-46bc-945d-eb9474e63702: Whats the whether in california\n", - "2024-09-20 00:38:07,876 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainStart: {'messages': [HumanMessage(content='Whats the whether in california')]}\n", - "2024-09-20 00:38:07,901 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainStart: {'input': ''}\n", - "2024-09-20 00:38:08,012 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainStart: {'input': ''}\n", - "2024-09-20 00:38:08,035 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainStart: {'input': ''}\n", - "2024-09-20 00:38:08,038 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainStart: {'input': ''}\n", - "2024-09-20 00:38:08,041 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainEnd: []\n", - "2024-09-20 00:38:08,042 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainEnd: {'agent_scratchpad': []}\n", - "2024-09-20 00:38:08,043 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainEnd: {'messages': [HumanMessage(content='Whats the whether in california')], 'intermediate_steps': [], 'agent_scratchpad': []}\n", - "2024-09-20 00:38:08,045 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainStart: {'messages': [HumanMessage(content='Whats the whether in california')], 'intermediate_steps': [], 'agent_scratchpad': []}\n", - "2024-09-20 00:38:08,047 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainEnd: messages=[SystemMessage(content='Given the city name you are capable of answering the latest whether this time of the year by searching the internet\\n'), HumanMessage(content='Whats the whether in california')]\n", - "2024-09-20 00:38:08,048 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onLLMStart: ['System: Given the city name you are capable of answering the latest whether this time of the year by searching the internet\\n\\nHuman: Whats the whether in california']\n" + "2024-09-22 13:22:34,352 - COMMON - INFO - Invoking query for session e7f22b4d-7380-4d00-97c9-5267a468468a: Whats the whether in New Delhi, India ?\n" ] }, { @@ -238,361 +169,40 @@ "text": [ "\n", "\n", - "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2024-09-20 00:38:09,158 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: \n", - "2024-09-20 00:38:09,160 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: \n", - "2024-09-20 00:38:09,171 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: \n", - "2024-09-20 00:38:09,173 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: \n", - "2024-09-20 00:38:09,196 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: \n", - "2024-09-20 00:38:09,199 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: \n", - "2024-09-20 00:38:09,215 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: \n", - "2024-09-20 00:38:09,218 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: \n", - "2024-09-20 00:38:09,359 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: \n", - "2024-09-20 00:38:09,364 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: \n", - "2024-09-20 00:38:09,367 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: \n", - "2024-09-20 00:38:09,370 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: \n", - "2024-09-20 00:38:09,373 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onLLMEnd: [[ChatGenerationChunk(generation_info={'finish_reason': 'tool_calls', 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_1bb46167f9'}, message=AIMessageChunk(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'function': {'arguments': '{\"query\":\"California weather October 2023\"}', 'name': 'tavily_search_results_json'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls', 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_1bb46167f9'}, id='run-456fe998-ec19-48fa-ad0b-c22361d37f68', tool_calls=[{'name': 'tavily_search_results_json', 'args': {'query': 'California weather October 2023'}, 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'type': 'tool_call'}], tool_call_chunks=[{'name': 'tavily_search_results_json', 'args': '{\"query\":\"California weather October 2023\"}', 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'index': 0, 'type': 'tool_call_chunk'}]))]]\n", - "2024-09-20 00:38:09,375 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainStart: content='' additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'function': {'arguments': '{\"query\":\"California weather October 2023\"}', 'name': 'tavily_search_results_json'}, 'type': 'function'}]} response_metadata={'finish_reason': 'tool_calls', 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_1bb46167f9'} id='run-456fe998-ec19-48fa-ad0b-c22361d37f68' tool_calls=[{'name': 'tavily_search_results_json', 'args': {'query': 'California weather October 2023'}, 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'type': 'tool_call'}] tool_call_chunks=[{'name': 'tavily_search_results_json', 'args': '{\"query\":\"California weather October 2023\"}', 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'index': 0, 'type': 'tool_call_chunk'}]\n", - "2024-09-20 00:38:09,381 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainEnd: [ToolAgentAction(tool='tavily_search_results_json', tool_input={'query': 'California weather October 2023'}, log=\"\\nInvoking: `tavily_search_results_json` with `{'query': 'California weather October 2023'}`\\n\\n\\n\", message_log=[AIMessageChunk(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'function': {'arguments': '{\"query\":\"California weather October 2023\"}', 'name': 'tavily_search_results_json'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls', 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_1bb46167f9'}, id='run-456fe998-ec19-48fa-ad0b-c22361d37f68', tool_calls=[{'name': 'tavily_search_results_json', 'args': {'query': 'California weather October 2023'}, 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'type': 'tool_call'}], tool_call_chunks=[{'name': 'tavily_search_results_json', 'args': '{\"query\":\"California weather October 2023\"}', 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'index': 0, 'type': 'tool_call_chunk'}])], tool_call_id='call_BiZ1tUx2CkEuvDao92dT9JNk')]\n", - "2024-09-20 00:38:09,383 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainEnd: [ToolAgentAction(tool='tavily_search_results_json', tool_input={'query': 'California weather October 2023'}, log=\"\\nInvoking: `tavily_search_results_json` with `{'query': 'California weather October 2023'}`\\n\\n\\n\", message_log=[AIMessageChunk(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'function': {'arguments': '{\"query\":\"California weather October 2023\"}', 'name': 'tavily_search_results_json'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls', 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_1bb46167f9'}, id='run-456fe998-ec19-48fa-ad0b-c22361d37f68', tool_calls=[{'name': 'tavily_search_results_json', 'args': {'query': 'California weather October 2023'}, 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'type': 'tool_call'}], tool_call_chunks=[{'name': 'tavily_search_results_json', 'args': '{\"query\":\"California weather October 2023\"}', 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'index': 0, 'type': 'tool_call_chunk'}])], tool_call_id='call_BiZ1tUx2CkEuvDao92dT9JNk')]\n", - "2024-09-20 00:38:09,384 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onAgentAction: tavily_search_results_json - {'query': 'California weather October 2023'}\n", - "2024-09-20 00:38:09,388 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onToolStart: {'query': 'California weather October 2023'}\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", "\u001b[32;1m\u001b[1;3m\n", - "Invoking: `tavily_search_results_json` with `{'query': 'California weather October 2023'}`\n", + "Invoking: `tavily_search_results_json` with `{'query': 'current weather in New Delhi, India'}`\n", "\n", "\n", - "\u001b[0m" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2024-09-20 00:38:13,560 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onToolEnd: [{'url': 'https://www.weatherapi.com/', 'content': \"{'location': {'name': 'California City', 'region': 'California', 'country': 'United States of America', 'lat': 35.13, 'lon': -117.99, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1726772854, 'localtime': '2024-09-19 12:07'}, 'current': {'last_updated_epoch': 1726772400, 'last_updated': '2024-09-19 12:00', 'temp_c': 22.3, 'temp_f': 72.1, 'is_day': 1, 'condition': {'text': 'Sunny', 'icon': '//cdn.weatherapi.com/weather/64x64/day/113.png', 'code': 1000}, 'wind_mph': 3.4, 'wind_kph': 5.4, 'wind_degree': 153, 'wind_dir': 'SSE', 'pressure_mb': 1013.0, 'pressure_in': 29.91, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 35, 'cloud': 0, 'feelslike_c': 23.9, 'feelslike_f': 75.1, 'windchill_c': 24.3, 'windchill_f': 75.7, 'heatindex_c': 24.5, 'heatindex_f': 76.0, 'dewpoint_c': 7.6, 'dewpoint_f': 45.6, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 6.0, 'gust_mph': 3.9, 'gust_kph': 6.2}}\"}, {'url': 'https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023', 'content': 'Weather reports from October 2023 in Los Angeles, California, USA with highs and lows. Sep 17-18. Sign in. News. News Home; Astronomy News; Time Zone News; Calendar & Holiday News; Newsletter; Live events. ... High & Low Weather Summary for October 2023 Temperature Humidity Pressure; High: 92 °F (Oct 5, 11:53 am) 100% (Oct 7, 9:02 am) 30.11 ...'}, {'url': 'https://www.meteoprog.com/weather/California-california/month/october/', 'content': 'California (United States) weather in October 2023 ☀️ Accurate weather forecast for California in October ⛅ Detailed forecast By month Current temperature \"near me\" Weather news ⊳ Widget of weather ⊳ Water temperature | METEOPROG'}, {'url': 'https://world-weather.info/forecast/usa/california/october-2023/', 'content': \"Weather in California in October 2023 (Maryland) - Detailed Weather Forecast for a Month Weather Weather in California Weather in California in October 2023 California Weather Forecast for October 2023 is based on statistical data. 1 +77°+61° 2 +79°+63° 3 +79°+61° 4 +77°+59° 5 +75°+59° 6 +77°+66° 7 +64°+64° 8 +64°+52° 9 +66°+50° 10 +70°+55° 11 +72°+54° 12 +70°+54° 13 +68°+54° 14 +64°+54° 15 +63°+59° 16 +61°+50° 17 +63°+54° 18 +63°+50° 19 +70°+50° Average weather in October 2023 Weather in Washington, D.C.+79° Annapolis+77° Fairfax+77° Fredericksburg+77° Manassas+79° McLean+79° Mechanicsville+77° Vienna+77° Alexandria+79° Waldorf+77° Salisbury+75° Rockville+77° Woodmere+77° Windsor+75° world's temperature today Temperature units\"}, {'url': 'https://weatherspark.com/h/m/1828/2023/10/Historical-Weather-in-October-2023-in-Anaheim-California-United-States', 'content': 'October 2023 Weather History in Anaheim California, United States This report shows the past weather for Anaheim, providing a weather history for October 2023. It features all historical weather data series we have available, including the Anaheim temperature history for October 2023. Anaheim Temperature History October 2023 Hourly Temperature in October 2023 in Anaheim Cloud Cover in October 2023 in Anaheim Daily Precipitation in October 2023 in Anaheim Observed Weather in October 2023 in Anaheim Hours of Daylight and Twilight in October 2023 in Anaheim Solar Elevation and Azimuth in October 2023 in Anaheim Oct 2023 Humidity Comfort Levels in October 2023 in Anaheim Wind Speed in October 2023 in Anaheim Hourly Wind Speed in October 2023 in Anaheim'}]\n", - "2024-09-20 00:38:13,574 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainStart: {'input': ''}\n", - "2024-09-20 00:38:13,585 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainStart: {'input': ''}\n", - "2024-09-20 00:38:13,591 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainStart: {'input': ''}\n", - "2024-09-20 00:38:13,595 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainStart: {'input': ''}\n", - "2024-09-20 00:38:13,597 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainEnd: [AIMessageChunk(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'function': {'arguments': '{\"query\":\"California weather October 2023\"}', 'name': 'tavily_search_results_json'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls', 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_1bb46167f9'}, id='run-456fe998-ec19-48fa-ad0b-c22361d37f68', tool_calls=[{'name': 'tavily_search_results_json', 'args': {'query': 'California weather October 2023'}, 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'type': 'tool_call'}], tool_call_chunks=[{'name': 'tavily_search_results_json', 'args': '{\"query\":\"California weather October 2023\"}', 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'index': 0, 'type': 'tool_call_chunk'}]), ToolMessage(content='[{\"url\": \"https://www.weatherapi.com/\", \"content\": \"{\\'location\\': {\\'name\\': \\'California City\\', \\'region\\': \\'California\\', \\'country\\': \\'United States of America\\', \\'lat\\': 35.13, \\'lon\\': -117.99, \\'tz_id\\': \\'America/Los_Angeles\\', \\'localtime_epoch\\': 1726772854, \\'localtime\\': \\'2024-09-19 12:07\\'}, \\'current\\': {\\'last_updated_epoch\\': 1726772400, \\'last_updated\\': \\'2024-09-19 12:00\\', \\'temp_c\\': 22.3, \\'temp_f\\': 72.1, \\'is_day\\': 1, \\'condition\\': {\\'text\\': \\'Sunny\\', \\'icon\\': \\'//cdn.weatherapi.com/weather/64x64/day/113.png\\', \\'code\\': 1000}, \\'wind_mph\\': 3.4, \\'wind_kph\\': 5.4, \\'wind_degree\\': 153, \\'wind_dir\\': \\'SSE\\', \\'pressure_mb\\': 1013.0, \\'pressure_in\\': 29.91, \\'precip_mm\\': 0.0, \\'precip_in\\': 0.0, \\'humidity\\': 35, \\'cloud\\': 0, \\'feelslike_c\\': 23.9, \\'feelslike_f\\': 75.1, \\'windchill_c\\': 24.3, \\'windchill_f\\': 75.7, \\'heatindex_c\\': 24.5, \\'heatindex_f\\': 76.0, \\'dewpoint_c\\': 7.6, \\'dewpoint_f\\': 45.6, \\'vis_km\\': 16.0, \\'vis_miles\\': 9.0, \\'uv\\': 6.0, \\'gust_mph\\': 3.9, \\'gust_kph\\': 6.2}}\"}, {\"url\": \"https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023\", \"content\": \"Weather reports from October 2023 in Los Angeles, California, USA with highs and lows. Sep 17-18. Sign in. News. News Home; Astronomy News; Time Zone News; Calendar & Holiday News; Newsletter; Live events. ... High & Low Weather Summary for October 2023 Temperature Humidity Pressure; High: 92 °F (Oct 5, 11:53 am) 100% (Oct 7, 9:02 am) 30.11 ...\"}, {\"url\": \"https://www.meteoprog.com/weather/California-california/month/october/\", \"content\": \"California (United States) weather in October 2023 ☀️ Accurate weather forecast for California in October ⛅ Detailed forecast By month Current temperature \\\\\"near me\\\\\" Weather news ⊳ Widget of weather ⊳ Water temperature | METEOPROG\"}, {\"url\": \"https://world-weather.info/forecast/usa/california/october-2023/\", \"content\": \"Weather in California in October 2023 (Maryland) - Detailed Weather Forecast for a Month Weather Weather in California Weather in California in October 2023 California Weather Forecast for October 2023 is based on statistical data. 1 +77°+61° 2 +79°+63° 3 +79°+61° 4 +77°+59° 5 +75°+59° 6 +77°+66° 7 +64°+64° 8 +64°+52° 9 +66°+50° 10 +70°+55° 11 +72°+54° 12 +70°+54° 13 +68°+54° 14 +64°+54° 15 +63°+59° 16 +61°+50° 17 +63°+54° 18 +63°+50° 19 +70°+50° Average weather in October 2023 Weather in Washington, D.C.+79° Annapolis+77° Fairfax+77° Fredericksburg+77° Manassas+79° McLean+79° Mechanicsville+77° Vienna+77° Alexandria+79° Waldorf+77° Salisbury+75° Rockville+77° Woodmere+77° Windsor+75° world\\'s temperature today Temperature units\"}, {\"url\": \"https://weatherspark.com/h/m/1828/2023/10/Historical-Weather-in-October-2023-in-Anaheim-California-United-States\", \"content\": \"October 2023 Weather History in Anaheim California, United States This report shows the past weather for Anaheim, providing a weather history for October 2023. It features all historical weather data series we have available, including the Anaheim temperature history for October 2023. Anaheim Temperature History October 2023 Hourly Temperature in October 2023 in Anaheim Cloud Cover in October 2023 in Anaheim Daily Precipitation in October 2023 in Anaheim Observed Weather in October 2023 in Anaheim Hours of Daylight and Twilight in October 2023 in Anaheim Solar Elevation and Azimuth in October 2023 in Anaheim Oct 2023 Humidity Comfort Levels in October 2023 in Anaheim Wind Speed in October 2023 in Anaheim Hourly Wind Speed in October 2023 in Anaheim\"}]', additional_kwargs={'name': 'tavily_search_results_json'}, tool_call_id='call_BiZ1tUx2CkEuvDao92dT9JNk')]\n", - "2024-09-20 00:38:13,598 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainEnd: {'agent_scratchpad': [AIMessageChunk(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'function': {'arguments': '{\"query\":\"California weather October 2023\"}', 'name': 'tavily_search_results_json'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls', 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_1bb46167f9'}, id='run-456fe998-ec19-48fa-ad0b-c22361d37f68', tool_calls=[{'name': 'tavily_search_results_json', 'args': {'query': 'California weather October 2023'}, 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'type': 'tool_call'}], tool_call_chunks=[{'name': 'tavily_search_results_json', 'args': '{\"query\":\"California weather October 2023\"}', 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'index': 0, 'type': 'tool_call_chunk'}]), ToolMessage(content='[{\"url\": \"https://www.weatherapi.com/\", \"content\": \"{\\'location\\': {\\'name\\': \\'California City\\', \\'region\\': \\'California\\', \\'country\\': \\'United States of America\\', \\'lat\\': 35.13, \\'lon\\': -117.99, \\'tz_id\\': \\'America/Los_Angeles\\', \\'localtime_epoch\\': 1726772854, \\'localtime\\': \\'2024-09-19 12:07\\'}, \\'current\\': {\\'last_updated_epoch\\': 1726772400, \\'last_updated\\': \\'2024-09-19 12:00\\', \\'temp_c\\': 22.3, \\'temp_f\\': 72.1, \\'is_day\\': 1, \\'condition\\': {\\'text\\': \\'Sunny\\', \\'icon\\': \\'//cdn.weatherapi.com/weather/64x64/day/113.png\\', \\'code\\': 1000}, \\'wind_mph\\': 3.4, \\'wind_kph\\': 5.4, \\'wind_degree\\': 153, \\'wind_dir\\': \\'SSE\\', \\'pressure_mb\\': 1013.0, \\'pressure_in\\': 29.91, \\'precip_mm\\': 0.0, \\'precip_in\\': 0.0, \\'humidity\\': 35, \\'cloud\\': 0, \\'feelslike_c\\': 23.9, \\'feelslike_f\\': 75.1, \\'windchill_c\\': 24.3, \\'windchill_f\\': 75.7, \\'heatindex_c\\': 24.5, \\'heatindex_f\\': 76.0, \\'dewpoint_c\\': 7.6, \\'dewpoint_f\\': 45.6, \\'vis_km\\': 16.0, \\'vis_miles\\': 9.0, \\'uv\\': 6.0, \\'gust_mph\\': 3.9, \\'gust_kph\\': 6.2}}\"}, {\"url\": \"https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023\", \"content\": \"Weather reports from October 2023 in Los Angeles, California, USA with highs and lows. Sep 17-18. Sign in. News. News Home; Astronomy News; Time Zone News; Calendar & Holiday News; Newsletter; Live events. ... High & Low Weather Summary for October 2023 Temperature Humidity Pressure; High: 92 °F (Oct 5, 11:53 am) 100% (Oct 7, 9:02 am) 30.11 ...\"}, {\"url\": \"https://www.meteoprog.com/weather/California-california/month/october/\", \"content\": \"California (United States) weather in October 2023 ☀️ Accurate weather forecast for California in October ⛅ Detailed forecast By month Current temperature \\\\\"near me\\\\\" Weather news ⊳ Widget of weather ⊳ Water temperature | METEOPROG\"}, {\"url\": \"https://world-weather.info/forecast/usa/california/october-2023/\", \"content\": \"Weather in California in October 2023 (Maryland) - Detailed Weather Forecast for a Month Weather Weather in California Weather in California in October 2023 California Weather Forecast for October 2023 is based on statistical data. 1 +77°+61° 2 +79°+63° 3 +79°+61° 4 +77°+59° 5 +75°+59° 6 +77°+66° 7 +64°+64° 8 +64°+52° 9 +66°+50° 10 +70°+55° 11 +72°+54° 12 +70°+54° 13 +68°+54° 14 +64°+54° 15 +63°+59° 16 +61°+50° 17 +63°+54° 18 +63°+50° 19 +70°+50° Average weather in October 2023 Weather in Washington, D.C.+79° Annapolis+77° Fairfax+77° Fredericksburg+77° Manassas+79° McLean+79° Mechanicsville+77° Vienna+77° Alexandria+79° Waldorf+77° Salisbury+75° Rockville+77° Woodmere+77° Windsor+75° world\\'s temperature today Temperature units\"}, {\"url\": \"https://weatherspark.com/h/m/1828/2023/10/Historical-Weather-in-October-2023-in-Anaheim-California-United-States\", \"content\": \"October 2023 Weather History in Anaheim California, United States This report shows the past weather for Anaheim, providing a weather history for October 2023. It features all historical weather data series we have available, including the Anaheim temperature history for October 2023. Anaheim Temperature History October 2023 Hourly Temperature in October 2023 in Anaheim Cloud Cover in October 2023 in Anaheim Daily Precipitation in October 2023 in Anaheim Observed Weather in October 2023 in Anaheim Hours of Daylight and Twilight in October 2023 in Anaheim Solar Elevation and Azimuth in October 2023 in Anaheim Oct 2023 Humidity Comfort Levels in October 2023 in Anaheim Wind Speed in October 2023 in Anaheim Hourly Wind Speed in October 2023 in Anaheim\"}]', additional_kwargs={'name': 'tavily_search_results_json'}, tool_call_id='call_BiZ1tUx2CkEuvDao92dT9JNk')]}\n", - "2024-09-20 00:38:13,600 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainEnd: {'messages': [HumanMessage(content='Whats the whether in california')], 'intermediate_steps': [(ToolAgentAction(tool='tavily_search_results_json', tool_input={'query': 'California weather October 2023'}, log=\"\\nInvoking: `tavily_search_results_json` with `{'query': 'California weather October 2023'}`\\n\\n\\n\", message_log=[AIMessageChunk(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'function': {'arguments': '{\"query\":\"California weather October 2023\"}', 'name': 'tavily_search_results_json'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls', 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_1bb46167f9'}, id='run-456fe998-ec19-48fa-ad0b-c22361d37f68', tool_calls=[{'name': 'tavily_search_results_json', 'args': {'query': 'California weather October 2023'}, 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'type': 'tool_call'}], tool_call_chunks=[{'name': 'tavily_search_results_json', 'args': '{\"query\":\"California weather October 2023\"}', 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'index': 0, 'type': 'tool_call_chunk'}])], tool_call_id='call_BiZ1tUx2CkEuvDao92dT9JNk'), [{'url': 'https://www.weatherapi.com/', 'content': \"{'location': {'name': 'California City', 'region': 'California', 'country': 'United States of America', 'lat': 35.13, 'lon': -117.99, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1726772854, 'localtime': '2024-09-19 12:07'}, 'current': {'last_updated_epoch': 1726772400, 'last_updated': '2024-09-19 12:00', 'temp_c': 22.3, 'temp_f': 72.1, 'is_day': 1, 'condition': {'text': 'Sunny', 'icon': '//cdn.weatherapi.com/weather/64x64/day/113.png', 'code': 1000}, 'wind_mph': 3.4, 'wind_kph': 5.4, 'wind_degree': 153, 'wind_dir': 'SSE', 'pressure_mb': 1013.0, 'pressure_in': 29.91, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 35, 'cloud': 0, 'feelslike_c': 23.9, 'feelslike_f': 75.1, 'windchill_c': 24.3, 'windchill_f': 75.7, 'heatindex_c': 24.5, 'heatindex_f': 76.0, 'dewpoint_c': 7.6, 'dewpoint_f': 45.6, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 6.0, 'gust_mph': 3.9, 'gust_kph': 6.2}}\"}, {'url': 'https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023', 'content': 'Weather reports from October 2023 in Los Angeles, California, USA with highs and lows. Sep 17-18. Sign in. News. News Home; Astronomy News; Time Zone News; Calendar & Holiday News; Newsletter; Live events. ... High & Low Weather Summary for October 2023 Temperature Humidity Pressure; High: 92 °F (Oct 5, 11:53 am) 100% (Oct 7, 9:02 am) 30.11 ...'}, {'url': 'https://www.meteoprog.com/weather/California-california/month/october/', 'content': 'California (United States) weather in October 2023 ☀️ Accurate weather forecast for California in October ⛅ Detailed forecast By month Current temperature \"near me\" Weather news ⊳ Widget of weather ⊳ Water temperature | METEOPROG'}, {'url': 'https://world-weather.info/forecast/usa/california/october-2023/', 'content': \"Weather in California in October 2023 (Maryland) - Detailed Weather Forecast for a Month Weather Weather in California Weather in California in October 2023 California Weather Forecast for October 2023 is based on statistical data. 1 +77°+61° 2 +79°+63° 3 +79°+61° 4 +77°+59° 5 +75°+59° 6 +77°+66° 7 +64°+64° 8 +64°+52° 9 +66°+50° 10 +70°+55° 11 +72°+54° 12 +70°+54° 13 +68°+54° 14 +64°+54° 15 +63°+59° 16 +61°+50° 17 +63°+54° 18 +63°+50° 19 +70°+50° Average weather in October 2023 Weather in Washington, D.C.+79° Annapolis+77° Fairfax+77° Fredericksburg+77° Manassas+79° McLean+79° Mechanicsville+77° Vienna+77° Alexandria+79° Waldorf+77° Salisbury+75° Rockville+77° Woodmere+77° Windsor+75° world's temperature today Temperature units\"}, {'url': 'https://weatherspark.com/h/m/1828/2023/10/Historical-Weather-in-October-2023-in-Anaheim-California-United-States', 'content': 'October 2023 Weather History in Anaheim California, United States This report shows the past weather for Anaheim, providing a weather history for October 2023. It features all historical weather data series we have available, including the Anaheim temperature history for October 2023. Anaheim Temperature History October 2023 Hourly Temperature in October 2023 in Anaheim Cloud Cover in October 2023 in Anaheim Daily Precipitation in October 2023 in Anaheim Observed Weather in October 2023 in Anaheim Hours of Daylight and Twilight in October 2023 in Anaheim Solar Elevation and Azimuth in October 2023 in Anaheim Oct 2023 Humidity Comfort Levels in October 2023 in Anaheim Wind Speed in October 2023 in Anaheim Hourly Wind Speed in October 2023 in Anaheim'}])], 'agent_scratchpad': [AIMessageChunk(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'function': {'arguments': '{\"query\":\"California weather October 2023\"}', 'name': 'tavily_search_results_json'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls', 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_1bb46167f9'}, id='run-456fe998-ec19-48fa-ad0b-c22361d37f68', tool_calls=[{'name': 'tavily_search_results_json', 'args': {'query': 'California weather October 2023'}, 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'type': 'tool_call'}], tool_call_chunks=[{'name': 'tavily_search_results_json', 'args': '{\"query\":\"California weather October 2023\"}', 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'index': 0, 'type': 'tool_call_chunk'}]), ToolMessage(content='[{\"url\": \"https://www.weatherapi.com/\", \"content\": \"{\\'location\\': {\\'name\\': \\'California City\\', \\'region\\': \\'California\\', \\'country\\': \\'United States of America\\', \\'lat\\': 35.13, \\'lon\\': -117.99, \\'tz_id\\': \\'America/Los_Angeles\\', \\'localtime_epoch\\': 1726772854, \\'localtime\\': \\'2024-09-19 12:07\\'}, \\'current\\': {\\'last_updated_epoch\\': 1726772400, \\'last_updated\\': \\'2024-09-19 12:00\\', \\'temp_c\\': 22.3, \\'temp_f\\': 72.1, \\'is_day\\': 1, \\'condition\\': {\\'text\\': \\'Sunny\\', \\'icon\\': \\'//cdn.weatherapi.com/weather/64x64/day/113.png\\', \\'code\\': 1000}, \\'wind_mph\\': 3.4, \\'wind_kph\\': 5.4, \\'wind_degree\\': 153, \\'wind_dir\\': \\'SSE\\', \\'pressure_mb\\': 1013.0, \\'pressure_in\\': 29.91, \\'precip_mm\\': 0.0, \\'precip_in\\': 0.0, \\'humidity\\': 35, \\'cloud\\': 0, \\'feelslike_c\\': 23.9, \\'feelslike_f\\': 75.1, \\'windchill_c\\': 24.3, \\'windchill_f\\': 75.7, \\'heatindex_c\\': 24.5, \\'heatindex_f\\': 76.0, \\'dewpoint_c\\': 7.6, \\'dewpoint_f\\': 45.6, \\'vis_km\\': 16.0, \\'vis_miles\\': 9.0, \\'uv\\': 6.0, \\'gust_mph\\': 3.9, \\'gust_kph\\': 6.2}}\"}, {\"url\": \"https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023\", \"content\": \"Weather reports from October 2023 in Los Angeles, California, USA with highs and lows. Sep 17-18. Sign in. News. News Home; Astronomy News; Time Zone News; Calendar & Holiday News; Newsletter; Live events. ... High & Low Weather Summary for October 2023 Temperature Humidity Pressure; High: 92 °F (Oct 5, 11:53 am) 100% (Oct 7, 9:02 am) 30.11 ...\"}, {\"url\": \"https://www.meteoprog.com/weather/California-california/month/october/\", \"content\": \"California (United States) weather in October 2023 ☀️ Accurate weather forecast for California in October ⛅ Detailed forecast By month Current temperature \\\\\"near me\\\\\" Weather news ⊳ Widget of weather ⊳ Water temperature | METEOPROG\"}, {\"url\": \"https://world-weather.info/forecast/usa/california/october-2023/\", \"content\": \"Weather in California in October 2023 (Maryland) - Detailed Weather Forecast for a Month Weather Weather in California Weather in California in October 2023 California Weather Forecast for October 2023 is based on statistical data. 1 +77°+61° 2 +79°+63° 3 +79°+61° 4 +77°+59° 5 +75°+59° 6 +77°+66° 7 +64°+64° 8 +64°+52° 9 +66°+50° 10 +70°+55° 11 +72°+54° 12 +70°+54° 13 +68°+54° 14 +64°+54° 15 +63°+59° 16 +61°+50° 17 +63°+54° 18 +63°+50° 19 +70°+50° Average weather in October 2023 Weather in Washington, D.C.+79° Annapolis+77° Fairfax+77° Fredericksburg+77° Manassas+79° McLean+79° Mechanicsville+77° Vienna+77° Alexandria+79° Waldorf+77° Salisbury+75° Rockville+77° Woodmere+77° Windsor+75° world\\'s temperature today Temperature units\"}, {\"url\": \"https://weatherspark.com/h/m/1828/2023/10/Historical-Weather-in-October-2023-in-Anaheim-California-United-States\", \"content\": \"October 2023 Weather History in Anaheim California, United States This report shows the past weather for Anaheim, providing a weather history for October 2023. It features all historical weather data series we have available, including the Anaheim temperature history for October 2023. Anaheim Temperature History October 2023 Hourly Temperature in October 2023 in Anaheim Cloud Cover in October 2023 in Anaheim Daily Precipitation in October 2023 in Anaheim Observed Weather in October 2023 in Anaheim Hours of Daylight and Twilight in October 2023 in Anaheim Solar Elevation and Azimuth in October 2023 in Anaheim Oct 2023 Humidity Comfort Levels in October 2023 in Anaheim Wind Speed in October 2023 in Anaheim Hourly Wind Speed in October 2023 in Anaheim\"}]', additional_kwargs={'name': 'tavily_search_results_json'}, tool_call_id='call_BiZ1tUx2CkEuvDao92dT9JNk')]}\n", - "2024-09-20 00:38:13,602 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainStart: {'messages': [HumanMessage(content='Whats the whether in california')], 'intermediate_steps': [(ToolAgentAction(tool='tavily_search_results_json', tool_input={'query': 'California weather October 2023'}, log=\"\\nInvoking: `tavily_search_results_json` with `{'query': 'California weather October 2023'}`\\n\\n\\n\", message_log=[AIMessageChunk(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'function': {'arguments': '{\"query\":\"California weather October 2023\"}', 'name': 'tavily_search_results_json'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls', 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_1bb46167f9'}, id='run-456fe998-ec19-48fa-ad0b-c22361d37f68', tool_calls=[{'name': 'tavily_search_results_json', 'args': {'query': 'California weather October 2023'}, 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'type': 'tool_call'}], tool_call_chunks=[{'name': 'tavily_search_results_json', 'args': '{\"query\":\"California weather October 2023\"}', 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'index': 0, 'type': 'tool_call_chunk'}])], tool_call_id='call_BiZ1tUx2CkEuvDao92dT9JNk'), [{'url': 'https://www.weatherapi.com/', 'content': \"{'location': {'name': 'California City', 'region': 'California', 'country': 'United States of America', 'lat': 35.13, 'lon': -117.99, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1726772854, 'localtime': '2024-09-19 12:07'}, 'current': {'last_updated_epoch': 1726772400, 'last_updated': '2024-09-19 12:00', 'temp_c': 22.3, 'temp_f': 72.1, 'is_day': 1, 'condition': {'text': 'Sunny', 'icon': '//cdn.weatherapi.com/weather/64x64/day/113.png', 'code': 1000}, 'wind_mph': 3.4, 'wind_kph': 5.4, 'wind_degree': 153, 'wind_dir': 'SSE', 'pressure_mb': 1013.0, 'pressure_in': 29.91, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 35, 'cloud': 0, 'feelslike_c': 23.9, 'feelslike_f': 75.1, 'windchill_c': 24.3, 'windchill_f': 75.7, 'heatindex_c': 24.5, 'heatindex_f': 76.0, 'dewpoint_c': 7.6, 'dewpoint_f': 45.6, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 6.0, 'gust_mph': 3.9, 'gust_kph': 6.2}}\"}, {'url': 'https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023', 'content': 'Weather reports from October 2023 in Los Angeles, California, USA with highs and lows. Sep 17-18. Sign in. News. News Home; Astronomy News; Time Zone News; Calendar & Holiday News; Newsletter; Live events. ... High & Low Weather Summary for October 2023 Temperature Humidity Pressure; High: 92 °F (Oct 5, 11:53 am) 100% (Oct 7, 9:02 am) 30.11 ...'}, {'url': 'https://www.meteoprog.com/weather/California-california/month/october/', 'content': 'California (United States) weather in October 2023 ☀️ Accurate weather forecast for California in October ⛅ Detailed forecast By month Current temperature \"near me\" Weather news ⊳ Widget of weather ⊳ Water temperature | METEOPROG'}, {'url': 'https://world-weather.info/forecast/usa/california/october-2023/', 'content': \"Weather in California in October 2023 (Maryland) - Detailed Weather Forecast for a Month Weather Weather in California Weather in California in October 2023 California Weather Forecast for October 2023 is based on statistical data. 1 +77°+61° 2 +79°+63° 3 +79°+61° 4 +77°+59° 5 +75°+59° 6 +77°+66° 7 +64°+64° 8 +64°+52° 9 +66°+50° 10 +70°+55° 11 +72°+54° 12 +70°+54° 13 +68°+54° 14 +64°+54° 15 +63°+59° 16 +61°+50° 17 +63°+54° 18 +63°+50° 19 +70°+50° Average weather in October 2023 Weather in Washington, D.C.+79° Annapolis+77° Fairfax+77° Fredericksburg+77° Manassas+79° McLean+79° Mechanicsville+77° Vienna+77° Alexandria+79° Waldorf+77° Salisbury+75° Rockville+77° Woodmere+77° Windsor+75° world's temperature today Temperature units\"}, {'url': 'https://weatherspark.com/h/m/1828/2023/10/Historical-Weather-in-October-2023-in-Anaheim-California-United-States', 'content': 'October 2023 Weather History in Anaheim California, United States This report shows the past weather for Anaheim, providing a weather history for October 2023. It features all historical weather data series we have available, including the Anaheim temperature history for October 2023. Anaheim Temperature History October 2023 Hourly Temperature in October 2023 in Anaheim Cloud Cover in October 2023 in Anaheim Daily Precipitation in October 2023 in Anaheim Observed Weather in October 2023 in Anaheim Hours of Daylight and Twilight in October 2023 in Anaheim Solar Elevation and Azimuth in October 2023 in Anaheim Oct 2023 Humidity Comfort Levels in October 2023 in Anaheim Wind Speed in October 2023 in Anaheim Hourly Wind Speed in October 2023 in Anaheim'}])], 'agent_scratchpad': [AIMessageChunk(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'function': {'arguments': '{\"query\":\"California weather October 2023\"}', 'name': 'tavily_search_results_json'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls', 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_1bb46167f9'}, id='run-456fe998-ec19-48fa-ad0b-c22361d37f68', tool_calls=[{'name': 'tavily_search_results_json', 'args': {'query': 'California weather October 2023'}, 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'type': 'tool_call'}], tool_call_chunks=[{'name': 'tavily_search_results_json', 'args': '{\"query\":\"California weather October 2023\"}', 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'index': 0, 'type': 'tool_call_chunk'}]), ToolMessage(content='[{\"url\": \"https://www.weatherapi.com/\", \"content\": \"{\\'location\\': {\\'name\\': \\'California City\\', \\'region\\': \\'California\\', \\'country\\': \\'United States of America\\', \\'lat\\': 35.13, \\'lon\\': -117.99, \\'tz_id\\': \\'America/Los_Angeles\\', \\'localtime_epoch\\': 1726772854, \\'localtime\\': \\'2024-09-19 12:07\\'}, \\'current\\': {\\'last_updated_epoch\\': 1726772400, \\'last_updated\\': \\'2024-09-19 12:00\\', \\'temp_c\\': 22.3, \\'temp_f\\': 72.1, \\'is_day\\': 1, \\'condition\\': {\\'text\\': \\'Sunny\\', \\'icon\\': \\'//cdn.weatherapi.com/weather/64x64/day/113.png\\', \\'code\\': 1000}, \\'wind_mph\\': 3.4, \\'wind_kph\\': 5.4, \\'wind_degree\\': 153, \\'wind_dir\\': \\'SSE\\', \\'pressure_mb\\': 1013.0, \\'pressure_in\\': 29.91, \\'precip_mm\\': 0.0, \\'precip_in\\': 0.0, \\'humidity\\': 35, \\'cloud\\': 0, \\'feelslike_c\\': 23.9, \\'feelslike_f\\': 75.1, \\'windchill_c\\': 24.3, \\'windchill_f\\': 75.7, \\'heatindex_c\\': 24.5, \\'heatindex_f\\': 76.0, \\'dewpoint_c\\': 7.6, \\'dewpoint_f\\': 45.6, \\'vis_km\\': 16.0, \\'vis_miles\\': 9.0, \\'uv\\': 6.0, \\'gust_mph\\': 3.9, \\'gust_kph\\': 6.2}}\"}, {\"url\": \"https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023\", \"content\": \"Weather reports from October 2023 in Los Angeles, California, USA with highs and lows. Sep 17-18. Sign in. News. News Home; Astronomy News; Time Zone News; Calendar & Holiday News; Newsletter; Live events. ... High & Low Weather Summary for October 2023 Temperature Humidity Pressure; High: 92 °F (Oct 5, 11:53 am) 100% (Oct 7, 9:02 am) 30.11 ...\"}, {\"url\": \"https://www.meteoprog.com/weather/California-california/month/october/\", \"content\": \"California (United States) weather in October 2023 ☀️ Accurate weather forecast for California in October ⛅ Detailed forecast By month Current temperature \\\\\"near me\\\\\" Weather news ⊳ Widget of weather ⊳ Water temperature | METEOPROG\"}, {\"url\": \"https://world-weather.info/forecast/usa/california/october-2023/\", \"content\": \"Weather in California in October 2023 (Maryland) - Detailed Weather Forecast for a Month Weather Weather in California Weather in California in October 2023 California Weather Forecast for October 2023 is based on statistical data. 1 +77°+61° 2 +79°+63° 3 +79°+61° 4 +77°+59° 5 +75°+59° 6 +77°+66° 7 +64°+64° 8 +64°+52° 9 +66°+50° 10 +70°+55° 11 +72°+54° 12 +70°+54° 13 +68°+54° 14 +64°+54° 15 +63°+59° 16 +61°+50° 17 +63°+54° 18 +63°+50° 19 +70°+50° Average weather in October 2023 Weather in Washington, D.C.+79° Annapolis+77° Fairfax+77° Fredericksburg+77° Manassas+79° McLean+79° Mechanicsville+77° Vienna+77° Alexandria+79° Waldorf+77° Salisbury+75° Rockville+77° Woodmere+77° Windsor+75° world\\'s temperature today Temperature units\"}, {\"url\": \"https://weatherspark.com/h/m/1828/2023/10/Historical-Weather-in-October-2023-in-Anaheim-California-United-States\", \"content\": \"October 2023 Weather History in Anaheim California, United States This report shows the past weather for Anaheim, providing a weather history for October 2023. It features all historical weather data series we have available, including the Anaheim temperature history for October 2023. Anaheim Temperature History October 2023 Hourly Temperature in October 2023 in Anaheim Cloud Cover in October 2023 in Anaheim Daily Precipitation in October 2023 in Anaheim Observed Weather in October 2023 in Anaheim Hours of Daylight and Twilight in October 2023 in Anaheim Solar Elevation and Azimuth in October 2023 in Anaheim Oct 2023 Humidity Comfort Levels in October 2023 in Anaheim Wind Speed in October 2023 in Anaheim Hourly Wind Speed in October 2023 in Anaheim\"}]', additional_kwargs={'name': 'tavily_search_results_json'}, tool_call_id='call_BiZ1tUx2CkEuvDao92dT9JNk')]}\n", - "2024-09-20 00:38:13,603 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainEnd: messages=[SystemMessage(content='Given the city name you are capable of answering the latest whether this time of the year by searching the internet\\n'), HumanMessage(content='Whats the whether in california'), AIMessageChunk(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'function': {'arguments': '{\"query\":\"California weather October 2023\"}', 'name': 'tavily_search_results_json'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls', 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_1bb46167f9'}, id='run-456fe998-ec19-48fa-ad0b-c22361d37f68', tool_calls=[{'name': 'tavily_search_results_json', 'args': {'query': 'California weather October 2023'}, 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'type': 'tool_call'}], tool_call_chunks=[{'name': 'tavily_search_results_json', 'args': '{\"query\":\"California weather October 2023\"}', 'id': 'call_BiZ1tUx2CkEuvDao92dT9JNk', 'index': 0, 'type': 'tool_call_chunk'}]), ToolMessage(content='[{\"url\": \"https://www.weatherapi.com/\", \"content\": \"{\\'location\\': {\\'name\\': \\'California City\\', \\'region\\': \\'California\\', \\'country\\': \\'United States of America\\', \\'lat\\': 35.13, \\'lon\\': -117.99, \\'tz_id\\': \\'America/Los_Angeles\\', \\'localtime_epoch\\': 1726772854, \\'localtime\\': \\'2024-09-19 12:07\\'}, \\'current\\': {\\'last_updated_epoch\\': 1726772400, \\'last_updated\\': \\'2024-09-19 12:00\\', \\'temp_c\\': 22.3, \\'temp_f\\': 72.1, \\'is_day\\': 1, \\'condition\\': {\\'text\\': \\'Sunny\\', \\'icon\\': \\'//cdn.weatherapi.com/weather/64x64/day/113.png\\', \\'code\\': 1000}, \\'wind_mph\\': 3.4, \\'wind_kph\\': 5.4, \\'wind_degree\\': 153, \\'wind_dir\\': \\'SSE\\', \\'pressure_mb\\': 1013.0, \\'pressure_in\\': 29.91, \\'precip_mm\\': 0.0, \\'precip_in\\': 0.0, \\'humidity\\': 35, \\'cloud\\': 0, \\'feelslike_c\\': 23.9, \\'feelslike_f\\': 75.1, \\'windchill_c\\': 24.3, \\'windchill_f\\': 75.7, \\'heatindex_c\\': 24.5, \\'heatindex_f\\': 76.0, \\'dewpoint_c\\': 7.6, \\'dewpoint_f\\': 45.6, \\'vis_km\\': 16.0, \\'vis_miles\\': 9.0, \\'uv\\': 6.0, \\'gust_mph\\': 3.9, \\'gust_kph\\': 6.2}}\"}, {\"url\": \"https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023\", \"content\": \"Weather reports from October 2023 in Los Angeles, California, USA with highs and lows. Sep 17-18. Sign in. News. News Home; Astronomy News; Time Zone News; Calendar & Holiday News; Newsletter; Live events. ... High & Low Weather Summary for October 2023 Temperature Humidity Pressure; High: 92 °F (Oct 5, 11:53 am) 100% (Oct 7, 9:02 am) 30.11 ...\"}, {\"url\": \"https://www.meteoprog.com/weather/California-california/month/october/\", \"content\": \"California (United States) weather in October 2023 ☀️ Accurate weather forecast for California in October ⛅ Detailed forecast By month Current temperature \\\\\"near me\\\\\" Weather news ⊳ Widget of weather ⊳ Water temperature | METEOPROG\"}, {\"url\": \"https://world-weather.info/forecast/usa/california/october-2023/\", \"content\": \"Weather in California in October 2023 (Maryland) - Detailed Weather Forecast for a Month Weather Weather in California Weather in California in October 2023 California Weather Forecast for October 2023 is based on statistical data. 1 +77°+61° 2 +79°+63° 3 +79°+61° 4 +77°+59° 5 +75°+59° 6 +77°+66° 7 +64°+64° 8 +64°+52° 9 +66°+50° 10 +70°+55° 11 +72°+54° 12 +70°+54° 13 +68°+54° 14 +64°+54° 15 +63°+59° 16 +61°+50° 17 +63°+54° 18 +63°+50° 19 +70°+50° Average weather in October 2023 Weather in Washington, D.C.+79° Annapolis+77° Fairfax+77° Fredericksburg+77° Manassas+79° McLean+79° Mechanicsville+77° Vienna+77° Alexandria+79° Waldorf+77° Salisbury+75° Rockville+77° Woodmere+77° Windsor+75° world\\'s temperature today Temperature units\"}, {\"url\": \"https://weatherspark.com/h/m/1828/2023/10/Historical-Weather-in-October-2023-in-Anaheim-California-United-States\", \"content\": \"October 2023 Weather History in Anaheim California, United States This report shows the past weather for Anaheim, providing a weather history for October 2023. It features all historical weather data series we have available, including the Anaheim temperature history for October 2023. Anaheim Temperature History October 2023 Hourly Temperature in October 2023 in Anaheim Cloud Cover in October 2023 in Anaheim Daily Precipitation in October 2023 in Anaheim Observed Weather in October 2023 in Anaheim Hours of Daylight and Twilight in October 2023 in Anaheim Solar Elevation and Azimuth in October 2023 in Anaheim Oct 2023 Humidity Comfort Levels in October 2023 in Anaheim Wind Speed in October 2023 in Anaheim Hourly Wind Speed in October 2023 in Anaheim\"}]', additional_kwargs={'name': 'tavily_search_results_json'}, tool_call_id='call_BiZ1tUx2CkEuvDao92dT9JNk')]\n", - "2024-09-20 00:38:13,605 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onLLMStart: ['System: Given the city name you are capable of answering the latest whether this time of the year by searching the internet\\n\\nHuman: Whats the whether in california\\nAI: \\nTool: [{\"url\": \"https://www.weatherapi.com/\", \"content\": \"{\\'location\\': {\\'name\\': \\'California City\\', \\'region\\': \\'California\\', \\'country\\': \\'United States of America\\', \\'lat\\': 35.13, \\'lon\\': -117.99, \\'tz_id\\': \\'America/Los_Angeles\\', \\'localtime_epoch\\': 1726772854, \\'localtime\\': \\'2024-09-19 12:07\\'}, \\'current\\': {\\'last_updated_epoch\\': 1726772400, \\'last_updated\\': \\'2024-09-19 12:00\\', \\'temp_c\\': 22.3, \\'temp_f\\': 72.1, \\'is_day\\': 1, \\'condition\\': {\\'text\\': \\'Sunny\\', \\'icon\\': \\'//cdn.weatherapi.com/weather/64x64/day/113.png\\', \\'code\\': 1000}, \\'wind_mph\\': 3.4, \\'wind_kph\\': 5.4, \\'wind_degree\\': 153, \\'wind_dir\\': \\'SSE\\', \\'pressure_mb\\': 1013.0, \\'pressure_in\\': 29.91, \\'precip_mm\\': 0.0, \\'precip_in\\': 0.0, \\'humidity\\': 35, \\'cloud\\': 0, \\'feelslike_c\\': 23.9, \\'feelslike_f\\': 75.1, \\'windchill_c\\': 24.3, \\'windchill_f\\': 75.7, \\'heatindex_c\\': 24.5, \\'heatindex_f\\': 76.0, \\'dewpoint_c\\': 7.6, \\'dewpoint_f\\': 45.6, \\'vis_km\\': 16.0, \\'vis_miles\\': 9.0, \\'uv\\': 6.0, \\'gust_mph\\': 3.9, \\'gust_kph\\': 6.2}}\"}, {\"url\": \"https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023\", \"content\": \"Weather reports from October 2023 in Los Angeles, California, USA with highs and lows. Sep 17-18. Sign in. News. News Home; Astronomy News; Time Zone News; Calendar & Holiday News; Newsletter; Live events. ... High & Low Weather Summary for October 2023 Temperature Humidity Pressure; High: 92 °F (Oct 5, 11:53 am) 100% (Oct 7, 9:02 am) 30.11 ...\"}, {\"url\": \"https://www.meteoprog.com/weather/California-california/month/october/\", \"content\": \"California (United States) weather in October 2023 ☀️ Accurate weather forecast for California in October ⛅ Detailed forecast By month Current temperature \\\\\"near me\\\\\" Weather news ⊳ Widget of weather ⊳ Water temperature | METEOPROG\"}, {\"url\": \"https://world-weather.info/forecast/usa/california/october-2023/\", \"content\": \"Weather in California in October 2023 (Maryland) - Detailed Weather Forecast for a Month Weather Weather in California Weather in California in October 2023 California Weather Forecast for October 2023 is based on statistical data. 1 +77°+61° 2 +79°+63° 3 +79°+61° 4 +77°+59° 5 +75°+59° 6 +77°+66° 7 +64°+64° 8 +64°+52° 9 +66°+50° 10 +70°+55° 11 +72°+54° 12 +70°+54° 13 +68°+54° 14 +64°+54° 15 +63°+59° 16 +61°+50° 17 +63°+54° 18 +63°+50° 19 +70°+50° Average weather in October 2023 Weather in Washington, D.C.+79° Annapolis+77° Fairfax+77° Fredericksburg+77° Manassas+79° McLean+79° Mechanicsville+77° Vienna+77° Alexandria+79° Waldorf+77° Salisbury+75° Rockville+77° Woodmere+77° Windsor+75° world\\'s temperature today Temperature units\"}, {\"url\": \"https://weatherspark.com/h/m/1828/2023/10/Historical-Weather-in-October-2023-in-Anaheim-California-United-States\", \"content\": \"October 2023 Weather History in Anaheim California, United States This report shows the past weather for Anaheim, providing a weather history for October 2023. It features all historical weather data series we have available, including the Anaheim temperature history for October 2023. Anaheim Temperature History October 2023 Hourly Temperature in October 2023 in Anaheim Cloud Cover in October 2023 in Anaheim Daily Precipitation in October 2023 in Anaheim Observed Weather in October 2023 in Anaheim Hours of Daylight and Twilight in October 2023 in Anaheim Solar Elevation and Azimuth in October 2023 in Anaheim Oct 2023 Humidity Comfort Levels in October 2023 in Anaheim Wind Speed in October 2023 in Anaheim Hourly Wind Speed in October 2023 in Anaheim\"}]']\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[36;1m\u001b[1;3m[{'url': 'https://www.weatherapi.com/', 'content': \"{'location': {'name': 'California City', 'region': 'California', 'country': 'United States of America', 'lat': 35.13, 'lon': -117.99, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1726772854, 'localtime': '2024-09-19 12:07'}, 'current': {'last_updated_epoch': 1726772400, 'last_updated': '2024-09-19 12:00', 'temp_c': 22.3, 'temp_f': 72.1, 'is_day': 1, 'condition': {'text': 'Sunny', 'icon': '//cdn.weatherapi.com/weather/64x64/day/113.png', 'code': 1000}, 'wind_mph': 3.4, 'wind_kph': 5.4, 'wind_degree': 153, 'wind_dir': 'SSE', 'pressure_mb': 1013.0, 'pressure_in': 29.91, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 35, 'cloud': 0, 'feelslike_c': 23.9, 'feelslike_f': 75.1, 'windchill_c': 24.3, 'windchill_f': 75.7, 'heatindex_c': 24.5, 'heatindex_f': 76.0, 'dewpoint_c': 7.6, 'dewpoint_f': 45.6, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 6.0, 'gust_mph': 3.9, 'gust_kph': 6.2}}\"}, {'url': 'https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023', 'content': 'Weather reports from October 2023 in Los Angeles, California, USA with highs and lows. Sep 17-18. Sign in. News. News Home; Astronomy News; Time Zone News; Calendar & Holiday News; Newsletter; Live events. ... High & Low Weather Summary for October 2023 Temperature Humidity Pressure; High: 92 °F (Oct 5, 11:53 am) 100% (Oct 7, 9:02 am) 30.11 ...'}, {'url': 'https://www.meteoprog.com/weather/California-california/month/october/', 'content': 'California (United States) weather in October 2023 ☀️ Accurate weather forecast for California in October ⛅ Detailed forecast By month Current temperature \"near me\" Weather news ⊳ Widget of weather ⊳ Water temperature | METEOPROG'}, {'url': 'https://world-weather.info/forecast/usa/california/october-2023/', 'content': \"Weather in California in October 2023 (Maryland) - Detailed Weather Forecast for a Month Weather Weather in California Weather in California in October 2023 California Weather Forecast for October 2023 is based on statistical data. 1 +77°+61° 2 +79°+63° 3 +79°+61° 4 +77°+59° 5 +75°+59° 6 +77°+66° 7 +64°+64° 8 +64°+52° 9 +66°+50° 10 +70°+55° 11 +72°+54° 12 +70°+54° 13 +68°+54° 14 +64°+54° 15 +63°+59° 16 +61°+50° 17 +63°+54° 18 +63°+50° 19 +70°+50° Average weather in October 2023 Weather in Washington, D.C.+79° Annapolis+77° Fairfax+77° Fredericksburg+77° Manassas+79° McLean+79° Mechanicsville+77° Vienna+77° Alexandria+79° Waldorf+77° Salisbury+75° Rockville+77° Woodmere+77° Windsor+75° world's temperature today Temperature units\"}, {'url': 'https://weatherspark.com/h/m/1828/2023/10/Historical-Weather-in-October-2023-in-Anaheim-California-United-States', 'content': 'October 2023 Weather History in Anaheim California, United States This report shows the past weather for Anaheim, providing a weather history for October 2023. It features all historical weather data series we have available, including the Anaheim temperature history for October 2023. Anaheim Temperature History October 2023 Hourly Temperature in October 2023 in Anaheim Cloud Cover in October 2023 in Anaheim Daily Precipitation in October 2023 in Anaheim Observed Weather in October 2023 in Anaheim Hours of Daylight and Twilight in October 2023 in Anaheim Solar Elevation and Azimuth in October 2023 in Anaheim Oct 2023 Humidity Comfort Levels in October 2023 in Anaheim Wind Speed in October 2023 in Anaheim Hourly Wind Speed in October 2023 in Anaheim'}]\u001b[0m" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2024-09-20 00:38:14,560 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: \n", - "2024-09-20 00:38:14,563 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: The\n", - "2024-09-20 00:38:14,599 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: current\n", - "2024-09-20 00:38:14,600 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: weather\n", - "2024-09-20 00:38:14,628 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: in\n", - "2024-09-20 00:38:14,630 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: California\n", - "2024-09-20 00:38:14,666 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: is\n", - "2024-09-20 00:38:14,669 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: as\n", - "2024-09-20 00:38:14,744 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: follows\n", - "2024-09-20 00:38:14,747 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: :\n", - "\n", - "\n", - "2024-09-20 00:38:14,779 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: -\n", - "2024-09-20 00:38:14,782 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: **\n", - "2024-09-20 00:38:14,785 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: Temperature\n", - "2024-09-20 00:38:14,787 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: **\n", - "2024-09-20 00:38:14,791 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: :\n", - "2024-09-20 00:38:14,795 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: \n", - "2024-09-20 00:38:14,890 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: 22\n", - "2024-09-20 00:38:14,891 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: .\n", - "2024-09-20 00:38:14,914 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: 3\n", - "2024-09-20 00:38:14,915 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: °C\n", - "2024-09-20 00:38:14,926 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: (\n", - "2024-09-20 00:38:14,929 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: 72\n", - "2024-09-20 00:38:14,932 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: .\n", - "2024-09-20 00:38:14,935 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: 1\n", - "2024-09-20 00:38:14,948 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: °F\n", - "2024-09-20 00:38:14,950 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: )\n", - "\n", - "2024-09-20 00:38:14,976 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: -\n", - "2024-09-20 00:38:14,978 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: **\n", - "2024-09-20 00:38:15,019 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: Condition\n", - "2024-09-20 00:38:15,021 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: **\n", - "2024-09-20 00:38:15,065 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: :\n", - "2024-09-20 00:38:15,068 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: Sunny\n", - "2024-09-20 00:38:15,116 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: \n", - "\n", - "2024-09-20 00:38:15,117 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: -\n", - "2024-09-20 00:38:15,134 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: **\n", - "2024-09-20 00:38:15,136 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: Wind\n", - "2024-09-20 00:38:15,158 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: **\n", - "2024-09-20 00:38:15,160 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: :\n", - "2024-09-20 00:38:15,191 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: \n", - "2024-09-20 00:38:15,194 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: 3\n", - "2024-09-20 00:38:15,238 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: .\n", - "2024-09-20 00:38:15,242 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: 4\n", - "2024-09-20 00:38:15,260 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: mph\n", - "2024-09-20 00:38:15,262 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: (\n", - "2024-09-20 00:38:15,321 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: 5\n", - "2024-09-20 00:38:15,325 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: .\n", - "2024-09-20 00:38:15,346 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: 4\n", - "2024-09-20 00:38:15,348 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: k\n", - "2024-09-20 00:38:15,368 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: ph\n", - "2024-09-20 00:38:15,370 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: )\n", - "2024-09-20 00:38:15,417 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: from\n", - "2024-09-20 00:38:15,420 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: the\n", - "2024-09-20 00:38:15,443 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: SSE\n", - "2024-09-20 00:38:15,445 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: \n", - "\n", - "2024-09-20 00:38:15,477 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: -\n", - "2024-09-20 00:38:15,480 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: **\n", - "2024-09-20 00:38:15,528 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: Humidity\n", - "2024-09-20 00:38:15,530 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: **\n", - "2024-09-20 00:38:15,547 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: :\n", - "2024-09-20 00:38:15,549 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: \n", - "2024-09-20 00:38:15,585 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: 35\n", - "2024-09-20 00:38:15,587 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: %\n", - "\n", - "2024-09-20 00:38:15,614 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: -\n", - "2024-09-20 00:38:15,615 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: **\n", - "2024-09-20 00:38:15,656 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: Pressure\n", - "2024-09-20 00:38:15,660 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: **\n", - "2024-09-20 00:38:15,682 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: :\n", - "2024-09-20 00:38:15,684 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: \n", - "2024-09-20 00:38:15,713 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: 101\n", - "2024-09-20 00:38:15,715 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: 3\n", - "2024-09-20 00:38:15,742 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: mb\n", - "2024-09-20 00:38:15,744 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: \n", + "\u001b[0m\u001b[36;1m\u001b[1;3m[{'url': 'https://www.weatherapi.com/', 'content': \"{'location': {'name': 'New Delhi', 'region': 'Delhi', 'country': 'India', 'lat': 28.6, 'lon': 77.2, 'tz_id': 'Asia/Kolkata', 'localtime_epoch': 1726991371, 'localtime': '2024-09-22 13:19'}, 'current': {'last_updated_epoch': 1726991100, 'last_updated': '2024-09-22 13:15', 'temp_c': 35.3, 'temp_f': 95.5, 'is_day': 1, 'condition': {'text': 'Mist', 'icon': '//cdn.weatherapi.com/weather/64x64/day/143.png', 'code': 1030}, 'wind_mph': 3.4, 'wind_kph': 5.4, 'wind_degree': 350, 'wind_dir': 'N', 'pressure_mb': 1007.0, 'pressure_in': 29.74, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 56, 'cloud': 50, 'feelslike_c': 38.1, 'feelslike_f': 100.6, 'windchill_c': 36.6, 'windchill_f': 98.0, 'heatindex_c': 40.7, 'heatindex_f': 105.3, 'dewpoint_c': 20.3, 'dewpoint_f': 68.5, 'vis_km': 3.5, 'vis_miles': 2.0, 'uv': 9.0, 'gust_mph': 3.9, 'gust_kph': 6.2}}\"}, {'url': 'https://mausam.imd.gov.in/delhiums/', 'content': 'Urban Meteorological Services for Delhi - NCR India Meteorological Department Ministry of Earth Sciences Government of India. ... Sep 22, 2024. Sep 23, 2024. ... Sep 25, 2024. Interactive Display of weather and Thunderstorm warnings. Current Weather Across Delhi - NCR. Delhi; Gurugram; Faridabad; Gautam Budh Nagar; Ghaziabad; New Delhi. 33.0 ...'}, {'url': 'https://www.msn.com/en-in/news/India/delhi-weather-and-aqi-today-warm-start-at-2705-c-check-weather-forecast-for-september-22-2024/ar-AA1qYihM', 'content': \"The temperature in Delhi today, on September 22, 2024, is 35.08 °C. The day's forecast indicates a minimum and maximum temperature of 27.05 °C and 37.13 °C, respectively. The relative humidity ...\"}, {'url': 'https://weatherspark.com/h/m/109174/2024/9/Historical-Weather-in-September-2024-in-New-Delhi-NCT-India', 'content': '°F September 2024 Weather History in New Delhi NCT, India Latest Report — 3:00 PM °F Dew Pt. 73°F\\xa0\\xa0oppressive No Report Overcast 8,000 ft Mostly Clear 1,500 ft Mostly Clear 3,000 ft This report shows the past weather for New Delhi, providing a weather history for September 2024. It features all historical weather data series we have available, including the New Delhi temperature history for September 2024. New Delhi Temperature History September 2024 Sep 65°F 65°F 70°F 70°F 75°F 75°F 80°F 80°F 85°F 85°F 90°F 90°F 95°F 95°F 100°F 100°F Hourly Temperature in September 2024 in New Delhi Sep'}, {'url': 'https://www.timeanddate.com/weather/india/new-delhi/hourly', 'content': 'Hour-by-Hour Forecast for New Delhi, Delhi, India. Weather Today Weather Hourly 14 Day Forecast Yesterday/Past Weather Climate (Averages) Currently: 84 °F. Passing clouds. (Weather station: New Delhi / Safdarjung, India). See more current weather.'}]\u001b[0m\u001b[32;1m\u001b[1;3mThe current weather in New Delhi, India, is as follows:\n", "\n", - "2024-09-20 00:38:15,787 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: -\n", - "2024-09-20 00:38:15,792 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: **\n", - "2024-09-20 00:38:15,826 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: Visibility\n", - "2024-09-20 00:38:15,828 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: **\n", - "2024-09-20 00:38:15,865 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: :\n", - "2024-09-20 00:38:15,868 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: \n", - "2024-09-20 00:38:15,902 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: 16\n", - "2024-09-20 00:38:15,904 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: km\n", - "2024-09-20 00:38:15,927 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: (\n", - "2024-09-20 00:38:15,928 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: 9\n", - "2024-09-20 00:38:15,969 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: miles\n", - "2024-09-20 00:38:15,971 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: )\n", + "- **Temperature**: 35.3°C (95.5°F)\n", + "- **Condition**: Mist\n", + "- **Feels Like**: 38.1°C (100.6°F)\n", + "- **Humidity**: 56%\n", + "- **Wind**: 3.4 mph (5.4 kph) from the North\n", + "- **Visibility**: 3.5 km\n", + "- **Pressure**: 1007 mb\n", "\n", + "The forecast for today indicates a minimum temperature of 27.05°C and a maximum of 37.13°C.\n", "\n", - "2024-09-20 00:38:15,991 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: For\n", - "2024-09-20 00:38:15,993 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: more\n", - "2024-09-20 00:38:16,021 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: detailed\n", - "2024-09-20 00:38:16,025 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: weather\n", - "2024-09-20 00:38:16,075 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: information\n", - "2024-09-20 00:38:16,078 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: ,\n", - "2024-09-20 00:38:16,108 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: you\n", - "2024-09-20 00:38:16,110 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: can\n", - "2024-09-20 00:38:16,154 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: check\n", - "2024-09-20 00:38:16,158 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: the\n", - "2024-09-20 00:38:16,212 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: following\n", - "2024-09-20 00:38:16,214 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: sources\n", - "2024-09-20 00:38:16,243 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: :\n", + "For more details, you can check the [India Meteorological Department](https://mausam.imd.gov.in/delhiums/) or other weather services.\u001b[0m\n", "\n", - "2024-09-20 00:38:16,245 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: -\n", - "2024-09-20 00:38:16,275 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: [\n", - "2024-09-20 00:38:16,277 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: Weather\n", - "2024-09-20 00:38:16,279 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: API\n", - "2024-09-20 00:38:16,315 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: ](\n", - "2024-09-20 00:38:16,316 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: https\n", - "2024-09-20 00:38:16,343 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: ://\n", - "2024-09-20 00:38:16,345 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: www\n", - "2024-09-20 00:38:16,368 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: .weather\n", - "2024-09-20 00:38:16,369 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: api\n", - "2024-09-20 00:38:16,425 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: .com\n", - "2024-09-20 00:38:16,427 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: /)\n", - "\n", - "2024-09-20 00:38:16,435 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: -\n", - "2024-09-20 00:38:16,438 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: [\n", - "2024-09-20 00:38:16,493 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: Time\n", - "2024-09-20 00:38:16,496 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: and\n", - "2024-09-20 00:38:16,529 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: Date\n", - "2024-09-20 00:38:16,531 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: ](\n", - "2024-09-20 00:38:16,620 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: https\n", - "2024-09-20 00:38:16,624 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: ://\n", - "2024-09-20 00:38:16,631 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: www\n", - "2024-09-20 00:38:16,633 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: .time\n", - "2024-09-20 00:38:16,678 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: and\n", - "2024-09-20 00:38:16,680 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: date\n", - "2024-09-20 00:38:16,699 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: .com\n", - "2024-09-20 00:38:16,702 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: /weather\n", - "2024-09-20 00:38:16,723 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: /\n", - "2024-09-20 00:38:16,725 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: usa\n", - "2024-09-20 00:38:16,778 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: /\n", - "2024-09-20 00:38:16,780 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: los\n", - "2024-09-20 00:38:16,834 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: -ang\n", - "2024-09-20 00:38:16,836 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: eles\n", - "2024-09-20 00:38:16,872 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: /h\n", - "2024-09-20 00:38:16,874 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: istor\n", - "2024-09-20 00:38:16,877 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: ic\n", - "2024-09-20 00:38:16,878 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: ?\n", - "2024-09-20 00:38:16,920 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: month\n", - "2024-09-20 00:38:16,923 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: =\n", - "2024-09-20 00:38:16,937 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: 10\n", - "2024-09-20 00:38:16,939 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: &\n", - "2024-09-20 00:38:16,972 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: year\n", - "2024-09-20 00:38:16,975 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: =\n", - "2024-09-20 00:38:17,004 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: 202\n", - "2024-09-20 00:38:17,007 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: 3\n", - "2024-09-20 00:38:17,053 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: )\n", - "\n", - "2024-09-20 00:38:17,057 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: -\n", - "2024-09-20 00:38:17,087 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: [\n", - "2024-09-20 00:38:17,092 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: M\n", - "2024-09-20 00:38:17,109 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: ete\n", - "2024-09-20 00:38:17,111 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: op\n", - "2024-09-20 00:38:17,184 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: rog\n", - "2024-09-20 00:38:17,187 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: ](\n", - "2024-09-20 00:38:17,224 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: https\n", - "2024-09-20 00:38:17,227 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: ://\n", - "2024-09-20 00:38:17,263 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: www\n", - "2024-09-20 00:38:17,265 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: .m\n", - "2024-09-20 00:38:17,348 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: ete\n", - "2024-09-20 00:38:17,350 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: op\n", - "2024-09-20 00:38:17,367 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: rog\n", - "2024-09-20 00:38:17,371 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: .com\n", - "2024-09-20 00:38:17,397 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: /weather\n", - "2024-09-20 00:38:17,400 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: /\n", - "2024-09-20 00:38:17,435 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: California\n", - "2024-09-20 00:38:17,440 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: -cal\n", - "2024-09-20 00:38:17,465 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: ifornia\n", - "2024-09-20 00:38:17,467 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: /month\n", - "2024-09-20 00:38:17,507 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: /oct\n", - "2024-09-20 00:38:17,510 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: ober\n", - "2024-09-20 00:38:17,542 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: /)\n", - "\n", - "2024-09-20 00:38:17,544 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: -\n", - "2024-09-20 00:38:17,568 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: [\n", - "2024-09-20 00:38:17,569 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: World\n", - "2024-09-20 00:38:17,608 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: Weather\n", - "2024-09-20 00:38:17,611 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: ](\n", - "2024-09-20 00:38:17,644 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: https\n", - "2024-09-20 00:38:17,646 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: ://\n", - "2024-09-20 00:38:17,678 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: world\n", - "2024-09-20 00:38:17,680 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: -weather\n", - "2024-09-20 00:38:17,713 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: .info\n", - "2024-09-20 00:38:17,715 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: /\n", - "2024-09-20 00:38:17,746 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: forecast\n", - "2024-09-20 00:38:17,748 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: /\n", - "2024-09-20 00:38:17,773 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: usa\n", - "2024-09-20 00:38:17,777 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: /cal\n", - "2024-09-20 00:38:17,831 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: ifornia\n", - "2024-09-20 00:38:17,833 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: /oct\n", - "2024-09-20 00:38:17,848 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: ober\n", - "2024-09-20 00:38:17,850 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: -\n", - "2024-09-20 00:38:17,880 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: 202\n", - "2024-09-20 00:38:17,883 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: 3\n", - "2024-09-20 00:38:17,912 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: /\n", - "2024-09-20 00:38:17,914 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: )\n", - "\n", - "\n", - "2024-09-20 00:38:17,950 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: If\n", - "2024-09-20 00:38:17,952 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: you\n", - "2024-09-20 00:38:17,986 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: need\n", - "2024-09-20 00:38:17,990 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: specific\n", - "2024-09-20 00:38:18,015 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: weather\n", - "2024-09-20 00:38:18,016 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: details\n", - "2024-09-20 00:38:18,080 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: for\n", - "2024-09-20 00:38:18,083 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: a\n", - "2024-09-20 00:38:18,087 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: particular\n", - "2024-09-20 00:38:18,090 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: city\n", - "2024-09-20 00:38:18,121 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: in\n", - "2024-09-20 00:38:18,124 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: California\n", - "2024-09-20 00:38:18,156 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: ,\n", - "2024-09-20 00:38:18,160 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: let\n", - "2024-09-20 00:38:18,193 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: me\n", - "2024-09-20 00:38:18,195 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: know\n", - "2024-09-20 00:38:18,197 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: !\n", - "2024-09-20 00:38:18,198 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - DEBUG - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onNewToken: \n", - "2024-09-20 00:38:18,200 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onLLMEnd: [[ChatGenerationChunk(text='The current weather in California is as follows:\\n\\n- **Temperature**: 22.3°C (72.1°F)\\n- **Condition**: Sunny\\n- **Wind**: 3.4 mph (5.4 kph) from the SSE\\n- **Humidity**: 35%\\n- **Pressure**: 1013 mb\\n- **Visibility**: 16 km (9 miles)\\n\\nFor more detailed weather information, you can check the following sources:\\n- [Weather API](https://www.weatherapi.com/)\\n- [Time and Date](https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023)\\n- [Meteoprog](https://www.meteoprog.com/weather/California-california/month/october/)\\n- [World Weather](https://world-weather.info/forecast/usa/california/october-2023/)\\n\\nIf you need specific weather details for a particular city in California, let me know!', generation_info={'finish_reason': 'stop', 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_1bb46167f9'}, message=AIMessageChunk(content='The current weather in California is as follows:\\n\\n- **Temperature**: 22.3°C (72.1°F)\\n- **Condition**: Sunny\\n- **Wind**: 3.4 mph (5.4 kph) from the SSE\\n- **Humidity**: 35%\\n- **Pressure**: 1013 mb\\n- **Visibility**: 16 km (9 miles)\\n\\nFor more detailed weather information, you can check the following sources:\\n- [Weather API](https://www.weatherapi.com/)\\n- [Time and Date](https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023)\\n- [Meteoprog](https://www.meteoprog.com/weather/California-california/month/october/)\\n- [World Weather](https://world-weather.info/forecast/usa/california/october-2023/)\\n\\nIf you need specific weather details for a particular city in California, let me know!', response_metadata={'finish_reason': 'stop', 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_1bb46167f9'}, id='run-f2f049b4-55c5-4805-964e-91d2f1731b11'))]]\n", - "2024-09-20 00:38:18,202 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainStart: content='The current weather in California is as follows:\\n\\n- **Temperature**: 22.3°C (72.1°F)\\n- **Condition**: Sunny\\n- **Wind**: 3.4 mph (5.4 kph) from the SSE\\n- **Humidity**: 35%\\n- **Pressure**: 1013 mb\\n- **Visibility**: 16 km (9 miles)\\n\\nFor more detailed weather information, you can check the following sources:\\n- [Weather API](https://www.weatherapi.com/)\\n- [Time and Date](https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023)\\n- [Meteoprog](https://www.meteoprog.com/weather/California-california/month/october/)\\n- [World Weather](https://world-weather.info/forecast/usa/california/october-2023/)\\n\\nIf you need specific weather details for a particular city in California, let me know!' response_metadata={'finish_reason': 'stop', 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_1bb46167f9'} id='run-f2f049b4-55c5-4805-964e-91d2f1731b11'\n", - "2024-09-20 00:38:18,203 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainEnd: return_values={'output': 'The current weather in California is as follows:\\n\\n- **Temperature**: 22.3°C (72.1°F)\\n- **Condition**: Sunny\\n- **Wind**: 3.4 mph (5.4 kph) from the SSE\\n- **Humidity**: 35%\\n- **Pressure**: 1013 mb\\n- **Visibility**: 16 km (9 miles)\\n\\nFor more detailed weather information, you can check the following sources:\\n- [Weather API](https://www.weatherapi.com/)\\n- [Time and Date](https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023)\\n- [Meteoprog](https://www.meteoprog.com/weather/California-california/month/october/)\\n- [World Weather](https://world-weather.info/forecast/usa/california/october-2023/)\\n\\nIf you need specific weather details for a particular city in California, let me know!'} log='The current weather in California is as follows:\\n\\n- **Temperature**: 22.3°C (72.1°F)\\n- **Condition**: Sunny\\n- **Wind**: 3.4 mph (5.4 kph) from the SSE\\n- **Humidity**: 35%\\n- **Pressure**: 1013 mb\\n- **Visibility**: 16 km (9 miles)\\n\\nFor more detailed weather information, you can check the following sources:\\n- [Weather API](https://www.weatherapi.com/)\\n- [Time and Date](https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023)\\n- [Meteoprog](https://www.meteoprog.com/weather/California-california/month/october/)\\n- [World Weather](https://world-weather.info/forecast/usa/california/october-2023/)\\n\\nIf you need specific weather details for a particular city in California, let me know!'\n", - "2024-09-20 00:38:18,204 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainEnd: return_values={'output': 'The current weather in California is as follows:\\n\\n- **Temperature**: 22.3°C (72.1°F)\\n- **Condition**: Sunny\\n- **Wind**: 3.4 mph (5.4 kph) from the SSE\\n- **Humidity**: 35%\\n- **Pressure**: 1013 mb\\n- **Visibility**: 16 km (9 miles)\\n\\nFor more detailed weather information, you can check the following sources:\\n- [Weather API](https://www.weatherapi.com/)\\n- [Time and Date](https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023)\\n- [Meteoprog](https://www.meteoprog.com/weather/California-california/month/october/)\\n- [World Weather](https://world-weather.info/forecast/usa/california/october-2023/)\\n\\nIf you need specific weather details for a particular city in California, let me know!'} log='The current weather in California is as follows:\\n\\n- **Temperature**: 22.3°C (72.1°F)\\n- **Condition**: Sunny\\n- **Wind**: 3.4 mph (5.4 kph) from the SSE\\n- **Humidity**: 35%\\n- **Pressure**: 1013 mb\\n- **Visibility**: 16 km (9 miles)\\n\\nFor more detailed weather information, you can check the following sources:\\n- [Weather API](https://www.weatherapi.com/)\\n- [Time and Date](https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023)\\n- [Meteoprog](https://www.meteoprog.com/weather/California-california/month/october/)\\n- [World Weather](https://world-weather.info/forecast/usa/california/october-2023/)\\n\\nIf you need specific weather details for a particular city in California, let me know!'\n", - "2024-09-20 00:38:18,206 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onAgentFinish: {'output': 'The current weather in California is as follows:\\n\\n- **Temperature**: 22.3°C (72.1°F)\\n- **Condition**: Sunny\\n- **Wind**: 3.4 mph (5.4 kph) from the SSE\\n- **Humidity**: 35%\\n- **Pressure**: 1013 mb\\n- **Visibility**: 16 km (9 miles)\\n\\nFor more detailed weather information, you can check the following sources:\\n- [Weather API](https://www.weatherapi.com/)\\n- [Time and Date](https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023)\\n- [Meteoprog](https://www.meteoprog.com/weather/California-california/month/october/)\\n- [World Weather](https://world-weather.info/forecast/usa/california/october-2023/)\\n\\nIf you need specific weather details for a particular city in California, let me know!'}\n", - "2024-09-20 00:38:18,207 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainEnd: {'output': 'The current weather in California is as follows:\\n\\n- **Temperature**: 22.3°C (72.1°F)\\n- **Condition**: Sunny\\n- **Wind**: 3.4 mph (5.4 kph) from the SSE\\n- **Humidity**: 35%\\n- **Pressure**: 1013 mb\\n- **Visibility**: 16 km (9 miles)\\n\\nFor more detailed weather information, you can check the following sources:\\n- [Weather API](https://www.weatherapi.com/)\\n- [Time and Date](https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023)\\n- [Meteoprog](https://www.meteoprog.com/weather/California-california/month/october/)\\n- [World Weather](https://world-weather.info/forecast/usa/california/october-2023/)\\n\\nIf you need specific weather details for a particular city in California, let me know!'}\n" + "\u001b[1m> Finished chain.\u001b[0m\n", + "{'messages': [HumanMessage(content='Whats the whether in New Delhi, India ?')], 'output': 'The current weather in New Delhi, India, is as follows:\\n\\n- **Temperature**: 35.3°C (95.5°F)\\n- **Condition**: Mist\\n- **Feels Like**: 38.1°C (100.6°F)\\n- **Humidity**: 56%\\n- **Wind**: 3.4 mph (5.4 kph) from the North\\n- **Visibility**: 3.5 km\\n- **Pressure**: 1007 mb\\n\\nThe forecast for today indicates a minimum temperature of 27.05°C and a maximum of 37.13°C.\\n\\nFor more details, you can check the [India Meteorological Department](https://mausam.imd.gov.in/delhiums/) or other weather services.'}\n" ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[32;1m\u001b[1;3mThe current weather in California is as follows:\n", - "\n", - "- **Temperature**: 22.3°C (72.1°F)\n", - "- **Condition**: Sunny\n", - "- **Wind**: 3.4 mph (5.4 kph) from the SSE\n", - "- **Humidity**: 35%\n", - "- **Pressure**: 1013 mb\n", - "- **Visibility**: 16 km (9 miles)\n", - "\n", - "For more detailed weather information, you can check the following sources:\n", - "- [Weather API](https://www.weatherapi.com/)\n", - "- [Time and Date](https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023)\n", - "- [Meteoprog](https://www.meteoprog.com/weather/California-california/month/october/)\n", - "- [World Weather](https://world-weather.info/forecast/usa/california/october-2023/)\n", - "\n", - "If you need specific weather details for a particular city in California, let me know!\u001b[0m\n", - "\n", - "\u001b[1m> Finished chain.\u001b[0m\n" - ] - }, - { - "data": { - "text/plain": [ - "{'messages': [HumanMessage(content='Whats the whether in california')],\n", - " 'output': 'The current weather in California is as follows:\\n\\n- **Temperature**: 22.3°C (72.1°F)\\n- **Condition**: Sunny\\n- **Wind**: 3.4 mph (5.4 kph) from the SSE\\n- **Humidity**: 35%\\n- **Pressure**: 1013 mb\\n- **Visibility**: 16 km (9 miles)\\n\\nFor more detailed weather information, you can check the following sources:\\n- [Weather API](https://www.weatherapi.com/)\\n- [Time and Date](https://www.timeanddate.com/weather/usa/los-angeles/historic?month=10&year=2023)\\n- [Meteoprog](https://www.meteoprog.com/weather/California-california/month/october/)\\n- [World Weather](https://world-weather.info/forecast/usa/california/october-2023/)\\n\\nIf you need specific weather details for a particular city in California, let me know!'}" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" } ], "source": [ - "# with logging\n", - "\n", - "from flo_ai.common.flo_langchain_logger import FloLangchainLogger\n", - "\n", - "flo = Flo.build(session, simple_weather_checking_agent)\n", - "\n", - "handler = FloLangchainLogger(log_level=\"INFO\")\n", - "\n", - "config = {\n", - " 'callbacks' : [handler]\n", - "}\n", - "\n", - "query=\"Whats the whether in california\"\n", - "\n", - "flo.invoke(query=query, config=config)" + "result = flo.invoke(\"Whats the whether in New Delhi, India ?\")\n", + "print(result)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## LLM Agent (agentic)\n", + "## LLM Agent (llm)\n", "\n", "Here we are gonna create a simple llm math assitant flo agent that can check answer any math question\n", "\n", @@ -601,7 +211,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ @@ -619,68 +229,68 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2024-09-20 00:45:06,709 - BUILDER - INFO - Building Flo instance from YAML\n", - "2024-09-20 00:45:06,728 - COMMON - INFO - Flo instance created for session dd5c4a4c-4390-46bc-945d-eb9474e63702\n" + "2024-09-22 13:22:46,658 - BUILDER - INFO - Building Flo instance from YAML\n", + "2024-09-22 13:22:46,661 - COMMON - INFO - Flo instance created for session e7f22b4d-7380-4d00-97c9-5267a468468a\n" ] }, + { + "data": { + "image/jpeg": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "flo = Flo.build(session, simple_llm_agent)\n", + "\n", + "flo.draw()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "2024-09-20 00:45:06,730 - COMMON - INFO - Invoking query for session dd5c4a4c-4390-46bc-945d-eb9474e63702: What is pythagorus theorum\n", - "2024-09-20 00:45:06,783 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainStart: {'messages': [HumanMessage(content='What is pythagorus theorum')]}\n", - "2024-09-20 00:45:06,786 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainStart: {'messages': [HumanMessage(content='What is pythagorus theorum')]}\n", - "2024-09-20 00:45:06,788 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainEnd: messages=[SystemMessage(content='You are a high school maths teacher. Answer any questions the students ask \\n'), HumanMessage(content='What is pythagorus theorum')]\n", - "2024-09-20 00:45:06,792 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onLLMStart: ['System: You are a high school maths teacher. Answer any questions the students ask \\n\\nHuman: What is pythagorus theorum']\n", - "2024-09-20 00:45:11,061 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onLLMEnd: [[ChatGeneration(text=\"Pythagoras' Theorem is a fundamental principle in geometry that relates to right-angled triangles. It states that in a right triangle, the square of the length of the hypotenuse (the side opposite the right angle) is equal to the sum of the squares of the lengths of the other two sides. \\n\\nThe theorem can be expressed with the formula:\\n\\n\\\\[ c^2 = a^2 + b^2 \\\\]\\n\\nwhere:\\n- \\\\( c \\\\) is the length of the hypotenuse,\\n- \\\\( a \\\\) and \\\\( b \\\\) are the lengths of the other two sides.\\n\\nThis theorem is useful for calculating the length of one side of a right triangle if the lengths of the other two sides are known. Would you like to see an example of how to use it?\", generation_info={'finish_reason': 'stop', 'logprobs': None}, message=AIMessage(content=\"Pythagoras' Theorem is a fundamental principle in geometry that relates to right-angled triangles. It states that in a right triangle, the square of the length of the hypotenuse (the side opposite the right angle) is equal to the sum of the squares of the lengths of the other two sides. \\n\\nThe theorem can be expressed with the formula:\\n\\n\\\\[ c^2 = a^2 + b^2 \\\\]\\n\\nwhere:\\n- \\\\( c \\\\) is the length of the hypotenuse,\\n- \\\\( a \\\\) and \\\\( b \\\\) are the lengths of the other two sides.\\n\\nThis theorem is useful for calculating the length of one side of a right triangle if the lengths of the other two sides are known. Would you like to see an example of how to use it?\", response_metadata={'token_usage': {'completion_tokens': 162, 'prompt_tokens': 34, 'total_tokens': 196, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_e9627b5346', 'finish_reason': 'stop', 'logprobs': None}, id='run-5851e0be-448a-4e3c-a517-187dcdfbea46-0', usage_metadata={'input_tokens': 34, 'output_tokens': 162, 'total_tokens': 196}))]]\n", - "2024-09-20 00:45:11,063 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainStart: content=\"Pythagoras' Theorem is a fundamental principle in geometry that relates to right-angled triangles. It states that in a right triangle, the square of the length of the hypotenuse (the side opposite the right angle) is equal to the sum of the squares of the lengths of the other two sides. \\n\\nThe theorem can be expressed with the formula:\\n\\n\\\\[ c^2 = a^2 + b^2 \\\\]\\n\\nwhere:\\n- \\\\( c \\\\) is the length of the hypotenuse,\\n- \\\\( a \\\\) and \\\\( b \\\\) are the lengths of the other two sides.\\n\\nThis theorem is useful for calculating the length of one side of a right triangle if the lengths of the other two sides are known. Would you like to see an example of how to use it?\" response_metadata={'token_usage': {'completion_tokens': 162, 'prompt_tokens': 34, 'total_tokens': 196, 'completion_tokens_details': {'reasoning_tokens': 0}}, 'model_name': 'gpt-4o-mini-2024-07-18', 'system_fingerprint': 'fp_e9627b5346', 'finish_reason': 'stop', 'logprobs': None} id='run-5851e0be-448a-4e3c-a517-187dcdfbea46-0' usage_metadata={'input_tokens': 34, 'output_tokens': 162, 'total_tokens': 196}\n", - "2024-09-20 00:45:11,064 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainEnd: Pythagoras' Theorem is a fundamental principle in geometry that relates to right-angled triangles. It states that in a right triangle, the square of the length of the hypotenuse (the side opposite the right angle) is equal to the sum of the squares of the lengths of the other two sides. \n", - "\n", - "The theorem can be expressed with the formula:\n", - "\n", - "\\[ c^2 = a^2 + b^2 \\]\n", - "\n", - "where:\n", - "- \\( c \\) is the length of the hypotenuse,\n", - "- \\( a \\) and \\( b \\) are the lengths of the other two sides.\n", - "\n", - "This theorem is useful for calculating the length of one side of a right triangle if the lengths of the other two sides are known. Would you like to see an example of how to use it?\n", - "2024-09-20 00:45:11,065 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onChainEnd: Pythagoras' Theorem is a fundamental principle in geometry that relates to right-angled triangles. It states that in a right triangle, the square of the length of the hypotenuse (the side opposite the right angle) is equal to the sum of the squares of the lengths of the other two sides. \n", - "\n", - "The theorem can be expressed with the formula:\n", - "\n", - "\\[ c^2 = a^2 + b^2 \\]\n", - "\n", - "where:\n", - "- \\( c \\) is the length of the hypotenuse,\n", - "- \\( a \\) and \\( b \\) are the lengths of the other two sides.\n", - "\n", - "This theorem is useful for calculating the length of one side of a right triangle if the lengths of the other two sides are known. Would you like to see an example of how to use it?\n" + "2024-09-22 13:22:49,285 - COMMON - INFO - Invoking query for session e7f22b4d-7380-4d00-97c9-5267a468468a: What is pythagorus theorum, just give me the formula\n" ] }, { "data": { "text/plain": [ - "\"Pythagoras' Theorem is a fundamental principle in geometry that relates to right-angled triangles. It states that in a right triangle, the square of the length of the hypotenuse (the side opposite the right angle) is equal to the sum of the squares of the lengths of the other two sides. \\n\\nThe theorem can be expressed with the formula:\\n\\n\\\\[ c^2 = a^2 + b^2 \\\\]\\n\\nwhere:\\n- \\\\( c \\\\) is the length of the hypotenuse,\\n- \\\\( a \\\\) and \\\\( b \\\\) are the lengths of the other two sides.\\n\\nThis theorem is useful for calculating the length of one side of a right triangle if the lengths of the other two sides are known. Would you like to see an example of how to use it?\"" + "'The Pythagorean theorem states that in a right triangle, the square of the length of the hypotenuse (the side opposite the right angle) is equal to the sum of the squares of the lengths of the other two sides. The formula is:\\n\\n\\\\( a^2 + b^2 = c^2 \\\\)\\n\\nwhere \\\\( c \\\\) is the length of the hypotenuse, and \\\\( a \\\\) and \\\\( b \\\\) are the lengths of the other two sides.'" ] }, - "execution_count": 7, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "flo = Flo.build(session, simple_llm_agent)\n", + "flo.invoke(\"What is pythagorus theorum, just give me the formula\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Tool Agent (tool)\n", "\n", - "flo.invoke(\"What is pythagorus theorum\")\n", - "# print(flo.invoke(\"What is pythagorus theorum\"))" + "Lets create a simple tool agent, which has just a tool and nothing else. The tool agent just executes a tool and nothing else. The tool can invoke llms within if in needs to" ] }, { @@ -699,36 +309,23 @@ "name": "stderr", "output_type": "stream", "text": [ - "2024-09-20 00:45:45,169 - SESSION - INFO - Tool 'printStateTool' registered for session dd5c4a4c-4390-46bc-945d-eb9474e63702\n", - "2024-09-20 00:45:45,170 - BUILDER - INFO - Building Flo instance from YAML\n", - "2024-09-20 00:45:45,173 - COMMON - INFO - Flo instance created for session dd5c4a4c-4390-46bc-945d-eb9474e63702\n", - "2024-09-20 00:45:45,175 - COMMON - INFO - Invoking query for session dd5c4a4c-4390-46bc-945d-eb9474e63702: Print what I am saying\n", - "2024-09-20 00:45:45,177 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onToolStart: {'messages': [HumanMessage(content='Print what I am saying')]}\n", - "2024-09-20 00:45:45,178 - FloLangChainLogger-dd5c4a4c-4390-46bc-945d-eb9474e63702 - INFO - Session ID: dd5c4a4c-4390-46bc-945d-eb9474e63702, onToolEnd: Tool call success\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'messages': [HumanMessage(content='Print what I am saying')]}\n" + "2024-09-23 14:19:07,287 - BUILDER - INFO - Building Flo instance from YAML\n", + "2024-09-23 14:19:07,290 - COMMON - INFO - Flo instance created for session a1e122c1-ed97-46c7-ad31-e67d373636be\n" ] }, { "data": { + "image/jpeg": "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", "text/plain": [ - "'Tool call success'" + "" ] }, - "execution_count": 8, "metadata": {}, - "output_type": "execute_result" + "output_type": "display_data" } ], "source": [ - "from typing import Optional, Type\n", - "from langchain.pydantic_v1 import BaseModel, Field\n", - "from langchain.tools import BaseTool, StructuredTool, tool\n", + "from langchain.tools import BaseTool\n", "\n", "class PrintStateTool(BaseTool):\n", " name = \"printStateTool\"\n", @@ -738,7 +335,7 @@ " self, **kwargs\n", " ) -> str:\n", " print(kwargs)\n", - " return \"Tool call success\"\n", + " return \"Print tool call success\"\n", " \n", "session.register_tool(\n", " name=\"printStateTool\", \n", @@ -758,7 +355,188 @@ "\n", "flo = Flo.build(session, simple_tool_agent)\n", "\n", - "flo.invoke(\"Print what I am saying\")" + "flo.draw()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-09-23 14:19:14,084 - COMMON - INFO - Invoking query for session a1e122c1-ed97-46c7-ad31-e67d373636be: Print what I am saying\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'messages': [HumanMessage(content='Print what I am saying')]}\n", + "Print tool call success\n" + ] + } + ], + "source": [ + "print(flo.invoke(\"Print what I am saying\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Reflection Agent (reflection)\n", + "These agents help evaluate a work based on certain criteria. In the graph you can see flo has automatically added reflection manager to handle retries and its count." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-09-22 13:22:57,657 - BUILDER - INFO - Building Flo instance from YAML\n", + "2024-09-22 13:22:57,664 - COMMON - INFO - Flo instance created for session 71b7747f-6530-45d7-b78d-54b8cc8bbb02\n" + ] + }, + { + "data": { + "image/jpeg": "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P/mVnXRj/wCUT9I+0LIiIudBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBV7MUbGLy3ftCA2XOibDeqs+PNE0ktcwet7S53T98CR4hqsKLOiuaJuu5h4rMUs5TbaoWY7UBJbzRnflcPFrh4tcPAtOxB6ELMUHldGYrLXTddFLTyBABuUZ315nAeAc5hHOB8jtx9CwzoiYABup88xo9XbxH+8xkrbo4VW6q3rHLlBsWhFqvifj8rpHSYyOP1TmDZ7xx9X9nlhLeSa7DDJ/sx15JHbfTt4+Ctn3E2ParPf8ArQ/VJ1eH4/4ktGa0KFzWo20ZvMKLG5DNSN3ipNfty7+Ekp69nGPW4jc7bNDnENOD9wgl6WdQZ21HtsWG72O4/liax3/IqZxGCoYGu6HH1Y6zHHmeWjdz3eG7nHq4/SSSlsKjbfS+3P8Au82Q89P4VuCx5hMvnFmWR09mwW8pmled3O23Ow9QG52aGj1KTRFpqqmqZqnegiIsQREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREGvuO5aOHo5iQO+cP4fL3nV29Y/wD78vgtgrX3Hbf4PRty/fnD/GAI++dX5f8A/fk6rYKAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiINeceQDw7G7mt/wBNYbq4b/8AedXothrXnHnb4OxuSB31hvAb/wDelVbDQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBEWHl8rXwmOmu2nOEMQG4Y0uc4kgNa0DqSSQAPWSFYiaptG8ZiKlP1DqubZ8OKxVdjuojsXZHSNH+9yx7b/KASPkJXz37rD+IYP3ub6tdeq15xxhbLuipHfusP4hg/e5vq0791h/EMH73N9Wmq15xxgsu6Kkd+6w/iGD97m+rTv3WH8Qwfvc31aarXnHGCzn7y5fKfn4KSYbTc+jpctQyZqZKLLC6ImCStcZK+DkMTtztEz0t+nab7dOu8fJ/wCK1/jZwyx+sb2m3aXiyL3uqU33POXyQA8olJ5GcvMQ7YbHoAd/S6a78ongrkfKP0fTwWcrYmiadxluC7WsSGWP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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "yaml_data = \"\"\"\n", + "apiVersion: flo/alpha-v1\n", + "kind: FloRoutedTeam\n", + "name: adding-team\n", + "team:\n", + " name: EssayTeam\n", + " agents:\n", + " - name: EssayWriter\n", + " kind: llm\n", + " job: >\n", + " You are an essay assistant tasked with writing excellent 300-words essays. Generate the best essay possible for the user's request. \n", + " If the you are provided critique view, respond with a revised version of your previous attempts. A maximum of total 100 words\n", + " - name: ReflectionAgent\n", + " kind: reflection\n", + " retry: 1\n", + " to: \n", + " - name: EssayWriter\n", + " job: >\n", + " You are a teacher grading an essay submission. Generate critique and recommendations for the user's submission.\n", + " Provide detailed recommendations, including requests for length, depth, style, etc.\n", + " - name: FinalEssayProducer\n", + " kind: llm\n", + " job: >\n", + " Generate the final assay to be returned to the user\n", + " router:\n", + " name: router\n", + " kind: linear\n", + "\"\"\"\n", + "\n", + "input_prompt = \"\"\"\n", + "Question: Write me an interesting blog about latest advancements in agentic AI by reasearching the internet\n", + "\"\"\"\n", + "\n", + "llm = ChatOpenAI(temperature=0, model_name='gpt-4o-mini')\n", + "session = FloSession(llm).register_tool(\n", + " name=\"TavilySearchResults\", \n", + " tool=TavilySearchResults()\n", + ")\n", + "\n", + "flo: Flo = Flo.build(session, yaml=yaml_data)\n", + "flo.draw()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Delegator Agent (delegator)\n", + "\n", + "Using these agents you can do redirects, this can help redirecting calls as well as retrying previous steps" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-09-22 13:25:01,619 - BUILDER - INFO - Building Flo instance from YAML\n", + "2024-09-22 13:25:01,627 - COMMON - INFO - Flo instance created for session 11351ff8-1110-4724-9e15-042eeccd99b4\n" + ] + }, + { + "data": { + "image/jpeg": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "yaml_data = \"\"\"\n", + "apiVersion: flo/alpha-v1\n", + "kind: FloRoutedTeam\n", + "name: adding-team\n", + "team:\n", + " name: EssayTeam\n", + " agents:\n", + " - name: EssayWriter\n", + " kind: llm\n", + " job: >\n", + " You are an essay assistant tasked with writing excellent 300 words essay. Generate the best essay possible for the user's request. \n", + " If the you are provided critique view, respond with a revised version of your previous attempts. A maximum of total 100 words\n", + " - name: DelegatorAgent\n", + " kind: delegator\n", + " retry: 1\n", + " to: \n", + " - name: EssayWriter\n", + " job: >\n", + " You are a teacher grading an essay submission. Score the essay between 1 to 10, with 10 being perfect\n", + " If the score is greater than 7 sent it to FinalEssayProducer\n", + " else if its less than or equal to 7 sent it to EssayWriter with suggestions to change\n", + " - name: FinalEssayProducer\n", + " kind: llm\n", + " job: >\n", + " Generate the final assay to be returned to the user\n", + " router:\n", + " name: router\n", + " kind: linear\n", + "\"\"\"\n", + "\n", + "input_prompt = \"\"\"\n", + "Question: Write me an interesting blog about latest advancements in agentic AI by reasearching the internet\n", + "\"\"\"\n", + "\n", + "llm = ChatOpenAI(temperature=0, model_name='gpt-4o-mini')\n", + "session = FloSession(llm).register_tool(\n", + " name=\"TavilySearchResults\", \n", + " tool=TavilySearchResults()\n", + ")\n", + "\n", + "flo: Flo = Flo.build(session, yaml=yaml_data)\n", + "flo.draw()\n", + "# data = flo.invoke(input_prompt)\n", + "# print((data['messages'][-1]).content)" ] } ], diff --git a/examples/agentic_rag.ipynb b/examples/agentic_rag.ipynb new file mode 100644 index 00000000..09f3b3f8 --- /dev/null +++ b/examples/agentic_rag.ipynb @@ -0,0 +1,251 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Agentic RAG implemented using FloAI\n", + "\n", + "FloAI has just made implementing agentic RAG simple and easy to manage. The Diagram shows what we are going to implement:\n", + "\n", + "
\n", + " \"Sample\n", + "
\n", + "\n", + "To implement this we use the following components, already available in flo-ai:\n", + "\n", + "1. `tool` agent: This will be a tool agent to retrieve the records from vector store\n", + "2. `delegator` agent: The agent will check if the retrieved records are relevent, else it will re-write the query and send it back for re-retrieval\n", + "3. `llm` agent: This will generate the output from the relevant documents" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from flo_ai import Flo\n", + "from flo_ai import FloSession\n", + "from langchain_openai import ChatOpenAI, OpenAIEmbeddings\n", + "from langchain_chroma import Chroma\n", + "from langchain_community.document_loaders import TextLoader\n", + "from langchain_community.embeddings.sentence_transformer import (\n", + " SentenceTransformerEmbeddings,\n", + ")\n", + "from langchain_text_splitters import CharacterTextSplitter\n", + "\n", + "from dotenv import load_dotenv\n", + "load_dotenv()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setting up Vector Store with Sample Data\n", + "\n", + "Using Chroma is this example" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/vizsatiz/Documents/hub/flo/.venv/lib/python3.11/site-packages/sentence_transformers/cross_encoder/CrossEncoder.py:11: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from tqdm.autonotebook import tqdm, trange\n", + "/Users/vizsatiz/Documents/hub/flo/.venv/lib/python3.11/site-packages/transformers/tokenization_utils_base.py:1601: FutureWarning: `clean_up_tokenization_spaces` was not set. It will be set to `True` by default. This behavior will be depracted in transformers v4.45, and will be then set to `False` by default. For more details check this issue: https://github.com/huggingface/transformers/issues/31884\n", + " warnings.warn(\n" + ] + } + ], + "source": [ + "# load the document and split it into chunks\n", + "loader = TextLoader(\"./rag_document.txt\")\n", + "documents = loader.load()\n", + "\n", + "# split it into chunks\n", + "text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)\n", + "docs = text_splitter.split_documents(documents)\n", + "\n", + "# create the open-source embedding function\n", + "embedding_function = SentenceTransformerEmbeddings(model_name=\"all-MiniLM-L6-v2\")\n", + "\n", + "# load it into Chroma\n", + "db = Chroma.from_documents(docs, embedding_function)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Creating the retrival tool\n", + "\n", + "This tool will retrive the records from vector db" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-09-23 14:42:29,261 - SESSION - INFO - New FloSession created with ID: fb386a6f-07b9-4cf4-a83a-21f322c7289c\n", + "2024-09-23 14:42:29,359 - SESSION - INFO - Tool 'HousingLoanTool' registered for session fb386a6f-07b9-4cf4-a83a-21f322c7289c\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from flo_ai.retrievers.flo_retriever import FloRagBuilder\n", + "from flo_ai.retrievers.flo_compression_pipeline import FloCompressionPipeline\n", + "\n", + "llm = ChatOpenAI(temperature=0, model_name='gpt-4o-mini')\n", + "session = FloSession(llm)\n", + "builder = FloRagBuilder(session, db.as_retriever())\n", + "compression_pipeline = FloCompressionPipeline(OpenAIEmbeddings(model=\"text-embedding-3-small\"))\n", + "compression_pipeline.add_embedding_reduntant_filter()\n", + "compression_pipeline.add_embedding_relevant_filter()\n", + "\n", + "retriever_tool = builder.with_compression(compression_pipeline).build_retriever_tool(name=\"HousingLoanRetreiver\",\n", + " description=\"Tool to fetch data around housing loans\")\n", + "session.register_tool(name=\"HousingLoanTool\", tool=retriever_tool)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Creating the flo\n", + "\n", + "This follow as you can see consist of the following components:\n", + "\n", + "1. HousingLoanRetriver: This is a `tool agent`, with ability to retrieve from vector store\n", + "2. RelevancyChecker: This is a `delegator agent` with ability to delegate based on relevancy\n", + "3. ResponseGenerator: This is a `llm agent` with ability to response based on documents" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-09-23 14:45:06,389 - BUILDER - INFO - Building Flo instance from YAML\n", + "2024-09-23 14:45:06,398 - COMMON - INFO - Flo instance created for session fb386a6f-07b9-4cf4-a83a-21f322c7289c\n" + ] + }, + { + "data": { + "image/jpeg": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "agent_yaml = \"\"\"\n", + "apiVersion: flo/alpha-v1\n", + "kind: FloRoutedTeam\n", + "name: agentic-rag\n", + "team:\n", + " name: AgenticRAGTeam\n", + " router:\n", + " name: SupportSupervisor\n", + " kind: linear\n", + " agents:\n", + " - name: HousingLoanRetriver\n", + " kind: tool\n", + " job: Fetching the loan information from the loan tool\n", + " tools:\n", + " - name: HousingLoanTool\n", + " - name: RelevancyChecker\n", + " kind: delegator\n", + " to:\n", + " - name: HousingLoanRetriver\n", + " - name: ResponseGenerator\n", + " retry: 1\n", + " job: >\n", + " Your job is to check if the records fetched by the retriever are relevent to the question.\n", + " If its not relevant re-write the query send to HousingLoanRetriver for re-retrieval.\n", + " If its relevant then send to ResponseGenerator for response generation\n", + " - name: ResponseGenerator\n", + " kind: llm\n", + " job: Based on the documents given answer the user question that was asked\n", + "\"\"\"\n", + "\n", + "flo = Flo.build(session, agent_yaml)\n", + "\n", + "flo.draw()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2024-09-23 14:45:11,703 - COMMON - INFO - Invoking query for session fb386a6f-07b9-4cf4-a83a-21f322c7289c: Whats the interest rate for housing loan ?\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'messages': [HumanMessage(content='Whats the interest rate for housing loan ?'), HumanMessage(content='You can use any one of the ways to repay the loan:\\n \\n Cheques\\n Standing instructions at your branch\\n FedNet - Internet Banking\\n Automated Payment through ECS\\n Mobile Banking\\n\\n Housing loan interest rates will change subject to the changes made by Bank/RBI from time to time. \\n\\nPresent Repo Rate\\t 6.50% (p.a)\\n \\n\\nLoan scheme\\n\\nInterest Rate (%) * \\n\\nHome Loan \\n\\n8.80 (Repo Rate+ 2.30) Onwards \\n\\n*T&C Apply\\nHousing Loan\\n\\nYour dream home is never far away! Get hassle free home loans from Federal Bank to turn your dream home into reality. We assist you to realize your dream home. Avail your Housing Loan from us at competitive interest rates. The loan scheme assists borrowers for construction of house, acquisition of land & construction of house, repairs / renovation / remodeling / extension of house, reimbursement of debt incurred for construction / purchase / furnishing / beautification / purchase of flat / villa / house plots / takeover of housing loans / supplementary housing loan to employees of well-run companies / purchase of house plot for subsequent construction of house etc.', name='HousingLoanRetriver'), HumanMessage(content='The interest rate for housing loans currently starts at 8.80% per annum, which is based on the present repo rate of 6.50% plus an additional margin of 2.30%. Please note that interest rates may change based on adjustments made by the bank or the Reserve Bank of India (RBI) over time.', name='ResponseGenerator')], 'next': 'ResponseGenerator', 'loop_tracker': {'RelevancyChecker': 1}}\n" + ] + } + ], + "source": [ + "print(flo.invoke(\"Whats the interest rate for housing loan ?\"))" + ] + } + ], + "metadata": { + "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.11.6" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/delegator_example.py b/examples/delegator_example.py new file mode 100644 index 00000000..d1a3b4cf --- /dev/null +++ b/examples/delegator_example.py @@ -0,0 +1,51 @@ +from flo_ai.core import Flo +from flo_ai import FloSession +from langchain_openai import ChatOpenAI +from langchain_community.tools.tavily_search.tool import TavilySearchResults +from dotenv import load_dotenv +load_dotenv() + +yaml_data = """ +apiVersion: flo/alpha-v1 +kind: FloRoutedTeam +name: adding-team +team: + name: EssayTeam + agents: + - name: EssayWriter + kind: llm + job: > + You are an essay assistant tasked with writing excellent 300 words essay. Generate the best essay possible for the user's request. + If the you are provided critique view, respond with a revised version of your previous attempts. A maximum of total 100 words + - name: DelegatorAgent + kind: delegator + retry: 1 + to: + - name: EssayWriter + job: > + You are a teacher grading an essay submission. Score the essay between 1 to 10, with 10 being perfect + If the score is greater than 7 sent it to FinalEssayProducer + else if its less than or equal to 7 sent it to EssayWriter with suggestions to change + - name: FinalEssayProducer + kind: llm + job: > + Generate the final assay to be returned to the user + router: + name: router + kind: linear +""" + +input_prompt = """ +Question: Write me an interesting blog about latest advancements in agentic AI by reasearching the internet +""" + +llm = ChatOpenAI(temperature=0, model_name='gpt-4o-mini') +session = FloSession(llm).register_tool( + name="TavilySearchResults", + tool=TavilySearchResults() +) + +flo: Flo = Flo.build(session, yaml=yaml_data) +flo.draw_to_file("delegate.png", xray=True) +# data = flo.invoke(input_prompt) +# print((data['messages'][-1]).content) \ No newline at end of file diff --git a/examples/linear_router_team.py b/examples/linear_router_team.py index 27d0af67..b5b183d3 100644 --- a/examples/linear_router_team.py +++ b/examples/linear_router_team.py @@ -42,14 +42,14 @@ async def _arun( name: data-processing-pipline kind: linear agents: - - name: Reasercher - job: Do a research on the internet and find articles of relevent to the topic asked by the user, always try to find the latest information on the same - tools: - - name: TavilySearchResults - - name: Blogger - job: From the documents provider by the researcher write a blog of 300 words with can be readily published, make in engaging and add reference links to original blogs - tools: - - name: TavilySearchResults + - name: Reasercher + job: Do a research on the internet and find articles of relevent to the topic asked by the user, always try to find the latest information on the same + tools: + - name: TavilySearchResults + - name: Blogger + job: From the documents provider by the researcher write a blog of 300 words with can be readily published, make in engaging and add reference links to original blogs + tools: + - name: TavilySearchResults """ input_prompt = """ diff --git a/examples/rag_tool.py b/examples/rag_tool.py new file mode 100644 index 00000000..1160fa43 --- /dev/null +++ b/examples/rag_tool.py @@ -0,0 +1,70 @@ +from langchain.tools import BaseTool +from flo_ai import Flo +from flo_ai import FloSession +from flo_ai.common.flo_logger import get_logger +from flo_ai.common.flo_langchain_logger import FloLangchainLogger +from langchain_openai import ChatOpenAI, OpenAIEmbeddings +from langchain_openai import ChatOpenAI, OpenAIEmbeddings +from langchain_chroma import Chroma +from langchain_community.document_loaders import TextLoader +from langchain_community.embeddings.sentence_transformer import ( + SentenceTransformerEmbeddings, +) +from langchain_text_splitters import CharacterTextSplitter + +from dotenv import load_dotenv +load_dotenv() + + + +llm = ChatOpenAI(temperature=0, model_name='gpt-4o-mini') + +session = FloSession( + llm, + log_level="ERROR" +) + +# load the document and split it into chunks +loader = TextLoader("./examples/rag_document.txt") +documents = loader.load() + +# split it into chunks +text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0) +docs = text_splitter.split_documents(documents) + +# create the open-source embedding function +embedding_function = SentenceTransformerEmbeddings(model_name="all-MiniLM-L6-v2") + +# load it into Chroma +db = Chroma.from_documents(docs, embedding_function) + +from flo_ai.retrievers.flo_retriever import FloRagBuilder +from flo_ai.retrievers.flo_compression_pipeline import FloCompressionPipeline + +llm = ChatOpenAI(temperature=0, model_name='gpt-4o-mini') +session = FloSession(llm) +builder = FloRagBuilder(session, db.as_retriever()) +compression_pipeline = FloCompressionPipeline(OpenAIEmbeddings(model="text-embedding-3-small")) +compression_pipeline.add_embedding_reduntant_filter() +compression_pipeline.add_embedding_relevant_filter() +# Reranking + +retriever_tool = builder.with_compression(compression_pipeline).build_rag_tool(name="HousingLoanRetreiver", + description="Tool to fetch data around housing loans") +session.register_tool(name="HousingLoanTool", tool=retriever_tool) + +simple_tool_agent = """ +apiVersion: flo/alpha-v1 +kind: FloAgent +name: llm-assistant +agent: + name: tool-get-loan + kind: agentic + job: To retrieve and answer user questions + tools: + - name: HousingLoanTool +""" + +flo = Flo.build(session, simple_tool_agent) + +print(flo.invoke("Whats interest rate on loan")) \ No newline at end of file diff --git a/examples/rag_with_reranking.py b/examples/rag_with_reranking.py index ef128dfb..91999dd1 100644 --- a/examples/rag_with_reranking.py +++ b/examples/rag_with_reranking.py @@ -47,10 +47,15 @@ ] ) +from langchain.schema import BaseMessage compression_pipeline = FloCompressionPipeline(OpenAIEmbeddings(model="text-embedding-3-small")) compression_pipeline.add_embedding_reduntant_filter() compression_pipeline.add_embedding_relevant_filter() -rag = rag_builder.with_prompt(custom_prompt).with_multi_query().with_compression(compression_pipeline).build_rag() +rag = rag_builder.with_prompt( + custom_prompt +).with_multi_query().with_compression( + compression_pipeline + ).build_rag() print(rag.invoke({ "question": "What are the documents applying for housing loan" })) diff --git a/examples/reflection_example.py b/examples/reflection_example.py new file mode 100644 index 00000000..ba893af8 --- /dev/null +++ b/examples/reflection_example.py @@ -0,0 +1,50 @@ +from flo_ai.core import Flo +from flo_ai import FloSession +from langchain_openai import ChatOpenAI +from langchain_community.tools.tavily_search.tool import TavilySearchResults +from dotenv import load_dotenv +load_dotenv() + +yaml_data = """ +apiVersion: flo/alpha-v1 +kind: FloRoutedTeam +name: adding-team +team: + name: EssayTeam + agents: + - name: EssayWriter + kind: llm + job: > + You are an essay assistant tasked with writing excellent 300-words essays. Generate the best essay possible for the user's request. + If the you are provided critique view, respond with a revised version of your previous attempts. A maximum of total 100 words + - name: ReflectionAgent + kind: reflection + retry: 1 + to: + - name: EssayWriter + job: > + You are a teacher grading an essay submission. Generate critique and recommendations for the user's submission. + Provide detailed recommendations, including requests for length, depth, style, etc. + - name: FinalEssayProducer + kind: llm + job: > + Generate the final assay to be returned to the user + router: + name: router + kind: linear +""" + +input_prompt = """ +Question: Write me an interesting blog about latest advancements in agentic AI by reasearching the internet +""" + +llm = ChatOpenAI(temperature=0, model_name='gpt-4o-mini') +session = FloSession(llm).register_tool( + name="TavilySearchResults", + tool=TavilySearchResults() +) + +flo: Flo = Flo.build(session, yaml=yaml_data) +flo.draw_to_file("event.png", xray=True) +data = flo.invoke(input_prompt) +print((data['messages'][-1]).content) \ No newline at end of file diff --git a/examples/tool_agent.py b/examples/tool_agent.py new file mode 100644 index 00000000..abfda1b0 --- /dev/null +++ b/examples/tool_agent.py @@ -0,0 +1,54 @@ +from flo_ai import Flo +from flo_ai import FloSession +from flo_ai.common.flo_logger import get_logger +from flo_ai.common.flo_langchain_logger import FloLangchainLogger +from langchain_openai import ChatOpenAI, OpenAIEmbeddings + +from dotenv import load_dotenv +load_dotenv() + +from langchain_community.tools.tavily_search.tool import TavilySearchResults +from flo_ai.common.flo_langchain_logger import FloLangchainLogger + +llm = ChatOpenAI(temperature=0, model_name='gpt-4o-mini') + +session = FloSession( + llm, + log_level="ERROR" +) + +from langchain.tools import BaseTool + +class PrintStateTool(BaseTool): + name = "printStateTool" + description = "Just print the state" + + def _run( + self, **kwargs + ) -> str: + return "Print tool call success" + +session.register_tool( + name="printStateTool", + tool=PrintStateTool() +) + +simple_tool_agent = """ +apiVersion: flo/alpha-v1 +kind: FloRoutedTeam +name: llm-assistant +team: + name: tool-to-print-state + router: + name: LinearRouter + kind: linear + agents: + - name: tool-to-print + kind: tool + tools: + - name: printStateTool +""" + +flo = Flo.build(session, simple_tool_agent) + +print(flo.invoke("Testing ....")) \ No newline at end of file diff --git a/flo_ai/builders/yaml_builder.py b/flo_ai/builders/yaml_builder.py index 2772de37..86ad74b2 100644 --- a/flo_ai/builders/yaml_builder.py +++ b/flo_ai/builders/yaml_builder.py @@ -1,53 +1,35 @@ from flo_ai.models.flo_team import FloTeam from flo_ai.models.flo_agent import FloAgent -from flo_ai.yaml.flo_team_builder import (FloRoutedTeamConfig, TeamConfig, - AgentConfig, FloAgentConfig) +from flo_ai.yaml.config import (FloRoutedTeamConfig, TeamConfig, AgentConfig, FloAgentConfig) from flo_ai.models.flo_executable import ExecutableFlo -from flo_ai.models.flo_planner import FloPlannerBuilder from flo_ai.state.flo_session import FloSession from flo_ai.router.flo_router_factory import FloRouterFactory from flo_ai.factory.agent_factory import AgentFactory -from typing import Union -def build_supervised_team( - session: FloSession, - flo_config: Union[FloRoutedTeamConfig, FloAgentConfig]) -> ExecutableFlo: +def build_supervised_team(session: FloSession) -> ExecutableFlo: + flo_config = session.config if isinstance(flo_config, FloRoutedTeamConfig): team_config: TeamConfig = flo_config.team - team = parse_and_build_subteams(session, team_config, session.tools) + team = parse_and_build_subteams(session, team_config) return team elif isinstance(flo_config, FloAgentConfig): agent_config: AgentConfig = flo_config.agent - agent = AgentFactory.create(session, agent_config, session.tools) + agent = AgentFactory.create(session, agent_config) return agent -def parse_and_build_subteams( - session: FloSession, - team_config: TeamConfig, - tool_map) -> ExecutableFlo: +def parse_and_build_subteams(session: FloSession, team_config: TeamConfig) -> ExecutableFlo: flo_team = None if team_config.agents: - agents = [] - for agent in team_config.agents: - flo_agent: FloAgent = AgentFactory.create(session, agent, tool_map) - agents.append(flo_agent) - flo_team = FloTeam.Builder( - session=session, - name=team_config.name, - members=agents - ).build() + members = [AgentFactory.create(session, agent) for agent in team_config.agents] + flo_team = FloTeam.Builder(team_config, members=members).build() router = FloRouterFactory.create(session, team_config, flo_team) flo_routed_team = router.build_routed_team() else: flo_teams = [] for subteam in team_config.subteams: - flo_subteam = parse_and_build_subteams(session, subteam, tool_map) + flo_subteam = parse_and_build_subteams(session, subteam) flo_teams.append(flo_subteam) - flo_team = FloTeam.Builder( - session=session, - name=team_config.name, - members=flo_teams - ).build() + flo_team = FloTeam.Builder(team_config, members=flo_teams).build() router = FloRouterFactory.create(session, team_config, flo_team) flo_routed_team = router.build_routed_team() return flo_routed_team diff --git a/flo_ai/common/flo_langchain_logger.py b/flo_ai/common/flo_langchain_logger.py index 022aee7a..b8a07c31 100644 --- a/flo_ai/common/flo_langchain_logger.py +++ b/flo_ai/common/flo_langchain_logger.py @@ -14,40 +14,40 @@ def __init__(self, self.session_id = session_id def on_llm_start(self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any) -> None: - self.logger.info(f"Session ID: {self.session_id}: onLLMStart: {prompts}") + self.logger.debug(f"Session ID: {self.session_id}: onLLMStart: {prompts}") def on_llm_new_token(self, token: str, **kwargs: Any) -> None: self.logger.debug(f"Session ID: {self.session_id}: onNewToken: {token}") def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None: - self.logger.info(f"Session ID: {self.session_id}: onLLMEnd: {response.generations}") + self.logger.debug(f"Session ID: {self.session_id}: onLLMEnd: {response.generations}") def on_llm_error(self, error: Union[Exception, KeyboardInterrupt], **kwargs: Any) -> None: self.logger.error(f"Session ID: {self.session_id}: onLLMError: {error}") def on_chain_start(self, serialized: Dict[str, Any], inputs: Dict[str, Any], **kwargs: Any) -> None: - self.logger.info(f"Session ID: {self.session_id}: onChainStart: {inputs}") + self.logger.debug(f"Session ID: {self.session_id}: onChainStart: {inputs}") def on_chain_end(self, outputs: Dict[str, Any], **kwargs: Any) -> None: - self.logger.info(f"Session ID: {self.session_id}: onChainEnd: {outputs}") + self.logger.debug(f"Session ID: {self.session_id}: onChainEnd: {outputs}") def on_chain_error(self, error: Union[Exception, KeyboardInterrupt], **kwargs: Any) -> None: self.logger.error(f"Session ID: {self.session_id}: onChainError: {error}") def on_tool_start(self, serialized: Dict[str, Any], input_str: str, **kwargs: Any) -> None: - self.logger.info(f"Session ID: {self.session_id}: onToolStart: {input_str}") + self.logger.debug(f"Session ID: {self.session_id}: onToolStart: {input_str}") def on_tool_end(self, output: str, **kwargs: Any) -> None: - self.logger.info(f"Session ID: {self.session_id}: onToolEnd: {output}") + self.logger.debug(f"Session ID: {self.session_id}: onToolEnd: {output}") def on_tool_error(self, error: Union[Exception, KeyboardInterrupt], **kwargs: Any) -> None: self.logger.error(f"Session ID: {self.session_id}: onToolError: {error}") def on_text(self, text: str, **kwargs: Any) -> None: - self.logger.info(f"Session ID: {self.session_id}: onText: {text}") + self.logger.debug(f"Session ID: {self.session_id}: onText: {text}") def on_agent_action(self, action: AgentAction, **kwargs: Any) -> Any: - self.logger.info(f"Session ID: {self.session_id}: onAgentAction: {action.tool} - {action.tool_input}") + self.logger.debug(f"Session ID: {self.session_id}: onAgentAction: {action.tool} - {action.tool_input}") def on_agent_finish(self, finish: AgentFinish, **kwargs: Any) -> None: - self.logger.info(f"Session ID: {self.session_id}: onAgentFinish: {finish.return_values}") \ No newline at end of file + self.logger.debug(f"Session ID: {self.session_id}: onAgentFinish: {finish.return_values}") \ No newline at end of file diff --git a/flo_ai/constants/flo_node_contants.py b/flo_ai/constants/flo_node_contants.py new file mode 100644 index 00000000..6106d5c3 --- /dev/null +++ b/flo_ai/constants/flo_node_contants.py @@ -0,0 +1,2 @@ +INTERNAL_NODE_REFLECTION_MANAGER = "f/ReflectionManager" +INTERNAL_NODE_DELEGATION_MANAGER = "f/DelegationManager" \ No newline at end of file diff --git a/flo_ai/core.py b/flo_ai/core.py index 1f8210e2..f857bae9 100644 --- a/flo_ai/core.py +++ b/flo_ai/core.py @@ -1,4 +1,4 @@ -from flo_ai.yaml.flo_team_builder import to_supervised_team +from flo_ai.yaml.config import to_supervised_team from flo_ai.builders.yaml_builder import build_supervised_team, FloRoutedTeamConfig from typing import Any, Iterator, Union from flo_ai.state.flo_session import FloSession @@ -11,9 +11,10 @@ def __init__(self, session: FloSession, config: FloRoutedTeamConfig, log_level: str = "INFO") -> None: - self.config = config self.session = session - self.runnable: ExecutableFlo = build_supervised_team(session, config) + self.config = config + session.config = config + self.runnable: ExecutableFlo = build_supervised_team(session) set_global_log_level(log_level) self.logger = common_logger @@ -37,7 +38,8 @@ def build(session: FloSession, yaml: str, log_level: str = "INFO"): return Flo(session, to_supervised_team(yaml), log_level) def draw(self, xray=True): - return self.runnable.draw(xray) + from IPython.display import Image, display + return display(Image(self.runnable.draw(xray))) def draw_to_file(self, filename: str, xray=True): from PIL import Image as PILImage diff --git a/flo_ai/factory/agent_factory.py b/flo_ai/factory/agent_factory.py index 949f18b3..1820015e 100644 --- a/flo_ai/factory/agent_factory.py +++ b/flo_ai/factory/agent_factory.py @@ -1,8 +1,11 @@ from flo_ai.state.flo_session import FloSession -from flo_ai.yaml.flo_team_builder import (AgentConfig) +from flo_ai.yaml.config import (AgentConfig) from flo_ai.models.flo_agent import FloAgent from flo_ai.models.flo_llm_agent import FloLLMAgent -from flo_ai.models.flo_executable import ExecutableFlo +from flo_ai.models.flo_reflection_agent import FloReflectionAgent +from flo_ai.models.flo_delegation_agent import FloDelegatorAgent +from flo_ai.models.flo_tool_agent import FloToolAgent +from flo_ai.models.flo_executable import ExecutableFlo, ExecutableType from enum import Enum class AgentKinds(Enum): @@ -10,12 +13,15 @@ class AgentKinds(Enum): llm = "llm" tool = "tool" function = "function" + reflection = "reflection" + delegator = "delegator" class AgentFactory(): @staticmethod - def create(session: FloSession, agent: AgentConfig, tool_map): + def create(session: FloSession, agent: AgentConfig): kind = agent.kind + tool_map = session.tools if kind is not None: agent_kind = getattr(AgentKinds, kind, None) if agent_kind is None: @@ -25,6 +31,10 @@ def create(session: FloSession, agent: AgentConfig, tool_map): return AgentFactory.__create_llm_agent(session, agent) case AgentKinds.tool: return AgentFactory.__create_runnable_agent(session, agent) + case AgentKinds.reflection: + return AgentFactory.__create_reflection_agent(session, agent) + case AgentKinds.delegator: + return AgentFactory.__create_delegator_agent(session, agent) return AgentFactory.__create_agentic_agent(session, agent, tool_map) @staticmethod @@ -32,19 +42,26 @@ def __create_agentic_agent(session: FloSession, agent: AgentConfig, tool_map) -> tools = [tool_map[tool.name] for tool in agent.tools] flo_agent: FloAgent = FloAgent.Builder( session, - agent.name, - agent.job, + agent, tools ).build() return flo_agent @staticmethod def __create_llm_agent(session: FloSession, agent: AgentConfig) -> FloLLMAgent: - builder = FloLLMAgent.Builder(session, agent.name, agent.job, agent.role) + builder = FloLLMAgent.Builder(session, agent) llm_agent: FloLLMAgent = builder.build() return llm_agent @staticmethod def __create_runnable_agent(session: FloSession, agent: AgentConfig) -> FloLLMAgent: runnable = session.tools[agent.tools[0].name] - return ExecutableFlo(agent.name, runnable, "agent") \ No newline at end of file + return FloToolAgent.Builder(session, agent, runnable).build() + + @staticmethod + def __create_reflection_agent(session: FloSession, agent: AgentConfig) -> FloReflectionAgent: + return FloReflectionAgent.Builder(session, agent).build() + + @staticmethod + def __create_delegator_agent(session: FloSession, agent: AgentConfig) -> FloReflectionAgent: + return FloDelegatorAgent.Builder(session, agent).build() \ No newline at end of file diff --git a/flo_ai/models/flo_agent.py b/flo_ai/models/flo_agent.py index b82083a3..abdd47d4 100644 --- a/flo_ai/models/flo_agent.py +++ b/flo_ai/models/flo_agent.py @@ -8,29 +8,34 @@ from flo_ai.models.flo_executable import ExecutableFlo from flo_ai.state.flo_session import FloSession from typing import Union, Optional +from flo_ai.yaml.config import AgentConfig +from flo_ai.models.flo_executable import ExecutableType class FloAgent(ExecutableFlo): def __init__(self, agent: Runnable, executor: AgentExecutor, - name: str) -> None: - super().__init__(name, executor, "agent") + config: AgentConfig) -> None: + super().__init__(config.name, executor, ExecutableType.agentic) self.agent: Runnable = agent, self.executor: AgentExecutor = executor + self.config: AgentConfig = config class Builder: def __init__(self, session: FloSession, - name: str, - prompt: Union[ChatPromptTemplate, str], + config: AgentConfig, tools: list[BaseTool], verbose: bool = True, role: Optional[str] = None, llm: Union[BaseLanguageModel, None] = None, return_intermediate_steps: bool = False, handle_parsing_errors: bool = True) -> None: - self.name: str = randomize_name(name) + prompt: Union[ChatPromptTemplate, str] = config.job + + self.name: str = randomize_name(config.name) self.llm = llm if llm is not None else session.llm + self.config = config # TODO improve to add more context of what other agents are available system_prompts = [("system", "You are a {}".format(role)), ("system", prompt)] if role is not None else [("system", prompt)] system_prompts.append(MessagesPlaceholder(variable_name="messages")) @@ -51,4 +56,4 @@ def build(self) -> AgentExecutor: verbose=self.verbose, return_intermediate_steps=self.return_intermediate_steps, handle_parsing_errors=self.handle_parsing_errors) - return FloAgent(agent, executor, self.name) + return FloAgent(agent, executor, self.config) diff --git a/flo_ai/models/flo_delegation_agent.py b/flo_ai/models/flo_delegation_agent.py new file mode 100644 index 00000000..bfdd2066 --- /dev/null +++ b/flo_ai/models/flo_delegation_agent.py @@ -0,0 +1,78 @@ +from langchain_core.runnables import Runnable +from flo_ai.yaml.config import AgentConfig +from flo_ai.state.flo_session import FloSession +from flo_ai.models.flo_executable import ExecutableFlo +from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder +from flo_ai.models.flo_executable import ExecutableType +from langchain_core.output_parsers.openai_functions import JsonOutputFunctionsParser + + +class FloDelegatorAgent(ExecutableFlo): + + def __init__(self, + executor: Runnable, + config: AgentConfig) -> None: + super().__init__(config.name, executor, ExecutableType.delegator) + self.executor: Runnable = executor + self.config: AgentConfig = config + + + class Builder(): + def __init__(self, + session: FloSession, + agentConfig: AgentConfig) -> None: + self.config = agentConfig + delegator_base_system_message = ( + "You are a delegator tasked with routing a conversation between the" + " following {member_type}: {members}. Given the following rules," + " respond with the worker to act next " + ) + self.llm = session.llm + self.options = [x.name for x in agentConfig.to] + self.llm_router_prompt = ChatPromptTemplate.from_messages( + [ + ("system", delegator_base_system_message), + MessagesPlaceholder(variable_name="messages"), + ("system", "Rules: {delegator_rules}"), + ( + "system", + "Given the conversation above, who should act next?" + "Select one of: {options}", + ), + ] + ).partial( + options=str(self.options), + members=", ".join(self.options), + member_type="agents", + delegator_rules=agentConfig.job + ) + + def build(self): + function_def = { + "name": "route", + "description": "Select the next role.", + "parameters": { + "title": "routeSchema", + "type": "object", + "properties": { + "next": { + "title": "Next", + "anyOf": [ + {"enum": self.options}, + ], + } + }, + "required": ["next"], + } + } + + chain = ( + self.llm_router_prompt + | self.llm.bind_functions(functions=[function_def], function_call="route") + | JsonOutputFunctionsParser() + ) + + return FloDelegatorAgent(executor = chain, + config=self.config) + + \ No newline at end of file diff --git a/flo_ai/models/flo_executable.py b/flo_ai/models/flo_executable.py index 32fb101a..508bdde2 100644 --- a/flo_ai/models/flo_executable.py +++ b/flo_ai/models/flo_executable.py @@ -1,6 +1,26 @@ from flo_ai.models.flo_member import FloMember from langchain_core.runnables import Runnable from langchain_core.messages import HumanMessage +from enum import Enum +from flo_ai.state.flo_state import STATE_NAME_MESSAGES + +class ExecutableType(Enum): + agentic = "agentic" + llm = "llm" + tool = "tool" + reflection = "reflection" + delegator = "delegator" + + @staticmethod + def isAgent(type: 'ExecutableType'): + match(type): + case ExecutableType.agentic: + return True + case ExecutableType.llm: + return True + case ExecutableType.tool: + return True + return False class ExecutableFlo(FloMember): def __init__(self, @@ -12,14 +32,18 @@ def __init__(self, def stream(self, work, config = None): return self.runnable.stream({ - "messages": [ + STATE_NAME_MESSAGES: [ HumanMessage(content=work) ] }, config) def invoke(self, work, config = None): return self.runnable.invoke({ - "messages": [ + STATE_NAME_MESSAGES: [ HumanMessage(content=work) - ] - }, config) \ No newline at end of file + ], + }, config) + + + def draw(self, xray=True): + return self.runnable.get_graph().draw_mermaid_png() \ No newline at end of file diff --git a/flo_ai/models/flo_llm_agent.py b/flo_ai/models/flo_llm_agent.py index 5b3b9111..d753dd47 100644 --- a/flo_ai/models/flo_llm_agent.py +++ b/flo_ai/models/flo_llm_agent.py @@ -1,40 +1,41 @@ -from langchain_core.tools import BaseTool -from langchain_core.runnables import Runnable -from langchain.agents import create_tool_calling_agent from langchain_core.runnables import Runnable from langchain_core.language_models import BaseLanguageModel from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from flo_ai.helpers.utils import randomize_name from flo_ai.models.flo_executable import ExecutableFlo from flo_ai.state.flo_session import FloSession -from typing import Union, Optional +from typing import Union from langchain_core.output_parsers import StrOutputParser +from flo_ai.yaml.config import AgentConfig +from flo_ai.models.flo_executable import ExecutableType class FloLLMAgent(ExecutableFlo): def __init__(self, executor: Runnable, - name: str) -> None: - super().__init__(name, executor, "agent") + config: AgentConfig) -> None: + super().__init__(config.name, executor, ExecutableType.llm) self.executor: Runnable = executor + self.config: AgentConfig = config class Builder: def __init__(self, session: FloSession, - name: str, - prompt: Union[ChatPromptTemplate, str], - role: Optional[str] = None, + config: AgentConfig, llm: Union[BaseLanguageModel, None] = None) -> None: - self.name: str = randomize_name(name) + prompt: Union[ChatPromptTemplate, str] = config.job + + self.name: str = randomize_name(config.name) self.llm = llm if llm is not None else session.llm # TODO improve to add more context of what other agents are available - system_prompts = [("system", "You are a {}".format(role)), ("system", prompt)] if role is not None else [("system", prompt)] + system_prompts = [("system", "You are a {}".format(config.role)), ("system", prompt)] if config.role is not None else [("system", prompt)] system_prompts.append(MessagesPlaceholder(variable_name="messages")) self.prompt: ChatPromptTemplate = ChatPromptTemplate.from_messages( system_prompts ) if isinstance(prompt, str) else prompt + self.config = config def build(self) -> Runnable: executor = self.prompt | self.llm | StrOutputParser() - return FloLLMAgent(executor, self.name) + return FloLLMAgent(executor, self.config) diff --git a/flo_ai/models/flo_node.py b/flo_ai/models/flo_node.py index 8c9f752e..ea302f11 100644 --- a/flo_ai/models/flo_node.py +++ b/flo_ai/models/flo_node.py @@ -2,48 +2,55 @@ from flo_ai.models.flo_agent import FloAgent from flo_ai.models.flo_routed_team import FloRoutedTeam from langchain.agents import AgentExecutor -from flo_ai.state.flo_state import TeamFloAgentState +from flo_ai.state.flo_state import TeamFloAgentState, STATE_NAME_MESSAGES from langchain_core.messages import HumanMessage +from flo_ai.yaml.config import AgentConfig, TeamConfig +from flo_ai.models.flo_executable import ExecutableType +from typing import Union class FloNode(): def __init__(self, func: functools.partial, - name: str) -> None: + name: str, + kind: ExecutableType, + config: Union[AgentConfig | TeamConfig]) -> None: self.name = name self.func = func + self.kind: ExecutableType = kind + self.config: Union[AgentConfig | TeamConfig] = config class Builder(): + def build_from_agent(self, flo_agent: FloAgent) -> 'FloNode': + agent_func = functools.partial(FloNode.Builder.__teamflo_agent_node, agent=flo_agent.runnable, name=flo_agent.name, agent_config=flo_agent.config) + return FloNode(agent_func, flo_agent.name, flo_agent.type, flo_agent.config) + + def build_from_team(self, flo_team: FloRoutedTeam) -> 'FloNode': + team_chain = (functools.partial(FloNode.Builder.__teamflo_team_node, members=flo_team.runnable.nodes) | flo_team.runnable) + return FloNode(( + FloNode.Builder.__get_last_message | team_chain | FloNode.Builder.__join_graph + ), flo_team.name, flo_team.type, flo_team.config) + @staticmethod - def teamflo_agent_node(state: TeamFloAgentState, agent: AgentExecutor, name: str): + def __teamflo_agent_node(state: TeamFloAgentState, agent: AgentExecutor, name: str, agent_config: AgentConfig): result = agent.invoke(state) # TODO see how to fix this output = result if isinstance(result, str) else result["output"] - return { "messages": [HumanMessage(content=output, name=name)] } + return { STATE_NAME_MESSAGES: [HumanMessage(content=output, name=name)] } @staticmethod - def get_last_message(state: TeamFloAgentState) -> str: - return state["messages"][-1].content + def __get_last_message(state: TeamFloAgentState) -> str: + return state[STATE_NAME_MESSAGES][-1].content @staticmethod - def join_graph(response: dict): - return { "messages": [ response["messages"][-1] ] } + def __join_graph(response: dict): + return { STATE_NAME_MESSAGES: [ response[STATE_NAME_MESSAGES][-1] ] } @staticmethod - def teamflo_team_node(message: str, members: list[str]): + def __teamflo_team_node(message: str, members: list[str]): results = { - "messages": [HumanMessage(content=message)], + STATE_NAME_MESSAGES: [HumanMessage(content=message)], "team_members": ", ".join(members), } return results - - def build_from_agent(self, flo_agent: FloAgent): - agent_func = functools.partial(FloNode.Builder.teamflo_agent_node, agent=flo_agent.executor, name=flo_agent.name) - return FloNode(agent_func, flo_agent.name) - - def build_from_team(self, flo_team: FloRoutedTeam): - team_chain = (functools.partial(FloNode.Builder.teamflo_team_node, members=flo_team.runnable.nodes) | flo_team.runnable) - return FloNode(( - FloNode.Builder.get_last_message | team_chain | FloNode.Builder.join_graph - ), flo_team.name) \ No newline at end of file diff --git a/flo_ai/models/flo_reflection_agent.py b/flo_ai/models/flo_reflection_agent.py new file mode 100644 index 00000000..2d531581 --- /dev/null +++ b/flo_ai/models/flo_reflection_agent.py @@ -0,0 +1,38 @@ +from typing import Union +from langchain_core.runnables import Runnable +from flo_ai.yaml.config import AgentConfig +from flo_ai.state.flo_session import FloSession +from flo_ai.models.flo_executable import ExecutableFlo +from langchain_core.language_models import BaseLanguageModel +from flo_ai.helpers.utils import randomize_name +from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder +from flo_ai.models.flo_executable import ExecutableType +from langchain_core.output_parsers import StrOutputParser + + +class FloReflectionAgent(ExecutableFlo): + + def __init__(self, executor: Runnable, config: AgentConfig) -> None: + super().__init__(config.name, executor, ExecutableType.reflection) + self.config = config + + class Builder(): + def __init__(self, + session: FloSession, + config: AgentConfig, + llm: Union[BaseLanguageModel, None] = None) -> None: + + prompt_message: Union[ChatPromptTemplate, str] = config.job + self.name: str = randomize_name(config.name) + self.llm = llm if llm is not None else session.llm + self.config = config + + system_prompts = [("system", "You are a {}".format(config.role)), ("system", prompt_message)] if config.role is not None else [("system", prompt_message)] + system_prompts.append(MessagesPlaceholder(variable_name="messages")) + self.prompt: ChatPromptTemplate = ChatPromptTemplate.from_messages( + system_prompts + ) if isinstance(prompt_message, str) else prompt_message + + def build(self): + executor = self.prompt | self.llm | StrOutputParser() + return FloReflectionAgent(executor, self.config) \ No newline at end of file diff --git a/flo_ai/models/flo_routed_team.py b/flo_ai/models/flo_routed_team.py index 0eb4270e..552258b7 100644 --- a/flo_ai/models/flo_routed_team.py +++ b/flo_ai/models/flo_routed_team.py @@ -1,10 +1,13 @@ from flo_ai.models.flo_executable import ExecutableFlo from langgraph.graph.graph import CompiledGraph +from flo_ai.yaml.config import TeamConfig class FloRoutedTeam(ExecutableFlo): - def __init__(self, name: str, graph: CompiledGraph) -> None: + def __init__(self, name: str, graph: CompiledGraph, config: TeamConfig) -> None: super().__init__(name, graph) + self.config = config + # Overridden for xray use, doesnt work in base class def draw(self, xray=True): return self.runnable.get_graph(xray=xray).draw_mermaid_png() \ No newline at end of file diff --git a/flo_ai/models/flo_team.py b/flo_ai/models/flo_team.py index db21a709..e2a7313a 100644 --- a/flo_ai/models/flo_team.py +++ b/flo_ai/models/flo_team.py @@ -1,30 +1,21 @@ from flo_ai.models.flo_member import FloMember -from flo_ai.state.flo_session import FloSession from flo_ai.helpers.utils import randomize_name - +from flo_ai.yaml.config import TeamConfig class FloTeam(): - def __init__(self, - session: FloSession, - name: str, - members: list[FloMember]) -> None: - self.name = name - self.session = session + def __init__(self, team_config: TeamConfig, members: list[FloMember]) -> None: + self.name = randomize_name(team_config.name) + self.config = team_config self.members = members class Builder: - def __init__(self, - session: FloSession, - name: str, - members: list[FloMember]) -> None: - self.name = randomize_name(name) - self.session = session + def __init__(self, team_config: TeamConfig, members: list[FloMember]) -> None: + self.team_config = team_config self.members = members self.member_names= list(map(lambda x: x.name, self.members)) def build(self): return FloTeam( - name = self.name, - session=self.session, + team_config=self.team_config, members=self.members ) \ No newline at end of file diff --git a/flo_ai/models/flo_tool_agent.py b/flo_ai/models/flo_tool_agent.py new file mode 100644 index 00000000..365e2452 --- /dev/null +++ b/flo_ai/models/flo_tool_agent.py @@ -0,0 +1,28 @@ +from langchain_core.runnables import Runnable +from flo_ai.helpers.utils import randomize_name +from flo_ai.models.flo_executable import ExecutableFlo +from flo_ai.state.flo_session import FloSession +from flo_ai.yaml.config import AgentConfig +from flo_ai.models.flo_executable import ExecutableType + +class FloToolAgent(ExecutableFlo): + + def __init__(self, + executor: Runnable, + config: AgentConfig) -> None: + super().__init__(config.name, executor, ExecutableType.tool) + self.executor: Runnable = executor + self.config: AgentConfig = config + + class Builder: + def __init__(self, + session: FloSession, + config: AgentConfig, + tool_runnable: Runnable) -> None: + self.name: str = config.name + self.runnable = tool_runnable + self.config = config + + + def build(self) -> Runnable: + return FloToolAgent(self.runnable, self.config) diff --git a/flo_ai/retrievers/flo_retriever.py b/flo_ai/retrievers/flo_retriever.py index dbd2d3b0..57b22f89 100644 --- a/flo_ai/retrievers/flo_retriever.py +++ b/flo_ai/retrievers/flo_retriever.py @@ -3,7 +3,7 @@ from flo_ai.state.flo_session import FloSession from langchain.schema.output_parser import StrOutputParser from langchain.schema.runnable import RunnablePassthrough -from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder +from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder, BasePromptTemplate from flo_ai.retrievers.flo_multi_query import FloMultiQueryRetriverBuilder from langchain.retrievers import ContextualCompressionRetriever from langchain.retrievers.document_compressors import DocumentCompressorPipeline @@ -12,9 +12,45 @@ from functools import partial from langchain.pydantic_v1 import BaseModel, Field from langchain_core.tools import Tool +from typing import Optional +from langchain_core.callbacks import Callbacks +from langchain_core.prompts import ( + BasePromptTemplate, + PromptTemplate, + aformat_document, + format_document, +) +from typing import List + +class FloRagBaseMessage(BaseModel): + content: str class FloRagToolInput(BaseModel): - query: str = Field(description="query to look up in retriever") + messages: List[FloRagBaseMessage] = Field(description="query to look up in the vector store") + +def _get_relevant_documents( + messages: List[FloRagBaseMessage], + retriever: VectorStoreRetriever, + document_prompt: BasePromptTemplate, + document_separator: str, + callbacks: Callbacks = None, +) -> str: + docs = retriever.invoke(messages[-1].content, config={"callbacks": callbacks}) + return document_separator.join( + format_document(doc, document_prompt) for doc in docs + ) + +async def _aget_relevant_documents( + messages: List[str], + retriever: VectorStoreRetriever, + document_prompt: BasePromptTemplate, + document_separator: str, + callbacks: Callbacks = None +) -> str: + docs = await retriever.ainvoke(messages[-1].content, config={"callbacks": callbacks}) + return document_separator.join( + [await aformat_document(doc, document_prompt) for doc in docs] + ) class FloRagBuilder(): def __init__(self, @@ -113,20 +149,54 @@ def build_rag(self): return self.__build_history_aware_rag() def build_retriever_tool(self, name, description): - return create_retriever_tool(self.retriever, name, description) + return self.__create_retriever_tool(self.retriever, name, description) @staticmethod - def __get_rag_answer(query: str, runnable: Runnable): - result = runnable.invoke({ "question": query }) + def __get_rag_answer(messages: List[FloRagBaseMessage], runnable: Runnable): + question = messages[-1].content + chat_history = messages[:-1] + result = runnable.invoke({ "question": question, "chat_history": chat_history }) return result["answer"].content @staticmethod - async def __aget_rag_answer(query: str, runnable: Runnable): - result = await runnable.ainvoke({ "question": query }) + async def __aget_rag_answer(messages: List[FloRagBaseMessage], runnable: Runnable): + question = messages[-1].content + chat_history = messages[:-1] + result = await runnable.ainvoke({ "question": question, "chat_history": chat_history }) return result["answer"].content + + def __create_retriever_tool( + self, + retriever: VectorStoreRetriever, + name: str, + description: str, + *, + document_prompt: Optional[BasePromptTemplate] = None, + document_separator: str = "\n", + ) -> Tool: + document_prompt = document_prompt or PromptTemplate.from_template("{page_content}") + func = partial( + _get_relevant_documents, + retriever=retriever, + document_prompt=document_prompt, + document_separator=document_separator, + ) + afunc = partial( + _aget_relevant_documents, + retriever=retriever, + document_prompt=document_prompt, + document_separator=document_separator, + ) + return Tool( + name=name, + description=description, + func=func, + coroutine=afunc, + args_schema=FloRagToolInput, + ) @staticmethod - def __create_flo_rag_tool( + def __create_rag_tool( runnable_rag: Runnable, name: str, description: str @@ -151,4 +221,4 @@ def __create_flo_rag_tool( def build_rag_tool(self, name, description) -> Tool: rag = self.__build_history_aware_rag() - return FloRagBuilder.__create_flo_rag_tool(rag, name, description) \ No newline at end of file + return FloRagBuilder.__create_rag_tool(rag, name, description) \ No newline at end of file diff --git a/flo_ai/router/flo_custom_router.py b/flo_ai/router/flo_custom_router.py new file mode 100644 index 00000000..bea0fffa --- /dev/null +++ b/flo_ai/router/flo_custom_router.py @@ -0,0 +1,132 @@ +from flo_ai.yaml.config import TeamConfig +from flo_ai.router.flo_router import FloRouter +from langgraph.graph import StateGraph, END, START +from flo_ai.state.flo_state import TeamFloAgentState +from flo_ai.models.flo_routed_team import FloRoutedTeam +from flo_ai.models.flo_team import FloTeam +from flo_ai.state.flo_session import FloSession +from flo_ai.helpers.utils import agent_name_from_randomized_name, randomize_name +from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder +from langchain_core.output_parsers.openai_functions import JsonOutputFunctionsParser + +class FloCustomRouter(FloRouter): + + def __init__(self, session: FloSession, config: TeamConfig, flo_team: FloTeam): + self.llm = session.llm + super().__init__(session=session, name=randomize_name(config.name), + flo_team=flo_team, executor=None, config=config) + self.router_config = config.router + + def build_router_fn(self, members, rule): + def router_fn(state: TeamFloAgentState): + conditional_map = {k: k for k in members} + + prompt = ChatPromptTemplate.from_messages( + [ + MessagesPlaceholder(variable_name="messages"), + ( + "system", + "Given the conversation above, who should act next? Select one of: {members}. The rule is given below:" + ), + ('system', rule) + ] + ).partial(members=", ".join(members)) + + + function_def = { + "name": "route", + "description": "Select the next role.", + "parameters": { + "title": "routeSchema", + "type": "object", + "properties": { + "next": { + "title": "Next", + "anyOf": [ + {"enum": members}, + ], + } + }, + "required": ["next"], + } + } + + chain = prompt | self.llm.bind_functions(functions=[function_def], function_call="route") | JsonOutputFunctionsParser() + output = chain.invoke(state) + + next = output['next'] + state['next'] = next + + return conditional_map[next] + + return router_fn + + def build_agent_graph(self): + flo_agent_nodes = [self.build_node(flo_agent) for flo_agent in self.members] + workflow = StateGraph(TeamFloAgentState) + + for flo_agent_node in flo_agent_nodes: + agent_name = agent_name_from_randomized_name(flo_agent_node.name) + workflow.add_node(agent_name, flo_agent_node.func) + + router_config = self.router_config + workflow.add_edge(START, router_config.start_node) + for edge_config in router_config.edges: + edge = edge_config.edge + if len(edge) > 2: + if edge_config.type == 'conditional_llm': + members = edge[1:] + router = self.build_router_fn(members, edge_config.rule) + workflow.add_conditional_edges(edge[0], router, {item: item for item in members}) + else: + workflow.add_edge(edge[0], edge[1]) + + if isinstance(router_config.end_node, list): + for node in router_config.end_node: + workflow.add_edge(node, END) + else: + workflow.add_edge(router_config.end_node, END) + + workflow_graph = workflow.compile() + + return FloRoutedTeam(self.flo_team.name, workflow_graph, self.flo_team.config) + + def build_team_graph(self): + flo_team_entry_chains = [self.build_node_for_teams(flo_agent) for flo_agent in self.members] + + super_graph = StateGraph(TeamFloAgentState) + + for flo_team_chain in flo_team_entry_chains: + agent_name = agent_name_from_randomized_name(flo_team_chain.name) + super_graph.add_node(agent_name, flo_team_chain.func) + + router_config = self.router_config + super_graph.add_edge(START, router_config.start_node) + for edge_config in router_config.edges: + edge = edge_config.edge + if len(edge) > 2: + teams = edge[1:] + router = self.build_router_fn(teams, edge_config.rule) + super_graph.add_conditional_edges(edge[0], router, {item: item for item in teams}) + else: + super_graph.add_edge(edge[0], edge[1]) + + if isinstance(router_config.end_node, list): + for node in router_config.end_node: + super_graph.add_edge(node, END) + else: + super_graph.add_edge(router_config.end_node, END) + + workflow_graph = super_graph.compile() + + return FloRoutedTeam(self.flo_team.name, workflow_graph, self.flo_team.config) + + class Builder(): + + def __init__(self, session: FloSession, config: TeamConfig, flo_team: FloTeam,) -> None: + self.session = session + self.config = config + self.team = flo_team + + def build(self): + return FloCustomRouter(self.session, self.config, self.team, ) \ No newline at end of file diff --git a/flo_ai/router/flo_linear.py b/flo_ai/router/flo_linear.py index 1a165e0d..49add530 100644 --- a/flo_ai/router/flo_linear.py +++ b/flo_ai/router/flo_linear.py @@ -1,44 +1,58 @@ -from flo_ai.yaml.flo_team_builder import RouterConfig +from flo_ai.yaml.config import TeamConfig from flo_ai.router.flo_router import FloRouter from langgraph.graph import StateGraph, END, START from flo_ai.state.flo_state import TeamFloAgentState from flo_ai.models.flo_routed_team import FloRoutedTeam from flo_ai.models.flo_team import FloTeam from flo_ai.state.flo_session import FloSession +from flo_ai.models.flo_executable import ExecutableType from flo_ai.helpers.utils import agent_name_from_randomized_name, randomize_name class FloLinear(FloRouter): - def __init__(self, session: FloSession, flo_team: FloTeam, config: RouterConfig): + def __init__(self, session: FloSession, config: TeamConfig, flo_team: FloTeam): super().__init__(session=session, name=randomize_name(config.name), flo_team=flo_team, executor=None, config=config) + self.router_config = config.router def build_agent_graph(self): - flo_agent_nodes = [self.build_node(flo_agent) for flo_agent in self.members] + flo_agent_nodes = [self.build_node(member) for member in self.members] + workflow = StateGraph(TeamFloAgentState) - for flo_agent_node in flo_agent_nodes: - agent_name = agent_name_from_randomized_name(flo_agent_node.name) - workflow.add_node(agent_name, flo_agent_node.func) - if self.config.edges is None: + for flo_node in flo_agent_nodes: + agent_name = agent_name_from_randomized_name(flo_node.name) + workflow.add_node(agent_name, flo_node.func) + + if self.router_config.edges is None: start_node_name = agent_name_from_randomized_name(flo_agent_nodes[0].name) end_node_name = agent_name_from_randomized_name(flo_agent_nodes[-1].name) workflow.add_edge(START, start_node_name) for i in range(len(flo_agent_nodes) - 1): agent1_name = agent_name_from_randomized_name(flo_agent_nodes[i].name) agent2_name = agent_name_from_randomized_name(flo_agent_nodes[i+1].name) - workflow.add_edge(agent1_name, agent2_name) - workflow.add_edge(end_node_name, END) + if (flo_agent_nodes[i].kind == ExecutableType.reflection): + self.add_reflection_edge(workflow, flo_agent_nodes[i], flo_agent_nodes[i+1]) + else: + if (flo_agent_nodes[i+1].kind != ExecutableType.reflection and flo_agent_nodes[i].kind != ExecutableType.delegator): + if flo_agent_nodes[i+1].kind == ExecutableType.delegator: + self.add_delegation_edge(workflow, flo_agent_nodes[i], flo_agent_nodes[i+1], flo_agent_nodes[i+2] if (i+2) None: + def __init__(self, session: FloSession, config: TeamConfig, flo_team: FloTeam,) -> None: self.config = config self.session = session self.team = flo_team def build(self): - return FloLinear(self.session, self.team, self.config) + return FloLinear(self.session, self.config, self.team) diff --git a/flo_ai/router/flo_llm_router.py b/flo_ai/router/flo_llm_router.py index 388dd6dc..1d1c06a1 100644 --- a/flo_ai/router/flo_llm_router.py +++ b/flo_ai/router/flo_llm_router.py @@ -11,6 +11,7 @@ from flo_ai.models.flo_routed_team import FloRoutedTeam from langgraph.graph import StateGraph from flo_ai.state.flo_state import TeamFloAgentState +from flo_ai.yaml.config import TeamConfig class StateUpdateComponent: def __init__(self, name: str, session: FloSession) -> None: @@ -46,7 +47,7 @@ def build_agent_graph(self): workflow.add_conditional_edges(self.router_name, self.router_fn) workflow.set_entry_point(self.router_name) workflow_graph = workflow.compile() - return FloRoutedTeam(self.flo_team.name, workflow_graph) + return FloRoutedTeam(self.flo_team.name, workflow_graph, self.flo_team.config) def build_team_graph(self): flo_team_entry_chains = [self.build_node_for_teams(flo_agent) for flo_agent in self.members] @@ -64,17 +65,17 @@ def build_team_graph(self): super_graph.set_entry_point(self.router_name) super_graph = super_graph.compile() - return FloRoutedTeam(self.flo_team.name, super_graph) + return FloRoutedTeam(self.flo_team.name, super_graph, self.flo_team.config) class Builder: def __init__(self, session: FloSession, - name: str, + team_config: TeamConfig, flo_team: FloTeam, router_prompt: ChatPromptTemplate = None, llm: Union[BaseLanguageModel, None] = None) -> None: - self.name = randomize_name(name) + self.name = randomize_name(team_config.router.name) self.session = session self.llm = llm if llm is not None else session.llm self.flo_team = flo_team diff --git a/flo_ai/router/flo_router.py b/flo_ai/router/flo_router.py index 71333c2a..d2634fd7 100644 --- a/flo_ai/router/flo_router.py +++ b/flo_ai/router/flo_router.py @@ -1,30 +1,35 @@ -import functools from abc import ABC, abstractmethod from flo_ai.state.flo_session import FloSession from flo_ai.models.flo_team import FloTeam -from flo_ai.yaml.flo_team_builder import RouterConfig +from flo_ai.yaml.config import TeamConfig from flo_ai.models.flo_routed_team import FloRoutedTeam from flo_ai.models.flo_agent import FloAgent -from flo_ai.state.flo_state import TeamFloAgentState +from flo_ai.state.flo_state import TeamFloAgentState, STATE_NAME_LOOP_CONTROLLER, STATE_NAME_NEXT from flo_ai.models.flo_node import FloNode from flo_ai.constants.prompt_constants import FLO_FINISH -from langgraph.graph import END +from langgraph.graph import END,StateGraph +from flo_ai.models.flo_node import FloNode +from flo_ai.models.flo_executable import ExecutableType +import functools +from typing import Union +from flo_ai.constants.flo_node_contants import (INTERNAL_NODE_REFLECTION_MANAGER, INTERNAL_NODE_DELEGATION_MANAGER) + class FloRouter(ABC): - def __init__(self, session: FloSession, name: str, flo_team: FloTeam, executor, config: RouterConfig = None): + def __init__(self, session: FloSession, name: str, flo_team: FloTeam, executor, config: TeamConfig = None): self.router_name = name self.session: FloSession = session self.flo_team: FloTeam = flo_team self.members = flo_team.members self.member_names = [x.name for x in flo_team.members] - self.type = flo_team.members[0].type + self.type: ExecutableType = flo_team.members[0].type self.executor = executor self.config = config def is_agent_supervisor(self): - return self.type == "agent" + return ExecutableType.isAgent(self.type) def build_routed_team(self) -> FloRoutedTeam: if self.is_agent_supervisor(): @@ -40,7 +45,9 @@ def build_agent_graph(): def build_team_graph(): pass - def build_node(self, flo_agent: FloAgent): + def build_node(self, flo_agent: FloAgent) -> FloNode: + if (flo_agent.type == ExecutableType.delegator): + return FloNode(flo_agent.executor, flo_agent.name, flo_agent.type, flo_agent.config) node_builder = FloNode.Builder() return node_builder.build_from_agent(flo_agent) @@ -52,10 +59,93 @@ def router_fn(self, state: TeamFloAgentState): if self.session.is_looping(node=next): return conditional_map[FLO_FINISH] return conditional_map[next] - def build_node_for_teams(self, flo_team: FloRoutedTeam): node_builder = FloNode.Builder() return node_builder.build_from_team(flo_team) + + def update_reflection_state(self, state: TeamFloAgentState, reflection_agent_name: str): + tracker = None + if STATE_NAME_LOOP_CONTROLLER not in state or state[STATE_NAME_LOOP_CONTROLLER] is None: + tracker = dict() + else: + tracker = state[STATE_NAME_LOOP_CONTROLLER] + + if reflection_agent_name in tracker: + tracker[reflection_agent_name] += 1 + else: + tracker[reflection_agent_name] = 1 + + return { + STATE_NAME_LOOP_CONTROLLER: tracker + } + + def add_delegation_edge(self, workflow: StateGraph, parent: FloNode, delegation_node: FloNode, nextNode: Union[FloNode|str]): + to_agent_names = [x.name for x in delegation_node.config.to] + delegation_node_name = delegation_node.name + next_node_name = nextNode if isinstance(nextNode, str) else nextNode.name + retry = delegation_node.config.retry or 1 + + conditional_map = {} + for agent_name in to_agent_names: + conditional_map[agent_name] = agent_name + conditional_map[next_node_name] = next_node_name + + workflow.add_node( + INTERNAL_NODE_DELEGATION_MANAGER, + functools.partial( + self.update_reflection_state, + reflection_agent_name=delegation_node_name + ) + ) + workflow.add_edge(parent.name, INTERNAL_NODE_DELEGATION_MANAGER) + workflow.add_conditional_edges( + INTERNAL_NODE_DELEGATION_MANAGER, + self.__get_refelection_routing_fn(retry, delegation_node_name, next_node_name), + { delegation_node_name: delegation_node_name, next_node_name: next_node_name} + ) + + workflow.add_conditional_edges( + delegation_node_name, + FloRouter.__get_delegation_router_fn(next_node_name), + conditional_map + ) + + @staticmethod + def __get_delegation_router_fn(nextNode: str): + def delegation_router(state: TeamFloAgentState): + if STATE_NAME_NEXT not in state: + return nextNode + return state[STATE_NAME_NEXT] + return delegation_router + + def add_reflection_edge(self, workflow: StateGraph, reflection_node: FloNode, nextNode: Union[FloNode | str]): + to_agent_name = reflection_node.config.to[0].name + retry = reflection_node.config.retry or 1 + reflection_agent_name = reflection_node.name + next = nextNode if isinstance(nextNode, str) else nextNode.name + + workflow.add_node(INTERNAL_NODE_REFLECTION_MANAGER, functools.partial(self.update_reflection_state, reflection_agent_name=reflection_agent_name)) + workflow.add_edge(to_agent_name, INTERNAL_NODE_REFLECTION_MANAGER) + workflow.add_conditional_edges( + INTERNAL_NODE_REFLECTION_MANAGER, + self.__get_refelection_routing_fn(retry, reflection_agent_name, next), + { reflection_agent_name: reflection_agent_name, next: next } + ) + workflow.add_edge(reflection_agent_name, to_agent_name) + + @staticmethod + def __get_refelection_routing_fn(retries: int, reflection_agent_name, next_node_name): + def reflection_routing_fn(state: TeamFloAgentState): + tracker = state[STATE_NAME_LOOP_CONTROLLER] + if tracker is not None and reflection_agent_name in tracker and tracker[reflection_agent_name] > retries: + return next_node_name + return reflection_agent_name + + return reflection_routing_fn + + + + \ No newline at end of file diff --git a/flo_ai/router/flo_router_factory.py b/flo_ai/router/flo_router_factory.py index f66613cf..279f84a4 100644 --- a/flo_ai/router/flo_router_factory.py +++ b/flo_ai/router/flo_router_factory.py @@ -2,19 +2,23 @@ from flo_ai.router.flo_supervisor import FloSupervisor from flo_ai.router.flo_llm_router import FloLLMRouter from flo_ai.router.flo_linear import FloLinear -from flo_ai.yaml.flo_team_builder import TeamConfig +from flo_ai.yaml.config import TeamConfig from flo_ai.models.flo_team import FloTeam from flo_ai.router.flo_router import FloRouter +from flo_ai.router.flo_custom_router import FloCustomRouter class FloRouterFactory: @staticmethod def create(session: FloSession, team_config: TeamConfig, flo_team: FloTeam) -> FloRouter: - if team_config.router.kind == 'supervisor': - return FloSupervisor.Builder(session, team_config.router.name, flo_team).build() - elif team_config.router.kind == 'linear': - return FloLinear.Builder(session, flo_team, team_config.router).build() - elif team_config.router.kind == 'llm': - return FloLLMRouter.Builder(session, team_config.router.name, flo_team).build() + router_kind = team_config.router.kind + if router_kind == 'supervisor': + return FloSupervisor.Builder(session, team_config, flo_team).build() + elif router_kind == 'linear': + return FloLinear.Builder(session, team_config, flo_team).build() + elif router_kind == 'llm': + return FloLLMRouter.Builder(session, team_config, flo_team).build() + elif router_kind == 'custom': + return FloCustomRouter.Builder(session, team_config, flo_team).build() else: raise Exception("Unknown router type") diff --git a/flo_ai/router/flo_supervisor.py b/flo_ai/router/flo_supervisor.py index d340e3b4..f1fc5577 100644 --- a/flo_ai/router/flo_supervisor.py +++ b/flo_ai/router/flo_supervisor.py @@ -8,9 +8,7 @@ from flo_ai.helpers.utils import randomize_name from flo_ai.router.flo_llm_router import FloLLMRouter, StateUpdateComponent from flo_ai.models.flo_team import FloTeam -from flo_ai.models.flo_routed_team import FloRoutedTeam -from langgraph.graph import StateGraph -from flo_ai.state.flo_state import TeamFloAgentState +from flo_ai.yaml.config import TeamConfig # TODO, maybe add description about what team members can do supervisor_system_message = ( @@ -38,11 +36,11 @@ def __init__(self, class Builder: def __init__(self, session: FloSession, - name: str, + team_config: TeamConfig, flo_team: FloTeam, llm: Union[BaseLanguageModel, None] = None) -> None: # TODO add validation for reporteess - self.name = randomize_name(name) + self.name = randomize_name(team_config.router.name) self.session = session self.llm = llm if llm is not None else session.llm self.flo_team = flo_team diff --git a/flo_ai/state/flo_session.py b/flo_ai/state/flo_session.py index 9954cc6a..17c98dc0 100644 --- a/flo_ai/state/flo_session.py +++ b/flo_ai/state/flo_session.py @@ -1,8 +1,11 @@ import uuid +from typing import Union from langchain_core.language_models import BaseLanguageModel from langchain_core.tools import BaseTool -from flo_ai.common.flo_logger import session_logger, FloLogger, FloLogConfig +from flo_ai.common.flo_logger import session_logger, FloLogger from flo_ai.common.flo_langchain_logger import FloLangchainLogger +from flo_ai.yaml.config import FloRoutedTeamConfig, FloAgentConfig + from typing import Optional class FloSession: @@ -24,9 +27,9 @@ def __init__(self, self.init_logger(log_level) self.logger = session_logger + self.config: Union[FloRoutedTeamConfig, FloAgentConfig] = None self.logger.info(f"New FloSession created with ID: {self.session_id}") self.langchain_logger = custom_langchainlog_handler or FloLangchainLogger(self.session_id, log_level=log_level, logger_name=f"FloLangChainLogger-{self.session_id}") - self.langchain_logger.set_session_id(self.session_id) def init_logger(self, log_level: str): FloLogger.set_log_level("SESSION", log_level) diff --git a/flo_ai/state/flo_state.py b/flo_ai/state/flo_state.py index 2d609c1d..9e35b7e3 100644 --- a/flo_ai/state/flo_state.py +++ b/flo_ai/state/flo_state.py @@ -1,9 +1,13 @@ from typing import Annotated, List, Sequence, TypedDict from langchain_core.messages import BaseMessage -from typing import List, Tuple, Annotated, TypedDict, Dict +from typing import List, Tuple, Annotated, TypedDict import operator +STATE_NAME_LOOP_CONTROLLER = "loop_tracker" +STATE_NAME_NEXT = "next" +STATE_NAME_MESSAGES = "messages" + # The agent state is the input to each node in the graph class TeamFloAgentState(TypedDict): # The annotation tells the graph that new messages will always @@ -11,6 +15,8 @@ class TeamFloAgentState(TypedDict): messages: Annotated[Sequence[BaseMessage], operator.add] # The 'next' field indicates where to route to next next: str + # used for reflection agents + loop_tracker: dict class TeamFloAgentStateWithPlan(TypedDict): input: str diff --git a/flo_ai/tools/flo_pdf_rag_tool.py b/flo_ai/tools/flo_pdf_rag_tool.py deleted file mode 100644 index 412ff194..00000000 --- a/flo_ai/tools/flo_pdf_rag_tool.py +++ /dev/null @@ -1,17 +0,0 @@ -from langchain.tools import Tool -from langchain_core.runnables import Runnable -from flo_ai.retrievers.flo_retriever import FloRagBuilder -from flo_ai.state.flo_session import FloSession -from flo_ai.retrievers.flo_compression_pipeline import FloCompressionPipeline -from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder -from langchain_core.vectorstores import VectorStoreRetriever -from flo_ai.tools.flo_rag_retriver_tool import FloRagRetrieverTool - -class FloPDFRagTool(): - - def __init__(self) -> None: - raise ValueError("You are supposed to use Builder, FloRagRetriverTool.Builder()") - - class Builder(FloRagRetrieverTool.Builder): - def __init__(self) -> None: - super().__init__() \ No newline at end of file diff --git a/flo_ai/tools/flo_rag_retriver_tool.py b/flo_ai/tools/flo_rag_retriver_tool.py deleted file mode 100644 index ddadbe51..00000000 --- a/flo_ai/tools/flo_rag_retriver_tool.py +++ /dev/null @@ -1,57 +0,0 @@ -from langchain.tools import Tool -from langchain_core.runnables import Runnable -from flo_ai.retrievers.flo_retriever import FloRagBuilder -from flo_ai.state.flo_session import FloSession -from flo_ai.retrievers.flo_compression_pipeline import FloCompressionPipeline -from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder -from langchain_core.vectorstores import VectorStoreRetriever - -class FloRagRetrieverTool(): - - def __init__(self) -> None: - raise ValueError("You are supposed to use Builder, FloRagRetriverTool.Builder()") - - class Builder(): - - def __init__(self, - session: FloSession, - retriever: VectorStoreRetriever) -> None: - self.session = session - self.retriver = retriever - self.multiquery = False - self.custom_prompt: ChatPromptTemplate = None - self.extraction_pipeline: FloCompressionPipeline = None - - def add_custom_prompt(self, custom_prompt: ChatPromptTemplate): - self.custom_prompt = custom_prompt - - def add_custom_system_prompt(self, custom_system_prompt: str): - system_prompt = custom_system_prompt if custom_system_prompt is not None else """You are an assistant for question-answering tasks. - Use the following pieces of retrieved context to answer the question. - If you don't know the answer, just say that you don't know. - Use three sentences maximum and keep the answer concise.""" - self.custom_prompt = ChatPromptTemplate.from_messages( - [ - ("system", system_prompt), - MessagesPlaceholder(variable_name="chat_history"), - ("human", "{question}"), - ] - ) - - def add_extraction_pipeline(self, pipeline: FloCompressionPipeline): - self.extraction_pipeline = pipeline - - def enable_multi_query(self): - self.multiquery = True - - def build(self, name: str, description: str) -> Tool: - rag_builder = FloRagBuilder(self.session, self.retriver) - if self.custom_prompt is not None: - rag_builder.with_prompt(self.custom_prompt) - if self.multiquery: - rag_builder.with_multi_query() - if self.extraction_pipeline is not None: - rag_builder.with_compression(self.extraction_pipeline) - return rag_builder.build_rag_tool(name=name, description=description) - - diff --git a/flo_ai/yaml/flo_team_builder.py b/flo_ai/yaml/config.py similarity index 83% rename from flo_ai/yaml/flo_team_builder.py rename to flo_ai/yaml/config.py index 66a75b2e..06d30faf 100644 --- a/flo_ai/yaml/flo_team_builder.py +++ b/flo_ai/yaml/config.py @@ -1,5 +1,5 @@ from pydantic import BaseModel -from typing import List +from typing import List, Union import yaml import re from typing import Optional @@ -29,20 +29,36 @@ class ToolConfig(BaseModel): properties: Optional[List[KeyValueArgs]] = None filters: Optional[List[FilterArgs]] = None +class PromptStrategy(BaseModel): + kind: str + agent_name: str + retries: int + next: str | None = None + +class MemberKey(BaseModel): + name: str + class AgentConfig(BaseModel): name: str role: Optional[str] = None kind: Optional[str] = None job: Optional[str] = None tools: List[ToolConfig] = [] + to: Optional[List[MemberKey]] = None + retry: Optional[int] = 1 + +class EdgeConfig(BaseModel): + edge: List[str] + type: Optional[str] = None + rule: Optional[str] = None class RouterConfig(BaseModel): name: str kind: str job: Optional[str] = None start_node: Optional[str] = None - end_node: Optional[str] = None - edges: Optional[List[List[str]]] = None + end_node: Union[Optional[str], List[str]] = None + edges: Optional[List[EdgeConfig]] = None class PlannerConfig(BaseModel): name: str