diff --git a/examples/build_agents_by_code.ipynb b/examples/build_agents_by_code.ipynb index e7fbaba..fa113b7 100644 --- a/examples/build_agents_by_code.ipynb +++ b/examples/build_agents_by_code.ipynb @@ -28,8 +28,8 @@ "source": [ "from flo_ai import FloSupervisor, FloAgent, FloSession, FloTeam, FloLinear\n", "from langchain_openai import ChatOpenAI\n", - "# TODO router config needs fixing\n", - "from flo_ai.yaml.flo_team_builder import RouterConfig\n", + "from flo_ai.models.flo_reflection_agent import FloReflectionAgent\n", + "from flo_ai.models.delegate import Delegate\n", "from langchain_community.tools.tavily_search.tool import TavilySearchResults\n", "from dotenv import load_dotenv\n", "\n", @@ -47,7 +47,17 @@ "cell_type": "code", "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Edge : Researcher to Head-of-Marketing\n", + "Edge : BlogWriter to Head-of-Marketing\n", + "Edge : __start__ to Head-of-Marketing\n" + ] + } + ], "source": [ "llm = ChatOpenAI(temperature=0, model_name='gpt-4o')\n", "session = FloSession(llm).register_tool(\n", @@ -55,286 +65,243 @@ " tool=TavilySearchResults()\n", ")\n", "\n", - "researcher = FloAgent.Builder(session, \"Researcher\", \n", - " \"Do a research on the internet and find articles of relevent to the topic asked by the user\", [TavilySearchResults()]).build()\n", - "blogger = FloAgent.Builder(session, \"BlogWriter\", \n", - " \"Able to write a blog using information provided\", [TavilySearchResults()]).build()\n", + "researcher = FloAgent.Builder(\n", + " session,\n", + " \"Researcher\", \n", + " \"Do a research on the internet and find articles of relevent to the topic asked by the user\", \n", + " [TavilySearchResults()]\n", + ").build()\n", + "\n", + "blogger = FloAgent.Builder(\n", + " session, \n", + " \"BlogWriter\", \n", + " \"Able to write a blog using information provided\", \n", + " [TavilySearchResults()]\n", + ").build()\n", "\n", "marketing_team = FloTeam.Builder(session, \"Marketing\", [researcher, blogger]).build()\n", "r1 = FloSupervisor.Builder(session, \"Head-of-Marketing\", marketing_team).build()\n", - "flo_team_1 = r1.build_routed_team()\n" + "marketing_flo = r1.to_flo()\n" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ - "def draw_to_file(graph, filename: str, xray=False):\n", - " from PIL import Image as PILImage\n", - " import io\n", - " byte_image = graph.draw(xray)\n", - " with io.BytesIO(byte_image) as image_io:\n", - " image = PILImage.open(image_io)\n", - " image.save(filename)" + "from IPython.display import Image, display\n", + "\n", + "display(Image(marketing_flo.draw()))" ] }, { - "cell_type": "code", - "execution_count": 4, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "draw_to_file(flo_team_1, \"dk.png\", True)" + "A second team created for doing editorial suggestions" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": 4, "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Edge : Senior-Editor to Editor-Team-Routing\n", + "Edge : __start__ to Editor-Team-Routing\n" + ] + } + ], "source": [ - "A second team created for doing editorial suggestions" + "chief_editorial = FloAgent.Builder(\n", + " session, \n", + " \"Senior-Editor\", \n", + " \"Have a look at the article created and give editorial suggestions\", \n", + " [TavilySearchResults()]\n", + ").build()\n", + "\n", + "edit_team = FloTeam.Builder(session, \"Editorial-Team\", [chief_editorial]).build()\n", + "r2 = FloSupervisor.Builder(session, \"Editor-Team-Routing\", edit_team).build()\n", + "\n", + "editorial_flo = r2.to_flo()" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ - "chief_editorial = FloAgent.Builder(session, \"Senior-Editor\", \n", - " \"Have a look at the article created and give editorial suggestions\", [TavilySearchResults()]).build()\n", + "from IPython.display import Image, display\n", "\n", - "edit_team = FloTeam.Builder(session, \"Editorial-Team\", [chief_editorial]).build()\n", - "r2 = FloSupervisor.Builder(session, \"Editor-Team-Routing\", edit_team).build()\n", - "\n", - "editorial_team = r2.build_routed_team()\n", - "draw_to_file(editorial_team, \"editorial.png\", True)" + "display(Image(editorial_flo.draw()))" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Edge : __start__ to Marketing\n", + "Marketing\n", + "Editorial-Team\n", + "Edge : Marketing to Editorial-Team\n", + "Edge : Editorial-Team to __end__\n" + ] + } + ], "source": [ - "journal_company = FloTeam.Builder(session, \"Newspaper\", [flo_team_1, editorial_team])\n", + "journal_company = FloTeam.Builder(session, \"Newspaper\", [marketing_flo, editorial_flo])\n", "\n", - "# TODO fix router config\n", - "r3 = FloLinear.Builder(session,\n", - " journal_company, \n", - " RouterConfig(**{\"name\" :\"Serial\", \"kind\": \"linear\"})).build()\n", + "r3 = FloLinear.Builder(\n", + " session,\n", + " \"linear-router\",\n", + " journal_company\n", + ").build()\n", "\n", - "master_team = r3.build_routed_team()" + "master_flo = r3.to_flo()" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ - "draw_to_file(master_team, \"master.png\")" + "from IPython.display import Image, display\n", + "\n", + "display(Image(master_flo.draw()))" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, + "outputs": [], + "source": [ + "# master_flo.invoke(\"Write an article about CR7\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, "outputs": [ { "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': 'Cristiano Ronaldo biography'}`\n", - "\n", - "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[{'url': 'https://www.liveabout.com/cristiano-ronaldo-3557502', 'content': 'Learn about the life and career of Cristiano Ronaldo, the Portuguese footballer who plays for Real Madrid and is one of the best players in the world. Find out his achievements, awards, records, and controversies in this comprehensive biography.'}, {'url': 'https://www.biographyonline.net/sport/football/cristiano-ronaldo.html', 'content': \"Learn about the life and career of Cristiano Ronaldo, one of the world's best footballers. From his early days in Portugal to his success at Manchester United, Real Madrid and Juventus, and his international achievements with Portugal.\"}, {'url': 'https://eurofootballer.com/who-is-cristiano-ronaldo-complete-biography-and-life-history/', 'content': \"Learn about the life and achievements of Cristiano Ronaldo, one of the world's best footballers. From his early days in Portugal to his record-breaking stints in England, Spain and Italy, and his current contract with Al-Nassr in Saudi Arabia.\"}, {'url': 'https://en.wikipedia.org/wiki/Career_of_Cristiano_Ronaldo', 'content': 'Learn about the life and achievements of Cristiano Ronaldo, one of the greatest footballers of all time. From his early days at Sporting CP to his record-breaking moves and awards, this article covers his career in detail.'}, {'url': 'https://www.britannica.com/biography/Cristiano-Ronaldo', 'content': 'He scored a total of 66 goals in 56 appearances with Madrid and the Portuguese national team in 2013 to earn his second world player of the year award (the FIFA World Player of the Year was renamed the FIFA Ballon d’Or in 2010). Endorsements and legal issues\\nRonaldo was one of the most well-known sports stars off the field, and numerous studies of athletes’ popularity showed that he was the most-beloved athlete in the world during his playing peak. In 2016 he helped Portugal win the European Championship, the country’s first major international tournament title, although he only played sparingly in the final because of a knee injury that he had sustained early in the match. Ronaldo came into the 2014 World Cup hot off of his second world player of the year win, but his play at the tournament was spotty, and the entire Portugal team struggled during a group-stage elimination. His extreme popularity made Ronaldo one of the highest-paid endorsers in sports history, and in November 2016 he became the third person (after basketball superstars Michael Jordan and LeBron James) to earn a “lifetime” contract from the sportswear company Nike.'}]\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `tavily_search_results_json` with `{'query': 'Cristiano Ronaldo career achievements'}`\n", - "\n", - "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[{'url': 'https://en.wikipedia.org/wiki/List_of_career_achievements_by_Cristiano_Ronaldo', 'content': \"Inclusions in theoretical teams\\nSelections for international sportsperson of the year\\nInternational man of the match awards\\nOrders\\nMiscellaneous\\nRecords\\nGoalscoring statistics\\nClub\\n[494][495][496]\\nCountry\\nSource: Rec.Sport. Widely regarded as one of the greatest players of all time, Ronaldo holds the record for most goals and assists in the UEFA Champions League (140 and 42 respectively), and the record for most goals in the UEFA European Championship (14), its qualification stage (40), and the FIFA Club World Cup (7), as well as most goals scored in a UEFA Champions League season (17 in\\n2013-14), most international goals (128), and most appearances in a national team (204). Ronaldo with then President of the Community of Madrid, Cristina Cifuentes, during Champions League title celebrations in Madrid in 2016\\nRonaldo (second from the right) raising his hand in the air as Real Madrid celebrate winning the UEFA Champions League, on 26 May 2018\\nSee also\\nFootnotes\\nReferences\\nWorks cited\\nBiographies Contents\\nList of career achievements by Cristiano Ronaldo\\nPortuguese professional footballer\\nEponyms and public art\\nFilms\\nOver the course of his career, Portuguese footballer Cristiano Ronaldo has received five Ballon d'Or/FIFA Ballon d'Or awards,[a] the most for a European player. All in all he had won over 300 trophies and medals by January 2021, with some of them dating back to his childhood.[1]\\nCollective awards\\nFriendly competitions\\nIndividual honours\\nRonaldo has obtained many other minor achievements, awards and recognitions, by the major sport magazines and newspapers, which are not reported.\\n\"}, {'url': 'https://www.sportingnews.com/us/soccer/news/cristiano-ronaldo-career-trophies-how-many-has-cr7-won/sgkll9jwwmnkarutohgptsvj', 'content': \"In 2021, Ronaldo received The Best FIFA Special Award for Outstanding Career Achievement as he broke the record for most international goals scored by a male footballer. Ronaldo's time at ...\"}, {'url': 'https://www.transfermarkt.com/cristiano-ronaldo/erfolge/spieler/8198', 'content': 'This statistic shows the achievements of Al-Nasr Riad player Cristiano Ronaldo. ... #7 Cristiano Ronaldo. 3 5 1 5 4. Al-Nassr Saudi ... Career . Contact . About Us . TM-Team FAQ . Social media . Transfermarkt Company Projects ...'}, {'url': 'https://www.britannica.com/biography/Cristiano-Ronaldo', 'content': 'He scored a total of 66 goals in 56 appearances with Madrid and the Portuguese national team in 2013 to earn his second world player of the year award (the FIFA World Player of the Year was renamed the FIFA Ballon d’Or in 2010). Endorsements and legal issues\\nRonaldo was one of the most well-known sports stars off the field, and numerous studies of athletes’ popularity showed that he was the most-beloved athlete in the world during his playing peak. In 2016 he helped Portugal win the European Championship, the country’s first major international tournament title, although he only played sparingly in the final because of a knee injury that he had sustained early in the match. Ronaldo came into the 2014 World Cup hot off of his second world player of the year win, but his play at the tournament was spotty, and the entire Portugal team struggled during a group-stage elimination. His extreme popularity made Ronaldo one of the highest-paid endorsers in sports history, and in November 2016 he became the third person (after basketball superstars Michael Jordan and LeBron James) to earn a “lifetime” contract from the sportswear company Nike.'}, {'url': 'https://www.biographyonline.net/sport/football/cristiano-ronaldo.html', 'content': \"Cristiano Ronaldo is a Portuguese professional footballer who has played for Manchester United, Real Madrid, Juventus and Portugal. Along with Lionel Messi, he is regularly considered to be one of the top two players in the world. He became the world's most expensive player when Real Madrid signed him for 94 million Euros in 2009 from ...\"}]\u001b[0m\u001b[32;1m\u001b[1;3m\n", - "Invoking: `tavily_search_results_json` with `{'query': 'Cristiano Ronaldo personal life'}`\n", - "\n", - "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[{'url': 'https://talksport.com/football/1752006/cristiano-ronaldo-georgina-rodriguez-family-children/', 'content': \"Ronaldo has been with Rodriguez since 2016 Credit: @cristiano Instagram Of course, there are also plenty of eyes on the superstar's personal life and his partner Georgina Rodriguez has become a ...\"}, {'url': 'https://www.sportskeeda.com/football/ronaldo-family', 'content': \"Learn about the Portuguese football legend's family, including his girlfriend Georgina Rodriguez, his twins Eva Maria and Mateo, and his son Cristiano Jr. Find out how he lost his father at a young age and who is the mother of his twins.\"}, {'url': 'https://people.com/parents/everything-to-know-about-cristiano-ronaldo-family-kids/', 'content': '\"\\nNow nearly 12 years old, Cristiano Jr. is taking after his father in more than just looks — he plays soccer just like Dad!\\nEva Maria and Mateo Ronaldo, 6\\nIn June 2017, Ronaldo welcomed twins Eva and Mateo via surrogate, sharing the happy news of their arrival in a Facebook post captioned, \"So happy to be able to hold the two new loves of my life 🙏❤. Everything to Know About Cristiano Ronaldo\\'s Family\\nCristiano Ronaldo shares his children with girlfriend Georgina Rodriguez\\nCristiano Ronaldo and Georgina Rodriguez are finding \"hope and happiness\" after the birth of their daughter and amid mourning the loss of their newborn son.\\n This year, I had the best and the worst moment of my life in an instant,\" she said, adding that Ronaldo \"encouraged\" her to start enjoying life again after the heavy loss. \"\\nMonths before the twins\\' arrival, Ronaldo began dating model Georgina Rodriguez, with the pair making their first public appearance at the Best FIFA Football Awards in January 2017.\\n \"After one week I say, \\'Let\\'s be upfront, and let\\'s be honest with the kids, let\\'s say that, Ángel, which is his name, he go to the Heaven.\\''}, {'url': 'https://www.thisisamericansoccer.com/cristiano-ronaldos-family/', 'content': 'Learn about the Ronaldo family tree, from his humble origins in Madeira to his global fame as a football legend. Discover how his parents, siblings, partner, and children shaped his character and supported his dreams.'}, {'url': 'https://en.wikipedia.org/wiki/Cristiano_Ronaldo', 'content': 'After scoring in the following matches against Chelsea and Brentford, he was named the Premier League Player of the Month for April.[313]\\nHe finished the season with 24 goals in all competitions, 18 of those goals being in the Premier League, making him the third-highest goalscorer in the league behind Golden Boot winners Mohamed Salah and Son Heung-min, being named in the Premier League Team of the Year and the winner of United\\'s Sir Matt Busby Player of the Year award, given to the club\\'s best player from the previous season;[314][315] however, with United finishing in a disappointing sixth place and qualifying for the UEFA Europa League, Ronaldo went trophyless for the first time since 2010.[316]\\nAfter growing dissatisfaction with the direction of United on and off the field, Ronaldo missed the club\\'s pre-season tour of Thailand and Australia due to family reasons, amid reports of his desire to leave to join a club competing in the Champions League, despite incoming manager Erik ten Hag insisting that he was not for sale and was part of the club\\'s plans.[317] Ronaldo was awarded the Player of the Month award for February after scoring eight goals and assisting twice.[346] Ronaldo spent another season without winning a league title, as Al Nassr finished second in the league in the 2022–23 season.[347]\\nRonaldo\\'s signing for Al-Nassr resulted in increased popularity both domestically and internationally of the Saudi Pro League, with various European players such as Karim Benzema, Sadio Mané, N\\'Golo Kanté, Rúben Neves, Riyad Mahrez, Roberto Firmino and Neymar moving to the Saudi Pro League during the summer transfer window, crediting Ronaldo as one of the main factors for moving to the league.[348]\\nHe scored his first goal of the 2023–24 season in a 4–1 win over Union Monastirienne in the Arab Club Champions Cup on 31 July.[349] This unique role has been described by pundits as that of a \"false\", \"attacking\", or \"goalscoring winger\", as Ronaldo effectively almost functioned as a striker at times with his central runs into the penalty area, despite actually playing on the left flank.[488][493] From 2013 onwards, under manager Carlo Ancelotti, he effectively adapted his style to the physical effects of ageing with increasingly reduced off-the-ball movement and general involvement, completing fewer dribbles and passes per game, and instead focusing on short-distance creating and goalscoring.[487][494][495] Since 2017, Ronaldo adapted his style of play yet again to become more of a free-roaming centre forward under manager Zinedine Zidane, a role in which he continued to excel and maintain a prolific goalscoring record; in this position, he earned praise in the media for his intelligent movement both on and off the ball, positional sense, link-up play and finishing, as well as his ability to lose or anticipate his markers, find space in the box and score from few touches or opportunities.[496][497][498]\\n Ronaldo then missed United\\'s following matches before the World Cup break, with Ten Hag saying that Ronaldo was ill.[329]\\nOn 14 November, an interview with Piers Morgan was published, where Ronaldo said that he felt \"betrayed\" by Ten Hag and senior executives who wanted Ronaldo to leave the club, and accused the club of doubting him regarding the illness of his daughter that led him to miss pre-season, adding that he did not respect ten Hag \"because he doesn\\'t show respect for me\", leading him to be disappointed with the communication of the club.[330] Ronaldo claimed that ten Hag deliberately provoked him by first leaving him on the bench against City, and then wanting to bring him on in the final moments against Tottenham, but added that he regretted his decision to leave early.[330] Ronaldo ended his first season in English football by scoring the opening goal in United\\'s 3–0 win over Millwall in the 2004 FA Cup Final, earning his first trophy.[52] BBC pundit Alan Hansen described him as the star of the final.[53] The British press had been critical of Ronaldo during the season for his \"elaborate\" step-overs in trying to beat opponents,[54] but teammate Gary Neville said he was \"not a show pony, but the real thing\", and predicted he would become a world-class player.[55]\\n\"He has got the tricks and party pieces, we know that, but they\\'re not much good unless there is something at the end of it all.'}]\u001b[0m\u001b[32;1m\u001b[1;3m### Cristiano Ronaldo: A Football Legend\n", - "\n", - "#### Early Life and Career Beginnings\n", - "\n", - "Cristiano Ronaldo dos Santos Aveiro, commonly known as Cristiano Ronaldo or CR7, was born on February 5, 1985, in Funchal, Madeira, Portugal. From a young age, Ronaldo displayed an extraordinary talent for football, which led him to join the youth academy of Sporting CP in Lisbon. His exceptional skills quickly caught the attention of scouts from top European clubs.\n", - "\n", - "#### Rise to Stardom\n", - "\n", - "Ronaldo's professional career began at Sporting CP, where he made his debut in the Primeira Liga at just 17 years old. His performance against Manchester United in a friendly match in 2003 was so impressive that it led to his transfer to the English club. At Manchester United, Ronaldo's career skyrocketed. Under the guidance of Sir Alex Ferguson, he developed into one of the best players in the world, winning three Premier League titles, a UEFA Champions League title, and his first Ballon d'Or in 2008.\n", - "\n", - "#### Real Madrid Era\n", - "\n", - "In 2009, Ronaldo made a record-breaking transfer to Real Madrid for €94 million. His time at Real Madrid was marked by unprecedented success. He became the club's all-time top scorer, won four Champions League titles, and added four more Ballon d'Or awards to his collection. Ronaldo's rivalry with Lionel Messi during this period became one of the most talked-about aspects of modern football.\n", - "\n", - "#### Juventus and Beyond\n", - "\n", - "In 2018, Ronaldo transferred to Juventus for €100 million. He continued to break records and win titles, including two Serie A championships. In 2021, he returned to Manchester United, where he continued to perform at a high level. As of 2023, Ronaldo plays for Al-Nassr in Saudi Arabia, further expanding his global influence.\n", - "\n", - "#### International Career\n", - "\n", - "Ronaldo's international career with Portugal has been equally illustrious. He has scored the most goals in international football history and has made the most appearances for the Portuguese national team. His crowning achievement came in 2016 when he led Portugal to victory in the UEFA European Championship, the country's first major international tournament win.\n", - "\n", - "#### Personal Life\n", - "\n", - "Off the field, Ronaldo is known for his philanthropic efforts and business ventures. He has a long-term relationship with Georgina Rodriguez, and together they have a large family, including his son Cristiano Jr. and twins Eva Maria and Mateo. Ronaldo's personal life has been a subject of media attention, but he has managed to maintain a positive public image.\n", - "\n", - "#### Achievements and Records\n", - "\n", - "Ronaldo's list of achievements is extensive. He holds the record for the most goals and assists in the UEFA Champions League, the most goals in the UEFA European Championship, and the most international goals. He has won over 300 trophies and medals, including five Ballon d'Or awards, making him one of the most decorated players in football history.\n", - "\n", - "#### Legacy\n", - "\n", - "Cristiano Ronaldo's impact on football is immeasurable. He has set new standards for excellence and professionalism, inspiring countless young athletes around the world. His dedication, work ethic, and relentless pursuit of greatness have cemented his place as one of the greatest footballers of all time.\n", - "\n", - "#### Conclusion\n", - "\n", - "Cristiano Ronaldo's journey from a young boy in Madeira to a global football icon is a testament to his talent, hard work, and determination. His legacy will continue to influence the world of football for generations to come. Whether on the field or off it, Ronaldo's name will always be synonymous with greatness.\u001b[0m\n", - "\n", - "\u001b[1m> Finished chain.\u001b[0m\n", - "\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': 'Cristiano Ronaldo latest news 2023'}`\n", - "\n", - "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3m[{'url': 'https://abcnews.go.com/Sports/cristiano-ronaldo-end-2023-worlds-top-goalscorer/story?id=106012559', 'content': \"Cristiano Ronaldo to end 2023 as world's top goalscorer - ABC News ABC News Cristiano Ronaldo is set to end the year as the world's top goalscorer after scoring his 54th goal of 2023 in Al Nassr's 4-1 victory at Al Taawoun in the Saudi Pro League on Saturday. Ronaldo's latest goal on Saturday came on the one-year anniversary of him signing for Saudi club Al Nassr, following his controversial exit from Manchester United. Al Nassr were leading 3-1 through goals from Marcelo Brozovic, Aymeric Laporte and Otavio\\xa0on Saturday when Ronaldo headed in from six yards out in the second minute of stoppage time. How to watch the Harris-Trump ABC News debate --------------------------------------------- * Sep 9, 9:01 AM ABC News Live ABC News Network © 2024 ABC News\"}, {'url': 'https://www.newsnow.co.uk/h/Sport/Football/International+Stars/Cristiano+Ronaldo', 'content': 'Latest headlines on Cristiano Ronaldo, one of the greatest ever footballers, goal scorers, and most successful players ever to kick a ball. ... About our Cristiano Ronaldo News Born in 1985, Cristiano Ronaldo is one of the greatest footballers of all-time. ... he missed the match against Al-Tai on 5 January 2023. Ronaldo played his first game ...'}, {'url': 'https://www.cnn.com/2023/12/12/sport/cristiano-ronaldo-50-goals-2023-spt-intl/index.html', 'content': 'CNN values your feedback\\nCristiano Ronaldo scores 50th goal of 2023 as potential Lionel Messi clash is announced\\nCristiano Ronaldo scored his 50th goal of the calendar year on Monday as Al Nassr advanced to the semifinals of the Saudi King Cup with a 5-2 victory against rival Al Shabab.\\n Lionel Messi says he is focused on playing at next year’s Copa América but doesn’t rule out appearing at 2026 World Cup\\nLast week, the 38-year-old forward played the 1,200th game of his professional career, scoring a league-leading 16th goal in the Saudi Pro League this season.\\n Cristiano Ronaldo says his long-standing ‘rivalry’ with Lionel Messi is over\\n“Great victory and I’m thrilled to announce my 50th goal in 2023, all thanks to the unwavering support of my teammates, fans, and my family!” Ronaldo netted his team’s fourth goal with a powerful strike in the 74th minute, continuing his impressive scoring rate since playing his first game in Saudi Arabia in January.\\n “We are excited to connect with new supporters in Saudi Arabia, and also hope people all over the world will be tuning in to see a pair of dream matches like these.”\\n'}, {'url': 'https://www.bbc.co.uk/sport/football/67688432', 'content': 'Cristiano Ronaldo scored his 50th goal in 2023 as Al-Nassr beat rivals Al-Shabab 5-2 to reach the semi-finals of the Saudi King Cup. The former Real Madrid and Manchester United forward got his ...'}, {'url': 'https://www.cnn.com/2023/05/28/football/lionel-messi-record-psg-ligue-1-title-spt-intl/index.html', 'content': 'There was another landmark in the long rivalry between Lionel Messi and Cristiano Ronaldo on Saturday. ... Published 9:01 AM EDT, Sun May 28, 2023 ... But this latest triumph masks an increasingly ...'}]\u001b[0m\u001b[32;1m\u001b[1;3m### Cristiano Ronaldo: A Football Legend\n", - "\n", - "#### Early Life and Career Beginnings\n", - "\n", - "Cristiano Ronaldo dos Santos Aveiro, commonly known as Cristiano Ronaldo or CR7, was born on February 5, 1985, in Funchal, Madeira, Portugal. From a young age, Ronaldo displayed an extraordinary talent for football, which led him to join the youth academy of Sporting CP in Lisbon. His exceptional skills quickly caught the attention of scouts from top European clubs.\n", - "\n", - "#### Rise to Stardom\n", - "\n", - "Ronaldo's professional career began at Sporting CP, where he made his debut in the Primeira Liga at just 17 years old. His performance against Manchester United in a friendly match in 2003 was so impressive that it led to his transfer to the English club. At Manchester United, Ronaldo's career skyrocketed. Under the guidance of Sir Alex Ferguson, he developed into one of the best players in the world, winning three Premier League titles, a UEFA Champions League title, and his first Ballon d'Or in 2008.\n", - "\n", - "#### Real Madrid Era\n", - "\n", - "In 2009, Ronaldo made a record-breaking transfer to Real Madrid for €94 million. His time at Real Madrid was marked by unprecedented success. He became the club's all-time top scorer, won four Champions League titles, and added four more Ballon d'Or awards to his collection. Ronaldo's rivalry with Lionel Messi during this period became one of the most talked-about aspects of modern football.\n", - "\n", - "#### Juventus and Beyond\n", - "\n", - "In 2018, Ronaldo transferred to Juventus for €100 million. He continued to break records and win titles, including two Serie A championships. In 2021, he returned to Manchester United, where he continued to perform at a high level. As of 2023, Ronaldo plays for Al-Nassr in Saudi Arabia, further expanding his global influence.\n", - "\n", - "#### International Career\n", - "\n", - "Ronaldo's international career with Portugal has been equally illustrious. He has scored the most goals in international football history and has made the most appearances for the Portuguese national team. His crowning achievement came in 2016 when he led Portugal to victory in the UEFA European Championship, the country's first major international tournament win.\n", - "\n", - "#### Personal Life\n", - "\n", - "Off the field, Ronaldo is known for his philanthropic efforts and business ventures. He has a long-term relationship with Georgina Rodriguez, and together they have a large family, including his son Cristiano Jr. and twins Eva Maria and Mateo. Ronaldo's personal life has been a subject of media attention, but he has managed to maintain a positive public image.\n", - "\n", - "#### Achievements and Records\n", - "\n", - "Ronaldo's list of achievements is extensive. He holds the record for the most goals and assists in the UEFA Champions League, the most goals in the UEFA European Championship, and the most international goals. He has won over 300 trophies and medals, including five Ballon d'Or awards, making him one of the most decorated players in football history.\n", - "\n", - "#### Latest Milestones in 2023\n", - "\n", - "As of 2023, Cristiano Ronaldo continues to break records and achieve new milestones. He is set to end the year as the world's top goalscorer, having scored his 54th goal of 2023 in Al Nassr's 4-1 victory at Al Taawoun in the Saudi Pro League. This goal came on the one-year anniversary of his signing with Al Nassr, following his controversial exit from Manchester United. Ronaldo also scored his 50th goal of the calendar year in a match against Al Shabab, leading Al Nassr to the semifinals of the Saudi King Cup. This year, he also played his 1,200th professional game, continuing to demonstrate his remarkable longevity and consistency.\n", - "\n", - "#### Legacy\n", - "\n", - "Cristiano Ronaldo's impact on football is immeasurable. He has set new standards for excellence and professionalism, inspiring countless young athletes around the world. His dedication, work ethic, and relentless pursuit of greatness have cemented his place as one of the greatest footballers of all time.\n", - "\n", - "#### Conclusion\n", - "\n", - "Cristiano Ronaldo's journey from a young boy in Madeira to a global football icon is a testament to his talent, hard work, and determination. His legacy will continue to influence the world of football for generations to come. Whether on the field or off it, Ronaldo's name will always be synonymous with greatness.\u001b[0m\n", - "\n", - "\u001b[1m> Finished chain.\u001b[0m\n", - "\n", - "\n", - "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", - "\u001b[32;1m\u001b[1;3m### Cristiano Ronaldo: A Football Legend\n", - "\n", - "#### Early Life and Career Beginnings\n", - "\n", - "Cristiano Ronaldo dos Santos Aveiro, commonly known as Cristiano Ronaldo or CR7, was born on February 5, 1985, in Funchal, Madeira, Portugal. From a young age, Ronaldo displayed an extraordinary talent for football, which led him to join the youth academy of Sporting CP in Lisbon. His exceptional skills quickly caught the attention of scouts from top European clubs.\n", - "\n", - "#### Rise to Stardom\n", - "\n", - "Ronaldo's professional career began at Sporting CP, where he made his debut in the Primeira Liga at just 17 years old. His performance against Manchester United in a friendly match in 2003 was so impressive that it led to his transfer to the English club. At Manchester United, Ronaldo's career skyrocketed. Under the guidance of Sir Alex Ferguson, he developed into one of the best players in the world, winning three Premier League titles, a UEFA Champions League title, and his first Ballon d'Or in 2008.\n", - "\n", - "#### Real Madrid Era\n", - "\n", - "In 2009, Ronaldo made a record-breaking transfer to Real Madrid for €94 million. His time at Real Madrid was marked by unprecedented success. He became the club's all-time top scorer, won four Champions League titles, and added four more Ballon d'Or awards to his collection. Ronaldo's rivalry with Lionel Messi during this period became one of the most talked-about aspects of modern football.\n", - "\n", - "#### Juventus and Beyond\n", - "\n", - "In 2018, Ronaldo transferred to Juventus for €100 million. He continued to break records and win titles, including two Serie A championships. In 2021, he returned to Manchester United, where he continued to perform at a high level. As of 2023, Ronaldo plays for Al-Nassr in Saudi Arabia, further expanding his global influence.\n", - "\n", - "#### International Career\n", - "\n", - "Ronaldo's international career with Portugal has been equally illustrious. He has scored the most goals in international football history and has made the most appearances for the Portuguese national team. His crowning achievement came in 2016 when he led Portugal to victory in the UEFA European Championship, the country's first major international tournament win.\n", - "\n", - "#### Personal Life\n", - "\n", - "Off the field, Ronaldo is known for his philanthropic efforts and business ventures. He has a long-term relationship with Georgina Rodriguez, and together they have a large family, including his son Cristiano Jr. and twins Eva Maria and Mateo. Ronaldo's personal life has been a subject of media attention, but he has managed to maintain a positive public image.\n", - "\n", - "#### Achievements and Records\n", - "\n", - "Ronaldo's list of achievements is extensive. He holds the record for the most goals and assists in the UEFA Champions League, the most goals in the UEFA European Championship, and the most international goals. He has won over 300 trophies and medals, including five Ballon d'Or awards, making him one of the most decorated players in football history.\n", - "\n", - "#### Latest Milestones in 2023\n", - "\n", - "As of 2023, Cristiano Ronaldo continues to break records and achieve new milestones. He is set to end the year as the world's top goalscorer, having scored his 54th goal of 2023 in Al Nassr's 4-1 victory at Al Taawoun in the Saudi Pro League. This goal came on the one-year anniversary of his signing with Al Nassr, following his controversial exit from Manchester United. Ronaldo also scored his 50th goal of the calendar year in a match against Al Shabab, leading Al Nassr to the semifinals of the Saudi King Cup. This year, he also played his 1,200th professional game, continuing to demonstrate his remarkable longevity and consistency.\n", - "\n", - "#### Legacy\n", - "\n", - "Cristiano Ronaldo's impact on football is immeasurable. He has set new standards for excellence and professionalism, inspiring countless young athletes around the world. His dedication, work ethic, and relentless pursuit of greatness have cemented his place as one of the greatest footballers of all time.\n", - "\n", - "#### Conclusion\n", - "\n", - "Cristiano Ronaldo's journey from a young boy in Madeira to a global football icon is a testament to his talent, hard work, and determination. His legacy will continue to influence the world of football for generations to come. Whether on the field or off it, Ronaldo's name will always be synonymous with greatness.\n", - "\n", - "---\n", - "\n", - "### Editorial Suggestions:\n", - "\n", - "1. **Introduction**: Consider adding a brief introductory paragraph that encapsulates Ronaldo's significance in football. This will set the stage for the detailed sections that follow.\n", - "\n", - "2. **Subheadings**: Ensure consistency in the formatting of subheadings. For example, \"Real Madrid Era\" could be \"The Real Madrid Era\" to match the style of \"Juventus and Beyond.\"\n", - "\n", - "3. **Transitions**: Add transitional sentences between sections to improve the flow of the article. For instance, a sentence at the end of the \"Rise to Stardom\" section could hint at his upcoming move to Real Madrid.\n", - "\n", - "4. **Details and Anecdotes**: Incorporate more personal anecdotes or lesser-known facts to make the article more engaging. For example, mention specific memorable matches or goals.\n", - "\n", - "5. **Quotes**: Including quotes from Ronaldo, his coaches, or teammates can add depth and authenticity to the article.\n", - "\n", - "6. **Visuals**: If this article is intended for a digital platform, consider adding images, infographics, or videos to complement the text and provide a richer experience for the reader.\n", - "\n", - "7. **Sources and References**: If possible, cite sources or references for key statistics and claims, especially in the \"Achievements and Records\" and \"Latest Milestones in 2023\" sections.\n", - "\n", - "8. **Conclusion**: The conclusion could be more impactful by summarizing his influence on both football and popular culture, and perhaps speculating on his future contributions to the sport.\n", - "\n", - "By incorporating these suggestions, the article can become more comprehensive, engaging, and polished.\u001b[0m\n", - "\n", - "\u001b[1m> Finished chain.\u001b[0m\n" + "Edge : __start__ to Marketing\n", + "Marketing\n", + "Editorial-Team\n", + "Edge : Marketing to Editorial-Team\n", + "Editorial-Team\n", + "journal-reflection\n", + "next node\n", + "__end__\n", + "add node\n", + "f/ReflectionManager\n", + "Edge : M to f/ReflectionManager\n", + "Edge : journal-reflection to M\n" ] }, + { + "ename": "ValueError", + "evalue": "Found edge starting at unknown node 'M'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[9], line 16\u001b[0m\n\u001b[1;32m 8\u001b[0m journal_company_with_reflection \u001b[38;5;241m=\u001b[39m FloTeam\u001b[38;5;241m.\u001b[39mBuilder(session, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNewspaper\u001b[39m\u001b[38;5;124m\"\u001b[39m, [marketing_flo, editorial_flo, reflection_agent])\n\u001b[1;32m 10\u001b[0m r4 \u001b[38;5;241m=\u001b[39m FloLinear\u001b[38;5;241m.\u001b[39mBuilder(\n\u001b[1;32m 11\u001b[0m session,\n\u001b[1;32m 12\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mlinear-router\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 13\u001b[0m journal_company_with_reflection\n\u001b[1;32m 14\u001b[0m )\u001b[38;5;241m.\u001b[39mbuild()\n\u001b[0;32m---> 16\u001b[0m master_flo_with_reflection \u001b[38;5;241m=\u001b[39m \u001b[43mr4\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mto_flo\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Documents/hub/flo/flo_ai/router/flo_router.py:42\u001b[0m, in \u001b[0;36mFloRouter.to_flo\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 41\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mto_flo\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m FloRoutedTeam:\n\u001b[0;32m---> 42\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbuild_graph\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/Documents/hub/flo/flo_ai/router/flo_linear.py:57\u001b[0m, in \u001b[0;36mFloLinear.build_graph\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 54\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m end_node\u001b[38;5;241m.\u001b[39mkind \u001b[38;5;241m!=\u001b[39m ExecutableType\u001b[38;5;241m.\u001b[39mdelegator:\n\u001b[1;32m 55\u001b[0m workflow\u001b[38;5;241m.\u001b[39madd_edge(end_node\u001b[38;5;241m.\u001b[39mname, END)\n\u001b[0;32m---> 57\u001b[0m workflow_graph \u001b[38;5;241m=\u001b[39m \u001b[43mworkflow\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcompile\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 59\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m FloRoutedTeam(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mflo_team\u001b[38;5;241m.\u001b[39mname, workflow_graph)\n", + "File \u001b[0;32m~/Documents/hub/flo/.venv/lib/python3.11/site-packages/langgraph/graph/state.py:431\u001b[0m, in \u001b[0;36mStateGraph.compile\u001b[0;34m(self, checkpointer, store, interrupt_before, interrupt_after, debug)\u001b[0m\n\u001b[1;32m 428\u001b[0m interrupt_after \u001b[38;5;241m=\u001b[39m interrupt_after \u001b[38;5;129;01mor\u001b[39;00m []\n\u001b[1;32m 430\u001b[0m \u001b[38;5;66;03m# validate the graph\u001b[39;00m\n\u001b[0;32m--> 431\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mvalidate\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 432\u001b[0m \u001b[43m \u001b[49m\u001b[43minterrupt\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m(\u001b[49m\n\u001b[1;32m 433\u001b[0m \u001b[43m \u001b[49m\u001b[43m(\u001b[49m\u001b[43minterrupt_before\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mif\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43minterrupt_before\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m!=\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m*\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01melse\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43m[\u001b[49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\u001b[43m \u001b[49m\u001b[43minterrupt_after\u001b[49m\n\u001b[1;32m 434\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43;01mif\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43minterrupt_after\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m!=\u001b[39;49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m*\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\n\u001b[1;32m 435\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43;01melse\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43m[\u001b[49m\u001b[43m]\u001b[49m\n\u001b[1;32m 436\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 437\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 439\u001b[0m \u001b[38;5;66;03m# prepare output channels\u001b[39;00m\n\u001b[1;32m 440\u001b[0m output_channels \u001b[38;5;241m=\u001b[39m (\n\u001b[1;32m 441\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m__root__\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 442\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mschemas[\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39moutput]) \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m1\u001b[39m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 448\u001b[0m ]\n\u001b[1;32m 449\u001b[0m )\n", + "File \u001b[0;32m~/Documents/hub/flo/.venv/lib/python3.11/site-packages/langgraph/graph/graph.py:370\u001b[0m, in \u001b[0;36mGraph.validate\u001b[0;34m(self, interrupt)\u001b[0m\n\u001b[1;32m 368\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m source \u001b[38;5;129;01min\u001b[39;00m all_sources:\n\u001b[1;32m 369\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m source \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mnodes \u001b[38;5;129;01mand\u001b[39;00m source \u001b[38;5;241m!=\u001b[39m START:\n\u001b[0;32m--> 370\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mFound edge starting at unknown node \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00msource\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 372\u001b[0m \u001b[38;5;66;03m# assemble targets\u001b[39;00m\n\u001b[1;32m 373\u001b[0m all_targets \u001b[38;5;241m=\u001b[39m {end \u001b[38;5;28;01mfor\u001b[39;00m _, end \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_all_edges}\n", + "\u001b[0;31mValueError\u001b[0m: Found edge starting at unknown node 'M'" + ] + } + ], + "source": [ + "\n", + "reflection_agent = FloReflectionAgent.Builder(\n", + " session,\n", + " \"journal-reflection\",\n", + " \"You are critic who looks are the article and create a list of improvements that can be done.\",\n", + " Delegate(to=[\"Marketing\"], retry=1)\n", + ").build()\n", + "\n", + "journal_company_with_reflection = FloTeam.Builder(session, \"Newspaper\", [marketing_flo, editorial_flo, reflection_agent])\n", + "\n", + "r4 = FloLinear.Builder(\n", + " session,\n", + " \"linear-router\",\n", + " journal_company_with_reflection\n", + ").build()\n", + "\n", + "master_flo_with_reflection = r4.to_flo()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ { "data": { + "image/png": "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", "text/plain": [ - "{'messages': [HumanMessage(content='Write an article about CR7'),\n", - " HumanMessage(content=\"### Cristiano Ronaldo: A Football Legend\\n\\n#### Early Life and Career Beginnings\\n\\nCristiano Ronaldo dos Santos Aveiro, commonly known as Cristiano Ronaldo or CR7, was born on February 5, 1985, in Funchal, Madeira, Portugal. From a young age, Ronaldo displayed an extraordinary talent for football, which led him to join the youth academy of Sporting CP in Lisbon. His exceptional skills quickly caught the attention of scouts from top European clubs.\\n\\n#### Rise to Stardom\\n\\nRonaldo's professional career began at Sporting CP, where he made his debut in the Primeira Liga at just 17 years old. His performance against Manchester United in a friendly match in 2003 was so impressive that it led to his transfer to the English club. At Manchester United, Ronaldo's career skyrocketed. Under the guidance of Sir Alex Ferguson, he developed into one of the best players in the world, winning three Premier League titles, a UEFA Champions League title, and his first Ballon d'Or in 2008.\\n\\n#### Real Madrid Era\\n\\nIn 2009, Ronaldo made a record-breaking transfer to Real Madrid for €94 million. His time at Real Madrid was marked by unprecedented success. He became the club's all-time top scorer, won four Champions League titles, and added four more Ballon d'Or awards to his collection. Ronaldo's rivalry with Lionel Messi during this period became one of the most talked-about aspects of modern football.\\n\\n#### Juventus and Beyond\\n\\nIn 2018, Ronaldo transferred to Juventus for €100 million. He continued to break records and win titles, including two Serie A championships. In 2021, he returned to Manchester United, where he continued to perform at a high level. As of 2023, Ronaldo plays for Al-Nassr in Saudi Arabia, further expanding his global influence.\\n\\n#### International Career\\n\\nRonaldo's international career with Portugal has been equally illustrious. He has scored the most goals in international football history and has made the most appearances for the Portuguese national team. His crowning achievement came in 2016 when he led Portugal to victory in the UEFA European Championship, the country's first major international tournament win.\\n\\n#### Personal Life\\n\\nOff the field, Ronaldo is known for his philanthropic efforts and business ventures. He has a long-term relationship with Georgina Rodriguez, and together they have a large family, including his son Cristiano Jr. and twins Eva Maria and Mateo. Ronaldo's personal life has been a subject of media attention, but he has managed to maintain a positive public image.\\n\\n#### Achievements and Records\\n\\nRonaldo's list of achievements is extensive. He holds the record for the most goals and assists in the UEFA Champions League, the most goals in the UEFA European Championship, and the most international goals. He has won over 300 trophies and medals, including five Ballon d'Or awards, making him one of the most decorated players in football history.\\n\\n#### Latest Milestones in 2023\\n\\nAs of 2023, Cristiano Ronaldo continues to break records and achieve new milestones. He is set to end the year as the world's top goalscorer, having scored his 54th goal of 2023 in Al Nassr's 4-1 victory at Al Taawoun in the Saudi Pro League. This goal came on the one-year anniversary of his signing with Al Nassr, following his controversial exit from Manchester United. Ronaldo also scored his 50th goal of the calendar year in a match against Al Shabab, leading Al Nassr to the semifinals of the Saudi King Cup. This year, he also played his 1,200th professional game, continuing to demonstrate his remarkable longevity and consistency.\\n\\n#### Legacy\\n\\nCristiano Ronaldo's impact on football is immeasurable. He has set new standards for excellence and professionalism, inspiring countless young athletes around the world. His dedication, work ethic, and relentless pursuit of greatness have cemented his place as one of the greatest footballers of all time.\\n\\n#### Conclusion\\n\\nCristiano Ronaldo's journey from a young boy in Madeira to a global football icon is a testament to his talent, hard work, and determination. His legacy will continue to influence the world of football for generations to come. Whether on the field or off it, Ronaldo's name will always be synonymous with greatness.\", name='BlogWriter-BEsx9'),\n", - " HumanMessage(content='### Cristiano Ronaldo: A Football Legend\\n\\n#### Early Life and Career Beginnings\\n\\nCristiano Ronaldo dos Santos Aveiro, commonly known as Cristiano Ronaldo or CR7, was born on February 5, 1985, in Funchal, Madeira, Portugal. From a young age, Ronaldo displayed an extraordinary talent for football, which led him to join the youth academy of Sporting CP in Lisbon. His exceptional skills quickly caught the attention of scouts from top European clubs.\\n\\n#### Rise to Stardom\\n\\nRonaldo\\'s professional career began at Sporting CP, where he made his debut in the Primeira Liga at just 17 years old. His performance against Manchester United in a friendly match in 2003 was so impressive that it led to his transfer to the English club. At Manchester United, Ronaldo\\'s career skyrocketed. Under the guidance of Sir Alex Ferguson, he developed into one of the best players in the world, winning three Premier League titles, a UEFA Champions League title, and his first Ballon d\\'Or in 2008.\\n\\n#### Real Madrid Era\\n\\nIn 2009, Ronaldo made a record-breaking transfer to Real Madrid for €94 million. His time at Real Madrid was marked by unprecedented success. He became the club\\'s all-time top scorer, won four Champions League titles, and added four more Ballon d\\'Or awards to his collection. Ronaldo\\'s rivalry with Lionel Messi during this period became one of the most talked-about aspects of modern football.\\n\\n#### Juventus and Beyond\\n\\nIn 2018, Ronaldo transferred to Juventus for €100 million. He continued to break records and win titles, including two Serie A championships. In 2021, he returned to Manchester United, where he continued to perform at a high level. As of 2023, Ronaldo plays for Al-Nassr in Saudi Arabia, further expanding his global influence.\\n\\n#### International Career\\n\\nRonaldo\\'s international career with Portugal has been equally illustrious. He has scored the most goals in international football history and has made the most appearances for the Portuguese national team. His crowning achievement came in 2016 when he led Portugal to victory in the UEFA European Championship, the country\\'s first major international tournament win.\\n\\n#### Personal Life\\n\\nOff the field, Ronaldo is known for his philanthropic efforts and business ventures. He has a long-term relationship with Georgina Rodriguez, and together they have a large family, including his son Cristiano Jr. and twins Eva Maria and Mateo. Ronaldo\\'s personal life has been a subject of media attention, but he has managed to maintain a positive public image.\\n\\n#### Achievements and Records\\n\\nRonaldo\\'s list of achievements is extensive. He holds the record for the most goals and assists in the UEFA Champions League, the most goals in the UEFA European Championship, and the most international goals. He has won over 300 trophies and medals, including five Ballon d\\'Or awards, making him one of the most decorated players in football history.\\n\\n#### Latest Milestones in 2023\\n\\nAs of 2023, Cristiano Ronaldo continues to break records and achieve new milestones. He is set to end the year as the world\\'s top goalscorer, having scored his 54th goal of 2023 in Al Nassr\\'s 4-1 victory at Al Taawoun in the Saudi Pro League. This goal came on the one-year anniversary of his signing with Al Nassr, following his controversial exit from Manchester United. Ronaldo also scored his 50th goal of the calendar year in a match against Al Shabab, leading Al Nassr to the semifinals of the Saudi King Cup. This year, he also played his 1,200th professional game, continuing to demonstrate his remarkable longevity and consistency.\\n\\n#### Legacy\\n\\nCristiano Ronaldo\\'s impact on football is immeasurable. He has set new standards for excellence and professionalism, inspiring countless young athletes around the world. His dedication, work ethic, and relentless pursuit of greatness have cemented his place as one of the greatest footballers of all time.\\n\\n#### Conclusion\\n\\nCristiano Ronaldo\\'s journey from a young boy in Madeira to a global football icon is a testament to his talent, hard work, and determination. His legacy will continue to influence the world of football for generations to come. Whether on the field or off it, Ronaldo\\'s name will always be synonymous with greatness.\\n\\n---\\n\\n### Editorial Suggestions:\\n\\n1. **Introduction**: Consider adding a brief introductory paragraph that encapsulates Ronaldo\\'s significance in football. This will set the stage for the detailed sections that follow.\\n\\n2. **Subheadings**: Ensure consistency in the formatting of subheadings. For example, \"Real Madrid Era\" could be \"The Real Madrid Era\" to match the style of \"Juventus and Beyond.\"\\n\\n3. **Transitions**: Add transitional sentences between sections to improve the flow of the article. For instance, a sentence at the end of the \"Rise to Stardom\" section could hint at his upcoming move to Real Madrid.\\n\\n4. **Details and Anecdotes**: Incorporate more personal anecdotes or lesser-known facts to make the article more engaging. For example, mention specific memorable matches or goals.\\n\\n5. **Quotes**: Including quotes from Ronaldo, his coaches, or teammates can add depth and authenticity to the article.\\n\\n6. **Visuals**: If this article is intended for a digital platform, consider adding images, infographics, or videos to complement the text and provide a richer experience for the reader.\\n\\n7. **Sources and References**: If possible, cite sources or references for key statistics and claims, especially in the \"Achievements and Records\" and \"Latest Milestones in 2023\" sections.\\n\\n8. **Conclusion**: The conclusion could be more impactful by summarizing his influence on both football and popular culture, and perhaps speculating on his future contributions to the sport.\\n\\nBy incorporating these suggestions, the article can become more comprehensive, engaging, and polished.', name='Senior-Editor-hoWOe')]}" + "" ] }, - "execution_count": 8, "metadata": {}, - "output_type": "execute_result" + "output_type": "display_data" } ], "source": [ - "master_team.invoke(\"Write an article about CR7\")" + "from IPython.display import Image, display\n", + "\n", + "display(Image(master_flo_with_reflection.draw()))" ] } ], diff --git a/examples/delegator_example.py b/examples/delegator_example.py index 33cc592..f7f2287 100644 --- a/examples/delegator_example.py +++ b/examples/delegator_example.py @@ -46,6 +46,6 @@ ) 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) +Flo.set_log_level('INFO') +data = flo.invoke(input_prompt) +print((data['messages'][-1]).content) diff --git a/examples/email_reply_agent.ipynb b/examples/email_reply_agent.ipynb index 92d9f7a..30c2c1e 100644 --- a/examples/email_reply_agent.ipynb +++ b/examples/email_reply_agent.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 8, + "execution_count": 1, "metadata": {}, "outputs": [ { @@ -11,7 +11,7 @@ "True" ] }, - "execution_count": 8, + "execution_count": 1, "metadata": {}, "output_type": "execute_result" } @@ -34,7 +34,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -76,7 +76,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -116,7 +116,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -143,31 +143,16 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 5, "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2024-11-06 10:24:00,066 - SESSION - INFO - New FloSession created with ID: eMUGLvOrp7dclQJZ\n", - "2024-11-06 10:24:00,148 - SESSION - INFO - Tool 'HousingLoanTool' registered for session eMUGLvOrp7dclQJZ\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "**********\n" - ] - }, { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 14, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -198,24 +183,16 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 6, "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2024-11-06 10:24:03,385 - SESSION - INFO - Tool 'SendEmailTool' registered for session eMUGLvOrp7dclQJZ\n", - "2024-11-06 10:24:03,386 - SESSION - INFO - Tool 'FetchTransactionTool' registered for session eMUGLvOrp7dclQJZ\n" - ] - }, { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 15, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -239,7 +216,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -280,7 +257,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ @@ -320,7 +297,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ @@ -350,65 +327,29 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 10, "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2024-11-06 10:24:15,166 - BUILDER - INFO - Building Flo instance from YAML\n", - "2024-11-06 10:24:15,192 - COMMON - INFO - Flo instance created for session eMUGLvOrp7dclQJZ\n", - "2024-11-06 10:24:15,193 - COMMON - INFO - Streaming query for session eMUGLvOrp7dclQJZ: \n", - "You are a support ticket handling agent. You are expected to understand the email, and perform the following steps:\n", - "\n", - "1. Reply asking for more information if there is missing information in the email\n", - "2. Perform the neccessary steps to required to answer the users question and reply the user query as email.\n", - "3. If are not able to come up with a answer just reply I dont know over the email\n", - "\n", - "Email:\n", - "\n", - "\n", - "Hi Tom,\n", - "\n", - "We have a failed transaction. Can you tell me more about why this failed.\n", - "\n", - "Transaction ID: 12123123432\n", - "\n", - "Thanks\n", - "Vishnu\n", - "\n" - ] - }, { "name": "stdout", "output_type": "stream", "text": [ - "----->\n", - "{'messages': [{'content': 'You are a supervisor tasked with managing a conversation between the following team members: EmailSender, TransactionFetcher, HousingLoanTeamLead. Given the following user request, respond with the worker to act next. Each worker will perform a task and respond with their results and status. When the users question is answered or the assigned task is finished, respond with FINISH. ', 'role': 'system'}, {'content': '\\nYou are a support ticket handling agent. You are expected to understand the email, and perform the following steps:\\n\\n1. Reply asking for more information if there is missing information in the email\\n2. Perform the neccessary steps to required to answer the users question and reply the user query as email.\\n3. If are not able to come up with a answer just reply I dont know over the email\\n\\nEmail:\\n\\n\\nHi Tom,\\n\\nWe have a failed transaction. Can you tell me more about why this failed.\\n\\nTransaction ID: 12123123432\\n\\nThanks\\nVishnu\\n', 'role': 'user'}, {'content': 'Given the conversation above, who should act next? Or should we FINISH if the task is already answered, Select one of: [\\'EmailSender\\', \\'TransactionFetcher\\', \\'HousingLoanTeamLead\\', \\'FINISH\\'] \\n The output should be formatted as a JSON instance that conforms to the JSON schema below.\\n\\nAs an example, for the schema {\"properties\": {\"foo\": {\"title\": \"Foo\", \"description\": \"a list of strings\", \"type\": \"array\", \"items\": {\"type\": \"string\"}}}, \"required\": [\"foo\"]}\\nthe object {\"foo\": [\"bar\", \"baz\"]} is a well-formatted instance of the schema. The object {\"properties\": {\"foo\": [\"bar\", \"baz\"]}} is not well-formatted.\\n\\nHere is the output schema:\\n```\\n{\"properties\": {\"next\": {\"title\": \"Next\", \"description\": \"Name of the next member to be called\", \"type\": \"string\"}}, \"required\": [\"next\"]}\\n```', 'role': 'system'}], 'model': 'gpt-4o-mini', 'frequency_penalty': NOT_GIVEN, 'function_call': NOT_GIVEN, 'functions': NOT_GIVEN, 'logit_bias': NOT_GIVEN, 'logprobs': NOT_GIVEN, 'max_completion_tokens': NOT_GIVEN, 'max_tokens': NOT_GIVEN, 'metadata': NOT_GIVEN, 'n': 1, 'parallel_tool_calls': NOT_GIVEN, 'presence_penalty': NOT_GIVEN, 'response_format': NOT_GIVEN, 'seed': NOT_GIVEN, 'service_tier': NOT_GIVEN, 'stop': NOT_GIVEN, 'store': NOT_GIVEN, 'stream': False, 'stream_options': NOT_GIVEN, 'temperature': 0.0, 'tool_choice': NOT_GIVEN, 'tools': NOT_GIVEN, 'top_logprobs': NOT_GIVEN, 'top_p': NOT_GIVEN, 'user': NOT_GIVEN}\n", - "----->\n", - "{'SupportSupervisor': {'next': 'TransactionFetcher'}}\n", + "{'SupportTicketHandler': {'next': 'TransactionFetcher'}}\n", "----\n", "\n", "\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", - "----->\n", - "{'messages': [{'content': 'You are capable of fetching any kind of transactions from the database given transaction reference id', 'role': 'system'}, {'content': '\\nYou are a support ticket handling agent. You are expected to understand the email, and perform the following steps:\\n\\n1. Reply asking for more information if there is missing information in the email\\n2. Perform the neccessary steps to required to answer the users question and reply the user query as email.\\n3. If are not able to come up with a answer just reply I dont know over the email\\n\\nEmail:\\n\\n\\nHi Tom,\\n\\nWe have a failed transaction. Can you tell me more about why this failed.\\n\\nTransaction ID: 12123123432\\n\\nThanks\\nVishnu\\n', 'role': 'user'}], 'model': 'gpt-4o-mini', 'frequency_penalty': NOT_GIVEN, 'function_call': NOT_GIVEN, 'functions': NOT_GIVEN, 'logit_bias': NOT_GIVEN, 'logprobs': NOT_GIVEN, 'max_completion_tokens': NOT_GIVEN, 'max_tokens': NOT_GIVEN, 'metadata': NOT_GIVEN, 'n': 1, 'parallel_tool_calls': NOT_GIVEN, 'presence_penalty': NOT_GIVEN, 'response_format': NOT_GIVEN, 'seed': NOT_GIVEN, 'service_tier': NOT_GIVEN, 'stop': NOT_GIVEN, 'store': NOT_GIVEN, 'stream': True, 'stream_options': NOT_GIVEN, 'temperature': 0.0, 'tool_choice': NOT_GIVEN, 'tools': [{'type': 'function', 'function': {'name': 'fetch_transactions', 'description': 'useful for when you want to fetch the transaction details given reference number', 'parameters': {'properties': {'reference_number': {'description': 'The transaction reference number', 'type': 'string'}}, 'required': ['reference_number'], 'type': 'object'}}}], 'top_logprobs': NOT_GIVEN, 'top_p': NOT_GIVEN, 'user': NOT_GIVEN}\n", - "----->\n", "\u001b[32;1m\u001b[1;3m\n", "Invoking: `fetch_transactions` with `{'reference_number': '12123123432'}`\n", "\n", "\n", - "\u001b[0m\u001b[36;1m\u001b[1;3mThe transaction happened on 23/07/2024 IST and it failed because there was not enough balance in the account\u001b[0m----->\n", - "{'messages': [{'content': 'You are capable of fetching any kind of transactions from the database given transaction reference id', 'role': 'system'}, {'content': '\\nYou are a support ticket handling agent. You are expected to understand the email, and perform the following steps:\\n\\n1. Reply asking for more information if there is missing information in the email\\n2. Perform the neccessary steps to required to answer the users question and reply the user query as email.\\n3. If are not able to come up with a answer just reply I dont know over the email\\n\\nEmail:\\n\\n\\nHi Tom,\\n\\nWe have a failed transaction. Can you tell me more about why this failed.\\n\\nTransaction ID: 12123123432\\n\\nThanks\\nVishnu\\n', 'role': 'user'}, {'content': None, 'role': 'assistant', 'tool_calls': [{'type': 'function', 'id': 'call_gz8RGLLuebKNGo8t29nWXhPr', 'function': {'name': 'fetch_transactions', 'arguments': '{\"reference_number\": \"12123123432\"}'}}]}, {'content': 'The transaction happened on 23/07/2024 IST and it failed because there was not enough balance in the account', 'role': 'tool', 'tool_call_id': 'call_gz8RGLLuebKNGo8t29nWXhPr'}], 'model': 'gpt-4o-mini', 'frequency_penalty': NOT_GIVEN, 'function_call': NOT_GIVEN, 'functions': NOT_GIVEN, 'logit_bias': NOT_GIVEN, 'logprobs': NOT_GIVEN, 'max_completion_tokens': NOT_GIVEN, 'max_tokens': NOT_GIVEN, 'metadata': NOT_GIVEN, 'n': 1, 'parallel_tool_calls': NOT_GIVEN, 'presence_penalty': NOT_GIVEN, 'response_format': NOT_GIVEN, 'seed': NOT_GIVEN, 'service_tier': NOT_GIVEN, 'stop': NOT_GIVEN, 'store': NOT_GIVEN, 'stream': True, 'stream_options': NOT_GIVEN, 'temperature': 0.0, 'tool_choice': NOT_GIVEN, 'tools': [{'type': 'function', 'function': {'name': 'fetch_transactions', 'description': 'useful for when you want to fetch the transaction details given reference number', 'parameters': {'properties': {'reference_number': {'description': 'The transaction reference number', 'type': 'string'}}, 'required': ['reference_number'], 'type': 'object'}}}], 'top_logprobs': NOT_GIVEN, 'top_p': NOT_GIVEN, 'user': NOT_GIVEN}\n", - "----->\n", - "\u001b[32;1m\u001b[1;3mSubject: Re: Failed Transaction Inquiry\n", + "\u001b[0m\u001b[36;1m\u001b[1;3mThe transaction happened on 23/07/2024 IST and it failed because there was not enough balance in the account\u001b[0m\u001b[32;1m\u001b[1;3mSubject: Re: Failed Transaction Inquiry\n", "\n", "Hi Vishnu,\n", "\n", "Thank you for reaching out regarding the failed transaction.\n", "\n", - "The transaction with ID 12123123432 occurred on 23/07/2024 IST and unfortunately failed due to insufficient balance in the account.\n", + "The transaction with ID 12123123432 occurred on 23/07/2024 IST and failed due to insufficient balance in the account.\n", "\n", "If you have any further questions or need assistance with anything else, feel free to ask!\n", "\n", @@ -416,45 +357,35 @@ "Tom\u001b[0m\n", "\n", "\u001b[1m> Finished chain.\u001b[0m\n", - "{'TransactionFetcher': {'messages': [HumanMessage(content='Subject: Re: Failed Transaction Inquiry\\n\\nHi Vishnu,\\n\\nThank you for reaching out regarding the failed transaction.\\n\\nThe transaction with ID 12123123432 occurred on 23/07/2024 IST and unfortunately failed due to insufficient balance in the account.\\n\\nIf you have any further questions or need assistance with anything else, feel free to ask!\\n\\nBest regards, \\nTom', additional_kwargs={}, response_metadata={}, name='TransactionFetcher')]}}\n", + "{'TransactionFetcher': {'messages': [HumanMessage(content='Subject: Re: Failed Transaction Inquiry\\n\\nHi Vishnu,\\n\\nThank you for reaching out regarding the failed transaction.\\n\\nThe transaction with ID 12123123432 occurred on 23/07/2024 IST and failed due to insufficient balance in the account.\\n\\nIf you have any further questions or need assistance with anything else, feel free to ask!\\n\\nBest regards, \\nTom', additional_kwargs={}, response_metadata={}, name='TransactionFetcher')]}}\n", "----\n", - "----->\n", - "{'messages': [{'content': 'You are a supervisor tasked with managing a conversation between the following team members: EmailSender, TransactionFetcher, HousingLoanTeamLead. Given the following user request, respond with the worker to act next. Each worker will perform a task and respond with their results and status. When the users question is answered or the assigned task is finished, respond with FINISH. ', 'role': 'system'}, {'content': '\\nYou are a support ticket handling agent. You are expected to understand the email, and perform the following steps:\\n\\n1. Reply asking for more information if there is missing information in the email\\n2. Perform the neccessary steps to required to answer the users question and reply the user query as email.\\n3. If are not able to come up with a answer just reply I dont know over the email\\n\\nEmail:\\n\\n\\nHi Tom,\\n\\nWe have a failed transaction. Can you tell me more about why this failed.\\n\\nTransaction ID: 12123123432\\n\\nThanks\\nVishnu\\n', 'role': 'user'}, {'content': 'Subject: Re: Failed Transaction Inquiry\\n\\nHi Vishnu,\\n\\nThank you for reaching out regarding the failed transaction.\\n\\nThe transaction with ID 12123123432 occurred on 23/07/2024 IST and unfortunately failed due to insufficient balance in the account.\\n\\nIf you have any further questions or need assistance with anything else, feel free to ask!\\n\\nBest regards, \\nTom', 'name': 'TransactionFetcher', 'role': 'user'}, {'content': 'Given the conversation above, who should act next? Or should we FINISH if the task is already answered, Select one of: [\\'EmailSender\\', \\'TransactionFetcher\\', \\'HousingLoanTeamLead\\', \\'FINISH\\'] \\n The output should be formatted as a JSON instance that conforms to the JSON schema below.\\n\\nAs an example, for the schema {\"properties\": {\"foo\": {\"title\": \"Foo\", \"description\": \"a list of strings\", \"type\": \"array\", \"items\": {\"type\": \"string\"}}}, \"required\": [\"foo\"]}\\nthe object {\"foo\": [\"bar\", \"baz\"]} is a well-formatted instance of the schema. The object {\"properties\": {\"foo\": [\"bar\", \"baz\"]}} is not well-formatted.\\n\\nHere is the output schema:\\n```\\n{\"properties\": {\"next\": {\"title\": \"Next\", \"description\": \"Name of the next member to be called\", \"type\": \"string\"}}, \"required\": [\"next\"]}\\n```', 'role': 'system'}], 'model': 'gpt-4o-mini', 'frequency_penalty': NOT_GIVEN, 'function_call': NOT_GIVEN, 'functions': NOT_GIVEN, 'logit_bias': NOT_GIVEN, 'logprobs': NOT_GIVEN, 'max_completion_tokens': NOT_GIVEN, 'max_tokens': NOT_GIVEN, 'metadata': NOT_GIVEN, 'n': 1, 'parallel_tool_calls': NOT_GIVEN, 'presence_penalty': NOT_GIVEN, 'response_format': NOT_GIVEN, 'seed': NOT_GIVEN, 'service_tier': NOT_GIVEN, 'stop': NOT_GIVEN, 'store': NOT_GIVEN, 'stream': False, 'stream_options': NOT_GIVEN, 'temperature': 0.0, 'tool_choice': NOT_GIVEN, 'tools': NOT_GIVEN, 'top_logprobs': NOT_GIVEN, 'top_p': NOT_GIVEN, 'user': NOT_GIVEN}\n", - "----->\n", - "{'SupportSupervisor': {'next': 'EmailSender'}}\n", + "{'SupportTicketHandler': {'next': 'EmailSender'}}\n", "----\n", "\n", "\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", - "----->\n", - "{'messages': [{'content': 'You are capable of sending the reply email but constructing a apt response', 'role': 'system'}, {'content': '\\nYou are a support ticket handling agent. You are expected to understand the email, and perform the following steps:\\n\\n1. Reply asking for more information if there is missing information in the email\\n2. Perform the neccessary steps to required to answer the users question and reply the user query as email.\\n3. If are not able to come up with a answer just reply I dont know over the email\\n\\nEmail:\\n\\n\\nHi Tom,\\n\\nWe have a failed transaction. Can you tell me more about why this failed.\\n\\nTransaction ID: 12123123432\\n\\nThanks\\nVishnu\\n', 'role': 'user'}, {'content': 'Subject: Re: Failed Transaction Inquiry\\n\\nHi Vishnu,\\n\\nThank you for reaching out regarding the failed transaction.\\n\\nThe transaction with ID 12123123432 occurred on 23/07/2024 IST and unfortunately failed due to insufficient balance in the account.\\n\\nIf you have any further questions or need assistance with anything else, feel free to ask!\\n\\nBest regards, \\nTom', 'name': 'TransactionFetcher', 'role': 'user'}], 'model': 'gpt-4o-mini', 'frequency_penalty': NOT_GIVEN, 'function_call': NOT_GIVEN, 'functions': NOT_GIVEN, 'logit_bias': NOT_GIVEN, 'logprobs': NOT_GIVEN, 'max_completion_tokens': NOT_GIVEN, 'max_tokens': NOT_GIVEN, 'metadata': NOT_GIVEN, 'n': 1, 'parallel_tool_calls': NOT_GIVEN, 'presence_penalty': NOT_GIVEN, 'response_format': NOT_GIVEN, 'seed': NOT_GIVEN, 'service_tier': NOT_GIVEN, 'stop': NOT_GIVEN, 'store': NOT_GIVEN, 'stream': True, 'stream_options': NOT_GIVEN, 'temperature': 0.0, 'tool_choice': NOT_GIVEN, 'tools': [{'type': 'function', 'function': {'name': 'email_triage', 'description': 'useful for when you need to send an email to someone', 'parameters': {'properties': {'email': {'description': 'The email text to be sent', 'type': 'string'}}, 'required': ['email'], 'type': 'object'}}}], 'top_logprobs': NOT_GIVEN, 'top_p': NOT_GIVEN, 'user': NOT_GIVEN}\n", - "----->\n", "\u001b[32;1m\u001b[1;3m\n", - "Invoking: `email_triage` with `{'email': 'Hi Vishnu,\\n\\nThank you for reaching out regarding the failed transaction.\\n\\nThe transaction with ID 12123123432 occurred on 23/07/2024 IST and unfortunately failed due to insufficient balance in the account.\\n\\nIf you have any further questions or need assistance with anything else, feel free to ask!\\n\\nBest regards,\\nTom'}`\n", + "Invoking: `email_triage` with `{'email': 'Subject: Re: Failed Transaction Inquiry\\n\\nHi Vishnu,\\n\\nThank you for reaching out regarding the failed transaction.\\n\\nThe transaction with ID 12123123432 occurred on 23/07/2024 IST and failed due to insufficient balance in the account.\\n\\nIf you have any further questions or need assistance with anything else, feel free to ask!\\n\\nBest regards,\\nTom'}`\n", + "\n", "\n", + "\u001b[0mSubject: Re: Failed Transaction Inquiry\n", "\n", - "\u001b[0mHi Vishnu,\n", + "Hi Vishnu,\n", "\n", "Thank you for reaching out regarding the failed transaction.\n", "\n", - "The transaction with ID 12123123432 occurred on 23/07/2024 IST and unfortunately failed due to insufficient balance in the account.\n", + "The transaction with ID 12123123432 occurred on 23/07/2024 IST and failed due to insufficient balance in the account.\n", "\n", "If you have any further questions or need assistance with anything else, feel free to ask!\n", "\n", "Best regards,\n", "Tom\n", - "\u001b[36;1m\u001b[1;3mEmail sent successfully\u001b[0m----->\n", - "{'messages': [{'content': 'You are capable of sending the reply email but constructing a apt response', 'role': 'system'}, {'content': '\\nYou are a support ticket handling agent. You are expected to understand the email, and perform the following steps:\\n\\n1. Reply asking for more information if there is missing information in the email\\n2. Perform the neccessary steps to required to answer the users question and reply the user query as email.\\n3. If are not able to come up with a answer just reply I dont know over the email\\n\\nEmail:\\n\\n\\nHi Tom,\\n\\nWe have a failed transaction. Can you tell me more about why this failed.\\n\\nTransaction ID: 12123123432\\n\\nThanks\\nVishnu\\n', 'role': 'user'}, {'content': 'Subject: Re: Failed Transaction Inquiry\\n\\nHi Vishnu,\\n\\nThank you for reaching out regarding the failed transaction.\\n\\nThe transaction with ID 12123123432 occurred on 23/07/2024 IST and unfortunately failed due to insufficient balance in the account.\\n\\nIf you have any further questions or need assistance with anything else, feel free to ask!\\n\\nBest regards, \\nTom', 'name': 'TransactionFetcher', 'role': 'user'}, {'content': None, 'role': 'assistant', 'tool_calls': [{'type': 'function', 'id': 'call_tRgauP6bKTaqWhtyZBx6RHVM', 'function': {'name': 'email_triage', 'arguments': '{\"email\": \"Hi Vishnu,\\\\n\\\\nThank you for reaching out regarding the failed transaction.\\\\n\\\\nThe transaction with ID 12123123432 occurred on 23/07/2024 IST and unfortunately failed due to insufficient balance in the account.\\\\n\\\\nIf you have any further questions or need assistance with anything else, feel free to ask!\\\\n\\\\nBest regards,\\\\nTom\"}'}}]}, {'content': 'Email sent successfully', 'role': 'tool', 'tool_call_id': 'call_tRgauP6bKTaqWhtyZBx6RHVM'}], 'model': 'gpt-4o-mini', 'frequency_penalty': NOT_GIVEN, 'function_call': NOT_GIVEN, 'functions': NOT_GIVEN, 'logit_bias': NOT_GIVEN, 'logprobs': NOT_GIVEN, 'max_completion_tokens': NOT_GIVEN, 'max_tokens': NOT_GIVEN, 'metadata': NOT_GIVEN, 'n': 1, 'parallel_tool_calls': NOT_GIVEN, 'presence_penalty': NOT_GIVEN, 'response_format': NOT_GIVEN, 'seed': NOT_GIVEN, 'service_tier': NOT_GIVEN, 'stop': NOT_GIVEN, 'store': NOT_GIVEN, 'stream': True, 'stream_options': NOT_GIVEN, 'temperature': 0.0, 'tool_choice': NOT_GIVEN, 'tools': [{'type': 'function', 'function': {'name': 'email_triage', 'description': 'useful for when you need to send an email to someone', 'parameters': {'properties': {'email': {'description': 'The email text to be sent', 'type': 'string'}}, 'required': ['email'], 'type': 'object'}}}], 'top_logprobs': NOT_GIVEN, 'top_p': NOT_GIVEN, 'user': NOT_GIVEN}\n", - "----->\n", - "\u001b[32;1m\u001b[1;3mI have sent the response to Vishnu regarding the failed transaction. If you need any further assistance, feel free to ask!\u001b[0m\n", + "\u001b[36;1m\u001b[1;3mEmail sent successfully\u001b[0m\u001b[32;1m\u001b[1;3mI have sent the response to Vishnu regarding the failed transaction. If you need any further assistance, feel free to ask!\u001b[0m\n", "\n", "\u001b[1m> Finished chain.\u001b[0m\n", "{'EmailSender': {'messages': [HumanMessage(content='I have sent the response to Vishnu regarding the failed transaction. If you need any further assistance, feel free to ask!', additional_kwargs={}, response_metadata={}, name='EmailSender')]}}\n", "----\n", - "----->\n", - "{'messages': [{'content': 'You are a supervisor tasked with managing a conversation between the following team members: EmailSender, TransactionFetcher, HousingLoanTeamLead. Given the following user request, respond with the worker to act next. Each worker will perform a task and respond with their results and status. When the users question is answered or the assigned task is finished, respond with FINISH. ', 'role': 'system'}, {'content': '\\nYou are a support ticket handling agent. You are expected to understand the email, and perform the following steps:\\n\\n1. Reply asking for more information if there is missing information in the email\\n2. Perform the neccessary steps to required to answer the users question and reply the user query as email.\\n3. If are not able to come up with a answer just reply I dont know over the email\\n\\nEmail:\\n\\n\\nHi Tom,\\n\\nWe have a failed transaction. Can you tell me more about why this failed.\\n\\nTransaction ID: 12123123432\\n\\nThanks\\nVishnu\\n', 'role': 'user'}, {'content': 'Subject: Re: Failed Transaction Inquiry\\n\\nHi Vishnu,\\n\\nThank you for reaching out regarding the failed transaction.\\n\\nThe transaction with ID 12123123432 occurred on 23/07/2024 IST and unfortunately failed due to insufficient balance in the account.\\n\\nIf you have any further questions or need assistance with anything else, feel free to ask!\\n\\nBest regards, \\nTom', 'name': 'TransactionFetcher', 'role': 'user'}, {'content': 'I have sent the response to Vishnu regarding the failed transaction. If you need any further assistance, feel free to ask!', 'name': 'EmailSender', 'role': 'user'}, {'content': 'Given the conversation above, who should act next? Or should we FINISH if the task is already answered, Select one of: [\\'EmailSender\\', \\'TransactionFetcher\\', \\'HousingLoanTeamLead\\', \\'FINISH\\'] \\n The output should be formatted as a JSON instance that conforms to the JSON schema below.\\n\\nAs an example, for the schema {\"properties\": {\"foo\": {\"title\": \"Foo\", \"description\": \"a list of strings\", \"type\": \"array\", \"items\": {\"type\": \"string\"}}}, \"required\": [\"foo\"]}\\nthe object {\"foo\": [\"bar\", \"baz\"]} is a well-formatted instance of the schema. The object {\"properties\": {\"foo\": [\"bar\", \"baz\"]}} is not well-formatted.\\n\\nHere is the output schema:\\n```\\n{\"properties\": {\"next\": {\"title\": \"Next\", \"description\": \"Name of the next member to be called\", \"type\": \"string\"}}, \"required\": [\"next\"]}\\n```', 'role': 'system'}], 'model': 'gpt-4o-mini', 'frequency_penalty': NOT_GIVEN, 'function_call': NOT_GIVEN, 'functions': NOT_GIVEN, 'logit_bias': NOT_GIVEN, 'logprobs': NOT_GIVEN, 'max_completion_tokens': NOT_GIVEN, 'max_tokens': NOT_GIVEN, 'metadata': NOT_GIVEN, 'n': 1, 'parallel_tool_calls': NOT_GIVEN, 'presence_penalty': NOT_GIVEN, 'response_format': NOT_GIVEN, 'seed': NOT_GIVEN, 'service_tier': NOT_GIVEN, 'stop': NOT_GIVEN, 'store': NOT_GIVEN, 'stream': False, 'stream_options': NOT_GIVEN, 'temperature': 0.0, 'tool_choice': NOT_GIVEN, 'tools': NOT_GIVEN, 'top_logprobs': NOT_GIVEN, 'top_p': NOT_GIVEN, 'user': NOT_GIVEN}\n", - "----->\n", - "{'SupportSupervisor': {'next': 'FINISH'}}\n", + "{'SupportTicketHandler': {'next': 'FINISH'}}\n", "----\n" ] } diff --git a/examples/reflection_example.py b/examples/reflection_example.py index 7a9ad7b..203fdad 100644 --- a/examples/reflection_example.py +++ b/examples/reflection_example.py @@ -45,6 +45,5 @@ ) 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) diff --git a/flo_ai/builders/yaml_builder.py b/flo_ai/builders/yaml_builder.py index 81cee6c..e5da427 100644 --- a/flo_ai/builders/yaml_builder.py +++ b/flo_ai/builders/yaml_builder.py @@ -39,17 +39,17 @@ def parse_and_build_subteams( validate_team(name_set, team_config, session) if team_config.agents: members = [AgentFactory.create(session, agent) for agent in team_config.agents] - flo_team = FloTeam.Builder(team_config, members=members).build() + flo_team = FloTeam.Builder(session, team_config.name, members=members).build() router = FloRouterFactory.create(session, team_config, flo_team) - flo_routed_team = router.build_routed_team() + flo_routed_team = router.to_flo() else: flo_teams = [] for subteam in team_config.subteams: flo_subteam = parse_and_build_subteams(session, subteam, name_set) flo_teams.append(flo_subteam) - flo_team = FloTeam.Builder(team_config, members=flo_teams).build() + flo_team = FloTeam.Builder(session, team_config.name, members=flo_teams).build() router = FloRouterFactory.create(session, team_config, flo_team) - flo_routed_team = router.build_routed_team() + flo_routed_team = router.to_flo() return flo_routed_team diff --git a/flo_ai/factory/agent_factory.py b/flo_ai/factory/agent_factory.py index 1b2ef55..5ed8940 100644 --- a/flo_ai/factory/agent_factory.py +++ b/flo_ai/factory/agent_factory.py @@ -7,6 +7,7 @@ from flo_ai.models.flo_delegation_agent import FloDelegatorAgent from flo_ai.models.flo_tool_agent import FloToolAgent from flo_ai.error.flo_exception import FloException +from flo_ai.models.delegate import Delegate from flo_ai.constants.common_constants import DOCUMENTATION_AGENT_ANCHOR from enum import Enum @@ -61,8 +62,10 @@ def __create_agentic_agent( tools = [tool_map[tool.name] for tool in agent.tools] flo_agent: FloAgent = FloAgent.Builder( session, - agent, - tools, + name=agent.name, + job=agent.job, + tools=tools, + role=agent.role, llm=agent_model, on_error=session.on_agent_error, model_name=agent.model, @@ -73,7 +76,12 @@ def __create_agentic_agent( def __create_llm_agent(session: FloSession, agent: AgentConfig) -> FloLLMAgent: agent_model = AgentFactory.__resolve_model(session, agent.model) builder = FloLLMAgent.Builder( - session, agent, llm=agent_model, model_name=agent.model + session, + name=agent.name, + job=agent.job, + role=agent.role, + llm=agent_model, + model_name=agent.model, ) llm_agent: FloLLMAgent = builder.build() return llm_agent @@ -82,7 +90,7 @@ def __create_llm_agent(session: FloSession, agent: AgentConfig) -> FloLLMAgent: def __create_runnable_agent(session: FloSession, agent: AgentConfig) -> FloLLMAgent: runnable = session.tools[agent.tools[0].name] return FloToolAgent.Builder( - session, agent, runnable, model_name=agent.model + session, agent.name, runnable, model_name=agent.model ).build() @staticmethod @@ -90,11 +98,26 @@ def __create_reflection_agent( session: FloSession, agent: AgentConfig ) -> FloReflectionAgent: agent_model = AgentFactory.__resolve_model(session, agent.model) - return FloReflectionAgent.Builder(session, agent, llm=agent_model).build() + return FloReflectionAgent.Builder( + session, + name=agent.name, + job=agent.job, + role=agent.role, + llm=agent_model, + to=Delegate([x.name for x in agent.to], agent.retry), + model_name=agent.model, + ).build() @staticmethod def __create_delegator_agent( session: FloSession, agent: AgentConfig ) -> FloReflectionAgent: agent_model = AgentFactory.__resolve_model(session, agent.model) - return FloDelegatorAgent.Builder(session, agent, llm=agent_model).build() + return FloDelegatorAgent.Builder( + session, + agent.name, + agent.job, + delegate=Delegate([x.name for x in agent.to], agent.retry), + llm=agent_model, + model_name=agent.model, + ).build() diff --git a/flo_ai/models/delegate.py b/flo_ai/models/delegate.py new file mode 100644 index 0000000..62494b9 --- /dev/null +++ b/flo_ai/models/delegate.py @@ -0,0 +1,7 @@ +from dataclasses import dataclass + + +@dataclass +class Delegate: + to: list[str] + retry: int = 1 diff --git a/flo_ai/models/flo_agent.py b/flo_ai/models/flo_agent.py index 12d59ef..b098823 100644 --- a/flo_ai/models/flo_agent.py +++ b/flo_ai/models/flo_agent.py @@ -7,41 +7,39 @@ from flo_ai.models.flo_executable import ExecutableFlo from flo_ai.state.flo_session import FloSession from typing import Union, Optional, Callable -from flo_ai.yaml.config import AgentConfig from flo_ai.models.flo_executable import ExecutableType class FloAgent(ExecutableFlo): def __init__( self, + name: str, agent: Runnable, executor: AgentExecutor, - config: AgentConfig, - model_nick_name: str, + model_name: str, ) -> None: - super().__init__(config.name, executor, ExecutableType.agentic) - self.model_name = model_nick_name + super().__init__(name, executor, ExecutableType.agentic) + self.model_name = model_name self.agent: Runnable = (agent,) self.executor: AgentExecutor = executor - self.config: AgentConfig = config class Builder: def __init__( self, session: FloSession, - config: AgentConfig, + name: str, + job: str, tools: list[BaseTool], - verbose: bool = True, role: Optional[str] = None, + verbose: bool = True, llm: Union[BaseLanguageModel, None] = None, on_error: Union[str, Callable] = True, model_name: Union[str, None] = 'default', ) -> None: - prompt: Union[ChatPromptTemplate, str] = config.job - self.name: str = config.name + prompt: Union[ChatPromptTemplate, str] = job + self.name: str = name self.model_name = model_name self.llm = llm if llm is not None else session.llm - self.config = config system_prompts = ( [('system', 'You are a {}'.format(role)), ('system', prompt)] if role is not None @@ -67,6 +65,4 @@ def build(self) -> AgentExecutor: return_intermediate_steps=True, handle_parsing_errors=self.on_error, ) - return FloAgent( - agent, executor, self.config, model_nick_name=self.model_name - ) + return FloAgent(self.name, agent, executor, model_name=self.model_name) diff --git a/flo_ai/models/flo_delegation_agent.py b/flo_ai/models/flo_delegation_agent.py index 7c39544..93294bd 100644 --- a/flo_ai/models/flo_delegation_agent.py +++ b/flo_ai/models/flo_delegation_agent.py @@ -1,32 +1,46 @@ from typing import Optional 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 flo_ai.models.flo_executable import ExecutableFlo, ExecutableType +from flo_ai.models.delegate import Delegate from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder -from flo_ai.models.flo_executable import ExecutableType -from langchain_core.output_parsers.openai_functions import JsonOutputFunctionsParser from langchain_core.language_models import BaseLanguageModel +from pydantic import BaseModel, Field +from langchain_core.output_parsers import JsonOutputParser + + +class NextAgent(BaseModel): + next: str = Field(description='Name of the next member to be called') class FloDelegatorAgent(ExecutableFlo): def __init__( - self, executor: Runnable, config: AgentConfig, model_name: str + self, + session: FloSession, + executor: Runnable, + delegate: Delegate, + name: str, + model_name: str, ) -> None: - super().__init__(config.name, executor, ExecutableType.delegator) - self.executor: Runnable = executor - self.config: AgentConfig = config + super().__init__(name, executor, ExecutableType.delegator) + self.session = session + self.delegate = delegate + self.executor = executor self.model_name = model_name class Builder: def __init__( self, session: FloSession, - agentConfig: AgentConfig, + name: str, + job: str, + delegate: Delegate, llm: Optional[BaseLanguageModel] = None, model_name: str = None, ) -> None: - self.config = agentConfig + self.session = session + self.name = name + self.to = delegate delegator_base_system_message = ( 'You are a delegator tasked with routing a conversation between the' ' following {member_type}: {members}. Given the following rules,' @@ -34,7 +48,8 @@ def __init__( ) self.model_name = model_name self.llm = session.llm if llm is None else llm - self.options = [x.name for x in agentConfig.to] + self.options = delegate.to + self.parser = JsonOutputParser(pydantic_object=NextAgent) self.llm_router_prompt = ChatPromptTemplate.from_messages( [ ('system', delegator_base_system_message), @@ -43,43 +58,24 @@ def __init__( ( 'system', 'Given the conversation above, who should act next?' - 'Select one of: {options}', + 'Select one of: {options} \n {format_instructions}', ), ] ).partial( options=str(self.options), members=', '.join(self.options), member_type='agents', - delegator_rules=agentConfig.job, + delegator_rules=job, + format_instructions=self.parser.get_format_instructions(), ) 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() - ) + chain = self.llm_router_prompt | self.llm | self.parser return FloDelegatorAgent( - executor=chain, config=self.config, model_name=self.model_name + session=self.session, + name=self.name, + delegate=self.to, + executor=chain, + model_name=self.model_name, ) diff --git a/flo_ai/models/flo_llm_agent.py b/flo_ai/models/flo_llm_agent.py index fa6c83a..125133b 100644 --- a/flo_ai/models/flo_llm_agent.py +++ b/flo_ai/models/flo_llm_agent.py @@ -3,38 +3,36 @@ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from flo_ai.models.flo_executable import ExecutableFlo from flo_ai.state.flo_session import FloSession -from typing import Union +from typing import Union, Optional 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, config: AgentConfig, model_name: str - ) -> None: - super().__init__(config.name, executor, ExecutableType.llm) + def __init__(self, name: str, executor: Runnable, model_name: str) -> None: + super().__init__(name, executor, ExecutableType.llm) self.executor: Runnable = executor - self.config: AgentConfig = config self.model_name: str = model_name class Builder: def __init__( self, session: FloSession, - config: AgentConfig, + name: str, + job: str, + role: Optional[str] = None, llm: Union[BaseLanguageModel, None] = None, model_name: str = None, ) -> None: self.model_name = model_name - prompt: Union[ChatPromptTemplate, str] = config.job + prompt: Union[ChatPromptTemplate, str] = job - self.name: str = config.name + self.name: str = 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(config.role)), ('system', prompt)] - if config.role is not None + [('system', 'You are a {}'.format(role)), ('system', prompt)] + if role is not None else [('system', prompt)] ) system_prompts.append(MessagesPlaceholder(variable_name='messages')) @@ -43,8 +41,7 @@ def __init__( if isinstance(prompt, str) else prompt ) - self.config = config def build(self) -> Runnable: executor = self.prompt | self.llm | StrOutputParser() - return FloLLMAgent(executor, self.config, self.model_name) + return FloLLMAgent(self.name, executor, self.model_name) diff --git a/flo_ai/models/flo_node.py b/flo_ai/models/flo_node.py index 6bfd6aa..8971861 100644 --- a/flo_ai/models/flo_node.py +++ b/flo_ai/models/flo_node.py @@ -1,13 +1,14 @@ import functools from flo_ai.models.flo_agent import FloAgent +from flo_ai.models.flo_reflection_agent import FloReflectionAgent from flo_ai.models.flo_routed_team import FloRoutedTeam +from flo_ai.models.delegate import Delegate from langchain.agents import AgentExecutor 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 flo_ai.state.flo_session import FloSession -from typing import Union, Type, List +from typing import Optional, Type, List from flo_ai.state.flo_callbacks import FloAgentCallback, FloRouterCallback, FloCallback @@ -17,12 +18,12 @@ def __init__( func: functools.partial, name: str, kind: ExecutableType, - config: Union[AgentConfig | TeamConfig], + delegate: Optional[Delegate] = None, ) -> None: self.name = name self.func = func self.kind: ExecutableType = kind - self.config: Union[AgentConfig | TeamConfig] = config + self.delegate = delegate class Builder: def __init__(self, session: FloSession) -> None: @@ -33,18 +34,27 @@ def build_from_agent(self, flo_agent: FloAgent) -> 'FloNode': FloNode.Builder.__teamflo_agent_node, agent=flo_agent.runnable, name=flo_agent.name, - agent_config=flo_agent.config, session=self.session, model_name=flo_agent.model_name, ) - return FloNode(agent_func, flo_agent.name, flo_agent.type, flo_agent.config) + return FloNode(agent_func, flo_agent.name, flo_agent.type) + + def build_from_reflection(self, flo_agent: FloReflectionAgent) -> 'FloNode': + agent_func = functools.partial( + FloNode.Builder.__teamflo_agent_node, + agent=flo_agent.runnable, + name=flo_agent.name, + session=self.session, + model_name=flo_agent.model_name, + ) + return FloNode( + agent_func, flo_agent.name, flo_agent.type, delegate=flo_agent.delegate + ) def build_from_team(self, flo_team: FloRoutedTeam) -> 'FloNode': team_chain = ( functools.partial( - FloNode.Builder.__teamflo_team_node, - members=flo_team.runnable.nodes, - session=self.session, + FloNode.Builder.__teamflo_team_node, members=flo_team.runnable.nodes ) | flo_team.runnable ) @@ -56,20 +66,31 @@ def build_from_team(self, flo_team: FloRoutedTeam) -> 'FloNode': ), flo_team.name, flo_team.type, - flo_team.config, ) def build_from_router(self, flo_router) -> 'FloNode': router_func = functools.partial( FloNode.Builder.__teamflo_router_node, agent=flo_router.executor, - name=flo_router.router_name, - agent_config=flo_router.config, + name=flo_router.name, + session=self.session, + model_name=flo_router.model_name, + ) + return FloNode(router_func, flo_router.name, flo_router.type) + + def build_from_delegator(self, flo_router) -> 'FloNode': + router_func = functools.partial( + FloNode.Builder.__teamflo_router_node, + agent=flo_router.executor, + name=flo_router.name, session=self.session, model_name=flo_router.model_name, ) return FloNode( - router_func, flo_router.router_name, flo_router.type, flo_router.config + router_func, + flo_router.name, + flo_router.type, + delegate=flo_router.delegate, ) @staticmethod @@ -77,7 +98,6 @@ def __teamflo_agent_node( state: TeamFloAgentState, agent: AgentExecutor, name: str, - agent_config: AgentConfig, session: FloSession, model_name: str, ): @@ -128,7 +148,6 @@ def __teamflo_router_node( state: TeamFloAgentState, agent: AgentExecutor, name: str, - agent_config: AgentConfig, session: FloSession, model_name: str, ): diff --git a/flo_ai/models/flo_reflection_agent.py b/flo_ai/models/flo_reflection_agent.py index 94e8516..4da9e52 100644 --- a/flo_ai/models/flo_reflection_agent.py +++ b/flo_ai/models/flo_reflection_agent.py @@ -1,42 +1,45 @@ -from typing import Union +from typing import Union, Optional 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 langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from flo_ai.models.flo_executable import ExecutableType from langchain_core.output_parsers import StrOutputParser +from flo_ai.models.delegate import Delegate class FloReflectionAgent(ExecutableFlo): def __init__( - self, executor: Runnable, config: AgentConfig, model_name: str + self, name: str, executor: Runnable, model_name: str, delegate: Delegate ) -> None: - super().__init__(config.name, executor, ExecutableType.reflection) - self.config = config + super().__init__(name, executor, ExecutableType.reflection) self.model_name = model_name + self.delegate = delegate class Builder: def __init__( self, session: FloSession, - config: AgentConfig, + name: str, + job: str, + to: Delegate, + role: Optional[str] = None, llm: Union[BaseLanguageModel, None] = None, model_name: str = None, ) -> None: - prompt_message: Union[ChatPromptTemplate, str] = config.job - self.name: str = config.name + prompt_message: Union[ChatPromptTemplate, str] = job + self.name: str = name self.llm = llm if llm is not None else session.llm - self.config = config self.model_name = model_name + self.delegate = to system_prompts = ( [ - ('system', 'You are a {}'.format(config.role)), + ('system', 'You are a {}'.format(role)), ('system', prompt_message), ] - if config.role is not None + if role is not None else [('system', prompt_message)] ) system_prompts.append(MessagesPlaceholder(variable_name='messages')) @@ -48,4 +51,6 @@ def __init__( def build(self): executor = self.prompt | self.llm | StrOutputParser() - return FloReflectionAgent(executor, self.config, self.model_name) + return FloReflectionAgent( + self.name, executor, self.model_name, delegate=self.delegate + ) diff --git a/flo_ai/models/flo_routed_team.py b/flo_ai/models/flo_routed_team.py index 48fa0ff..cc118af 100644 --- a/flo_ai/models/flo_routed_team.py +++ b/flo_ai/models/flo_routed_team.py @@ -1,12 +1,10 @@ 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, config: TeamConfig) -> None: + def __init__(self, name: str, graph: CompiledGraph) -> None: super().__init__(name, graph) - self.config = config # Overridden for xray use, doesnt work in base class def draw(self, xray=True): diff --git a/flo_ai/models/flo_team.py b/flo_ai/models/flo_team.py index 7bc7db5..781c3c6 100644 --- a/flo_ai/models/flo_team.py +++ b/flo_ai/models/flo_team.py @@ -1,18 +1,23 @@ from flo_ai.models.flo_member import FloMember -from flo_ai.yaml.config import TeamConfig +from flo_ai.state.flo_session import FloSession class FloTeam: - def __init__(self, team_config: TeamConfig, members: list[FloMember]) -> None: - self.name = team_config.name - self.config = team_config + def __init__( + self, session: FloSession, name: str, members: list[FloMember] + ) -> None: + self.name = name self.members = members + self.session = session class Builder: - def __init__(self, team_config: TeamConfig, members: list[FloMember]) -> None: - self.team_config = team_config + def __init__( + self, session: FloSession, name: str, members: list[FloMember] + ) -> None: + self.name = name + self.session = session self.members = members self.member_names = list(map(lambda x: x.name, self.members)) def build(self): - return FloTeam(team_config=self.team_config, members=self.members) + return FloTeam(name=self.name, session=self.session, members=self.members) diff --git a/flo_ai/models/flo_tool_agent.py b/flo_ai/models/flo_tool_agent.py index 18dc973..e95ef20 100644 --- a/flo_ai/models/flo_tool_agent.py +++ b/flo_ai/models/flo_tool_agent.py @@ -1,31 +1,26 @@ from langchain_core.runnables import Runnable 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, model_name: str - ) -> None: - super().__init__(config.name, executor, ExecutableType.tool) + def __init__(self, name: str, executor: Runnable, model_name: str) -> None: + super().__init__(name, executor, ExecutableType.tool) self.executor: Runnable = executor - self.config: AgentConfig = config self.model_name: str = model_name class Builder: def __init__( self, session: FloSession, - config: AgentConfig, + name: str, tool_runnable: Runnable, model_name: str, ) -> None: - self.name: str = config.name + self.name: str = name self.runnable = tool_runnable - self.config = config self.model_name = model_name def build(self) -> Runnable: - return FloToolAgent(self.runnable, self.configs, self, self.model_name) + return FloToolAgent(self.runnable, self, self.model_name) diff --git a/flo_ai/models/flo_transformer.py b/flo_ai/models/flo_transformer.py deleted file mode 100644 index 35d6e26..0000000 --- a/flo_ai/models/flo_transformer.py +++ /dev/null @@ -1,6 +0,0 @@ -from flo_ai.models.flo_node import FloNode - - -class FloTransformer(FloNode): - def __init__(self, func: object, name: str) -> None: - super().__init__(func, name) diff --git a/flo_ai/router/flo_linear.py b/flo_ai/router/flo_linear.py index 846e752..492a24e 100644 --- a/flo_ai/router/flo_linear.py +++ b/flo_ai/router/flo_linear.py @@ -1,4 +1,3 @@ -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 @@ -9,72 +8,59 @@ class FloLinear(FloRouter): - def __init__(self, session: FloSession, config: TeamConfig, flo_team: FloTeam): + def __init__(self, session: FloSession, name: str, flo_team: FloTeam): super().__init__( session=session, - name=config.name, + name=name, flo_team=flo_team, executor=None, - config=config, model_name=None, ) - self.router_config = config.router def build_graph(self): flo_agent_nodes = [self.build_node(member) for member in self.members] - workflow = StateGraph(TeamFloAgentState) for flo_node in flo_agent_nodes: agent_name = flo_node.name workflow.add_node(agent_name, flo_node.func) - if self.router_config.edges is None: - start_node = flo_agent_nodes[0] - end_node = flo_agent_nodes[-1] - workflow.add_edge(START, start_node.name) - for i in range(len(flo_agent_nodes) - 1): - parent_node = flo_agent_nodes[i] - child_node = flo_agent_nodes[i + 1] - next_node = ( - flo_agent_nodes[i + 2] if (i + 2) < len(flo_agent_nodes) else END - ) - if parent_node.kind == ExecutableType.reflection: - self.add_reflection_edge(workflow, parent_node, child_node) - continue - if child_node.kind == ExecutableType.delegator: - self.add_delegation_edge( - workflow, parent_node, child_node, next_node - ) - continue + start_node = flo_agent_nodes[0] + end_node = flo_agent_nodes[-1] + workflow.add_edge(START, start_node.name) + for i in range(len(flo_agent_nodes) - 1): + parent_node = flo_agent_nodes[i] + child_node = flo_agent_nodes[i + 1] + next_node = ( + flo_agent_nodes[i + 2] if (i + 2) < len(flo_agent_nodes) else END + ) + if parent_node.kind == ExecutableType.reflection: + self.add_reflection_edge(workflow, parent_node, child_node) + continue + if child_node.kind == ExecutableType.delegator: + self.add_delegation_edge(workflow, parent_node, child_node, next_node) + continue - if ( - child_node.kind != ExecutableType.reflection - and parent_node.kind != ExecutableType.delegator - ): - workflow.add_edge(parent_node.name, child_node.name) + if ( + child_node.kind != ExecutableType.reflection + and parent_node.kind != ExecutableType.delegator + ): + workflow.add_edge(parent_node.name, child_node.name) - if end_node.kind == ExecutableType.reflection: - self.add_reflection_edge(workflow, end_node, END) - elif end_node.kind != ExecutableType.delegator: - workflow.add_edge(end_node.name, END) - else: - workflow.add_edge(START, self.router_config.start_node) - for edge in self.router_config.edges: - workflow.add_edge(edge[0], edge[1]) - workflow.add_edge(self.router_config.end_node, END) + if end_node.kind == ExecutableType.reflection: + self.add_reflection_edge(workflow, end_node, END) + elif end_node.kind != ExecutableType.delegator: + workflow.add_edge(end_node.name, END) workflow_graph = workflow.compile() - return FloRoutedTeam(self.flo_team.name, workflow_graph, self.flo_team.config) + return FloRoutedTeam(self.flo_team.name, workflow_graph) class Builder: - def __init__( - self, session: FloSession, config: TeamConfig, flo_team: FloTeam - ) -> None: - self.config = config + def __init__(self, session: FloSession, name: str, flo_team: FloTeam) -> None: + self.name = name self.session = session self.team = flo_team def build(self): - return FloLinear(self.session, self.config, self.team) + return FloLinear(self.session, self.name, self.team) diff --git a/flo_ai/router/flo_llm_router.py b/flo_ai/router/flo_llm_router.py index 66f319f..40536e1 100644 --- a/flo_ai/router/flo_llm_router.py +++ b/flo_ai/router/flo_llm_router.py @@ -9,7 +9,6 @@ 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 from langchain_core.output_parsers import JsonOutputParser from pydantic import BaseModel, Field @@ -40,24 +39,25 @@ def build_graph(self): workflow = StateGraph(TeamFloAgentState) for flo_agent_node in flo_agent_nodes: workflow.add_node(flo_agent_node.name, flo_agent_node.func) - workflow.add_node(self.router_name, self.build_node(self).func) + + workflow.add_node(self.name, self.build_node(self).func) for member in self.member_names: - workflow.add_edge(member, self.router_name) - workflow.add_conditional_edges(self.router_name, self.router_fn) - workflow.set_entry_point(self.router_name) + workflow.add_edge(member, self.name) + workflow.add_conditional_edges(self.name, self.router_fn) + workflow.set_entry_point(self.name) workflow_graph = workflow.compile() - return FloRoutedTeam(self.flo_team.name, workflow_graph, self.flo_team.config) + return FloRoutedTeam(self.flo_team.name, workflow_graph) class Builder: def __init__( self, session: FloSession, - team_config: TeamConfig, + name: str, flo_team: FloTeam, router_prompt: ChatPromptTemplate = None, llm: Union[BaseLanguageModel, None] = None, ) -> None: - self.name = team_config.router.name + self.name = 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 eb15388..b9d34bc 100644 --- a/flo_ai/router/flo_router.py +++ b/flo_ai/router/flo_router.py @@ -6,7 +6,6 @@ from flo_ai.state.flo_session import FloSession from flo_ai.models.flo_team import FloTeam from flo_ai.models.flo_member import FloMember -from flo_ai.yaml.config import TeamConfig from flo_ai.models.flo_routed_team import FloRoutedTeam from flo_ai.constants.prompt_constants import FLO_FINISH from flo_ai.models.flo_executable import ExecutableType @@ -28,20 +27,18 @@ def __init__( name: str, flo_team: FloTeam, executor, - config: TeamConfig = None, model_name: Union[str, None] = 'default', ): - self.router_name = name + self.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: ExecutableType = ExecutableType.router self.executor = executor - self.config = config self.model_name = model_name - def build_routed_team(self) -> FloRoutedTeam: + def to_flo(self) -> FloRoutedTeam: return self.build_graph() @abstractmethod @@ -55,10 +52,9 @@ def build_node(self, flo_member: FloMember) -> FloNode: if flo_member.type == ExecutableType.team: return node_builder.build_from_team(flo_member) if flo_member.type == ExecutableType.delegator: - return FloNode( - flo_member.executor, flo_member.name, flo_member.type, flo_member.config - ) - node_builder = FloNode.Builder(self.session) + return node_builder.build_from_delegator(flo_member) + if flo_member.type == ExecutableType.reflection: + return node_builder.build_from_reflection(flo_member) return node_builder.build_from_agent(flo_member) def router_fn(self, state: TeamFloAgentState): @@ -84,10 +80,11 @@ def add_delegation_edge( delegation_node: FloNode, nextNode: Union[FloNode | str], ): - to_agent_names = [x.name for x in delegation_node.config.to] + to_agent_names = delegation_node.delegate.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 + + retry = delegation_node.delegate.retry or 1 conditional_map = {} for agent_name in to_agent_names: @@ -134,8 +131,8 @@ def add_reflection_edge( reflection_node: FloNode, nextNode: Union[FloNode | str], ): - to_agent_name = reflection_node.config.to[0].name - retry = reflection_node.config.retry or 1 + to_agent_name = reflection_node.delegate.to[0] + retry = reflection_node.delegate.retry or 1 reflection_agent_name = reflection_node.name next = nextNode if isinstance(nextNode, str) else nextNode.name diff --git a/flo_ai/router/flo_router_factory.py b/flo_ai/router/flo_router_factory.py index 8ce6e5f..c0e85ce 100644 --- a/flo_ai/router/flo_router_factory.py +++ b/flo_ai/router/flo_router_factory.py @@ -22,17 +22,17 @@ def create( if router_kind == 'supervisor': return FloSupervisor.Builder( session, - team_config, + team_config.name, flo_team, llm=router_model, model_nick_name=team_config.router.model, ).build() elif router_kind == 'linear': - return FloLinear.Builder(session, team_config, flo_team).build() + return FloLinear.Builder(session, team_config.name, flo_team).build() elif router_kind == 'llm': return FloLLMRouter.Builder( session, - team_config, + team_config.router.name, flo_team, llm=router_model, model_nick_name=team_config.router.model, diff --git a/flo_ai/router/flo_supervisor.py b/flo_ai/router/flo_supervisor.py index c1f731b..31f957c 100644 --- a/flo_ai/router/flo_supervisor.py +++ b/flo_ai/router/flo_supervisor.py @@ -6,7 +6,6 @@ from flo_ai.constants.prompt_constants import FLO_FINISH from flo_ai.router.flo_llm_router import FloLLMRouter from flo_ai.models.flo_team import FloTeam -from flo_ai.yaml.config import TeamConfig from langchain_core.output_parsers import JsonOutputParser from flo_ai.router.flo_llm_router import NextAgent @@ -40,12 +39,12 @@ class Builder: def __init__( self, session: FloSession, - team_config: TeamConfig, + name: str, flo_team: FloTeam, llm: Union[BaseLanguageModel, None] = None, model_nick_name: str = 'default', ) -> None: - self.name = team_config.router.name + self.name = name self.session = session self.llm = llm if llm is not None else session.llm self.model_name = model_nick_name