diff --git a/libs/partners/cohere/docs/multi_hop_agent.ipynb b/libs/partners/cohere/docs/multi_hop_agent.ipynb
new file mode 100644
index 0000000000..1ee6806496
--- /dev/null
+++ b/libs/partners/cohere/docs/multi_hop_agent.ipynb
@@ -0,0 +1,318 @@
+{
+ "cells": [
+ {
+ "cell_type": "raw",
+ "metadata": {},
+ "source": [
+ "---\n",
+ "sidebar_position: 0\n",
+ "---"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Cohere Tools\n",
+ "\n",
+ "The following notebook goes over how to use the Cohere tools agent:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Prerequisites for this notebook:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# install package\n",
+ "!pip install -U langchain-cohere\n",
+ "%pip install wikipedia"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from langchain.agents import AgentExecutor\n",
+ "from langchain_cohere.chat_models import ChatCohere\n",
+ "from langchain_cohere.react_multi_hop.agent import create_cohere_react_agent\n",
+ "from langchain.retrievers import WikipediaRetriever\n",
+ "from langchain.tools.retriever import create_retriever_tool\n",
+ "from langchain_core.prompts import ChatPromptTemplate"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Next we create the prompt template and cohere model"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Create the prompt\n",
+ "prompt = ChatPromptTemplate.from_template(\n",
+ " \"Write all output in capital letters. {input}\"\n",
+ ")\n",
+ "\n",
+ "# Create the Cohere chat model\n",
+ "chat = ChatCohere(cohere_api_key=\"API_KEY\", model=\"command-r\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In this example we use a Wikipedia retrieval tool "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "retriever = WikipediaRetriever()\n",
+ "retriever_tool = create_retriever_tool(\n",
+ " retriever,\n",
+ " \"wikipedia\",\n",
+ " \"Search for information on Wikipedia\",\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Next, create the cohere tool agent and call with the input"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "\n",
+ "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
+ "\u001b[32;1m\u001b[1;3mPlan: First I will search for who the second person to walk on the moon was. Then I will search for that person's mother's hometown and write the answer in capital letters.\n",
+ "Action: ```json\n",
+ "[\n",
+ " {\n",
+ " \"tool_name\": \"wikipedia\",\n",
+ " \"parameters\": {\n",
+ " \"query\": \"second man to walk on the moon\"\n",
+ " }\n",
+ " }\n",
+ "]\n",
+ "```\u001b[0m\u001b[36;1m\u001b[1;3mWalk the Moon (stylized as WALK THE MOON) is an American pop rock band based in Cincinnati, Ohio. Lead singer Nicholas Petricca started the band in 2006, while a student at Kenyon College, deriving the band's name from the song \"Walking on the Moon\" by The Police. Although the band is best known for their most successful hit single to date \"Shut Up and Dance\", other notable songs include \"Anna Sun\" and \"One Foot\".\n",
+ "Walk the Moon has cited Talking Heads as influences. The band's use of 1980s musical mainstays, such as keyboard and synthesizer, is also notable.\n",
+ "\n",
+ "\n",
+ "== History ==\n",
+ "\n",
+ "\n",
+ "=== 2010–2011: Beginning, Anna Sun and i Want! i Want! ===\n",
+ "\n",
+ "The group independently released their debut studio album, I Want! I Want!, in November 2010, receiving airplay for the track \"Anna Sun\" on multiple alternative radio stations. Along with the success of \"Anna Sun\", Alt Nation named them a band you need to know for the summer of 2012. Influential music blog Neon Gold helped to break the band in January 2011, calling \"Anna Sun\", \"the kind of stuff British A&R dreams, and major label bidding wars, are made of.\" In February 2011, Walk the Moon signed to RCA Records.\n",
+ "In 2011, the band members began to paint their faces for live performances and they would bring enough paint to share with audience members. They have claimed it has become a “live tradition”. Bonnaroo’s camera crew documented the painting process in a short video from the 2011 festival. The band played at the Sasquatch Music Festival and Firefly Music Festival. In these years, they were known for their energetic performances and tireless touring schedule.\n",
+ "Before the release of their self-titled album, Walk the Moon joined many other performers at the Music Midtown festival and performed on the Great Southeast Music Hall Stage in Atlanta, Georgia in September 2011. In spring 2011, the band went on a short tour with the west coast band, Grouplove, as well as supporting Panic! at the Disco and Weezer on select dates. The band played on the main stage at the 20th Anniversary of Lollapalooza and also supported Local Natives in an Official Lollaplooza Aftershow at Lincoln Hall.\n",
+ "The band recorded i Want! i Want! with Chris Schmidt and Ben Cochran at Soap Floats Recording Studio in their hometown of Cincinnati, Ohio and then self-released it. The lead single from the album, \"Anna Sun\", became a surprise hit in the summer of 2011 following an endorsement by the Esquire article \"30 Summer Songs Every Man Should Listen To\". The song was written by Petricca and New York songwriter Nick Lerangis as their time at Kenyon College came to an end. \"It's about college, about maintaining that little bit of being a kid,\" Petricca said. \"Don't be afraid to play.\" The song was named after one of their favorite teachers. It was named song of the summer by MTV and Seventeen Mag, and one of the top songs of the year by Amazon. It has been officially remixed by Fool's Gold and received a Trouble Productions remix by Albert Hammond Jr. Anna Sun rose to the number one spot on Alt. Nation on Sirius XM Radio. \"Anna Sun\" was added to the video rotation of American Eagle Outfitters stores in May 2011. It was featured on the hit TV show Vampire Diaries in the first episode of season three. It was also the free single of the week on iTunes for the week of May 15.\n",
+ "Filmed in 2011 in Cincinnati's Over-the-Rhine neighborhood, the \"Anna Sun\" music video was released to coincide with the album. The video was shot on-location at the Cincinnati Mockbee building, as well as at a city park. It was directed and produced by Patrick Meier of the Cincinnati company, Contrast Productions, and features original choreography from Kim Popa of PONES Inc., as well as a cast full of the band's friends and locals from Cincinnati. MTV Hive calls the video a \"hilariously choreographed, neon-colored and awesomely shot in one take\" production.\n",
+ "\n",
+ "\n",
+ "=== 2012–2013: Walk the Moon and Tightrope EP ===\n",
+ "\n",
+ "The band's self-titled major label debut Walk t\n",
+ "\n",
+ "As part of the Apollo program by NASA, 24 astronauts flew nine missions to the Moon between December 1968 and December 1972. During six successful two-man landing missions, twelve men walked on the lunar surface, six of whom drove Lunar Roving Vehicles as part of the last three missions. Three men have been to the Moon twice, one orbited once and took a circumlunar trajectory the second time, while the other two landed once apiece. Apart from these 24 men, no human being has gone beyond low Earth orbit. No woman has been to the Moon, but a number of non-human animals have circled or orbited it, including two tortoises, several turtles, and five mice.\n",
+ "Apollo missions 8 and 10–17 were the nine crewed missions to the Moon. Apollo 4–6 and AS-201 and AS-202 were uncrewed, while AS-203 is considered a test flight. The Apollo program included three other crewed missions: Apollo 1 (AS-204) did not launch and its crew died in a ground-based capsule fire, while Apollo 7 and Apollo 9 were low Earth orbit missions that only tested spacecraft components and docking maneuvers. Apollo missions 18, 19, and 20 were canceled. Twelve astronauts later flew unused Apollo command modules in the Apollo Applications Program's Skylab and Apollo–Soyuz Test Project. Of the 24 astronauts who flew to the Moon, two went on to command a Skylab mission, one commanded Apollo–Soyuz, one flew as commander for Approach and Landing Tests of the Space Shuttle, and two commanded orbital Space Shuttle missions.\n",
+ "\n",
+ "\n",
+ "== Prime crew members ==\n",
+ "NASA's Director of Flight Crew Operations during the Gemini and Apollo programs was Donald K. \"Deke\" Slayton, one of the original Mercury Seven astronauts, who was medically grounded in September 1962 due to a minor cardiac arrhythmia – paroxysmal atrial fibrillation. Slayton was responsible for making all Gemini and Apollo crew assignments. In March 1972, Slayton was restored to flight status, and flew on the 1975 Apollo–Soyuz Test Project mission.\n",
+ "The prime crew members selected for actual missions are here grouped by their NASA astronaut selection groups, and within each group in the order selected for flight. Two versions of the Apollo Command/Service Module (CSM) spacecraft were developed: Block I, intended for preliminary low Earth orbit testing; and Block II, redesigned for the lunar landing. The Block I crew position titles were Command Pilot, Senior Pilot (second seat), and Pilot (third seat). The corresponding Block II titles were: Commander, Command Module Pilot, and Lunar Module Pilot. The second seat pilot was given secondary responsibility for celestial navigation to keep the CSM's guidance computer accurately calibrated with the spacecraft's true position, and the third seat pilot served as a flight engineer, monitoring the health of the spacecraft systems.\n",
+ "\n",
+ "\n",
+ "== Apollo astronauts by their dates of selection by NASA ==\n",
+ "\n",
+ "\n",
+ "=== 1959 ===\n",
+ "Virgil I. \"Gus\" Grissom began his career at NASA in 1959. In 1966, he was selected as Command Pilot for the first crewed Apollo mission, a low Earth orbit test. This mission ended a month before its scheduled launch, when a cabin fire on the launch pad killed Grissom, Ed White and Roger Chaffee on January 27, 1967.\n",
+ "Walter M. Schirra Jr. also began his NASA career in 1959. He was selected in October 1968 as Command Pilot for Apollo 7, an 11-day, low Earth orbit shakedown test of the three-man Apollo Command/Service Module and the first crewed launch for the Apollo project.\n",
+ "Alan B. Shepard Jr. – America's first man in space on Freedom 7 was originally selected to command Gemini 3, but was medically grounded for the duration of Gemini due to Ménière's disease and assisted Slayton in Flight Operations. After corrective surgery, Shepard was restored to flight status and commanded Apollo 14, the third successful Moon landing mission.\n",
+ "\n",
+ "\n",
+ "=== 1962 ===\n",
+ "\n",
+ "All of these astronauts flew on Gemini, and except for White, each commanded one Gemini and one Apollo mission:\n",
+ "\n",
+ "Edward H. White II – Second-seat \n",
+ "\n",
+ "\"Man on the Moon\" is a song by American alternative rock band R.E.M., released in November 1992 as the second single from their eighth album, Automatic for the People (1992). The lyrics were written by lead singer Michael Stipe, and the music by drummer Bill Berry and guitarist Peter Buck. The song was well received by critics and reached number 30 on the US Billboard Hot 100, number 17 on the US Cash Box Top 100, number 18 on the UK Singles Chart, and number one in Iceland. It remains one of R.E.M.'s most popular songs and was included on the compilations In Time: The Best of R.E.M. 1988–2003 and Part Lies, Part Heart, Part Truth, Part Garbage 1982–2011.\n",
+ "\"Man on the Moon\" is a tribute to comedian Andy Kaufman, with numerous references to his career including his Elvis impersonation, wrestling, and the film My Breakfast with Blassie. The song's title and chorus refer to Moon landing conspiracy theories, as an oblique allusion to rumors that Kaufman's death in 1984 was faked. The song gave its name to Miloš Forman's Kaufman biopic Man on the Moon (1999), and features prominently in the film's soundtrack.\n",
+ "\n",
+ "\n",
+ "== Composition ==\n",
+ "\"Man on the Moon\" is a mid-tempo country-rock song following a verse-chorus structure with an added pre-chorus and an instrumental bridge following the second and third choruses. The song has six lines in the first verse but only four in the second and third verses.An early instrumental demo of the song was known to the band as \"C to D Slide\". Guitarist Peter Buck has explained how the music came together: \"'Man on the Moon' was something that Bill [Berry] had, this one chord change that he came in with, which was C to D like the verse of the song, and he said: 'I don't know what to do with that.' I used to finish some of Bill's things ... he would come up with the riffs, but I would be the finish guy for that. I sat down and came up with the chorus, the bridges, and so forth. I remember we showed it to Mike and Michael when they came in later; definitely we had the song finished. I think Bill played bass and I played guitar; we kept going around with it. I think we might have played some mandolin on it in the rehearsal studio.\"Michael Stipe explained in an interview with Charlie Rose how the lyric was written independently of the music, which had no prior association with the song's eventual lyrical content regarding Kaufman. Stipe recounted the other R.E.M. members had written and performed the music of the song and recorded it along with the rest of the Automatic for the People album during studio sessions in Seattle. As of the final week of the recording sessions, Stipe was still struggling to write the lyric, and the others continued to plead with him to finish it. Stipe attempted to argue the track should be an instrumental, but his bandmates were insistent. Stipe listened to the track on a walk around Seattle on his Walkman cassette player and was inspired to write about Andy Kaufman. After Stipe went back to the studio to complete the vocal track, the track was mixed that night and sent out the following day to be mastered.\n",
+ "\n",
+ "\n",
+ "== Lyric ==\n",
+ "The song's lyric does not tell a conventional story and instead forms a collection of cultural references, images and ideas. There are repeated mentions of Andy Kaufman, including references to his Elvis impersonation and work with wrestlers Fred Blassie and Jerry Lawler. The song also invokes the conspiracy theories surrounding the Moon landing and Elvis Presley's death as an indirect nod to the persistent rumors that Kaufman faked his own death. Speaking in 2017 to the NME, Mike Mills explained that the perceived ambiguity of Kaufman's legacy, including questions of whether he was a comedian or a performance artist, and whether his work was funny or irritating, was a way to frame other questions about life within the song:\n",
+ "\n",
+ "He's the perfect ghost to lead you through this tour of questioning things. Did the moon landing really happen? Is Elvis really dead? He was ki\u001b[0m\u001b[32;1m\u001b[1;3mReflection: I have found that the second person to walk on the moon was Buzz Aldrin. Now I will search for the hometown of his mother and write the answer in capital letters.\n",
+ "Action: ```json\n",
+ "[\n",
+ " {\n",
+ " \"tool_name\": \"wikipedia\",\n",
+ " \"parameters\": {\n",
+ " \"query\": \"Buzz Aldrin mother's hometown\"\n",
+ " }\n",
+ " }\n",
+ "]\n",
+ "```\u001b[0m\u001b[36;1m\u001b[1;3mBuzz Aldrin (; born Edwin Eugene Aldrin Jr.; January 20, 1930) is an American former astronaut, engineer and fighter pilot. He made three spacewalks as pilot of the 1966 Gemini 12 mission, and was the Lunar Module Eagle pilot on the 1969 Apollo 11 mission. He was the second person to walk on the Moon after mission commander Neil Armstrong.\n",
+ "Born in Glen Ridge, New Jersey, Aldrin graduated third in the class of 1951 from the United States Military Academy at West Point with a degree in mechanical engineering. He was commissioned into the United States Air Force and served as a jet fighter pilot during the Korean War. He flew 66 combat missions and shot down two MiG-15 aircraft.\n",
+ "After earning a Doctor of Science degree in astronautics from the Massachusetts Institute of Technology (MIT), Aldrin was selected as a member of NASA's Astronaut Group 3, making him the first astronaut with a doctoral degree. His doctoral thesis, Line-of-Sight Guidance Techniques for Manned Orbital Rendezvous, earned him the nickname \"Dr. Rendezvous\" from fellow astronauts. His first space flight was in 1966 on Gemini 12, during which he spent over five hours on extravehicular activity. Three years later, Aldrin set foot on the Moon at 03:15:16 on July 21, 1969 (UTC), nineteen minutes after Armstrong first touched the surface, while command module pilot Michael Collins remained in lunar orbit. A Presbyterian elder, Aldrin became the first person to hold a religious ceremony on the Moon when he privately took communion.\n",
+ "After leaving NASA in 1971, Aldrin became Commandant of the U.S. Air Force Test Pilot School. He retired from the Air Force in 1972 after 21 years of service. His autobiographies Return to Earth (1973) and Magnificent Desolation (2009) recount his struggles with clinical depression and alcoholism in the years after leaving NASA. Aldrin continues to advocate for space exploration, particularly a human mission to Mars. He developed the Aldrin cycler, a special spacecraft trajectory that makes travel to Mars more efficient in terms of time and propellant. He has been accorded numerous honors, including the Presidential Medal of Freedom in 1969.\n",
+ "\n",
+ "\n",
+ "== Early life and education ==\n",
+ "Aldrin was born Edwin Eugene Aldrin Jr. on January 20, 1930, at Mountainside Hospital in Glen Ridge, New Jersey. His parents, Edwin Eugene Aldrin Sr. and Marion Aldrin (née Moon), lived in neighboring Montclair. His father was an Army aviator during World War I and the assistant commandant of the Army's test pilot school at McCook Field, Ohio, from 1919 to 1922, but left the Army in 1928 and became an executive at Standard Oil. Aldrin had two sisters: Madeleine, who was four years older, and Fay Ann, who was a year and a half older. His nickname, which became his legal first name in 1988, arose as a result of Fay's mispronouncing \"brother\" as \"buzzer\", which was then shortened to \"Buzz\". He was a Boy Scout, achieving the rank of Tenderfoot Scout.Aldrin did well in school, maintaining an A average. He played football and was the starting center for Montclair High School's undefeated 1946 state champion team. His father wanted him to go to the United States Naval Academy in Annapolis, Maryland, and enrolled him at nearby Severn School, a preparatory school for Annapolis, and even secured him a Naval Academy appointment from Albert W. Hawkes, one of the United States senators from New Jersey. Aldrin attended Severn School in 1946, but had other ideas about his future career. He suffered from seasickness and considered ships a distraction from flying airplanes. He faced down his father and told him to ask Hawkes to change the nomination to the United States Military Academy at West Point, New York.Aldrin entered West Point in 1947. He did well academically, finishing first in his class his plebe (first) year. Aldrin was also an excellent athlete, competing in pole vault for the academy track and field team. In 1950, he traveled with a group of West Point cadets to Japan and\n",
+ "\n",
+ "Neil Alden Armstrong (August 5, 1930 – August 25, 2012) was an American astronaut and aeronautical engineer who in 1969 became the first person to walk on the Moon. He was also a naval aviator, test pilot, and university professor.\n",
+ "Armstrong was born and raised in Wapakoneta, Ohio. He entered Purdue University, studying aeronautical engineering, with the U.S. Navy paying his tuition under the Holloway Plan. He became a midshipman in 1949 and a naval aviator the following year. He saw action in the Korean War, flying the Grumman F9F Panther from the aircraft carrier USS Essex. After the war, he completed his bachelor's degree at Purdue and became a test pilot at the National Advisory Committee for Aeronautics (NACA) High-Speed Flight Station at Edwards Air Force Base in California. He was the project pilot on Century Series fighters and flew the North American X-15 seven times. He was also a participant in the U.S. Air Force's Man in Space Soonest and X-20 Dyna-Soar human spaceflight programs.\n",
+ "Armstrong joined the NASA Astronaut Corps in the second group, which was selected in 1962. He made his first spaceflight as command pilot of Gemini 8 in March 1966, becoming NASA's first civilian astronaut to fly in space. During this mission with pilot David Scott, he performed the first docking of two spacecraft; the mission was aborted after Armstrong used some of his re-entry control fuel to stabilize a dangerous roll caused by a stuck thruster. During training for Armstrong's second and last spaceflight as commander of Apollo 11, he had to eject from the Lunar Landing Research Vehicle moments before a crash.\n",
+ "On July 20, 1969, Armstrong and Apollo 11 Lunar Module (LM) pilot Buzz Aldrin became the first people to land on the Moon, and the next day they spent two and a half hours outside the Lunar Module Eagle spacecraft while Michael Collins remained in lunar orbit in the Apollo Command Module Columbia. When Armstrong first stepped onto the lunar surface, he famously said: \"That's one small step for [a] man, one giant leap for mankind.\" It was broadcast live to an estimated 530 million viewers worldwide. Apollo 11 was a major U.S. victory in the Space Race, by fulfilling a national goal proposed in 1961 by President John F. Kennedy \"of landing a man on the Moon and returning him safely to the Earth\" before the end of the decade. Along with Collins and Aldrin, Armstrong was awarded the Presidential Medal of Freedom by President Richard Nixon and received the 1969 Collier Trophy. President Jimmy Carter presented him with the Congressional Space Medal of Honor in 1978, he was inducted into the National Aviation Hall of Fame in 1979, and with his former crewmates received the Congressional Gold Medal in 2009.\n",
+ "After he resigned from NASA in 1971, Armstrong taught in the Department of Aerospace Engineering at the University of Cincinnati until 1979. He served on the Apollo 13 accident investigation and on the Rogers Commission, which investigated the Space Shuttle Challenger disaster. In 2012, Armstrong died due to complications resulting from coronary bypass surgery, at the age of 82.\n",
+ "\n",
+ "\n",
+ "== Early life ==\n",
+ "Armstrong was born near Wapakoneta, Ohio, on August 5, 1930, the son of Viola Louise (née Engel) and Stephen Koenig Armstrong. He was of German, English, Scots-Irish, and Scottish descent. He is a descendant of Clan Armstrong. He had a younger sister, June, and a younger brother, Dean. His father was an auditor for the Ohio state government, and the family moved around the state repeatedly, living in 16 towns over the next 14 years. Armstrong's love for flying grew during this time, having started at the age of two when his father took him to the Cleveland Air Races. When he was five or six, he experienced his first airplane flight in Warren, Ohio, when he and his father took a ride in a Ford Trimotor (also known as the \"Tin Goose\").The family's last move was in 1944 and took them back to Wapakoneta, where Armstrong attended Blume High Scho\n",
+ "\n",
+ "David Kaufman (born July 23, 1961) is an American actor. He is best known for his voice roles of Dexter Douglas in Freakazoid!, Jimmy Olsen in various DC projects beginning with Superman: The Animated Series, the titular protagonist in Danny Phantom, Aldrin in The Buzz on Maggie, Marty McFly in Back to the Future, and Stuart Little in the animated series of the same name. He often is a voice double for Michael J. Fox.\n",
+ "\n",
+ "\n",
+ "== Early life ==\n",
+ "Kaufman was born and raised in St. Louis, Missouri. His father is Jewish, while his mother is Catholic. Kaufman began acting at a young age in his hometown when his kindergarten teacher handed him the plum lead role of Santa Claus in the class Christmas play.\n",
+ "At the age of 18, Kaufman moved from St. Louis to attend UCLA; he was a student in the Department of Theater Arts.\n",
+ "\n",
+ "\n",
+ "== Career ==\n",
+ "Since his college years, Kaufman has studied and worked extensively as a professional actor in films and television.\n",
+ "He has worked with the Daly family of actors on several projects: He worked with Tim Daly on Superman: The Animated Series and its subsequent spin-offs, playing Jimmy Olsen. He also appeared with Daly in the series Wings in 1995 with his wife Lisa; the two portrayed a couple whose wedding Daly's character Joe and his fiancée Helen crash. He worked with Tim's sister, Tyne Daly on Kids Like These and joined Tim again in Justice League: Doom, reprising his role of Jimmy Olsen.\n",
+ "Kaufman has also worked as a commercial actor. One of his most prominent roles was as a dancing stockboy in a 1989 commercial for Hi-C Ecto Cooler.\n",
+ "\n",
+ "\n",
+ "== Personal life ==\n",
+ "On June 30, 1990, Kaufman married actress Lisa Picotte; together, they have two children who are also actors, including Grace Kaufman and Henry Kaufman. He came out as bisexual on Celebrate Bisexuality Day in 2021.\n",
+ "\n",
+ "\n",
+ "== Filmography ==\n",
+ "\n",
+ "\n",
+ "=== Television series ===\n",
+ "\n",
+ "\n",
+ "=== Films ===\n",
+ "\n",
+ "\n",
+ "=== Video games ===\n",
+ "\n",
+ "\n",
+ "=== Commercials ===\n",
+ "AT&T (starring with Ray Walston)\n",
+ "Pepsi (starring with Cindy Crawford)\n",
+ "Blockbuster (starring with Magic Johnson)\n",
+ "Kid Cuisine (voice of K. C. Penguin)as well as spots for Honda, Hi-C Ecto-Cooler, Maxwell House, Dentyne, Chili's, Midas, Wendy's, Twiglets and British Petroleum, among others.\n",
+ "\n",
+ "\n",
+ "=== Stage work ===\n",
+ "Kaufman has earned several Los Angeles area critics' awards and nominations.\n",
+ "He has been a member of the West Coast Ensemble in Los Angeles for over ten years, performing such varied roles as:\n",
+ "\n",
+ "Skeets Miller in Floyd Collins\n",
+ "Prosecutor Gilmer in To Kill a Mockingbird\n",
+ "George Lewis in Kaufman and Hart's Once in a Lifetime\n",
+ "Orestes in Electra\n",
+ "Tyler in Sondheim and Furth's Merrily We Roll Along\n",
+ "Ronnie Shaughnessy in The House of Blue Leaves\n",
+ "Callimaco in Machiavelli's The Mandrake\n",
+ "Eugene Jerome in Neil Simon's Biloxi Blues\n",
+ "Paul Palmer in James Duff's A Quarrel of Sparrows at The Court Theatre in Los Angeles\n",
+ "Stewie in the premiere of Richard Greenberg's Night and Her Stars at South Coast Repertory.\n",
+ "\n",
+ "\n",
+ "== References ==\n",
+ "\n",
+ "\n",
+ "== External links ==\n",
+ "David Kaufman at IMDb\u001b[0m\u001b[32;1m\u001b[1;3mRelevant Documents: 1\n",
+ "Cited Documents: 1\n",
+ "Answer: MONTclair, NEW JERSEY.\n",
+ "Grounded answer: Montclair, New Jersey.\u001b[0m\n",
+ "\n",
+ "\u001b[1m> Finished chain.\u001b[0m\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ "{'input': 'What was the hometown of the mother of the second person to walk on the moon?',\n",
+ " 'output': 'MONTclair, NEW JERSEY.'}"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "agent = create_cohere_react_agent(\n",
+ " llm=chat,\n",
+ " tools=[retriever_tool],\n",
+ " prompt=prompt,\n",
+ ")\n",
+ "agent_executor = AgentExecutor(agent=agent, tools=[retriever_tool], verbose=True)\n",
+ "agent_executor.invoke({\"input\": \"What was the hometown of the mother of the second person to walk on the moon?\"})"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/libs/partners/cohere/langchain_cohere/__init__.py b/libs/partners/cohere/langchain_cohere/__init__.py
index 52d5336193..2c3ad73144 100644
--- a/libs/partners/cohere/langchain_cohere/__init__.py
+++ b/libs/partners/cohere/langchain_cohere/__init__.py
@@ -2,13 +2,14 @@ from langchain_cohere.chat_models import ChatCohere
from langchain_cohere.cohere_agent import create_cohere_tools_agent
from langchain_cohere.embeddings import CohereEmbeddings
from langchain_cohere.rag_retrievers import CohereRagRetriever
+from langchain_cohere.react_multi_hop.agent import create_cohere_react_agent
from langchain_cohere.rerank import CohereRerank
__all__ = [
"ChatCohere",
- "CohereVectorStore",
"CohereEmbeddings",
"CohereRagRetriever",
"CohereRerank",
"create_cohere_tools_agent",
+ "create_cohere_react_agent",
]
diff --git a/libs/partners/cohere/langchain_cohere/chat_models.py b/libs/partners/cohere/langchain_cohere/chat_models.py
index cfc2df4fe3..3f99feb187 100644
--- a/libs/partners/cohere/langchain_cohere/chat_models.py
+++ b/libs/partners/cohere/langchain_cohere/chat_models.py
@@ -76,6 +76,7 @@ def get_cohere_chat_request(
*,
documents: Optional[List[Document]] = None,
connectors: Optional[List[Dict[str, str]]] = None,
+ stop_sequences: Optional[List[str]] = None,
**kwargs: Any,
) -> Dict[str, Any]:
"""Get the request for the Cohere chat API.
@@ -130,6 +131,7 @@ def get_cohere_chat_request(
"documents": formatted_docs,
"connectors": connectors,
"prompt_truncation": prompt_truncation,
+ "stop_sequences": stop_sequences,
**kwargs,
}
@@ -226,7 +228,9 @@ class ChatCohere(BaseChatModel, BaseCohere):
run_manager: Optional[CallbackManagerForLLMRun] = None,
**kwargs: Any,
) -> Iterator[ChatGenerationChunk]:
- request = get_cohere_chat_request(messages, **self._default_params, **kwargs)
+ request = get_cohere_chat_request(
+ messages, stop_sequences=stop, **self._default_params, **kwargs
+ )
if hasattr(self.client, "chat_stream"): # detect and support sdk v5
stream = self.client.chat_stream(**request)
@@ -256,7 +260,9 @@ class ChatCohere(BaseChatModel, BaseCohere):
run_manager: Optional[AsyncCallbackManagerForLLMRun] = None,
**kwargs: Any,
) -> AsyncIterator[ChatGenerationChunk]:
- request = get_cohere_chat_request(messages, **self._default_params, **kwargs)
+ request = get_cohere_chat_request(
+ messages, stop_sequences=stop, **self._default_params, **kwargs
+ )
if hasattr(self.async_client, "chat_stream"): # detect and support sdk v5
stream = self.async_client.chat_stream(**request)
@@ -312,7 +318,9 @@ class ChatCohere(BaseChatModel, BaseCohere):
)
return generate_from_stream(stream_iter)
- request = get_cohere_chat_request(messages, **self._default_params, **kwargs)
+ request = get_cohere_chat_request(
+ messages, stop_sequences=stop, **self._default_params, **kwargs
+ )
response = self.client.chat(**request)
generation_info = self._get_generation_info(response)
@@ -336,7 +344,9 @@ class ChatCohere(BaseChatModel, BaseCohere):
)
return await agenerate_from_stream(stream_iter)
- request = get_cohere_chat_request(messages, **self._default_params, **kwargs)
+ request = get_cohere_chat_request(
+ messages, stop_sequences=stop, **self._default_params, **kwargs
+ )
response = self.client.chat(**request)
generation_info = self._get_generation_info(response)
diff --git a/libs/partners/cohere/langchain_cohere/cohere_agent.py b/libs/partners/cohere/langchain_cohere/cohere_agent.py
index b9c60fb743..1aa05709d1 100644
--- a/libs/partners/cohere/langchain_cohere/cohere_agent.py
+++ b/libs/partners/cohere/langchain_cohere/cohere_agent.py
@@ -17,7 +17,14 @@ from langchain_core.pydantic_v1 import BaseModel
from langchain_core.runnables import Runnable, RunnablePassthrough
from langchain_core.runnables.base import RunnableLambda
from langchain_core.tools import BaseTool
-from langchain_core.utils.function_calling import convert_to_openai_function
+from langchain_core.utils.function_calling import (
+ convert_to_openai_function,
+)
+
+from langchain_cohere.utils import (
+ JSON_TO_PYTHON_TYPES,
+ _remove_signature_from_tool_description,
+)
def create_cohere_tools_agent(
@@ -99,11 +106,17 @@ def _convert_to_cohere_tool(
if isinstance(tool, BaseTool):
return Tool(
name=tool.name,
- description=tool.description,
+ description=_remove_signature_from_tool_description(
+ tool.name, tool.description
+ ),
parameter_definitions={
param_name: ToolParameterDefinitionsValue(
- description=param_definition.get("description"),
- type=param_definition.get("type"),
+ description=param_definition.get("description")
+ if "description" in param_definition
+ else "",
+ type=JSON_TO_PYTHON_TYPES.get(
+ param_definition.get("type"), param_definition.get("type")
+ ),
required="default" not in param_definition,
)
for param_name, param_definition in tool.args.items()
@@ -120,7 +133,9 @@ def _convert_to_cohere_tool(
parameter_definitions={
param_name: ToolParameterDefinitionsValue(
description=param_definition.get("description"),
- type=param_definition.get("type"),
+ type=JSON_TO_PYTHON_TYPES.get(
+ param_definition.get("type"), param_definition.get("type")
+ ),
required="default" not in param_definition,
)
for param_name, param_definition in tool.get("properties", {}).items()
@@ -140,7 +155,9 @@ def _convert_to_cohere_tool(
parameter_definitions={
param_name: ToolParameterDefinitionsValue(
description=param_definition.get("description"),
- type=param_definition.get("type"),
+ type=JSON_TO_PYTHON_TYPES.get(
+ param_definition.get("type"), param_definition.get("type")
+ ),
required=param_name in parameters.get("required", []),
)
for param_name, param_definition in properties.items()
diff --git a/libs/partners/cohere/langchain_cohere/llms.py b/libs/partners/cohere/langchain_cohere/llms.py
index c0401b97ec..3b699a2ff3 100644
--- a/libs/partners/cohere/langchain_cohere/llms.py
+++ b/libs/partners/cohere/langchain_cohere/llms.py
@@ -66,12 +66,12 @@ class BaseCohere(Serializable):
streaming: bool = Field(default=False)
"""Whether to stream the results."""
- timeout: Optional[float] = 60
- """Timeout in seconds for the Cohere API request."""
-
user_agent: str = "langchain"
"""Identifier for the application making the request."""
+ timeout_seconds: Optional[float] = 300
+ """Timeout in seconds for the Cohere API request."""
+
base_url: Optional[str] = None
"""Override the default Cohere API URL."""
@@ -82,16 +82,17 @@ class BaseCohere(Serializable):
get_from_dict_or_env(values, "cohere_api_key", "COHERE_API_KEY")
)
client_name = values["user_agent"]
+ timeout_seconds = values.get("timeout_seconds")
values["client"] = cohere.Client(
api_key=values["cohere_api_key"].get_secret_value(),
+ timeout=timeout_seconds,
client_name=client_name,
- timeout=values["timeout"],
base_url=values["base_url"],
)
values["async_client"] = cohere.AsyncClient(
api_key=values["cohere_api_key"].get_secret_value(),
client_name=client_name,
- timeout=values["timeout"],
+ timeout=timeout_seconds,
base_url=values["base_url"],
)
return values
diff --git a/libs/partners/cohere/langchain_cohere/react_multi_hop/__init__.py b/libs/partners/cohere/langchain_cohere/react_multi_hop/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/libs/partners/cohere/langchain_cohere/react_multi_hop/agent.py b/libs/partners/cohere/langchain_cohere/react_multi_hop/agent.py
new file mode 100644
index 0000000000..a2583f1be7
--- /dev/null
+++ b/libs/partners/cohere/langchain_cohere/react_multi_hop/agent.py
@@ -0,0 +1,74 @@
+"""
+ Cohere multi-hop agent enables multiple tools to be used in sequence to complete a
+ task.
+
+ This agent uses a multi hop prompt by Cohere, which is experimental and subject
+ to change. The latest prompt can be used by upgrading the langchain-cohere package.
+"""
+from typing import Sequence
+
+from langchain_core.language_models import BaseLanguageModel
+from langchain_core.prompts.chat import ChatPromptTemplate
+from langchain_core.runnables import Runnable, RunnablePassthrough
+from langchain_core.tools import BaseTool
+
+from langchain_cohere.react_multi_hop.parsing import (
+ CohereToolsReactAgentOutputParser,
+)
+from langchain_cohere.react_multi_hop.prompt import (
+ multi_hop_prompt,
+)
+
+
+def create_cohere_react_agent(
+ llm: BaseLanguageModel,
+ tools: Sequence[BaseTool],
+ prompt: ChatPromptTemplate,
+) -> Runnable:
+ """
+ Create an agent that enables multiple tools to be used in sequence to complete
+ a task.
+
+ Args:
+ llm: The ChatCohere LLM instance to use.
+ tools: Tools this agent has access to.
+ prompt: The prompt to use.
+
+ Returns:
+ A Runnable sequence representing an agent. It takes as input all the same input
+ variables as the prompt passed in does and returns an AgentAction or
+ AgentFinish.
+
+ Example:
+ . code-block:: python
+ from langchain.agents import AgentExecutor
+ from langchain.prompts import ChatPromptTemplate
+ from langchain_cohere import ChatCohere, create_cohere_react_agent
+
+ prompt = ChatPromptTemplate.from_template("{input}")
+ tools = [] # Populate this with a list of tools you would like to use.
+
+ llm = ChatCohere()
+
+ agent = create_cohere_react_agent(
+ llm,
+ tools,
+ prompt
+ )
+ agent_executor = AgentExecutor(agent=agent, tools=tools)
+
+ agent_executor.invoke({
+ "input": "In what year was the company that was founded as Sound of Music added to the S&P 500?",
+ })
+ """ # noqa: E501
+ agent = (
+ RunnablePassthrough.assign(
+ # agent_scratchpad isn't used in this chain, but added here for
+ # interoperability with other chains that may require it.
+ agent_scratchpad=lambda _: [],
+ )
+ | multi_hop_prompt(tools=tools, prompt=prompt)
+ | llm.bind(stop=["\nObservation:"], raw_prompting=True)
+ | CohereToolsReactAgentOutputParser()
+ )
+ return agent
diff --git a/libs/partners/cohere/langchain_cohere/react_multi_hop/default_prompt_constants.py b/libs/partners/cohere/langchain_cohere/react_multi_hop/default_prompt_constants.py
new file mode 100644
index 0000000000..fb4dccce8d
--- /dev/null
+++ b/libs/partners/cohere/langchain_cohere/react_multi_hop/default_prompt_constants.py
@@ -0,0 +1,31 @@
+from enum import Enum
+
+
+class _SpecialToken(str, Enum):
+ bos = ""
+ start_turn = "<|START_OF_TURN_TOKEN|>"
+ end_turn = "<|END_OF_TURN_TOKEN|>"
+ role_system = "<|SYSTEM_TOKEN|>"
+ role_chatbot = "<|CHATBOT_TOKEN|>"
+ role_user = "<|USER_TOKEN|>"
+
+
+default_basic_rules = "You are a powerful language agent trained by Cohere to help people. You are capable of complex reasoning and augmented with a number of tools. Your job is to plan and reason about how you will use and consume the output of these tools to best help the user. You will see a conversation history between yourself and a user, ending with an utterance from the user. You will then see an instruction informing you what kind of response to generate. You will construct a plan and then perform a number of reasoning and action steps to solve the problem. When you have determined the answer to the user's request, you will cite your sources in your answers, according the instructions" # noqa: E501
+
+default_task_context = "You use your advanced complex reasoning capabilities to help people by answering their questions and other requests interactively. You will be asked a very wide array of requests on all kinds of topics. You will be equipped with a wide range of search engines or similar tools to help you, which you use to research your answer. You may need to use multiple tools in parallel or sequentially to complete your task. You should focus on serving the user's needs as best you can, which will be wide-ranging. The current date is {now}" # noqa: E501
+
+default_style_guide = "Unless the user asks for a different style of answer, you should answer in full sentences, using proper grammar and spelling" # noqa: E501
+
+default_safety_rules = "The instructions in this section override those in the task description and style guide sections. Don't answer questions that are harmful or immoral" # noqa: E501
+
+default_multi_hop_instruction = """Carefully perform the following instructions, in order, starting each with a new line.
+Firstly, You may need to use complex and advanced reasoning to complete your task and answer the question. Think about how you can use the provided tools to answer the question and come up with a high level plan you will execute.
+Write 'Plan:' followed by an initial high level plan of how you will solve the problem including the tools and steps required.
+Secondly, Carry out your plan by repeatedly using actions, reasoning over the results, and re-evaluating your plan. Perform Action, Observation, Reflection steps with the following format. Write 'Action:' followed by a json formatted action containing the "tool_name" and "parameters"
+ Next you will analyze the 'Observation:', this is the result of the action.
+After that you should always think about what to do next. Write 'Reflection:' followed by what you've figured out so far, any changes you need to make to your plan, and what you will do next including if you know the answer to the question.
+... (this Action/Observation/Reflection can repeat N times)
+Thirdly, Decide which of the retrieved documents are relevant to the user's last input by writing 'Relevant Documents:' followed by comma-separated list of document numbers. If none are relevant, you should instead write 'None'.
+Fourthly, Decide which of the retrieved documents contain facts that should be cited in a good answer to the user's last input by writing 'Cited Documents:' followed a comma-separated list of document numbers. If you dont want to cite any of them, you should instead write 'None'.
+Fifthly, Write 'Answer:' followed by a response to the user's last input in high quality natural english. Use the retrieved documents to help you. Do not insert any citations or grounding markup.
+Finally, Write 'Grounded answer:' followed by a response to the user's last input in high quality natural english. Use the symbols and to indicate when a fact comes from a document in the search result, e.g my fact for a fact from document 4.""" # noqa: E501
diff --git a/libs/partners/cohere/langchain_cohere/react_multi_hop/parsing.py b/libs/partners/cohere/langchain_cohere/react_multi_hop/parsing.py
new file mode 100644
index 0000000000..d6b86684d4
--- /dev/null
+++ b/libs/partners/cohere/langchain_cohere/react_multi_hop/parsing.py
@@ -0,0 +1,151 @@
+import json
+import logging
+import re
+from typing import Dict, List, Tuple, Union
+
+from langchain_core.agents import AgentAction, AgentActionMessageLog, AgentFinish
+from langchain_core.messages import AIMessage
+from langchain_core.output_parsers import BaseOutputParser
+
+
+class CohereToolsReactAgentOutputParser(
+ BaseOutputParser[Union[List[AgentAction], AgentFinish]]
+):
+ """Parses a message into agent actions/finish."""
+
+ def parse(self, text: str) -> Union[List[AgentAction], AgentFinish]:
+ # Parse the structured output of the final answer.
+ if "Answer: " in text:
+ prefix_map = {
+ "answer": "Answer:",
+ "grounded_answer": "Grounded answer:",
+ "relevant_docs": "Relevant Documents:",
+ "cited_docs": "Cited Documents:",
+ }
+ parsed_answer = parse_answer_with_prefixes(text, prefix_map)
+ return AgentFinish({"output": parsed_answer["answer"]}, text)
+ elif any([x in text for x in ["Plan: ", "Reflection: ", "Action: "]]):
+ completion, plan, actions = parse_actions(text)
+ agent_actions: List[AgentAction] = []
+ for i, action in enumerate(actions):
+ agent_action = AgentActionMessageLog(
+ tool=action["tool_name"],
+ tool_input=action["parameters"],
+ log=f"\n{action}\n" if i > 0 else f"\n{plan}\n{action}\n",
+ message_log=[AIMessage(content=completion)],
+ )
+ agent_actions.append(agent_action)
+
+ return agent_actions
+ else:
+ raise ValueError(
+ "\nCould not parse generation as it did not contain Plan, Reflection,"
+ + f"Action, or Answer. Input: {text}\n\n"
+ )
+
+
+def parse_jsonified_tool_use_generation(
+ tool_use_generation: str, tool_use_prefix: str
+) -> List[Dict]:
+ """Parses model-generated jsonified actions.
+
+ Expects input of the form
+ "{tool_use_prefix}: ```json\n[{list of jsonified objects}]```"
+
+ outputs parsed list of jsonified objects.
+ """
+
+ def _extract_codeblocks_from_md(text: str) -> List[str]:
+ return re.findall(r"`{3}([^`]*)`{0,3}", text)
+
+ raw_generation = re.sub(f"^{tool_use_prefix} ", "", tool_use_generation)
+ code_block_sections = _extract_codeblocks_from_md(raw_generation)
+
+ if len(code_block_sections) != 1: # should have exactly 1 code block
+ raise ValueError(f"Action Parsing Failed: {tool_use_generation}")
+ # only json allowed:
+ assert code_block_sections[0].startswith(
+ "json\n"
+ ), f"Action Parsing Failed: {tool_use_generation}"
+
+ actions = json.loads(re.sub("^json\n", "", code_block_sections[0]))
+
+ if not isinstance(actions, list):
+ raise ValueError(f"Action Parsing Failed: {tool_use_generation}")
+
+ if len(actions):
+ if any(
+ not isinstance(action, Dict) or "tool_name" not in action
+ for action in actions
+ ):
+ raise ValueError(f"Action Parsing Failed: {tool_use_generation}")
+ return actions
+
+
+def parse_answer_with_prefixes(
+ completion: str, prefixes: Dict[str, str]
+) -> Dict[str, str]:
+ """parses string into key-value pairs,
+ according to patterns supplied in prefixes. Also strips.
+
+ if inputs are:
+ completion = "\nhello: sam\ngoodbye then: paul.",
+ prefixes = {"greeting": "hello:", "farewell": "goodbye then:"}
+
+ the expected returned result is:
+ {"greeting": "sam", "farewell": "paul."}
+
+ Args:
+ completion (str): text to split
+ prefixes (Dict[str, str]): a key-value dict of keys and patterns.
+ See example above
+
+ Returns:
+ Dict[str, str]: parsed result
+ """
+ # sort out prefixes
+ re_pat = "(" + "|".join([re.escape(p) for p in prefixes.values()]) + ")"
+ reverse_prefix_map = {v: k for k, v in prefixes.items()}
+ split = re.split(re_pat, completion)
+ split = split[1:]
+ parsed = {}
+ for prefix, value in zip(split[::2], split[1::2]):
+ if prefix in reverse_prefix_map: # if the prefix is a match
+ if (
+ reverse_prefix_map[prefix] not in parsed
+ ): # first occurrence of a prefix is kept, others discarded
+ parsed[reverse_prefix_map[prefix]] = value.strip()
+ return parsed
+
+
+def parse_actions(generation: str) -> Tuple[str, str, List[Dict]]:
+ """Parse action selections from model output."""
+ plan = ""
+ actions = generation
+ try:
+ if "Plan: " in generation or "Reflection: " in generation:
+ # Model is trained to output a Plan or Reflection followed by an action.
+ # Use regex to extract the plan and action.
+ regex = r"^(Plan|Reflection)\s*\d*\s*:(.*?)(Action\s*\d*\s*:\s*\d*\s*```json\n.*?```)" # noqa: E501
+ action_match = re.search(regex, generation, re.DOTALL)
+ if not action_match:
+ raise ValueError(
+ f"Failed to parse multihop completion for input: {generation}"
+ )
+ plan = action_match.group(2).strip()
+ actions = action_match.group(3).strip()
+ else:
+ # Catch the case where model outputs only an action.
+ regex = r"^(Action\s*\d*\s*:\s*\d*\s*```json\n.*?```)"
+ action_match = re.search(regex, generation, re.DOTALL)
+ if not action_match:
+ raise ValueError(
+ f"Failed to parse multihop completion for input: {generation}"
+ )
+ actions = action_match.group(1).strip()
+ except Exception as e:
+ logging.error(f"Failed to parse multihop completion for input: {generation}")
+ logging.error(f"Error: {e}")
+
+ parsed_actions = parse_jsonified_tool_use_generation(actions, "Action:")
+ return generation, plan, parsed_actions
diff --git a/libs/partners/cohere/langchain_cohere/react_multi_hop/prompt.py b/libs/partners/cohere/langchain_cohere/react_multi_hop/prompt.py
new file mode 100644
index 0000000000..0c18d1cbcc
--- /dev/null
+++ b/libs/partners/cohere/langchain_cohere/react_multi_hop/prompt.py
@@ -0,0 +1,299 @@
+from __future__ import annotations
+
+from datetime import datetime
+from typing import (
+ Any,
+ Callable,
+ Dict,
+ List,
+ Mapping,
+ Optional,
+ Sequence,
+ Tuple,
+ Union,
+)
+
+from langchain_core.agents import AgentAction, AgentActionMessageLog
+from langchain_core.messages import AIMessage, BaseMessage, SystemMessage
+from langchain_core.prompts import (
+ BasePromptTemplate,
+ ChatPromptTemplate,
+ PromptTemplate,
+)
+from langchain_core.pydantic_v1 import BaseModel
+from langchain_core.tools import BaseTool
+
+from langchain_cohere.react_multi_hop.default_prompt_constants import (
+ _SpecialToken,
+ default_basic_rules,
+ default_multi_hop_instruction,
+ default_safety_rules,
+ default_style_guide,
+ default_task_context,
+)
+from langchain_cohere.utils import (
+ JSON_TO_PYTHON_TYPES,
+ _remove_signature_from_tool_description,
+)
+
+multi_hop_prompt_partial = PromptTemplate.from_template(
+ """{structured_preamble}
+
+## Available Tools
+Here is a list of tools that you have available to you:
+
+{tools}{end_turn}{history}{user_prompt}{start_turn}{system_role}{multi_hop_instruction}{end_turn}{steps}"""
+).partial(
+ start_turn=_SpecialToken.start_turn.value,
+ end_turn=_SpecialToken.end_turn.value,
+ system_role=_SpecialToken.role_system.value,
+ multi_hop_instruction=default_multi_hop_instruction,
+)
+
+
+def render_structured_preamble(
+ preamble: Optional[str] = None,
+) -> str:
+ """Renders the structured preamble part of the prompt content."""
+ if preamble is None:
+ default_preamble = """## Task And Context
+{task_and_context}
+
+## Style Guide
+{style_guide}"""
+ preamble = default_preamble.format(
+ task_and_context=default_task_context.format(
+ now=datetime.now().strftime("%A, %B %d, %Y %H:%M:%S")
+ ),
+ style_guide=default_style_guide,
+ )
+
+ structured_preamble_template = """{prompt_start}# Safety Preamble
+{safety_rules}
+
+# System Preamble
+## Basic Rules
+{basic_rules}
+
+# User Preamble
+{preamble}"""
+ return structured_preamble_template.format(
+ prompt_start=f"{_SpecialToken.bos.value}{_SpecialToken.start_turn.value}{_SpecialToken.role_system.value}",
+ safety_rules=default_safety_rules,
+ basic_rules=default_basic_rules,
+ preamble=preamble,
+ )
+
+
+def render_tool(tool: BaseTool) -> str:
+ """Renders a tool into prompt content"""
+
+ template = """```python
+{tool_signature}
+ \"\"\"{tool_description}{tool_args}
+ \"\"\"
+ pass
+```"""
+ return template.format(
+ tool_signature=render_tool_signature(tool),
+ tool_description=_remove_signature_from_tool_description(
+ tool.name, tool.description
+ ),
+ tool_args=render_tool_args(tool),
+ )
+
+
+def render_observations(
+ observations: Union[List[Mapping[str, str]], List[str], Mapping[str, str], str],
+ index: int,
+) -> Tuple[BaseMessage, int]:
+ """Renders the 'output' part of an Agent's intermediate step into prompt content."""
+ if (
+ not isinstance(observations, list)
+ and not isinstance(observations, str)
+ and not isinstance(observations, Mapping)
+ ):
+ raise ValueError("observation must be a list, a Mapping, or a string")
+
+ rendered_documents = []
+ document_prompt = """Document: {index}
+{fields}"""
+
+ if isinstance(observations, str):
+ # strings are turned into a key/value pair and a key of 'output' is added.
+ observations = [{"output": observations}] # type: ignore
+
+ if isinstance(observations, Mapping):
+ # single items are transformed into a list to simplify the rest of the code.
+ observations = [observations]
+
+ if isinstance(observations, list):
+ for doc in observations:
+ if isinstance(doc, str):
+ # strings are turned into a key/value pair.
+ doc = {"output": doc}
+
+ if not isinstance(doc, Mapping):
+ raise ValueError(
+ "all observation list items must be a Mapping or a string"
+ )
+
+ # Render document fields into Key: value strings.
+ fields: List[str] = []
+ for k, v in doc.items():
+ if k.lower() == "url":
+ # 'url' is a special key which is always upper case.
+ k = "URL"
+ else:
+ # keys are otherwise transformed into title case.
+ k = k.title()
+ fields.append(f"{k}: {v}")
+
+ rendered_documents.append(
+ document_prompt.format(
+ index=index,
+ fields="\n".join(fields),
+ )
+ )
+ index += 1
+
+ prompt_content = "\n" + "\n\n".join(rendered_documents) + "\n"
+ return SystemMessage(content=prompt_content), index
+
+
+def render_intermediate_steps(
+ intermediate_steps: List[Tuple[AgentAction, Any]],
+) -> str:
+ """Renders an agent's intermediate steps into prompt content."""
+ prompt_content = ""
+ if any(
+ not isinstance(action, AgentActionMessageLog)
+ for action, _ in intermediate_steps
+ ):
+ raise ValueError("all AgentAction steps must implement AgentActionMessageLog")
+
+ i = 0
+ for action, observation in intermediate_steps:
+ prompt_content += render_messages(action.messages)
+ observation_message, i = render_observations(observation, i)
+ prompt_content += render_messages([observation_message])
+ # Always add an 'open' chatbot turn because prompts for the current turn always end
+ # with an open turn.
+ prompt_content += (
+ f"{_SpecialToken.start_turn.value}{_SpecialToken.role_chatbot.value}"
+ )
+
+ return prompt_content
+
+
+def multi_hop_prompt(
+ tools: Sequence[BaseTool], prompt: ChatPromptTemplate
+) -> Callable[[Dict], BasePromptTemplate]:
+ """The returned function produces a BasePromptTemplate suitable for multi-hop."""
+
+ # the directly_answer tool is used internally by the model, but never produces an
+ # AgentAction, so we only need to add it to the prompt.
+ tools = list(tools)
+ tools.insert(0, create_directly_answer_tool())
+
+ def inner(x: Dict) -> BasePromptTemplate:
+ return multi_hop_prompt_partial.partial(
+ structured_preamble=render_structured_preamble(
+ preamble=x.get("preamble", None)
+ ),
+ tools="\n\n".join([render_tool(t) for t in tools]),
+ user_prompt=render_messages(prompt.invoke(x).to_messages()),
+ steps=render_intermediate_steps(x["intermediate_steps"]),
+ history=render_messages(x.get("chat_history", [])),
+ )
+
+ return inner
+
+
+def render_type(type_: str, is_optional: bool) -> str:
+ """
+ Renders a tool's type into prompt content. Types should be Python types, but JSON
+ schema is allowed and converted.
+ """
+ python_type = JSON_TO_PYTHON_TYPES.get(type_, type_)
+ if is_optional:
+ return f"Optional[{python_type}]"
+ else:
+ return python_type
+
+
+def render_tool_signature(tool: BaseTool) -> str:
+ """Renders the signature of a tool into prompt content."""
+ args = []
+ for parameter_name, parameter_definition in tool.args.items():
+ type_ = render_type(
+ parameter_definition.get("type"), "default" in parameter_definition
+ )
+ args.append(f"{parameter_name}: {type_}")
+ signature = ", ".join(args)
+ return f"def {tool.name}({signature}) -> List[Dict]:"
+
+
+def render_tool_args(tool: BaseTool) -> str:
+ """Renders the 'Args' section of a tool's prompt content."""
+ if not tool.args:
+ return ""
+ indent = " "
+
+ prompt_content = f"\n\n{indent * 4}Args:\n{indent * 8}"
+
+ rendered_args = []
+ for parameter_name, parameter_definition in tool.args.items():
+ type_ = render_type(
+ parameter_definition.get("type"), "default" in parameter_definition
+ )
+ description = parameter_definition.get("description", "")
+ rendered_args.append(f"{parameter_name} ({type_}): {description}")
+
+ prompt_content += f"\n{indent * 8}".join(rendered_args)
+ return prompt_content
+
+
+def create_directly_answer_tool() -> BaseTool:
+ """
+ directly_answer is a special tool that's always presented to the model as an
+ available tool. The model only ever invokes this whilst answering and no AgentAction
+ is produced, so it only needs to be added to the prompt.
+ """
+
+ class DirectlyAnswerTool(BaseTool):
+ class InputSchema(BaseModel):
+ pass
+
+ name = "directly_answer"
+ description = "Calls a standard (un-augmented) AI chatbot to generate a response given the conversation history" # noqa: E501
+ args_schema = InputSchema
+
+ @property
+ def args(self) -> dict:
+ return {}
+
+ def _run(self, *args: Any, **kwargs: Any) -> Any:
+ raise NotImplementedError()
+
+ return DirectlyAnswerTool()
+
+
+def render_role(message: BaseMessage) -> str:
+ """Renders the role of a message into prompt content."""
+ if isinstance(message, AIMessage):
+ return _SpecialToken.role_chatbot.value
+ elif isinstance(message, SystemMessage):
+ return _SpecialToken.role_system.value
+ else:
+ return _SpecialToken.role_user.value
+
+
+def render_messages(messages: Sequence[BaseMessage]) -> str:
+ """Renders one or more BaseMessage implementations into prompt content."""
+ return "".join(
+ [
+ f"{_SpecialToken.start_turn.value}{render_role(message)}{message.content}{_SpecialToken.end_turn.value}"
+ for message in messages
+ ]
+ )
diff --git a/libs/partners/cohere/langchain_cohere/utils.py b/libs/partners/cohere/langchain_cohere/utils.py
index 7c7cfcb074..87762fd710 100644
--- a/libs/partners/cohere/langchain_cohere/utils.py
+++ b/libs/partners/cohere/langchain_cohere/utils.py
@@ -1,6 +1,7 @@
from __future__ import annotations
import logging
+import re
from typing import Any, Callable
import cohere
@@ -14,6 +15,15 @@ from tenacity import (
logger = logging.getLogger(__name__)
+JSON_TO_PYTHON_TYPES = {
+ "string": "str",
+ "number": "float",
+ "boolean": "bool",
+ "integer": "int",
+ "array": "List",
+ "object": "Dict",
+}
+
def _create_retry_decorator(max_retries: int) -> Callable[[Any], Any]:
# support v4 and v5
@@ -34,3 +44,14 @@ def _create_retry_decorator(max_retries: int) -> Callable[[Any], Any]:
retry=retry_conditions,
before_sleep=before_sleep_log(logger, logging.WARNING),
)
+
+
+def _remove_signature_from_tool_description(name: str, description: str) -> str:
+ """
+ Removes the `{name}{signature} - ` prefix and Args: section from tool description.
+ The signature is usually present for tools created with the @tool decorator,
+ whereas the Args: section may be present in function doc blocks.
+ """
+ description = re.sub(rf"^{name}\(.*?\) -(?:> \w+? -)? ", "", description)
+ description = re.sub(r"(?s)(?:\n?\n\s*?)?Args:.*$", "", description)
+ return description
diff --git a/libs/partners/cohere/poetry.lock b/libs/partners/cohere/poetry.lock
index d18c8a94e5..f6ca66c6f1 100644
--- a/libs/partners/cohere/poetry.lock
+++ b/libs/partners/cohere/poetry.lock
@@ -1,5 +1,115 @@
# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
+[[package]]
+name = "aiohttp"
+version = "3.9.3"
+description = "Async http client/server framework (asyncio)"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:939677b61f9d72a4fa2a042a5eee2a99a24001a67c13da113b2e30396567db54"},
+ {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1f5cd333fcf7590a18334c90f8c9147c837a6ec8a178e88d90a9b96ea03194cc"},
+ {file = "aiohttp-3.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:82e6aa28dd46374f72093eda8bcd142f7771ee1eb9d1e223ff0fa7177a96b4a5"},
+ {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f56455b0c2c7cc3b0c584815264461d07b177f903a04481dfc33e08a89f0c26b"},
+ {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bca77a198bb6e69795ef2f09a5f4c12758487f83f33d63acde5f0d4919815768"},
+ {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e083c285857b78ee21a96ba1eb1b5339733c3563f72980728ca2b08b53826ca5"},
+ {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab40e6251c3873d86ea9b30a1ac6d7478c09277b32e14745d0d3c6e76e3c7e29"},
+ {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df822ee7feaaeffb99c1a9e5e608800bd8eda6e5f18f5cfb0dc7eeb2eaa6bbec"},
+ {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:acef0899fea7492145d2bbaaaec7b345c87753168589cc7faf0afec9afe9b747"},
+ {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cd73265a9e5ea618014802ab01babf1940cecb90c9762d8b9e7d2cc1e1969ec6"},
+ {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a78ed8a53a1221393d9637c01870248a6f4ea5b214a59a92a36f18151739452c"},
+ {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:6b0e029353361f1746bac2e4cc19b32f972ec03f0f943b390c4ab3371840aabf"},
+ {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7cf5c9458e1e90e3c390c2639f1017a0379a99a94fdfad3a1fd966a2874bba52"},
+ {file = "aiohttp-3.9.3-cp310-cp310-win32.whl", hash = "sha256:3e59c23c52765951b69ec45ddbbc9403a8761ee6f57253250c6e1536cacc758b"},
+ {file = "aiohttp-3.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:055ce4f74b82551678291473f66dc9fb9048a50d8324278751926ff0ae7715e5"},
+ {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6b88f9386ff1ad91ace19d2a1c0225896e28815ee09fc6a8932fded8cda97c3d"},
+ {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c46956ed82961e31557b6857a5ca153c67e5476972e5f7190015018760938da2"},
+ {file = "aiohttp-3.9.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:07b837ef0d2f252f96009e9b8435ec1fef68ef8b1461933253d318748ec1acdc"},
+ {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad46e6f620574b3b4801c68255492e0159d1712271cc99d8bdf35f2043ec266"},
+ {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ed3e046ea7b14938112ccd53d91c1539af3e6679b222f9469981e3dac7ba1ce"},
+ {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:039df344b45ae0b34ac885ab5b53940b174530d4dd8a14ed8b0e2155b9dddccb"},
+ {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7943c414d3a8d9235f5f15c22ace69787c140c80b718dcd57caaade95f7cd93b"},
+ {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84871a243359bb42c12728f04d181a389718710129b36b6aad0fc4655a7647d4"},
+ {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5eafe2c065df5401ba06821b9a054d9cb2848867f3c59801b5d07a0be3a380ae"},
+ {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9d3c9b50f19704552f23b4eaea1fc082fdd82c63429a6506446cbd8737823da3"},
+ {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:f033d80bc6283092613882dfe40419c6a6a1527e04fc69350e87a9df02bbc283"},
+ {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:2c895a656dd7e061b2fd6bb77d971cc38f2afc277229ce7dd3552de8313a483e"},
+ {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1f5a71d25cd8106eab05f8704cd9167b6e5187bcdf8f090a66c6d88b634802b4"},
+ {file = "aiohttp-3.9.3-cp311-cp311-win32.whl", hash = "sha256:50fca156d718f8ced687a373f9e140c1bb765ca16e3d6f4fe116e3df7c05b2c5"},
+ {file = "aiohttp-3.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:5fe9ce6c09668063b8447f85d43b8d1c4e5d3d7e92c63173e6180b2ac5d46dd8"},
+ {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:38a19bc3b686ad55804ae931012f78f7a534cce165d089a2059f658f6c91fa60"},
+ {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:770d015888c2a598b377bd2f663adfd947d78c0124cfe7b959e1ef39f5b13869"},
+ {file = "aiohttp-3.9.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee43080e75fc92bf36219926c8e6de497f9b247301bbf88c5c7593d931426679"},
+ {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52df73f14ed99cee84865b95a3d9e044f226320a87af208f068ecc33e0c35b96"},
+ {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc9b311743a78043b26ffaeeb9715dc360335e5517832f5a8e339f8a43581e4d"},
+ {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b955ed993491f1a5da7f92e98d5dad3c1e14dc175f74517c4e610b1f2456fb11"},
+ {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:504b6981675ace64c28bf4a05a508af5cde526e36492c98916127f5a02354d53"},
+ {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a6fe5571784af92b6bc2fda8d1925cccdf24642d49546d3144948a6a1ed58ca5"},
+ {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ba39e9c8627edc56544c8628cc180d88605df3892beeb2b94c9bc857774848ca"},
+ {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e5e46b578c0e9db71d04c4b506a2121c0cb371dd89af17a0586ff6769d4c58c1"},
+ {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:938a9653e1e0c592053f815f7028e41a3062e902095e5a7dc84617c87267ebd5"},
+ {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:c3452ea726c76e92f3b9fae4b34a151981a9ec0a4847a627c43d71a15ac32aa6"},
+ {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ff30218887e62209942f91ac1be902cc80cddb86bf00fbc6783b7a43b2bea26f"},
+ {file = "aiohttp-3.9.3-cp312-cp312-win32.whl", hash = "sha256:38f307b41e0bea3294a9a2a87833191e4bcf89bb0365e83a8be3a58b31fb7f38"},
+ {file = "aiohttp-3.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:b791a3143681a520c0a17e26ae7465f1b6f99461a28019d1a2f425236e6eedb5"},
+ {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0ed621426d961df79aa3b963ac7af0d40392956ffa9be022024cd16297b30c8c"},
+ {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7f46acd6a194287b7e41e87957bfe2ad1ad88318d447caf5b090012f2c5bb528"},
+ {file = "aiohttp-3.9.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:feeb18a801aacb098220e2c3eea59a512362eb408d4afd0c242044c33ad6d542"},
+ {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f734e38fd8666f53da904c52a23ce517f1b07722118d750405af7e4123933511"},
+ {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b40670ec7e2156d8e57f70aec34a7216407848dfe6c693ef131ddf6e76feb672"},
+ {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fdd215b7b7fd4a53994f238d0f46b7ba4ac4c0adb12452beee724ddd0743ae5d"},
+ {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:017a21b0df49039c8f46ca0971b3a7fdc1f56741ab1240cb90ca408049766168"},
+ {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e99abf0bba688259a496f966211c49a514e65afa9b3073a1fcee08856e04425b"},
+ {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:648056db9a9fa565d3fa851880f99f45e3f9a771dd3ff3bb0c048ea83fb28194"},
+ {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8aacb477dc26797ee089721536a292a664846489c49d3ef9725f992449eda5a8"},
+ {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:522a11c934ea660ff8953eda090dcd2154d367dec1ae3c540aff9f8a5c109ab4"},
+ {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5bce0dc147ca85caa5d33debc4f4d65e8e8b5c97c7f9f660f215fa74fc49a321"},
+ {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b4af9f25b49a7be47c0972139e59ec0e8285c371049df1a63b6ca81fdd216a2"},
+ {file = "aiohttp-3.9.3-cp38-cp38-win32.whl", hash = "sha256:298abd678033b8571995650ccee753d9458dfa0377be4dba91e4491da3f2be63"},
+ {file = "aiohttp-3.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:69361bfdca5468c0488d7017b9b1e5ce769d40b46a9f4a2eed26b78619e9396c"},
+ {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0fa43c32d1643f518491d9d3a730f85f5bbaedcbd7fbcae27435bb8b7a061b29"},
+ {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:835a55b7ca49468aaaac0b217092dfdff370e6c215c9224c52f30daaa735c1c1"},
+ {file = "aiohttp-3.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06a9b2c8837d9a94fae16c6223acc14b4dfdff216ab9b7202e07a9a09541168f"},
+ {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abf151955990d23f84205286938796c55ff11bbfb4ccfada8c9c83ae6b3c89a3"},
+ {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59c26c95975f26e662ca78fdf543d4eeaef70e533a672b4113dd888bd2423caa"},
+ {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f95511dd5d0e05fd9728bac4096319f80615aaef4acbecb35a990afebe953b0e"},
+ {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:595f105710293e76b9dc09f52e0dd896bd064a79346234b521f6b968ffdd8e58"},
+ {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7c8b816c2b5af5c8a436df44ca08258fc1a13b449393a91484225fcb7545533"},
+ {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f1088fa100bf46e7b398ffd9904f4808a0612e1d966b4aa43baa535d1b6341eb"},
+ {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f59dfe57bb1ec82ac0698ebfcdb7bcd0e99c255bd637ff613760d5f33e7c81b3"},
+ {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:361a1026c9dd4aba0109e4040e2aecf9884f5cfe1b1b1bd3d09419c205e2e53d"},
+ {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:363afe77cfcbe3a36353d8ea133e904b108feea505aa4792dad6585a8192c55a"},
+ {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e2c45c208c62e955e8256949eb225bd8b66a4c9b6865729a786f2aa79b72e9d"},
+ {file = "aiohttp-3.9.3-cp39-cp39-win32.whl", hash = "sha256:f7217af2e14da0856e082e96ff637f14ae45c10a5714b63c77f26d8884cf1051"},
+ {file = "aiohttp-3.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:27468897f628c627230dba07ec65dc8d0db566923c48f29e084ce382119802bc"},
+ {file = "aiohttp-3.9.3.tar.gz", hash = "sha256:90842933e5d1ff760fae6caca4b2b3edba53ba8f4b71e95dacf2818a2aca06f7"},
+]
+
+[package.dependencies]
+aiosignal = ">=1.1.2"
+async-timeout = {version = ">=4.0,<5.0", markers = "python_version < \"3.11\""}
+attrs = ">=17.3.0"
+frozenlist = ">=1.1.1"
+multidict = ">=4.5,<7.0"
+yarl = ">=1.0,<2.0"
+
+[package.extras]
+speedups = ["Brotli", "aiodns", "brotlicffi"]
+
+[[package]]
+name = "aiosignal"
+version = "1.3.1"
+description = "aiosignal: a list of registered asynchronous callbacks"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"},
+ {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"},
+]
+
+[package.dependencies]
+frozenlist = ">=1.1.0"
+
[[package]]
name = "annotated-types"
version = "0.6.0"
@@ -36,6 +146,36 @@ doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphin
test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"]
trio = ["trio (>=0.23)"]
+[[package]]
+name = "async-timeout"
+version = "4.0.3"
+description = "Timeout context manager for asyncio programs"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"},
+ {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"},
+]
+
+[[package]]
+name = "attrs"
+version = "23.2.0"
+description = "Classes Without Boilerplate"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"},
+ {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"},
+]
+
+[package.extras]
+cov = ["attrs[tests]", "coverage[toml] (>=5.3)"]
+dev = ["attrs[tests]", "pre-commit"]
+docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"]
+tests = ["attrs[tests-no-zope]", "zope-interface"]
+tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"]
+tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"]
+
[[package]]
name = "certifi"
version = "2024.2.2"
@@ -191,16 +331,20 @@ files = [
]
[[package]]
-name = "defusedxml"
-version = "0.7.1"
-description = "XML bomb protection for Python stdlib modules"
+name = "dataclasses-json"
+version = "0.6.4"
+description = "Easily serialize dataclasses to and from JSON."
optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = ">=3.7,<4.0"
files = [
- {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"},
- {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"},
+ {file = "dataclasses_json-0.6.4-py3-none-any.whl", hash = "sha256:f90578b8a3177f7552f4e1a6e535e84293cd5da421fcce0642d49c0d7bdf8df2"},
+ {file = "dataclasses_json-0.6.4.tar.gz", hash = "sha256:73696ebf24936560cca79a2430cbc4f3dd23ac7bf46ed17f38e5e5e7657a6377"},
]
+[package.dependencies]
+marshmallow = ">=3.18.0,<4.0.0"
+typing-inspect = ">=0.4.0,<1"
+
[[package]]
name = "exceptiongroup"
version = "1.2.0"
@@ -229,6 +373,163 @@ files = [
[package.dependencies]
python-dateutil = ">=2.7"
+[[package]]
+name = "frozenlist"
+version = "1.4.1"
+description = "A list-like structure which implements collections.abc.MutableSequence"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac"},
+ {file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868"},
+ {file = "frozenlist-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776"},
+ {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a"},
+ {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad"},
+ {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c"},
+ {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe"},
+ {file = "frozenlist-1.4.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a"},
+ {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98"},
+ {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75"},
+ {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5"},
+ {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950"},
+ {file = "frozenlist-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc"},
+ {file = "frozenlist-1.4.1-cp310-cp310-win32.whl", hash = "sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1"},
+ {file = "frozenlist-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439"},
+ {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0"},
+ {file = "frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49"},
+ {file = "frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced"},
+ {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0"},
+ {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106"},
+ {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068"},
+ {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2"},
+ {file = "frozenlist-1.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19"},
+ {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82"},
+ {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec"},
+ {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a"},
+ {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74"},
+ {file = "frozenlist-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2"},
+ {file = "frozenlist-1.4.1-cp311-cp311-win32.whl", hash = "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17"},
+ {file = "frozenlist-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825"},
+ {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae"},
+ {file = "frozenlist-1.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb"},
+ {file = "frozenlist-1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b"},
+ {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86"},
+ {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480"},
+ {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09"},
+ {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a"},
+ {file = "frozenlist-1.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd"},
+ {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6"},
+ {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1"},
+ {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b"},
+ {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e"},
+ {file = "frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8"},
+ {file = "frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89"},
+ {file = "frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5"},
+ {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:20b51fa3f588ff2fe658663db52a41a4f7aa6c04f6201449c6c7c476bd255c0d"},
+ {file = "frozenlist-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:410478a0c562d1a5bcc2f7ea448359fcb050ed48b3c6f6f4f18c313a9bdb1826"},
+ {file = "frozenlist-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6321c9efe29975232da3bd0af0ad216800a47e93d763ce64f291917a381b8eb"},
+ {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f6a4533887e189dae092f1cf981f2e3885175f7a0f33c91fb5b7b682b6bab6"},
+ {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6eb73fa5426ea69ee0e012fb59cdc76a15b1283d6e32e4f8dc4482ec67d1194d"},
+ {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fbeb989b5cc29e8daf7f976b421c220f1b8c731cbf22b9130d8815418ea45887"},
+ {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32453c1de775c889eb4e22f1197fe3bdfe457d16476ea407472b9442e6295f7a"},
+ {file = "frozenlist-1.4.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:693945278a31f2086d9bf3df0fe8254bbeaef1fe71e1351c3bd730aa7d31c41b"},
+ {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1d0ce09d36d53bbbe566fe296965b23b961764c0bcf3ce2fa45f463745c04701"},
+ {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3a670dc61eb0d0eb7080890c13de3066790f9049b47b0de04007090807c776b0"},
+ {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:dca69045298ce5c11fd539682cff879cc1e664c245d1c64da929813e54241d11"},
+ {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a06339f38e9ed3a64e4c4e43aec7f59084033647f908e4259d279a52d3757d09"},
+ {file = "frozenlist-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b7f2f9f912dca3934c1baec2e4585a674ef16fe00218d833856408c48d5beee7"},
+ {file = "frozenlist-1.4.1-cp38-cp38-win32.whl", hash = "sha256:e7004be74cbb7d9f34553a5ce5fb08be14fb33bc86f332fb71cbe5216362a497"},
+ {file = "frozenlist-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:5a7d70357e7cee13f470c7883a063aae5fe209a493c57d86eb7f5a6f910fae09"},
+ {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bfa4a17e17ce9abf47a74ae02f32d014c5e9404b6d9ac7f729e01562bbee601e"},
+ {file = "frozenlist-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b7e3ed87d4138356775346e6845cccbe66cd9e207f3cd11d2f0b9fd13681359d"},
+ {file = "frozenlist-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c99169d4ff810155ca50b4da3b075cbde79752443117d89429595c2e8e37fed8"},
+ {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edb678da49d9f72c9f6c609fbe41a5dfb9a9282f9e6a2253d5a91e0fc382d7c0"},
+ {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6db4667b187a6742b33afbbaf05a7bc551ffcf1ced0000a571aedbb4aa42fc7b"},
+ {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55fdc093b5a3cb41d420884cdaf37a1e74c3c37a31f46e66286d9145d2063bd0"},
+ {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82e8211d69a4f4bc360ea22cd6555f8e61a1bd211d1d5d39d3d228b48c83a897"},
+ {file = "frozenlist-1.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89aa2c2eeb20957be2d950b85974b30a01a762f3308cd02bb15e1ad632e22dc7"},
+ {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d3e0c25a2350080e9319724dede4f31f43a6c9779be48021a7f4ebde8b2d742"},
+ {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7268252af60904bf52c26173cbadc3a071cece75f873705419c8681f24d3edea"},
+ {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:0c250a29735d4f15321007fb02865f0e6b6a41a6b88f1f523ca1596ab5f50bd5"},
+ {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:96ec70beabbd3b10e8bfe52616a13561e58fe84c0101dd031dc78f250d5128b9"},
+ {file = "frozenlist-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:23b2d7679b73fe0e5a4560b672a39f98dfc6f60df63823b0a9970525325b95f6"},
+ {file = "frozenlist-1.4.1-cp39-cp39-win32.whl", hash = "sha256:a7496bfe1da7fb1a4e1cc23bb67c58fab69311cc7d32b5a99c2007b4b2a0e932"},
+ {file = "frozenlist-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e6a20a581f9ce92d389a8c7d7c3dd47c81fd5d6e655c8dddf341e14aa48659d0"},
+ {file = "frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7"},
+ {file = "frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b"},
+]
+
+[[package]]
+name = "greenlet"
+version = "3.0.3"
+description = "Lightweight in-process concurrent programming"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "greenlet-3.0.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9da2bd29ed9e4f15955dd1595ad7bc9320308a3b766ef7f837e23ad4b4aac31a"},
+ {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d353cadd6083fdb056bb46ed07e4340b0869c305c8ca54ef9da3421acbdf6881"},
+ {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dca1e2f3ca00b84a396bc1bce13dd21f680f035314d2379c4160c98153b2059b"},
+ {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ed7fb269f15dc662787f4119ec300ad0702fa1b19d2135a37c2c4de6fadfd4a"},
+ {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd4f49ae60e10adbc94b45c0b5e6a179acc1736cf7a90160b404076ee283cf83"},
+ {file = "greenlet-3.0.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:73a411ef564e0e097dbe7e866bb2dda0f027e072b04da387282b02c308807405"},
+ {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7f362975f2d179f9e26928c5b517524e89dd48530a0202570d55ad6ca5d8a56f"},
+ {file = "greenlet-3.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:649dde7de1a5eceb258f9cb00bdf50e978c9db1b996964cd80703614c86495eb"},
+ {file = "greenlet-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:68834da854554926fbedd38c76e60c4a2e3198c6fbed520b106a8986445caaf9"},
+ {file = "greenlet-3.0.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:b1b5667cced97081bf57b8fa1d6bfca67814b0afd38208d52538316e9422fc61"},
+ {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52f59dd9c96ad2fc0d5724107444f76eb20aaccb675bf825df6435acb7703559"},
+ {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:afaff6cf5200befd5cec055b07d1c0a5a06c040fe5ad148abcd11ba6ab9b114e"},
+ {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33"},
+ {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2797aa5aedac23af156bbb5a6aa2cd3427ada2972c828244eb7d1b9255846379"},
+ {file = "greenlet-3.0.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7f009caad047246ed379e1c4dbcb8b020f0a390667ea74d2387be2998f58a22"},
+ {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c5e1536de2aad7bf62e27baf79225d0d64360d4168cf2e6becb91baf1ed074f3"},
+ {file = "greenlet-3.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:894393ce10ceac937e56ec00bb71c4c2f8209ad516e96033e4b3b1de270e200d"},
+ {file = "greenlet-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:1ea188d4f49089fc6fb283845ab18a2518d279c7cd9da1065d7a84e991748728"},
+ {file = "greenlet-3.0.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:70fb482fdf2c707765ab5f0b6655e9cfcf3780d8d87355a063547b41177599be"},
+ {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4d1ac74f5c0c0524e4a24335350edad7e5f03b9532da7ea4d3c54d527784f2e"},
+ {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:149e94a2dd82d19838fe4b2259f1b6b9957d5ba1b25640d2380bea9c5df37676"},
+ {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15d79dd26056573940fcb8c7413d84118086f2ec1a8acdfa854631084393efcc"},
+ {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b7db1ebff4ba09aaaeae6aa491daeb226c8150fc20e836ad00041bcb11230"},
+ {file = "greenlet-3.0.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fcd2469d6a2cf298f198f0487e0a5b1a47a42ca0fa4dfd1b6862c999f018ebbf"},
+ {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1f672519db1796ca0d8753f9e78ec02355e862d0998193038c7073045899f305"},
+ {file = "greenlet-3.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2516a9957eed41dd8f1ec0c604f1cdc86758b587d964668b5b196a9db5bfcde6"},
+ {file = "greenlet-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:bba5387a6975598857d86de9eac14210a49d554a77eb8261cc68b7d082f78ce2"},
+ {file = "greenlet-3.0.3-cp37-cp37m-macosx_11_0_universal2.whl", hash = "sha256:5b51e85cb5ceda94e79d019ed36b35386e8c37d22f07d6a751cb659b180d5274"},
+ {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:daf3cb43b7cf2ba96d614252ce1684c1bccee6b2183a01328c98d36fcd7d5cb0"},
+ {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99bf650dc5d69546e076f413a87481ee1d2d09aaaaaca058c9251b6d8c14783f"},
+ {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dd6e660effd852586b6a8478a1d244b8dc90ab5b1321751d2ea15deb49ed414"},
+ {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3391d1e16e2a5a1507d83e4a8b100f4ee626e8eca43cf2cadb543de69827c4c"},
+ {file = "greenlet-3.0.3-cp37-cp37m-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1f145462f1fa6e4a4ae3c0f782e580ce44d57c8f2c7aae1b6fa88c0b2efdb41"},
+ {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1a7191e42732df52cb5f39d3527217e7ab73cae2cb3694d241e18f53d84ea9a7"},
+ {file = "greenlet-3.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6"},
+ {file = "greenlet-3.0.3-cp37-cp37m-win32.whl", hash = "sha256:b542be2440edc2d48547b5923c408cbe0fc94afb9f18741faa6ae970dbcb9b6d"},
+ {file = "greenlet-3.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67"},
+ {file = "greenlet-3.0.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:1996cb9306c8595335bb157d133daf5cf9f693ef413e7673cb07e3e5871379ca"},
+ {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc0f794e6ad661e321caa8d2f0a55ce01213c74722587256fb6566049a8b04"},
+ {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9db1c18f0eaad2f804728c67d6c610778456e3e1cc4ab4bbd5eeb8e6053c6fc"},
+ {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7170375bcc99f1a2fbd9c306f5be8764eaf3ac6b5cb968862cad4c7057756506"},
+ {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b66c9c1e7ccabad3a7d037b2bcb740122a7b17a53734b7d72a344ce39882a1b"},
+ {file = "greenlet-3.0.3-cp38-cp38-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:098d86f528c855ead3479afe84b49242e174ed262456c342d70fc7f972bc13c4"},
+ {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:81bb9c6d52e8321f09c3d165b2a78c680506d9af285bfccbad9fb7ad5a5da3e5"},
+ {file = "greenlet-3.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da"},
+ {file = "greenlet-3.0.3-cp38-cp38-win32.whl", hash = "sha256:d46677c85c5ba00a9cb6f7a00b2bfa6f812192d2c9f7d9c4f6a55b60216712f3"},
+ {file = "greenlet-3.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:419b386f84949bf0e7c73e6032e3457b82a787c1ab4a0e43732898a761cc9dbf"},
+ {file = "greenlet-3.0.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:da70d4d51c8b306bb7a031d5cff6cc25ad253affe89b70352af5f1cb68e74b53"},
+ {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:086152f8fbc5955df88382e8a75984e2bb1c892ad2e3c80a2508954e52295257"},
+ {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d73a9fe764d77f87f8ec26a0c85144d6a951a6c438dfe50487df5595c6373eac"},
+ {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7dcbe92cc99f08c8dd11f930de4d99ef756c3591a5377d1d9cd7dd5e896da71"},
+ {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1551a8195c0d4a68fac7a4325efac0d541b48def35feb49d803674ac32582f61"},
+ {file = "greenlet-3.0.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:64d7675ad83578e3fc149b617a444fab8efdafc9385471f868eb5ff83e446b8b"},
+ {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b37eef18ea55f2ffd8f00ff8fe7c8d3818abd3e25fb73fae2ca3b672e333a7a6"},
+ {file = "greenlet-3.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:77457465d89b8263bca14759d7c1684df840b6811b2499838cc5b040a8b5b113"},
+ {file = "greenlet-3.0.3-cp39-cp39-win32.whl", hash = "sha256:57e8974f23e47dac22b83436bdcf23080ade568ce77df33159e019d161ce1d1e"},
+ {file = "greenlet-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:c5ee858cfe08f34712f548c3c363e807e7186f03ad7a5039ebadb29e8c6be067"},
+ {file = "greenlet-3.0.3.tar.gz", hash = "sha256:43374442353259554ce33599da8b692d5aa96f8976d567d4badf263371fbe491"},
+]
+
+[package.extras]
+docs = ["Sphinx", "furo"]
+test = ["objgraph", "psutil"]
+
[[package]]
name = "h11"
version = "0.14.0"
@@ -333,8 +634,80 @@ files = [
]
[[package]]
-name = "langchain-core"
-version = "0.1.33"
+name = "langchain"
+version = "0.1.14"
+description = "Building applications with LLMs through composability"
+optional = false
+python-versions = ">=3.8.1,<4.0"
+files = []
+develop = true
+
+[package.dependencies]
+aiohttp = "^3.8.3"
+async-timeout = {version = "^4.0.0", markers = "python_version < \"3.11\""}
+dataclasses-json = ">= 0.5.7, < 0.7"
+jsonpatch = "^1.33"
+langchain-community = ">=0.0.30,<0.1"
+langchain-core = "^0.1.37"
+langchain-text-splitters = ">=0.0.1,<0.1"
+langsmith = "^0.1.17"
+numpy = "^1"
+pydantic = ">=1,<3"
+PyYAML = ">=5.3"
+requests = "^2"
+SQLAlchemy = ">=1.4,<3"
+tenacity = "^8.1.0"
+
+[package.extras]
+all = []
+azure = ["azure-ai-formrecognizer (>=3.2.1,<4.0.0)", "azure-ai-textanalytics (>=5.3.0,<6.0.0)", "azure-cognitiveservices-speech (>=1.28.0,<2.0.0)", "azure-core (>=1.26.4,<2.0.0)", "azure-cosmos (>=4.4.0b1,<5.0.0)", "azure-identity (>=1.12.0,<2.0.0)", "azure-search-documents (==11.4.0b8)", "openai (<2)"]
+clarifai = ["clarifai (>=9.1.0)"]
+cli = ["typer (>=0.9.0,<0.10.0)"]
+cohere = ["cohere (>=4,<6)"]
+docarray = ["docarray[hnswlib] (>=0.32.0,<0.33.0)"]
+embeddings = ["sentence-transformers (>=2,<3)"]
+extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cohere (>=4,<6)", "couchbase (>=4.1.9,<5.0.0)", "dashvector (>=1.0.1,<2.0.0)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "langchain-openai (>=0.0.2,<0.1)", "lxml (>=4.9.3,<6.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "openai (<2)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "rdflib (==7.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "upstash-redis (>=0.15.0,<0.16.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"]
+javascript = ["esprima (>=4.0.1,<5.0.0)"]
+llms = ["clarifai (>=9.1.0)", "cohere (>=4,<6)", "huggingface_hub (>=0,<1)", "manifest-ml (>=0.0.1,<0.0.2)", "nlpcloud (>=1,<2)", "openai (<2)", "openlm (>=0.0.5,<0.0.6)", "torch (>=1,<3)", "transformers (>=4,<5)"]
+openai = ["openai (<2)", "tiktoken (>=0.3.2,<0.6.0)"]
+qdrant = ["qdrant-client (>=1.3.1,<2.0.0)"]
+text-helpers = ["chardet (>=5.1.0,<6.0.0)"]
+
+[package.source]
+type = "directory"
+url = "../../langchain"
+
+[[package]]
+name = "langchain-community"
+version = "0.0.31"
+description = "Community contributed LangChain integrations."
+optional = false
+python-versions = ">=3.8.1,<4.0"
+files = []
+develop = true
+
+[package.dependencies]
+aiohttp = "^3.8.3"
+dataclasses-json = ">= 0.5.7, < 0.7"
+langchain-core = "^0.1.37"
+langsmith = "^0.1.0"
+numpy = "^1"
+PyYAML = ">=5.3"
+requests = "^2"
+SQLAlchemy = ">=1.4,<3"
+tenacity = "^8.1.0"
+
+[package.extras]
+cli = ["typer (>=0.9.0,<0.10.0)"]
+extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "azure-ai-documentintelligence (>=1.0.0b1,<2.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "cloudpickle (>=2.0.0)", "cloudpickle (>=2.0.0)", "cohere (>=4,<5)", "databricks-vectorsearch (>=0.21,<0.22)", "datasets (>=2.15.0,<3.0.0)", "dgml-utils (>=0.3.0,<0.4.0)", "elasticsearch (>=8.12.0,<9.0.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.9.0,<0.10.0)", "friendli-client (>=1.2.4,<2.0.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "gradientai (>=1.4.0,<2.0.0)", "hdbcli (>=2.19.21,<3.0.0)", "hologres-vector (>=0.0.6,<0.0.7)", "html2text (>=2020.1.16,<2021.0.0)", "httpx (>=0.24.1,<0.25.0)", "httpx-sse (>=0.4.0,<0.5.0)", "javelin-sdk (>=0.1.8,<0.2.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "lxml (>=4.9.3,<6.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "msal (>=1.25.0,<2.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "nvidia-riva-client (>=2.14.0,<3.0.0)", "oci (>=2.119.1,<3.0.0)", "openai (<2)", "openapi-pydantic (>=0.3.2,<0.4.0)", "oracle-ads (>=2.9.1,<3.0.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "praw (>=7.7.1,<8.0.0)", "premai (>=0.3.25,<0.4.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pyjwt (>=2.8.0,<3.0.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "rdflib (==7.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "tidb-vector (>=0.0.3,<1.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "tree-sitter (>=0.20.2,<0.21.0)", "tree-sitter-languages (>=1.8.0,<2.0.0)", "upstash-redis (>=0.15.0,<0.16.0)", "vdms (>=0.0.20,<0.0.21)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"]
+
+[package.source]
+type = "directory"
+url = "../../community"
+
+[[package]]
+name = "langchain-core"
+version = "0.1.38"
description = "Building applications with LLMs through composability"
optional = false
python-versions = ">=3.8.1,<4.0"
@@ -342,8 +715,6 @@ files = []
develop = true
[package.dependencies]
-anyio = ">=3,<5"
-defusedxml = "^0.7"
jsonpatch = "^1.33"
langsmith = "^0.1.0"
packaging = "^23.2"
@@ -359,6 +730,23 @@ extended-testing = ["jinja2 (>=3,<4)"]
type = "directory"
url = "../../core"
+[[package]]
+name = "langchain-text-splitters"
+version = "0.0.1"
+description = "LangChain text splitting utilities"
+optional = false
+python-versions = ">=3.8.1,<4.0"
+files = [
+ {file = "langchain_text_splitters-0.0.1-py3-none-any.whl", hash = "sha256:f5b802f873f5ff6a8b9259ff34d53ed989666ef4e1582e6d1adb3b5520e3839a"},
+ {file = "langchain_text_splitters-0.0.1.tar.gz", hash = "sha256:ac459fa98799f5117ad5425a9330b21961321e30bc19a2a2f9f761ddadd62aa1"},
+]
+
+[package.dependencies]
+langchain-core = ">=0.1.28,<0.2.0"
+
+[package.extras]
+extended-testing = ["lxml (>=5.1.0,<6.0.0)"]
+
[[package]]
name = "langsmith"
version = "0.1.31"
@@ -375,6 +763,124 @@ orjson = ">=3.9.14,<4.0.0"
pydantic = ">=1,<3"
requests = ">=2,<3"
+[[package]]
+name = "marshmallow"
+version = "3.21.1"
+description = "A lightweight library for converting complex datatypes to and from native Python datatypes."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "marshmallow-3.21.1-py3-none-any.whl", hash = "sha256:f085493f79efb0644f270a9bf2892843142d80d7174bbbd2f3713f2a589dc633"},
+ {file = "marshmallow-3.21.1.tar.gz", hash = "sha256:4e65e9e0d80fc9e609574b9983cf32579f305c718afb30d7233ab818571768c3"},
+]
+
+[package.dependencies]
+packaging = ">=17.0"
+
+[package.extras]
+dev = ["marshmallow[tests]", "pre-commit (>=3.5,<4.0)", "tox"]
+docs = ["alabaster (==0.7.16)", "autodocsumm (==0.2.12)", "sphinx (==7.2.6)", "sphinx-issues (==4.0.0)", "sphinx-version-warning (==1.1.2)"]
+tests = ["pytest", "pytz", "simplejson"]
+
+[[package]]
+name = "multidict"
+version = "6.0.5"
+description = "multidict implementation"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9"},
+ {file = "multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604"},
+ {file = "multidict-6.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600"},
+ {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c"},
+ {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5"},
+ {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f"},
+ {file = "multidict-6.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae"},
+ {file = "multidict-6.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182"},
+ {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf"},
+ {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442"},
+ {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a"},
+ {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef"},
+ {file = "multidict-6.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc"},
+ {file = "multidict-6.0.5-cp310-cp310-win32.whl", hash = "sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319"},
+ {file = "multidict-6.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8"},
+ {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba"},
+ {file = "multidict-6.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e"},
+ {file = "multidict-6.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd"},
+ {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3"},
+ {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf"},
+ {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29"},
+ {file = "multidict-6.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed"},
+ {file = "multidict-6.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733"},
+ {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f"},
+ {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4"},
+ {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1"},
+ {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc"},
+ {file = "multidict-6.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e"},
+ {file = "multidict-6.0.5-cp311-cp311-win32.whl", hash = "sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c"},
+ {file = "multidict-6.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea"},
+ {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e"},
+ {file = "multidict-6.0.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b"},
+ {file = "multidict-6.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5"},
+ {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450"},
+ {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496"},
+ {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a"},
+ {file = "multidict-6.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226"},
+ {file = "multidict-6.0.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271"},
+ {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb"},
+ {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef"},
+ {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24"},
+ {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6"},
+ {file = "multidict-6.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda"},
+ {file = "multidict-6.0.5-cp312-cp312-win32.whl", hash = "sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5"},
+ {file = "multidict-6.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556"},
+ {file = "multidict-6.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:19fe01cea168585ba0f678cad6f58133db2aa14eccaf22f88e4a6dccadfad8b3"},
+ {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf7a982604375a8d49b6cc1b781c1747f243d91b81035a9b43a2126c04766f5"},
+ {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:107c0cdefe028703fb5dafe640a409cb146d44a6ae201e55b35a4af8e95457dd"},
+ {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:403c0911cd5d5791605808b942c88a8155c2592e05332d2bf78f18697a5fa15e"},
+ {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aeaf541ddbad8311a87dd695ed9642401131ea39ad7bc8cf3ef3967fd093b626"},
+ {file = "multidict-6.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4972624066095e52b569e02b5ca97dbd7a7ddd4294bf4e7247d52635630dd83"},
+ {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d946b0a9eb8aaa590df1fe082cee553ceab173e6cb5b03239716338629c50c7a"},
+ {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b55358304d7a73d7bdf5de62494aaf70bd33015831ffd98bc498b433dfe5b10c"},
+ {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:a3145cb08d8625b2d3fee1b2d596a8766352979c9bffe5d7833e0503d0f0b5e5"},
+ {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d65f25da8e248202bd47445cec78e0025c0fe7582b23ec69c3b27a640dd7a8e3"},
+ {file = "multidict-6.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:c9bf56195c6bbd293340ea82eafd0071cb3d450c703d2c93afb89f93b8386ccc"},
+ {file = "multidict-6.0.5-cp37-cp37m-win32.whl", hash = "sha256:69db76c09796b313331bb7048229e3bee7928eb62bab5e071e9f7fcc4879caee"},
+ {file = "multidict-6.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:fce28b3c8a81b6b36dfac9feb1de115bab619b3c13905b419ec71d03a3fc1423"},
+ {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76f067f5121dcecf0d63a67f29080b26c43c71a98b10c701b0677e4a065fbd54"},
+ {file = "multidict-6.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b82cc8ace10ab5bd93235dfaab2021c70637005e1ac787031f4d1da63d493c1d"},
+ {file = "multidict-6.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5cb241881eefd96b46f89b1a056187ea8e9ba14ab88ba632e68d7a2ecb7aadf7"},
+ {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8e94e6912639a02ce173341ff62cc1201232ab86b8a8fcc05572741a5dc7d93"},
+ {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09a892e4a9fb47331da06948690ae38eaa2426de97b4ccbfafbdcbe5c8f37ff8"},
+ {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55205d03e8a598cfc688c71ca8ea5f66447164efff8869517f175ea632c7cb7b"},
+ {file = "multidict-6.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37b15024f864916b4951adb95d3a80c9431299080341ab9544ed148091b53f50"},
+ {file = "multidict-6.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2a1dee728b52b33eebff5072817176c172050d44d67befd681609b4746e1c2e"},
+ {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:edd08e6f2f1a390bf137080507e44ccc086353c8e98c657e666c017718561b89"},
+ {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:60d698e8179a42ec85172d12f50b1668254628425a6bd611aba022257cac1386"},
+ {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:3d25f19500588cbc47dc19081d78131c32637c25804df8414463ec908631e453"},
+ {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4cc0ef8b962ac7a5e62b9e826bd0cd5040e7d401bc45a6835910ed699037a461"},
+ {file = "multidict-6.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eca2e9d0cc5a889850e9bbd68e98314ada174ff6ccd1129500103df7a94a7a44"},
+ {file = "multidict-6.0.5-cp38-cp38-win32.whl", hash = "sha256:4a6a4f196f08c58c59e0b8ef8ec441d12aee4125a7d4f4fef000ccb22f8d7241"},
+ {file = "multidict-6.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:0275e35209c27a3f7951e1ce7aaf93ce0d163b28948444bec61dd7badc6d3f8c"},
+ {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e7be68734bd8c9a513f2b0cfd508802d6609da068f40dc57d4e3494cefc92929"},
+ {file = "multidict-6.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1d9ea7a7e779d7a3561aade7d596649fbecfa5c08a7674b11b423783217933f9"},
+ {file = "multidict-6.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ea1456df2a27c73ce51120fa2f519f1bea2f4a03a917f4a43c8707cf4cbbae1a"},
+ {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf590b134eb70629e350691ecca88eac3e3b8b3c86992042fb82e3cb1830d5e1"},
+ {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5c0631926c4f58e9a5ccce555ad7747d9a9f8b10619621f22f9635f069f6233e"},
+ {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dce1c6912ab9ff5f179eaf6efe7365c1f425ed690b03341911bf4939ef2f3046"},
+ {file = "multidict-6.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0868d64af83169e4d4152ec612637a543f7a336e4a307b119e98042e852ad9c"},
+ {file = "multidict-6.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141b43360bfd3bdd75f15ed811850763555a251e38b2405967f8e25fb43f7d40"},
+ {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7df704ca8cf4a073334e0427ae2345323613e4df18cc224f647f251e5e75a527"},
+ {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:6214c5a5571802c33f80e6c84713b2c79e024995b9c5897f794b43e714daeec9"},
+ {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd6c8fca38178e12c00418de737aef1261576bd1b6e8c6134d3e729a4e858b38"},
+ {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e02021f87a5b6932fa6ce916ca004c4d441509d33bbdbeca70d05dff5e9d2479"},
+ {file = "multidict-6.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ebd8d160f91a764652d3e51ce0d2956b38efe37c9231cd82cfc0bed2e40b581c"},
+ {file = "multidict-6.0.5-cp39-cp39-win32.whl", hash = "sha256:04da1bb8c8dbadf2a18a452639771951c662c5ad03aefe4884775454be322c9b"},
+ {file = "multidict-6.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:d6f6d4f185481c9669b9447bf9d9cf3b95a0e9df9d169bbc17e363b7d5487755"},
+ {file = "multidict-6.0.5-py3-none-any.whl", hash = "sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7"},
+ {file = "multidict-6.0.5.tar.gz", hash = "sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da"},
+]
+
[[package]]
name = "mypy"
version = "0.991"
@@ -436,6 +942,43 @@ files = [
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
]
+[[package]]
+name = "numpy"
+version = "1.24.4"
+description = "Fundamental package for array computing in Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "numpy-1.24.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c0bfb52d2169d58c1cdb8cc1f16989101639b34c7d3ce60ed70b19c63eba0b64"},
+ {file = "numpy-1.24.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ed094d4f0c177b1b8e7aa9cba7d6ceed51c0e569a5318ac0ca9a090680a6a1b1"},
+ {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79fc682a374c4a8ed08b331bef9c5f582585d1048fa6d80bc6c35bc384eee9b4"},
+ {file = "numpy-1.24.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ffe43c74893dbf38c2b0a1f5428760a1a9c98285553c89e12d70a96a7f3a4d6"},
+ {file = "numpy-1.24.4-cp310-cp310-win32.whl", hash = "sha256:4c21decb6ea94057331e111a5bed9a79d335658c27ce2adb580fb4d54f2ad9bc"},
+ {file = "numpy-1.24.4-cp310-cp310-win_amd64.whl", hash = "sha256:b4bea75e47d9586d31e892a7401f76e909712a0fd510f58f5337bea9572c571e"},
+ {file = "numpy-1.24.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f136bab9c2cfd8da131132c2cf6cc27331dd6fae65f95f69dcd4ae3c3639c810"},
+ {file = "numpy-1.24.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e2926dac25b313635e4d6cf4dc4e51c8c0ebfed60b801c799ffc4c32bf3d1254"},
+ {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:222e40d0e2548690405b0b3c7b21d1169117391c2e82c378467ef9ab4c8f0da7"},
+ {file = "numpy-1.24.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7215847ce88a85ce39baf9e89070cb860c98fdddacbaa6c0da3ffb31b3350bd5"},
+ {file = "numpy-1.24.4-cp311-cp311-win32.whl", hash = "sha256:4979217d7de511a8d57f4b4b5b2b965f707768440c17cb70fbf254c4b225238d"},
+ {file = "numpy-1.24.4-cp311-cp311-win_amd64.whl", hash = "sha256:b7b1fc9864d7d39e28f41d089bfd6353cb5f27ecd9905348c24187a768c79694"},
+ {file = "numpy-1.24.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1452241c290f3e2a312c137a9999cdbf63f78864d63c79039bda65ee86943f61"},
+ {file = "numpy-1.24.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:04640dab83f7c6c85abf9cd729c5b65f1ebd0ccf9de90b270cd61935eef0197f"},
+ {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5425b114831d1e77e4b5d812b69d11d962e104095a5b9c3b641a218abcc050e"},
+ {file = "numpy-1.24.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd80e219fd4c71fc3699fc1dadac5dcf4fd882bfc6f7ec53d30fa197b8ee22dc"},
+ {file = "numpy-1.24.4-cp38-cp38-win32.whl", hash = "sha256:4602244f345453db537be5314d3983dbf5834a9701b7723ec28923e2889e0bb2"},
+ {file = "numpy-1.24.4-cp38-cp38-win_amd64.whl", hash = "sha256:692f2e0f55794943c5bfff12b3f56f99af76f902fc47487bdfe97856de51a706"},
+ {file = "numpy-1.24.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2541312fbf09977f3b3ad449c4e5f4bb55d0dbf79226d7724211acc905049400"},
+ {file = "numpy-1.24.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9667575fb6d13c95f1b36aca12c5ee3356bf001b714fc354eb5465ce1609e62f"},
+ {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3a86ed21e4f87050382c7bc96571755193c4c1392490744ac73d660e8f564a9"},
+ {file = "numpy-1.24.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d11efb4dbecbdf22508d55e48d9c8384db795e1b7b51ea735289ff96613ff74d"},
+ {file = "numpy-1.24.4-cp39-cp39-win32.whl", hash = "sha256:6620c0acd41dbcb368610bb2f4d83145674040025e5536954782467100aa8835"},
+ {file = "numpy-1.24.4-cp39-cp39-win_amd64.whl", hash = "sha256:befe2bf740fd8373cf56149a5c23a0f601e82869598d41f8e188a0e9869926f8"},
+ {file = "numpy-1.24.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:31f13e25b4e304632a4619d0e0777662c2ffea99fcae2029556b17d8ff958aef"},
+ {file = "numpy-1.24.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95f7ac6540e95bc440ad77f56e520da5bf877f87dca58bd095288dce8940532a"},
+ {file = "numpy-1.24.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e98f220aa76ca2a977fe435f5b04d7b3470c0a2e6312907b37ba6068f26787f2"},
+ {file = "numpy-1.24.4.tar.gz", hash = "sha256:80f5e3a4e498641401868df4208b74581206afbee7cf7b8329daae82676d9463"},
+]
+
[[package]]
name = "orjson"
version = "3.9.15"
@@ -845,6 +1388,93 @@ files = [
{file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
]
+[[package]]
+name = "sqlalchemy"
+version = "2.0.29"
+description = "Database Abstraction Library"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "SQLAlchemy-2.0.29-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4c142852ae192e9fe5aad5c350ea6befe9db14370b34047e1f0f7cf99e63c63b"},
+ {file = "SQLAlchemy-2.0.29-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:99a1e69d4e26f71e750e9ad6fdc8614fbddb67cfe2173a3628a2566034e223c7"},
+ {file = "SQLAlchemy-2.0.29-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ef3fbccb4058355053c51b82fd3501a6e13dd808c8d8cd2561e610c5456013c"},
+ {file = "SQLAlchemy-2.0.29-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d6753305936eddc8ed190e006b7bb33a8f50b9854823485eed3a886857ab8d1"},
+ {file = "SQLAlchemy-2.0.29-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0f3ca96af060a5250a8ad5a63699180bc780c2edf8abf96c58af175921df847a"},
+ {file = "SQLAlchemy-2.0.29-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c4520047006b1d3f0d89e0532978c0688219857eb2fee7c48052560ae76aca1e"},
+ {file = "SQLAlchemy-2.0.29-cp310-cp310-win32.whl", hash = "sha256:b2a0e3cf0caac2085ff172c3faacd1e00c376e6884b5bc4dd5b6b84623e29e4f"},
+ {file = "SQLAlchemy-2.0.29-cp310-cp310-win_amd64.whl", hash = "sha256:01d10638a37460616708062a40c7b55f73e4d35eaa146781c683e0fa7f6c43fb"},
+ {file = "SQLAlchemy-2.0.29-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:308ef9cb41d099099fffc9d35781638986870b29f744382904bf9c7dadd08513"},
+ {file = "SQLAlchemy-2.0.29-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:296195df68326a48385e7a96e877bc19aa210e485fa381c5246bc0234c36c78e"},
+ {file = "SQLAlchemy-2.0.29-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a13b917b4ffe5a0a31b83d051d60477819ddf18276852ea68037a144a506efb9"},
+ {file = "SQLAlchemy-2.0.29-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f6d971255d9ddbd3189e2e79d743ff4845c07f0633adfd1de3f63d930dbe673"},
+ {file = "SQLAlchemy-2.0.29-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:61405ea2d563407d316c63a7b5271ae5d274a2a9fbcd01b0aa5503635699fa1e"},
+ {file = "SQLAlchemy-2.0.29-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:de7202ffe4d4a8c1e3cde1c03e01c1a3772c92858837e8f3879b497158e4cb44"},
+ {file = "SQLAlchemy-2.0.29-cp311-cp311-win32.whl", hash = "sha256:b5d7ed79df55a731749ce65ec20d666d82b185fa4898430b17cb90c892741520"},
+ {file = "SQLAlchemy-2.0.29-cp311-cp311-win_amd64.whl", hash = "sha256:205f5a2b39d7c380cbc3b5dcc8f2762fb5bcb716838e2d26ccbc54330775b003"},
+ {file = "SQLAlchemy-2.0.29-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d96710d834a6fb31e21381c6d7b76ec729bd08c75a25a5184b1089141356171f"},
+ {file = "SQLAlchemy-2.0.29-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:52de4736404e53c5c6a91ef2698c01e52333988ebdc218f14c833237a0804f1b"},
+ {file = "SQLAlchemy-2.0.29-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c7b02525ede2a164c5fa5014915ba3591730f2cc831f5be9ff3b7fd3e30958e"},
+ {file = "SQLAlchemy-2.0.29-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dfefdb3e54cd15f5d56fd5ae32f1da2d95d78319c1f6dfb9bcd0eb15d603d5d"},
+ {file = "SQLAlchemy-2.0.29-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a88913000da9205b13f6f195f0813b6ffd8a0c0c2bd58d499e00a30eb508870c"},
+ {file = "SQLAlchemy-2.0.29-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fecd5089c4be1bcc37c35e9aa678938d2888845a134dd016de457b942cf5a758"},
+ {file = "SQLAlchemy-2.0.29-cp312-cp312-win32.whl", hash = "sha256:8197d6f7a3d2b468861ebb4c9f998b9df9e358d6e1cf9c2a01061cb9b6cf4e41"},
+ {file = "SQLAlchemy-2.0.29-cp312-cp312-win_amd64.whl", hash = "sha256:9b19836ccca0d321e237560e475fd99c3d8655d03da80c845c4da20dda31b6e1"},
+ {file = "SQLAlchemy-2.0.29-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:87a1d53a5382cdbbf4b7619f107cc862c1b0a4feb29000922db72e5a66a5ffc0"},
+ {file = "SQLAlchemy-2.0.29-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a0732dffe32333211801b28339d2a0babc1971bc90a983e3035e7b0d6f06b93"},
+ {file = "SQLAlchemy-2.0.29-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90453597a753322d6aa770c5935887ab1fc49cc4c4fdd436901308383d698b4b"},
+ {file = "SQLAlchemy-2.0.29-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ea311d4ee9a8fa67f139c088ae9f905fcf0277d6cd75c310a21a88bf85e130f5"},
+ {file = "SQLAlchemy-2.0.29-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:5f20cb0a63a3e0ec4e169aa8890e32b949c8145983afa13a708bc4b0a1f30e03"},
+ {file = "SQLAlchemy-2.0.29-cp37-cp37m-win32.whl", hash = "sha256:e5bbe55e8552019c6463709b39634a5fc55e080d0827e2a3a11e18eb73f5cdbd"},
+ {file = "SQLAlchemy-2.0.29-cp37-cp37m-win_amd64.whl", hash = "sha256:c2f9c762a2735600654c654bf48dad388b888f8ce387b095806480e6e4ff6907"},
+ {file = "SQLAlchemy-2.0.29-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7e614d7a25a43a9f54fcce4675c12761b248547f3d41b195e8010ca7297c369c"},
+ {file = "SQLAlchemy-2.0.29-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:471fcb39c6adf37f820350c28aac4a7df9d3940c6548b624a642852e727ea586"},
+ {file = "SQLAlchemy-2.0.29-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:988569c8732f54ad3234cf9c561364221a9e943b78dc7a4aaf35ccc2265f1930"},
+ {file = "SQLAlchemy-2.0.29-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dddaae9b81c88083e6437de95c41e86823d150f4ee94bf24e158a4526cbead01"},
+ {file = "SQLAlchemy-2.0.29-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:334184d1ab8f4c87f9652b048af3f7abea1c809dfe526fb0435348a6fef3d380"},
+ {file = "SQLAlchemy-2.0.29-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:38b624e5cf02a69b113c8047cf7f66b5dfe4a2ca07ff8b8716da4f1b3ae81567"},
+ {file = "SQLAlchemy-2.0.29-cp38-cp38-win32.whl", hash = "sha256:bab41acf151cd68bc2b466deae5deeb9e8ae9c50ad113444151ad965d5bf685b"},
+ {file = "SQLAlchemy-2.0.29-cp38-cp38-win_amd64.whl", hash = "sha256:52c8011088305476691b8750c60e03b87910a123cfd9ad48576d6414b6ec2a1d"},
+ {file = "SQLAlchemy-2.0.29-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3071ad498896907a5ef756206b9dc750f8e57352113c19272bdfdc429c7bd7de"},
+ {file = "SQLAlchemy-2.0.29-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dba622396a3170974f81bad49aacebd243455ec3cc70615aeaef9e9613b5bca5"},
+ {file = "SQLAlchemy-2.0.29-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b184e3de58009cc0bf32e20f137f1ec75a32470f5fede06c58f6c355ed42a72"},
+ {file = "SQLAlchemy-2.0.29-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c37f1050feb91f3d6c32f864d8e114ff5545a4a7afe56778d76a9aec62638ba"},
+ {file = "SQLAlchemy-2.0.29-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bda7ce59b06d0f09afe22c56714c65c957b1068dee3d5e74d743edec7daba552"},
+ {file = "SQLAlchemy-2.0.29-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:25664e18bef6dc45015b08f99c63952a53a0a61f61f2e48a9e70cec27e55f699"},
+ {file = "SQLAlchemy-2.0.29-cp39-cp39-win32.whl", hash = "sha256:77d29cb6c34b14af8a484e831ab530c0f7188f8efed1c6a833a2c674bf3c26ec"},
+ {file = "SQLAlchemy-2.0.29-cp39-cp39-win_amd64.whl", hash = "sha256:04c487305ab035a9548f573763915189fc0fe0824d9ba28433196f8436f1449c"},
+ {file = "SQLAlchemy-2.0.29-py3-none-any.whl", hash = "sha256:dc4ee2d4ee43251905f88637d5281a8d52e916a021384ec10758826f5cbae305"},
+ {file = "SQLAlchemy-2.0.29.tar.gz", hash = "sha256:bd9566b8e58cabd700bc367b60e90d9349cd16f0984973f98a9a09f9c64e86f0"},
+]
+
+[package.dependencies]
+greenlet = {version = "!=0.4.17", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""}
+typing-extensions = ">=4.6.0"
+
+[package.extras]
+aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"]
+aioodbc = ["aioodbc", "greenlet (!=0.4.17)"]
+aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"]
+asyncio = ["greenlet (!=0.4.17)"]
+asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (!=0.4.17)"]
+mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5)"]
+mssql = ["pyodbc"]
+mssql-pymssql = ["pymssql"]
+mssql-pyodbc = ["pyodbc"]
+mypy = ["mypy (>=0.910)"]
+mysql = ["mysqlclient (>=1.4.0)"]
+mysql-connector = ["mysql-connector-python"]
+oracle = ["cx_oracle (>=8)"]
+oracle-oracledb = ["oracledb (>=1.0.1)"]
+postgresql = ["psycopg2 (>=2.7)"]
+postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"]
+postgresql-pg8000 = ["pg8000 (>=1.29.1)"]
+postgresql-psycopg = ["psycopg (>=3.0.7)"]
+postgresql-psycopg2binary = ["psycopg2-binary"]
+postgresql-psycopg2cffi = ["psycopg2cffi"]
+postgresql-psycopgbinary = ["psycopg[binary] (>=3.0.7)"]
+pymysql = ["pymysql"]
+sqlcipher = ["sqlcipher3_binary"]
+
[[package]]
name = "syrupy"
version = "4.6.1"
@@ -895,6 +1525,21 @@ files = [
{file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"},
]
+[[package]]
+name = "typing-inspect"
+version = "0.9.0"
+description = "Runtime inspection utilities for typing module."
+optional = false
+python-versions = "*"
+files = [
+ {file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"},
+ {file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"},
+]
+
+[package.dependencies]
+mypy-extensions = ">=0.3.0"
+typing-extensions = ">=3.7.4"
+
[[package]]
name = "urllib3"
version = "2.2.1"
@@ -953,7 +1598,110 @@ files = [
[package.extras]
watchmedo = ["PyYAML (>=3.10)"]
+[[package]]
+name = "yarl"
+version = "1.9.4"
+description = "Yet another URL library"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e"},
+ {file = "yarl-1.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2"},
+ {file = "yarl-1.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66"},
+ {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234"},
+ {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392"},
+ {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551"},
+ {file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455"},
+ {file = "yarl-1.9.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c"},
+ {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53"},
+ {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385"},
+ {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863"},
+ {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b"},
+ {file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541"},
+ {file = "yarl-1.9.4-cp310-cp310-win32.whl", hash = "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d"},
+ {file = "yarl-1.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b"},
+ {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099"},
+ {file = "yarl-1.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c"},
+ {file = "yarl-1.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0"},
+ {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525"},
+ {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8"},
+ {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9"},
+ {file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42"},
+ {file = "yarl-1.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe"},
+ {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce"},
+ {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9"},
+ {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572"},
+ {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958"},
+ {file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98"},
+ {file = "yarl-1.9.4-cp311-cp311-win32.whl", hash = "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31"},
+ {file = "yarl-1.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1"},
+ {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81"},
+ {file = "yarl-1.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142"},
+ {file = "yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074"},
+ {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129"},
+ {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2"},
+ {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78"},
+ {file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4"},
+ {file = "yarl-1.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0"},
+ {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51"},
+ {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff"},
+ {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7"},
+ {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc"},
+ {file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10"},
+ {file = "yarl-1.9.4-cp312-cp312-win32.whl", hash = "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7"},
+ {file = "yarl-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984"},
+ {file = "yarl-1.9.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63b20738b5aac74e239622d2fe30df4fca4942a86e31bf47a81a0e94c14df94f"},
+ {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d7f7de27b8944f1fee2c26a88b4dabc2409d2fea7a9ed3df79b67277644e17"},
+ {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c74018551e31269d56fab81a728f683667e7c28c04e807ba08f8c9e3bba32f14"},
+ {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca06675212f94e7a610e85ca36948bb8fc023e458dd6c63ef71abfd482481aa5"},
+ {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aef935237d60a51a62b86249839b51345f47564208c6ee615ed2a40878dccdd"},
+ {file = "yarl-1.9.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b134fd795e2322b7684155b7855cc99409d10b2e408056db2b93b51a52accc7"},
+ {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d25039a474c4c72a5ad4b52495056f843a7ff07b632c1b92ea9043a3d9950f6e"},
+ {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f7d6b36dd2e029b6bcb8a13cf19664c7b8e19ab3a58e0fefbb5b8461447ed5ec"},
+ {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:957b4774373cf6f709359e5c8c4a0af9f6d7875db657adb0feaf8d6cb3c3964c"},
+ {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d7eeb6d22331e2fd42fce928a81c697c9ee2d51400bd1a28803965883e13cead"},
+ {file = "yarl-1.9.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6a962e04b8f91f8c4e5917e518d17958e3bdee71fd1d8b88cdce74dd0ebbf434"},
+ {file = "yarl-1.9.4-cp37-cp37m-win32.whl", hash = "sha256:f3bc6af6e2b8f92eced34ef6a96ffb248e863af20ef4fde9448cc8c9b858b749"},
+ {file = "yarl-1.9.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4d7a90a92e528aadf4965d685c17dacff3df282db1121136c382dc0b6014d2"},
+ {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ec61d826d80fc293ed46c9dd26995921e3a82146feacd952ef0757236fc137be"},
+ {file = "yarl-1.9.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8be9e837ea9113676e5754b43b940b50cce76d9ed7d2461df1af39a8ee674d9f"},
+ {file = "yarl-1.9.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bef596fdaa8f26e3d66af846bbe77057237cb6e8efff8cd7cc8dff9a62278bbf"},
+ {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d47552b6e52c3319fede1b60b3de120fe83bde9b7bddad11a69fb0af7db32f1"},
+ {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fc30f71689d7fc9168b92788abc977dc8cefa806909565fc2951d02f6b7d57"},
+ {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4aa9741085f635934f3a2583e16fcf62ba835719a8b2b28fb2917bb0537c1dfa"},
+ {file = "yarl-1.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:206a55215e6d05dbc6c98ce598a59e6fbd0c493e2de4ea6cc2f4934d5a18d130"},
+ {file = "yarl-1.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07574b007ee20e5c375a8fe4a0789fad26db905f9813be0f9fef5a68080de559"},
+ {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5a2e2433eb9344a163aced6a5f6c9222c0786e5a9e9cac2c89f0b28433f56e23"},
+ {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6ad6d10ed9b67a382b45f29ea028f92d25bc0bc1daf6c5b801b90b5aa70fb9ec"},
+ {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:6fe79f998a4052d79e1c30eeb7d6c1c1056ad33300f682465e1b4e9b5a188b78"},
+ {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a825ec844298c791fd28ed14ed1bffc56a98d15b8c58a20e0e08c1f5f2bea1be"},
+ {file = "yarl-1.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8619d6915b3b0b34420cf9b2bb6d81ef59d984cb0fde7544e9ece32b4b3043c3"},
+ {file = "yarl-1.9.4-cp38-cp38-win32.whl", hash = "sha256:686a0c2f85f83463272ddffd4deb5e591c98aac1897d65e92319f729c320eece"},
+ {file = "yarl-1.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:a00862fb23195b6b8322f7d781b0dc1d82cb3bcac346d1e38689370cc1cc398b"},
+ {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:604f31d97fa493083ea21bd9b92c419012531c4e17ea6da0f65cacdcf5d0bd27"},
+ {file = "yarl-1.9.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8a854227cf581330ffa2c4824d96e52ee621dd571078a252c25e3a3b3d94a1b1"},
+ {file = "yarl-1.9.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ba6f52cbc7809cd8d74604cce9c14868306ae4aa0282016b641c661f981a6e91"},
+ {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a6327976c7c2f4ee6816eff196e25385ccc02cb81427952414a64811037bbc8b"},
+ {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8397a3817d7dcdd14bb266283cd1d6fc7264a48c186b986f32e86d86d35fbac5"},
+ {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0381b4ce23ff92f8170080c97678040fc5b08da85e9e292292aba67fdac6c34"},
+ {file = "yarl-1.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:23d32a2594cb5d565d358a92e151315d1b2268bc10f4610d098f96b147370136"},
+ {file = "yarl-1.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ddb2a5c08a4eaaba605340fdee8fc08e406c56617566d9643ad8bf6852778fc7"},
+ {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:26a1dc6285e03f3cc9e839a2da83bcbf31dcb0d004c72d0730e755b33466c30e"},
+ {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:18580f672e44ce1238b82f7fb87d727c4a131f3a9d33a5e0e82b793362bf18b4"},
+ {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:29e0f83f37610f173eb7e7b5562dd71467993495e568e708d99e9d1944f561ec"},
+ {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:1f23e4fe1e8794f74b6027d7cf19dc25f8b63af1483d91d595d4a07eca1fb26c"},
+ {file = "yarl-1.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:db8e58b9d79200c76956cefd14d5c90af54416ff5353c5bfd7cbe58818e26ef0"},
+ {file = "yarl-1.9.4-cp39-cp39-win32.whl", hash = "sha256:c7224cab95645c7ab53791022ae77a4509472613e839dab722a72abe5a684575"},
+ {file = "yarl-1.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:824d6c50492add5da9374875ce72db7a0733b29c2394890aef23d533106e2b15"},
+ {file = "yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad"},
+ {file = "yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf"},
+]
+
+[package.dependencies]
+idna = ">=2.0"
+multidict = ">=4.0"
+
[metadata]
lock-version = "2.0"
python-versions = ">=3.8.1,<4.0"
-content-hash = "6a5887a0391a649e1a45f3e3c766a880e133367d2656a9b5a37d75ebc33adef6"
+content-hash = "7546180410ed197e1c2aa9830e32e3a40ebcd930a86a9e3398cd8fe6123b6888"
diff --git a/libs/partners/cohere/pyproject.toml b/libs/partners/cohere/pyproject.toml
index 45a52d381f..e37861ad72 100644
--- a/libs/partners/cohere/pyproject.toml
+++ b/libs/partners/cohere/pyproject.toml
@@ -26,6 +26,8 @@ syrupy = "^4.0.2"
pytest-watcher = "^0.3.4"
pytest-asyncio = "^0.21.1"
langchain-core = { path = "../../core", develop = true }
+langchain-community = {path = "../../community", develop = true}
+langchain = {path = "../../langchain", develop = true}
[tool.poetry.group.codespell]
optional = true
diff --git a/libs/partners/cohere/tests/integration_tests/react_multi_hop/__init__.py b/libs/partners/cohere/tests/integration_tests/react_multi_hop/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/libs/partners/cohere/tests/integration_tests/react_multi_hop/test_cohere_react_agent.py b/libs/partners/cohere/tests/integration_tests/react_multi_hop/test_cohere_react_agent.py
new file mode 100644
index 0000000000..4e23395409
--- /dev/null
+++ b/libs/partners/cohere/tests/integration_tests/react_multi_hop/test_cohere_react_agent.py
@@ -0,0 +1,43 @@
+"""
+Tests the agent created by langchain_cohere.create_cohere_react_agent
+
+You will need to set:
+* COHERE_API_KEY
+* TAVILY_API_KEY
+"""
+
+from langchain.agents import AgentExecutor
+from langchain_community.tools.tavily_search import TavilySearchResults
+from langchain_core.prompts import ChatPromptTemplate
+
+from langchain_cohere import ChatCohere, create_cohere_react_agent
+
+
+def test_invoke_multihop_agent() -> None:
+ llm = ChatCohere(temperature=0.0)
+
+ internet_search = TavilySearchResults(max_results=4)
+ internet_search.name = "internet_search"
+ internet_search.description = "Route a user query to the internet"
+
+ prompt = ChatPromptTemplate.from_template("{input}")
+
+ agent = create_cohere_react_agent(llm, [internet_search], prompt)
+
+ agent_executor = AgentExecutor(agent=agent, tools=[internet_search])
+
+ actual = agent_executor.invoke(
+ {
+ "input": "In what year was the company that was founded as Sound of Music added to the S&P 500?", # noqa: E501
+ }
+ )
+
+ accepted_outputs = [
+ "Best Buy, the company founded as Sound of Music, was added to the S&P 500 in 1999.", # noqa: E501
+ "Best Buy, originally called Sound of Music, was added to Standard & Poor's S&P 500 in 1999.", # noqa: E501
+ "Best Buy, the company founded as Sound of Music, was added to the S&P 500 in 1999. The company was renamed Best Buy in 1983, when it became Best Buy Company, Inc.", # noqa: E501
+ "Sorry, I could not find any information about the company founded as Sound of Music being added to the S&P 500. However, I did find that Best Buy, the company founded as Sound of Music in 1966, was added to the S&P index in 1985, two years after its debut on the New York Stock Exchange.", # noqa: E501
+ ]
+
+ assert "output" in actual
+ assert actual["output"] in accepted_outputs
diff --git a/libs/partners/cohere/tests/integration_tests/test_chat_models.py b/libs/partners/cohere/tests/integration_tests/test_chat_models.py
index a94c9e627d..b76c302d12 100644
--- a/libs/partners/cohere/tests/integration_tests/test_chat_models.py
+++ b/libs/partners/cohere/tests/integration_tests/test_chat_models.py
@@ -5,7 +5,7 @@ from typing import Any
import pytest
from langchain_core.messages import AIMessage, AIMessageChunk
-from langchain_core.pydantic_v1 import BaseModel
+from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_cohere import ChatCohere
@@ -75,8 +75,8 @@ def test_invoke_tool_calls() -> None:
llm = ChatCohere(temperature=0)
class Person(BaseModel):
- name: str
- age: int
+ name: str = Field(type=str, description="The name of the person")
+ age: int = Field(type=int, description="The age of the person")
tool_llm = llm.bind_tools([Person])
diff --git a/libs/partners/cohere/tests/unit_tests/react_multi_hop/__init__.py b/libs/partners/cohere/tests/unit_tests/react_multi_hop/__init__.py
new file mode 100644
index 0000000000..4921c3c480
--- /dev/null
+++ b/libs/partners/cohere/tests/unit_tests/react_multi_hop/__init__.py
@@ -0,0 +1,27 @@
+import os
+from enum import Enum
+
+DATA_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data")
+
+
+class ExpectationType(str, Enum):
+ prompts = "prompts"
+ completions = "completions"
+
+
+def read_expectation_from_file(
+ expectation_type: ExpectationType, scenario_name: str
+) -> str:
+ """
+ Returns an expected prompt or completion from a given scenario name.
+ Expectations are stored as .txt files make it as easy as possible to read.
+ """
+ with open(
+ os.path.join(DATA_DIR, expectation_type.value, f"{scenario_name}.txt"), "r"
+ ) as f:
+ content = f.read()
+
+ # Remove a single trailing new line, if present, to aid authoring the txt file.
+ if content.endswith("\n"):
+ content = content[: -len("\n")]
+ return content
diff --git a/libs/partners/cohere/tests/unit_tests/react_multi_hop/agent/__init__.py b/libs/partners/cohere/tests/unit_tests/react_multi_hop/agent/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/completions/action_only_abnormal.txt b/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/completions/action_only_abnormal.txt
new file mode 100644
index 0000000000..e152f867ab
--- /dev/null
+++ b/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/completions/action_only_abnormal.txt
@@ -0,0 +1,11 @@
+Action: ```json
+[
+ {
+ "tool_name": "tool1",
+ "parameters": {
+ "arg1": "value1",
+ "arg2": 2
+ }
+ }
+]
+```
diff --git a/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/completions/answer_sound_of_music.txt b/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/completions/answer_sound_of_music.txt
new file mode 100644
index 0000000000..690918a4b8
--- /dev/null
+++ b/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/completions/answer_sound_of_music.txt
@@ -0,0 +1,4 @@
+Relevant Documents: 0,2,3
+Cited Documents: 0,2
+Answer: Best Buy, originally called Sound of Music, was added to Standard & Poor's S&P 500 in 1999.
+Grounded answer: Best Buy, originally called Sound of Music, was added to Standard & Poor's S&P 500 in 1999.
diff --git a/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/completions/not_a_plan_reflection_or_action.txt b/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/completions/not_a_plan_reflection_or_action.txt
new file mode 100644
index 0000000000..bc56c4d894
--- /dev/null
+++ b/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/completions/not_a_plan_reflection_or_action.txt
@@ -0,0 +1 @@
+Foo
diff --git a/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/completions/plan_with_action_normal.txt b/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/completions/plan_with_action_normal.txt
new file mode 100644
index 0000000000..3942da4b79
--- /dev/null
+++ b/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/completions/plan_with_action_normal.txt
@@ -0,0 +1,20 @@
+Plan: Do a thing.
+And then do another thing.
+Action: ```json
+[
+ {
+ "tool_name": "tool1",
+ "parameters": {
+ "arg1": "value1",
+ "arg2": 2
+ }
+ },
+ {
+ "tool_name": "tool2",
+ "parameters": {
+ "arg3": "value3",
+ "arg4": true
+ }
+ }
+]
+```
diff --git a/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/completions/reflection_with_action_normal.txt b/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/completions/reflection_with_action_normal.txt
new file mode 100644
index 0000000000..ed8f28a6ba
--- /dev/null
+++ b/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/completions/reflection_with_action_normal.txt
@@ -0,0 +1,13 @@
+Reflection: I found out a thing.
+And then do another thing.
+Action: ```json
+[
+ {
+ "tool_name": "tool1",
+ "parameters": {
+ "arg1": "value1",
+ "arg2": 2
+ }
+ }
+]
+```
diff --git a/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/prompts/base.txt b/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/prompts/base.txt
new file mode 100644
index 0000000000..036be01f5c
--- /dev/null
+++ b/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/prompts/base.txt
@@ -0,0 +1,43 @@
+<|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|># Safety Preamble
+The instructions in this section override those in the task description and style guide sections. Don't answer questions that are harmful or immoral
+
+# System Preamble
+## Basic Rules
+You are a powerful language agent trained by Cohere to help people. You are capable of complex reasoning and augmented with a number of tools. Your job is to plan and reason about how you will use and consume the output of these tools to best help the user. You will see a conversation history between yourself and a user, ending with an utterance from the user. You will then see an instruction informing you what kind of response to generate. You will construct a plan and then perform a number of reasoning and action steps to solve the problem. When you have determined the answer to the user's request, you will cite your sources in your answers, according the instructions
+
+# User Preamble
+## Task And Context
+You use your advanced complex reasoning capabilities to help people by answering their questions and other requests interactively. You will be asked a very wide array of requests on all kinds of topics. You will be equipped with a wide range of search engines or similar tools to help you, which you use to research your answer. You may need to use multiple tools in parallel or sequentially to complete your task. You should focus on serving the user's needs as best you can, which will be wide-ranging. The current date is Saturday, March 30, 2024 13:20:40
+
+## Style Guide
+Unless the user asks for a different style of answer, you should answer in full sentences, using proper grammar and spelling
+
+## Available Tools
+Here is a list of tools that you have available to you:
+
+```python
+def directly_answer() -> List[Dict]:
+ """Calls a standard (un-augmented) AI chatbot to generate a response given the conversation history
+ """
+ pass
+```
+
+```python
+def internet_search(query: str) -> List[Dict]:
+ """Returns a list of relevant document snippets for a textual query retrieved from the internet
+
+ Args:
+ query (str): Query to search the internet with
+ """
+ pass
+```<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|USER_TOKEN|>In what year was the company that was founded as Sound of Music added to the S&P 500?<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|>Carefully perform the following instructions, in order, starting each with a new line.
+Firstly, You may need to use complex and advanced reasoning to complete your task and answer the question. Think about how you can use the provided tools to answer the question and come up with a high level plan you will execute.
+Write 'Plan:' followed by an initial high level plan of how you will solve the problem including the tools and steps required.
+Secondly, Carry out your plan by repeatedly using actions, reasoning over the results, and re-evaluating your plan. Perform Action, Observation, Reflection steps with the following format. Write 'Action:' followed by a json formatted action containing the "tool_name" and "parameters"
+ Next you will analyze the 'Observation:', this is the result of the action.
+After that you should always think about what to do next. Write 'Reflection:' followed by what you've figured out so far, any changes you need to make to your plan, and what you will do next including if you know the answer to the question.
+... (this Action/Observation/Reflection can repeat N times)
+Thirdly, Decide which of the retrieved documents are relevant to the user's last input by writing 'Relevant Documents:' followed by comma-separated list of document numbers. If none are relevant, you should instead write 'None'.
+Fourthly, Decide which of the retrieved documents contain facts that should be cited in a good answer to the user's last input by writing 'Cited Documents:' followed a comma-separated list of document numbers. If you dont want to cite any of them, you should instead write 'None'.
+Fifthly, Write 'Answer:' followed by a response to the user's last input in high quality natural english. Use the retrieved documents to help you. Do not insert any citations or grounding markup.
+Finally, Write 'Grounded answer:' followed by a response to the user's last input in high quality natural english. Use the symbols and to indicate when a fact comes from a document in the search result, e.g my fact for a fact from document 4.<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>
diff --git a/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/prompts/base_after_one_hop.txt b/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/prompts/base_after_one_hop.txt
new file mode 100644
index 0000000000..71b8b3073b
--- /dev/null
+++ b/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/prompts/base_after_one_hop.txt
@@ -0,0 +1,65 @@
+<|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|># Safety Preamble
+The instructions in this section override those in the task description and style guide sections. Don't answer questions that are harmful or immoral
+
+# System Preamble
+## Basic Rules
+You are a powerful language agent trained by Cohere to help people. You are capable of complex reasoning and augmented with a number of tools. Your job is to plan and reason about how you will use and consume the output of these tools to best help the user. You will see a conversation history between yourself and a user, ending with an utterance from the user. You will then see an instruction informing you what kind of response to generate. You will construct a plan and then perform a number of reasoning and action steps to solve the problem. When you have determined the answer to the user's request, you will cite your sources in your answers, according the instructions
+
+# User Preamble
+## Task And Context
+You use your advanced complex reasoning capabilities to help people by answering their questions and other requests interactively. You will be asked a very wide array of requests on all kinds of topics. You will be equipped with a wide range of search engines or similar tools to help you, which you use to research your answer. You may need to use multiple tools in parallel or sequentially to complete your task. You should focus on serving the user's needs as best you can, which will be wide-ranging. The current date is Saturday, March 30, 2024 13:20:40
+
+## Style Guide
+Unless the user asks for a different style of answer, you should answer in full sentences, using proper grammar and spelling
+
+## Available Tools
+Here is a list of tools that you have available to you:
+
+```python
+def directly_answer() -> List[Dict]:
+ """Calls a standard (un-augmented) AI chatbot to generate a response given the conversation history
+ """
+ pass
+```
+
+```python
+def internet_search(query: str) -> List[Dict]:
+ """Returns a list of relevant document snippets for a textual query retrieved from the internet
+
+ Args:
+ query (str): Query to search the internet with
+ """
+ pass
+```<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|USER_TOKEN|>In what year was the company that was founded as Sound of Music added to the S&P 500?<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|>Carefully perform the following instructions, in order, starting each with a new line.
+Firstly, You may need to use complex and advanced reasoning to complete your task and answer the question. Think about how you can use the provided tools to answer the question and come up with a high level plan you will execute.
+Write 'Plan:' followed by an initial high level plan of how you will solve the problem including the tools and steps required.
+Secondly, Carry out your plan by repeatedly using actions, reasoning over the results, and re-evaluating your plan. Perform Action, Observation, Reflection steps with the following format. Write 'Action:' followed by a json formatted action containing the "tool_name" and "parameters"
+ Next you will analyze the 'Observation:', this is the result of the action.
+After that you should always think about what to do next. Write 'Reflection:' followed by what you've figured out so far, any changes you need to make to your plan, and what you will do next including if you know the answer to the question.
+... (this Action/Observation/Reflection can repeat N times)
+Thirdly, Decide which of the retrieved documents are relevant to the user's last input by writing 'Relevant Documents:' followed by comma-separated list of document numbers. If none are relevant, you should instead write 'None'.
+Fourthly, Decide which of the retrieved documents contain facts that should be cited in a good answer to the user's last input by writing 'Cited Documents:' followed a comma-separated list of document numbers. If you dont want to cite any of them, you should instead write 'None'.
+Fifthly, Write 'Answer:' followed by a response to the user's last input in high quality natural english. Use the retrieved documents to help you. Do not insert any citations or grounding markup.
+Finally, Write 'Grounded answer:' followed by a response to the user's last input in high quality natural english. Use the symbols and to indicate when a fact comes from a document in the search result, e.g my fact for a fact from document 4.<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>Plan: First, I need to find out which company was originally called Sound of Music, then I need to find out when it was added to the S&P 500.
+Action: ```json
+[
+ {
+ "tool_name": "internet_search",
+ "parameters": {
+ "query": "which company was originally called sound of music"
+ }
+ }
+]
+```<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|>
+Document: 0
+URL: https://www.cnbc.com/2015/05/26/19-famous-companies-that-originally-had-different-names.html
+Title: 19 famous companies that originally had different names
+Text: Sound of Music made more money during this "best buy" four-day sale than it did in a typical month – thus, the store was renamed to Best Buy in 1983.
+4. Apple Computers » Apple, Inc.
+Founded in 1976, the tech giant we know today as Apple was originally named Apple Computers by founders Steve Jobs, Ronald Wayne and Steve Wozniak. In 2007, Jobs announced that the company was dropping the word "Computer" from its name to better reflect their move into a wider field of consumer electronics. "The Mac, iPod, Apple TV and iPhone. Only one of those is a computer.
+
+Document: 1
+URL: https://en.wikipedia.org/wiki/The_Sound_of_Music_(film)
+Title: The Sound of Music (film) - Wikipedia
+Text: In 1966, American Express created the first Sound of Music guided tour in Salzburg. Since 1972, Panorama Tours has been the leading Sound of Music bus tour company in the city, taking approximately 50,000 tourists a year to various film locations in Salzburg and the surrounding region. Although the Salzburg tourism industry took advantage of the attention from foreign tourists, residents of the city were apathetic about "everything that is dubious about tourism." The guides on the bus tour "seem to have little idea of what really happened on the set." Even the ticket agent for the Sound of Music Dinner Show tried to dissuade Austrians from attending a performance that was intended for American tourists, saying that it "does not have anything to do with the real Austria."
+<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>
diff --git a/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/prompts/base_after_two_hops.txt b/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/prompts/base_after_two_hops.txt
new file mode 100644
index 0000000000..46588f92e2
--- /dev/null
+++ b/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/prompts/base_after_two_hops.txt
@@ -0,0 +1,90 @@
+<|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|># Safety Preamble
+The instructions in this section override those in the task description and style guide sections. Don't answer questions that are harmful or immoral
+
+# System Preamble
+## Basic Rules
+You are a powerful language agent trained by Cohere to help people. You are capable of complex reasoning and augmented with a number of tools. Your job is to plan and reason about how you will use and consume the output of these tools to best help the user. You will see a conversation history between yourself and a user, ending with an utterance from the user. You will then see an instruction informing you what kind of response to generate. You will construct a plan and then perform a number of reasoning and action steps to solve the problem. When you have determined the answer to the user's request, you will cite your sources in your answers, according the instructions
+
+# User Preamble
+## Task And Context
+You use your advanced complex reasoning capabilities to help people by answering their questions and other requests interactively. You will be asked a very wide array of requests on all kinds of topics. You will be equipped with a wide range of search engines or similar tools to help you, which you use to research your answer. You may need to use multiple tools in parallel or sequentially to complete your task. You should focus on serving the user's needs as best you can, which will be wide-ranging. The current date is Saturday, March 30, 2024 13:20:40
+
+## Style Guide
+Unless the user asks for a different style of answer, you should answer in full sentences, using proper grammar and spelling
+
+## Available Tools
+Here is a list of tools that you have available to you:
+
+```python
+def directly_answer() -> List[Dict]:
+ """Calls a standard (un-augmented) AI chatbot to generate a response given the conversation history
+ """
+ pass
+```
+
+```python
+def internet_search(query: str) -> List[Dict]:
+ """Returns a list of relevant document snippets for a textual query retrieved from the internet
+
+ Args:
+ query (str): Query to search the internet with
+ """
+ pass
+```<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|USER_TOKEN|>In what year was the company that was founded as Sound of Music added to the S&P 500?<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|>Carefully perform the following instructions, in order, starting each with a new line.
+Firstly, You may need to use complex and advanced reasoning to complete your task and answer the question. Think about how you can use the provided tools to answer the question and come up with a high level plan you will execute.
+Write 'Plan:' followed by an initial high level plan of how you will solve the problem including the tools and steps required.
+Secondly, Carry out your plan by repeatedly using actions, reasoning over the results, and re-evaluating your plan. Perform Action, Observation, Reflection steps with the following format. Write 'Action:' followed by a json formatted action containing the "tool_name" and "parameters"
+ Next you will analyze the 'Observation:', this is the result of the action.
+After that you should always think about what to do next. Write 'Reflection:' followed by what you've figured out so far, any changes you need to make to your plan, and what you will do next including if you know the answer to the question.
+... (this Action/Observation/Reflection can repeat N times)
+Thirdly, Decide which of the retrieved documents are relevant to the user's last input by writing 'Relevant Documents:' followed by comma-separated list of document numbers. If none are relevant, you should instead write 'None'.
+Fourthly, Decide which of the retrieved documents contain facts that should be cited in a good answer to the user's last input by writing 'Cited Documents:' followed a comma-separated list of document numbers. If you dont want to cite any of them, you should instead write 'None'.
+Fifthly, Write 'Answer:' followed by a response to the user's last input in high quality natural english. Use the retrieved documents to help you. Do not insert any citations or grounding markup.
+Finally, Write 'Grounded answer:' followed by a response to the user's last input in high quality natural english. Use the symbols and to indicate when a fact comes from a document in the search result, e.g my fact for a fact from document 4.<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>Plan: First, I need to find out which company was originally called Sound of Music, then I need to find out when it was added to the S&P 500.
+Action: ```json
+[
+ {
+ "tool_name": "internet_search",
+ "parameters": {
+ "query": "which company was originally called sound of music"
+ }
+ }
+]
+```<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|>
+Document: 0
+URL: https://www.cnbc.com/2015/05/26/19-famous-companies-that-originally-had-different-names.html
+Title: 19 famous companies that originally had different names
+Text: Sound of Music made more money during this "best buy" four-day sale than it did in a typical month – thus, the store was renamed to Best Buy in 1983.
+4. Apple Computers » Apple, Inc.
+Founded in 1976, the tech giant we know today as Apple was originally named Apple Computers by founders Steve Jobs, Ronald Wayne and Steve Wozniak. In 2007, Jobs announced that the company was dropping the word "Computer" from its name to better reflect their move into a wider field of consumer electronics. "The Mac, iPod, Apple TV and iPhone. Only one of those is a computer.
+
+Document: 1
+URL: https://en.wikipedia.org/wiki/The_Sound_of_Music_(film)
+Title: The Sound of Music (film) - Wikipedia
+Text: In 1966, American Express created the first Sound of Music guided tour in Salzburg. Since 1972, Panorama Tours has been the leading Sound of Music bus tour company in the city, taking approximately 50,000 tourists a year to various film locations in Salzburg and the surrounding region. Although the Salzburg tourism industry took advantage of the attention from foreign tourists, residents of the city were apathetic about "everything that is dubious about tourism." The guides on the bus tour "seem to have little idea of what really happened on the set." Even the ticket agent for the Sound of Music Dinner Show tried to dissuade Austrians from attending a performance that was intended for American tourists, saying that it "does not have anything to do with the real Austria."
+<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>Reflection: I found out that Sound of Music was renamed Best Buy in 1983, now I need to find out when Best Buy was added to the S&P 500.
+Action: ```json
+[
+ {
+ "tool_name": "internet_search",
+ "parameters": {
+ "query": "when was best buy added to S&P 500"
+ }
+ }
+]
+```<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|>
+Document: 2
+URL: https://en.wikipedia.org/wiki/Best_Buy
+Title: Best Buy - Wikipedia
+Text: Concept IV stores included an open layout with products organized by category, cash registers located throughout the store, and slightly smaller stores than Concept III stores. The stores also had large areas for demonstrating home theater systems and computer software.
+In 1999, Best Buy was added to Standard & Poor's S&P 500.
+2000s
+In 2000, Best Buy formed Redline Entertainment, an independent music label and action-sports video distributor. The company acquired Magnolia Hi-Fi, Inc., an audio-video retailer located in California, Washington, and Oregon, in December 2000.
+In January 2001, Best Buy acquired Musicland Stores Corporation, a Minnetonka, Minnesota-based retailer that sold home-entertainment products under the Sam Goody, Suncoast Motion Picture Company, Media Play, and OnCue brands.
+
+Document: 3
+URL: https://en.wikipedia.org/wiki/Best_Buy
+Title: Best Buy - Wikipedia
+Text: Later that year, Best Buy opened its first superstore in Burnsville, Minnesota. The Burnsville location featured a high-volume, low-price business model, which was borrowed partially from Schulze's successful Tornado Sale in 1981. In its first year, the Burnsville store out-performed all other Best Buy stores combined.
+Best Buy was taken public in 1985, and two years later it debuted on the New York Stock Exchange. In 1988, Best Buy was in a price and location war with Detroit-based appliance chain Highland Superstores, and Schulze attempted to sell the company to Circuit City for US$30 million. Circuit City rejected the offer, claiming they could open a store in Minneapolis and "blow them away."
+<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>
diff --git a/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/prompts/base_with_chat_history.txt b/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/prompts/base_with_chat_history.txt
new file mode 100644
index 0000000000..f214d71b18
--- /dev/null
+++ b/libs/partners/cohere/tests/unit_tests/react_multi_hop/data/prompts/base_with_chat_history.txt
@@ -0,0 +1,43 @@
+<|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|># Safety Preamble
+The instructions in this section override those in the task description and style guide sections. Don't answer questions that are harmful or immoral
+
+# System Preamble
+## Basic Rules
+You are a powerful language agent trained by Cohere to help people. You are capable of complex reasoning and augmented with a number of tools. Your job is to plan and reason about how you will use and consume the output of these tools to best help the user. You will see a conversation history between yourself and a user, ending with an utterance from the user. You will then see an instruction informing you what kind of response to generate. You will construct a plan and then perform a number of reasoning and action steps to solve the problem. When you have determined the answer to the user's request, you will cite your sources in your answers, according the instructions
+
+# User Preamble
+## Task And Context
+You use your advanced complex reasoning capabilities to help people by answering their questions and other requests interactively. You will be asked a very wide array of requests on all kinds of topics. You will be equipped with a wide range of search engines or similar tools to help you, which you use to research your answer. You may need to use multiple tools in parallel or sequentially to complete your task. You should focus on serving the user's needs as best you can, which will be wide-ranging. The current date is Saturday, March 30, 2024 13:20:40
+
+## Style Guide
+Unless the user asks for a different style of answer, you should answer in full sentences, using proper grammar and spelling
+
+## Available Tools
+Here is a list of tools that you have available to you:
+
+```python
+def directly_answer() -> List[Dict]:
+ """Calls a standard (un-augmented) AI chatbot to generate a response given the conversation history
+ """
+ pass
+```
+
+```python
+def internet_search(query: str) -> List[Dict]:
+ """Returns a list of relevant document snippets for a textual query retrieved from the internet
+
+ Args:
+ query (str): Query to search the internet with
+ """
+ pass
+```<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|USER_TOKEN|>Hello, how are you doing?<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>I'm doing well, thanks!<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|USER_TOKEN|>In what year was the company that was founded as Sound of Music added to the S&P 500?<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|SYSTEM_TOKEN|>Carefully perform the following instructions, in order, starting each with a new line.
+Firstly, You may need to use complex and advanced reasoning to complete your task and answer the question. Think about how you can use the provided tools to answer the question and come up with a high level plan you will execute.
+Write 'Plan:' followed by an initial high level plan of how you will solve the problem including the tools and steps required.
+Secondly, Carry out your plan by repeatedly using actions, reasoning over the results, and re-evaluating your plan. Perform Action, Observation, Reflection steps with the following format. Write 'Action:' followed by a json formatted action containing the "tool_name" and "parameters"
+ Next you will analyze the 'Observation:', this is the result of the action.
+After that you should always think about what to do next. Write 'Reflection:' followed by what you've figured out so far, any changes you need to make to your plan, and what you will do next including if you know the answer to the question.
+... (this Action/Observation/Reflection can repeat N times)
+Thirdly, Decide which of the retrieved documents are relevant to the user's last input by writing 'Relevant Documents:' followed by comma-separated list of document numbers. If none are relevant, you should instead write 'None'.
+Fourthly, Decide which of the retrieved documents contain facts that should be cited in a good answer to the user's last input by writing 'Cited Documents:' followed a comma-separated list of document numbers. If you dont want to cite any of them, you should instead write 'None'.
+Fifthly, Write 'Answer:' followed by a response to the user's last input in high quality natural english. Use the retrieved documents to help you. Do not insert any citations or grounding markup.
+Finally, Write 'Grounded answer:' followed by a response to the user's last input in high quality natural english. Use the symbols and to indicate when a fact comes from a document in the search result, e.g my fact for a fact from document 4.<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>
diff --git a/libs/partners/cohere/tests/unit_tests/react_multi_hop/parsing/__init__.py b/libs/partners/cohere/tests/unit_tests/react_multi_hop/parsing/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/libs/partners/cohere/tests/unit_tests/react_multi_hop/parsing/test_output_parser.py b/libs/partners/cohere/tests/unit_tests/react_multi_hop/parsing/test_output_parser.py
new file mode 100644
index 0000000000..7f5d043205
--- /dev/null
+++ b/libs/partners/cohere/tests/unit_tests/react_multi_hop/parsing/test_output_parser.py
@@ -0,0 +1,64 @@
+from typing import Any, Dict, List
+from unittest import mock
+
+import pytest
+from langchain_core.agents import AgentActionMessageLog, AgentFinish
+from langchain_core.messages import AIMessage
+
+from langchain_cohere.react_multi_hop.parsing import CohereToolsReactAgentOutputParser
+from tests.unit_tests.react_multi_hop import ExpectationType, read_expectation_from_file
+
+
+@pytest.mark.parametrize(
+ "scenario_name,expected",
+ [
+ pytest.param(
+ "answer_sound_of_music",
+ AgentFinish(
+ return_values={
+ "output": "Best Buy, originally called Sound of Music, was added to Standard & Poor's S&P 500 in 1999." # noqa: E501
+ },
+ log="Relevant Documents: 0,2,3\nCited Documents: 0,2\nAnswer: Best Buy, originally called Sound of Music, was added to Standard & Poor's S&P 500 in 1999.\nGrounded answer: Best Buy, originally called Sound of Music, was added to Standard & Poor's S&P 500 in 1999.", # noqa: E501
+ ),
+ id="best buy example",
+ )
+ ],
+)
+def test_it_parses_answer(scenario_name: str, expected: AgentFinish) -> None:
+ text = read_expectation_from_file(ExpectationType.completions, scenario_name)
+ actual = CohereToolsReactAgentOutputParser().parse(text)
+
+ assert expected == actual
+
+
+@mock.patch("langchain_cohere.react_multi_hop.parsing.parse_actions", autospec=True)
+def test_it_returns_parses_action(parse_actions_mock: mock.Mock) -> None:
+ # The actual parsing is mocked and tested elsewhere
+ text = "Reflection: mocked"
+ generation = "mocked generation"
+ plan = "mocked plan"
+ parser = CohereToolsReactAgentOutputParser()
+ parsed_actions: List[Dict[str, Any]] = [
+ {"tool_name": "tool1", "parameters": {"param1": "value1"}},
+ {"tool_name": "tool2", "parameters": {"param2": "value2"}},
+ ]
+ parse_actions_mock.return_value = (generation, plan, parsed_actions)
+ expected = [
+ AgentActionMessageLog(
+ tool=parsed_actions[0]["tool_name"],
+ tool_input=parsed_actions[0]["parameters"],
+ log=f"\n{plan}\n{str(parsed_actions[0])}\n",
+ message_log=[AIMessage(content=generation)],
+ ),
+ AgentActionMessageLog(
+ tool=parsed_actions[1]["tool_name"],
+ tool_input=parsed_actions[1]["parameters"],
+ log=f"\n{str(parsed_actions[1])}\n",
+ message_log=[AIMessage(content=generation)],
+ ),
+ ]
+
+ actual = parser.parse(text)
+
+ parse_actions_mock.assert_called_once_with(text)
+ assert expected == actual
diff --git a/libs/partners/cohere/tests/unit_tests/react_multi_hop/parsing/test_parse_actions.py b/libs/partners/cohere/tests/unit_tests/react_multi_hop/parsing/test_parse_actions.py
new file mode 100644
index 0000000000..3d72495024
--- /dev/null
+++ b/libs/partners/cohere/tests/unit_tests/react_multi_hop/parsing/test_parse_actions.py
@@ -0,0 +1,67 @@
+from typing import Any, Dict, List, Optional
+
+import pytest
+
+from langchain_cohere.react_multi_hop.parsing import parse_actions
+from tests.unit_tests.react_multi_hop import ExpectationType, read_expectation_from_file
+
+
+@pytest.mark.parametrize(
+ "scenario_name, expected_plan, expected_actions, expected_error",
+ [
+ pytest.param(
+ "plan_with_action_normal",
+ "Do a thing.\nAnd then do another thing.",
+ [
+ {"parameters": {"arg1": "value1", "arg2": 2}, "tool_name": "tool1"},
+ {"parameters": {"arg3": "value3", "arg4": True}, "tool_name": "tool2"},
+ ],
+ None,
+ id="plan with action (normal)",
+ ),
+ pytest.param(
+ "reflection_with_action_normal",
+ "I found out a thing.\nAnd then do another thing.",
+ [
+ {"parameters": {"arg1": "value1", "arg2": 2}, "tool_name": "tool1"},
+ ],
+ None,
+ id="plan with reflection (normal)",
+ ),
+ pytest.param(
+ "action_only_abnormal",
+ "",
+ [
+ {"parameters": {"arg1": "value1", "arg2": 2}, "tool_name": "tool1"},
+ ],
+ None,
+ id="action only (abnormal)",
+ ),
+ pytest.param(
+ "not_a_plan_reflection_or_action",
+ "",
+ [],
+ ValueError,
+ id="invalid generation (abnormal)",
+ ),
+ ],
+)
+def test_parse_actions(
+ scenario_name: str,
+ expected_plan: str,
+ expected_actions: List[Dict],
+ expected_error: Optional[Any],
+) -> None:
+ completion = read_expectation_from_file(ExpectationType.completions, scenario_name)
+
+ if expected_error:
+ with pytest.raises(expected_error):
+ parse_actions(generation=completion)
+ else:
+ actual_completion, actual_plan, actual_actions = parse_actions(
+ generation=completion
+ )
+
+ assert completion == actual_completion
+ assert expected_plan == actual_plan
+ assert expected_actions == actual_actions
diff --git a/libs/partners/cohere/tests/unit_tests/react_multi_hop/prompt/__init__.py b/libs/partners/cohere/tests/unit_tests/react_multi_hop/prompt/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/libs/partners/cohere/tests/unit_tests/react_multi_hop/prompt/test_multihop_prompt.py b/libs/partners/cohere/tests/unit_tests/react_multi_hop/prompt/test_multihop_prompt.py
new file mode 100644
index 0000000000..7c0ddea54b
--- /dev/null
+++ b/libs/partners/cohere/tests/unit_tests/react_multi_hop/prompt/test_multihop_prompt.py
@@ -0,0 +1,182 @@
+from typing import Any, Dict, List, Tuple, Type
+
+import pytest
+from freezegun import freeze_time
+from langchain_core.agents import AgentAction, AgentActionMessageLog
+from langchain_core.messages import AIMessage, HumanMessage
+from langchain_core.prompt_values import StringPromptValue
+from langchain_core.prompts import ChatPromptTemplate
+from langchain_core.pydantic_v1 import BaseModel, Field
+from langchain_core.runnables import RunnablePassthrough
+from langchain_core.tools import BaseTool
+
+from langchain_cohere.react_multi_hop.prompt import multi_hop_prompt
+from tests.unit_tests.react_multi_hop import ExpectationType, read_expectation_from_file
+
+
+class InternetSearchTool(BaseTool):
+ class _InputSchema(BaseModel):
+ query: str = Field(type=str, description="Query to search the internet with")
+
+ name = "internet_search"
+ description = (
+ "Returns a list of relevant document snippets for a textual query "
+ "retrieved from the internet"
+ )
+ args_schema: Type[_InputSchema] = _InputSchema
+
+ def _run(self, *args: Any, **kwargs: Any) -> Any:
+ pass
+
+
+TOOLS: List[BaseTool] = [InternetSearchTool()] # type: ignore
+DOCUMENTS = [
+ {
+ "URL": "https://www.cnbc.com/2015/05/26/19-famous-companies-that-originally-had-different-names.html",
+ "title": "19 famous companies that originally had different names",
+ "text": 'Sound of Music made more money during this "best buy" four-day sale than it did in a typical month – thus, the store was renamed to Best Buy in 1983.\n4. Apple Computers » Apple, Inc.\nFounded in 1976, the tech giant we know today as Apple was originally named Apple Computers by founders Steve Jobs, Ronald Wayne and Steve Wozniak. In 2007, Jobs announced that the company was dropping the word "Computer" from its name to better reflect their move into a wider field of consumer electronics. "The Mac, iPod, Apple TV and iPhone. Only one of those is a computer.', # noqa: E501
+ },
+ {
+ "URL": "https://en.wikipedia.org/wiki/The_Sound_of_Music_(film)",
+ "title": "The Sound of Music (film) - Wikipedia",
+ "text": 'In 1966, American Express created the first Sound of Music guided tour in Salzburg. Since 1972, Panorama Tours has been the leading Sound of Music bus tour company in the city, taking approximately 50,000 tourists a year to various film locations in Salzburg and the surrounding region. Although the Salzburg tourism industry took advantage of the attention from foreign tourists, residents of the city were apathetic about "everything that is dubious about tourism." The guides on the bus tour "seem to have little idea of what really happened on the set." Even the ticket agent for the Sound of Music Dinner Show tried to dissuade Austrians from attending a performance that was intended for American tourists, saying that it "does not have anything to do with the real Austria."', # noqa: E501
+ },
+ {
+ "URL": "https://en.wikipedia.org/wiki/Best_Buy",
+ "title": "Best Buy - Wikipedia",
+ "text": "Concept IV stores included an open layout with products organized by category, cash registers located throughout the store, and slightly smaller stores than Concept III stores. The stores also had large areas for demonstrating home theater systems and computer software.\nIn 1999, Best Buy was added to Standard & Poor's S&P 500.\n2000s\nIn 2000, Best Buy formed Redline Entertainment, an independent music label and action-sports video distributor. The company acquired Magnolia Hi-Fi, Inc., an audio-video retailer located in California, Washington, and Oregon, in December 2000.\nIn January 2001, Best Buy acquired Musicland Stores Corporation, a Minnetonka, Minnesota-based retailer that sold home-entertainment products under the Sam Goody, Suncoast Motion Picture Company, Media Play, and OnCue brands.", # noqa: E501
+ },
+ {
+ "URL": "https://en.wikipedia.org/wiki/Best_Buy",
+ "title": "Best Buy - Wikipedia",
+ "text": 'Later that year, Best Buy opened its first superstore in Burnsville, Minnesota. The Burnsville location featured a high-volume, low-price business model, which was borrowed partially from Schulze\'s successful Tornado Sale in 1981. In its first year, the Burnsville store out-performed all other Best Buy stores combined.\nBest Buy was taken public in 1985, and two years later it debuted on the New York Stock Exchange. In 1988, Best Buy was in a price and location war with Detroit-based appliance chain Highland Superstores, and Schulze attempted to sell the company to Circuit City for US$30 million. Circuit City rejected the offer, claiming they could open a store in Minneapolis and "blow them away."', # noqa: E501
+ },
+]
+COMPLETIONS = [
+ """Plan: First, I need to find out which company was originally called Sound of Music, then I need to find out when it was added to the S&P 500.
+Action: ```json
+[
+ {
+ "tool_name": "internet_search",
+ "parameters": {
+ "query": "which company was originally called sound of music"
+ }
+ }
+]
+```""", # noqa: E501
+ """Reflection: I found out that Sound of Music was renamed Best Buy in 1983, now I need to find out when Best Buy was added to the S&P 500.
+Action: ```json
+[
+ {
+ "tool_name": "internet_search",
+ "parameters": {
+ "query": "when was best buy added to S&P 500"
+ }
+ }
+]
+```""", # noqa: E501,
+]
+MESSAGES = [
+ HumanMessage(content="Hello, how are you doing?"),
+ AIMessage(content="I'm doing well, thanks!"),
+ HumanMessage(
+ content="In what year was the company that was founded as Sound of Music added to the S&P 500?" # noqa: E501
+ ),
+]
+
+
+@freeze_time("Saturday, March 30, 2024 13:20:40")
+@pytest.mark.parametrize(
+ "tools,template,invoke_with,intermediate_steps,scenario_name",
+ [
+ pytest.param(
+ [TOOLS[0]],
+ ChatPromptTemplate.from_template("{input}"),
+ {
+ "input": "In what year was the company that was founded as Sound of Music added to the S&P 500?" # noqa: E501
+ },
+ [],
+ "base",
+ id="base",
+ ),
+ pytest.param(
+ [TOOLS[0]],
+ ChatPromptTemplate.from_template("{input}"),
+ {
+ "input": "In what year was the company that was founded as Sound of Music added to the S&P 500?" # noqa: E501
+ },
+ [
+ (
+ AgentActionMessageLog(
+ tool=TOOLS[0].name,
+ tool_input={
+ "query": "which company was originally called sound of music" # noqa: E501
+ },
+ log="\nFirst I will search for the company founded as Sound of Music. Then I will search for the year this company was added to the S&P 500.{'tool_name': 'internet_search', 'parameters': {'query': 'company founded as Sound of Music'}}\n", # noqa: E501
+ message_log=[AIMessage(content=COMPLETIONS[0])],
+ ),
+ [DOCUMENTS[0], DOCUMENTS[1]],
+ ),
+ ],
+ "base_after_one_hop",
+ id="after one hop",
+ ),
+ pytest.param(
+ [TOOLS[0]],
+ ChatPromptTemplate.from_template("{input}"),
+ {
+ "input": "In what year was the company that was founded as Sound of Music added to the S&P 500?" # noqa: E501
+ },
+ [
+ (
+ AgentActionMessageLog(
+ tool=TOOLS[0].name,
+ tool_input={
+ "query": "which company was originally called sound of music" # noqa: E501
+ },
+ log="\nFirst I will search for the company founded as Sound of Music. Then I will search for the year this company was added to the S&P 500.{'tool_name': 'internet_search', 'parameters': {'query': 'company founded as Sound of Music'}}\n", # noqa: E501
+ message_log=[AIMessage(content=COMPLETIONS[0])],
+ ),
+ [DOCUMENTS[0], DOCUMENTS[1]],
+ ),
+ (
+ AgentActionMessageLog(
+ tool=TOOLS[0].name,
+ tool_input={"query": "when was best buy added to S&P 500"},
+ log="\nI found out that Sound of Music was renamed Best Buy in 1983, now I need to find out when Best Buy was added to the S&P 500.\n{'tool_name': 'internet_search', 'parameters': {'query': 'when was best buy added to S&P 500'}}\n", # noqa: E501
+ message_log=[AIMessage(content=COMPLETIONS[1])],
+ ),
+ [DOCUMENTS[2], DOCUMENTS[3]],
+ ),
+ ],
+ "base_after_two_hops",
+ id="after two hops",
+ ),
+ pytest.param(
+ [TOOLS[0]],
+ ChatPromptTemplate.from_messages([MESSAGES[0], MESSAGES[1], MESSAGES[2]]),
+ {},
+ [],
+ "base_with_chat_history",
+ id="base with chat history",
+ ),
+ ],
+)
+def test_multihop_prompt(
+ tools: List[BaseTool],
+ template: ChatPromptTemplate,
+ invoke_with: Dict[str, Any],
+ intermediate_steps: List[Tuple[AgentAction, Any]],
+ scenario_name: str,
+) -> None:
+ """Tests prompt rendering against hardcoded expectations."""
+ expected = read_expectation_from_file(ExpectationType.prompts, scenario_name)
+ chain = RunnablePassthrough.assign(
+ agent_scratchpad=lambda _: [], # Usually provided by create_cohere_react_agent.
+ intermediate_steps=lambda _: intermediate_steps,
+ ) | multi_hop_prompt(tools=tools, prompt=template)
+
+ actual = chain.invoke(invoke_with) # type: StringPromptValue # type: ignore
+
+ assert StringPromptValue == type(actual)
+ assert expected == actual.text
diff --git a/libs/partners/cohere/tests/unit_tests/react_multi_hop/prompt/test_prompt.py b/libs/partners/cohere/tests/unit_tests/react_multi_hop/prompt/test_prompt.py
new file mode 100644
index 0000000000..dae0c9fbfd
--- /dev/null
+++ b/libs/partners/cohere/tests/unit_tests/react_multi_hop/prompt/test_prompt.py
@@ -0,0 +1,72 @@
+from typing import Any
+
+import pytest
+from langchain_core.messages import SystemMessage
+
+from langchain_cohere.react_multi_hop.prompt import render_observations
+
+
+def test_render_observation_has_correct_indexes() -> None:
+ index = 13
+ observations = ["foo", "bar"]
+ expected_index = 15
+
+ _, actual = render_observations(observations=observations, index=index)
+
+ assert expected_index == actual
+
+
+document_template = """Document: {index}
+{fields}"""
+
+
+@pytest.mark.parametrize(
+ "observation,expected_content",
+ [
+ pytest.param(
+ "foo", document_template.format(index=0, fields="Output: foo"), id="string"
+ ),
+ pytest.param(
+ {"foo": "bar"},
+ document_template.format(index=0, fields="Foo: bar"),
+ id="dictionary",
+ ),
+ pytest.param(
+ {"url": "foo"},
+ document_template.format(index=0, fields="URL: foo"),
+ id="dictionary with url",
+ ),
+ pytest.param(
+ {"foo": "bar", "baz": "foobar"},
+ document_template.format(index=0, fields="Foo: bar\nBaz: foobar"),
+ id="dictionary with multiple keys",
+ ),
+ pytest.param(
+ ["foo", "bar"],
+ "\n\n".join(
+ [
+ document_template.format(index=0, fields="Output: foo"),
+ document_template.format(index=1, fields="Output: bar"),
+ ]
+ ),
+ id="list of strings",
+ ),
+ pytest.param(
+ [{"foo": "bar"}, {"baz": "foobar"}],
+ "\n\n".join(
+ [
+ document_template.format(index=0, fields="Foo: bar"),
+ document_template.format(index=1, fields="Baz: foobar"),
+ ]
+ ),
+ id="list of dictionaries",
+ ),
+ ],
+)
+def test_render_observation_has_correct_content(
+ observation: Any, expected_content: str
+) -> None:
+ actual, _ = render_observations(observations=observation, index=0)
+ expected_content = f"\n{expected_content}\n"
+
+ assert SystemMessage(content=expected_content) == actual
diff --git a/libs/partners/cohere/tests/unit_tests/test_cohere_agent.py b/libs/partners/cohere/tests/unit_tests/test_cohere_agent.py
index 5ef7e42d52..479fe88a60 100644
--- a/libs/partners/cohere/tests/unit_tests/test_cohere_agent.py
+++ b/libs/partners/cohere/tests/unit_tests/test_cohere_agent.py
@@ -17,17 +17,17 @@ expected_test_tool_definition = {
"arg_1": {
"description": "Arg1 description",
"required": True,
- "type": "string",
+ "type": "str",
},
"optional_arg_2": {
"description": "Arg2 description",
"required": False,
- "type": "string",
+ "type": "str",
},
"arg_3": {
"description": "Arg3 description",
"required": True,
- "type": "integer",
+ "type": "int",
},
},
}
diff --git a/libs/partners/cohere/tests/unit_tests/test_imports.py b/libs/partners/cohere/tests/unit_tests/test_imports.py
index 0159c19e94..da69f31f00 100644
--- a/libs/partners/cohere/tests/unit_tests/test_imports.py
+++ b/libs/partners/cohere/tests/unit_tests/test_imports.py
@@ -2,11 +2,11 @@ from langchain_cohere import __all__
EXPECTED_ALL = [
"ChatCohere",
- "CohereVectorStore",
"CohereEmbeddings",
"CohereRagRetriever",
"CohereRerank",
"create_cohere_tools_agent",
+ "create_cohere_react_agent",
]
diff --git a/libs/partners/cohere/tests/unit_tests/test_utils.py b/libs/partners/cohere/tests/unit_tests/test_utils.py
new file mode 100644
index 0000000000..4e12f19693
--- /dev/null
+++ b/libs/partners/cohere/tests/unit_tests/test_utils.py
@@ -0,0 +1,43 @@
+import pytest
+
+from langchain_cohere.utils import _remove_signature_from_tool_description
+
+
+@pytest.mark.parametrize(
+ "name,description,expected",
+ [
+ pytest.param(
+ "foo", "bar baz", "bar baz", id="description doesn't have signature"
+ ),
+ pytest.param("foo", "", "", id="description is empty"),
+ pytest.param("foo", "foo(a: str) - bar baz", "bar baz", id="signature"),
+ pytest.param(
+ "foo", "foo() - bar baz", "bar baz", id="signature with empty args"
+ ),
+ pytest.param(
+ "foo",
+ "foo(a: str) - foo(b: str) - bar",
+ "foo(b: str) - bar",
+ id="signature with edge case",
+ ),
+ pytest.param(
+ "foo", "foo() -> None - bar baz", "bar baz", id="signature with return type"
+ ),
+ pytest.param(
+ "foo",
+ """My description.
+
+Args:
+ Bar:
+""",
+ "My description.",
+ id="signature with Args: section",
+ ),
+ ],
+)
+def test_remove_signature_from_description(
+ name: str, description: str, expected: str
+) -> None:
+ actual = _remove_signature_from_tool_description(name=name, description=description)
+
+ assert expected == actual