diff options
-rw-r--r-- | src/client/views/nodes/ChatBox/Agent.ts | 52 | ||||
-rw-r--r-- | src/client/views/nodes/ChatBox/prompts.ts | 228 | ||||
-rw-r--r-- | src/client/views/nodes/ChatBox/tools/CalculateTool.ts | 1 | ||||
-rw-r--r-- | src/client/views/nodes/ChatBox/tools/CreateCollectionTool.ts | 1 | ||||
-rw-r--r-- | src/client/views/nodes/ChatBox/tools/DataAnalysisTool.ts | 36 | ||||
-rw-r--r-- | src/client/views/nodes/ChatBox/tools/SearchTool.ts | 63 | ||||
-rw-r--r-- | src/client/views/nodes/ChatBox/tools/WebsiteInfoScraperTool.ts | 52 | ||||
-rw-r--r-- | src/server/ApiManagers/AssistantManager.ts | 3 |
8 files changed, 260 insertions, 176 deletions
diff --git a/src/client/views/nodes/ChatBox/Agent.ts b/src/client/views/nodes/ChatBox/Agent.ts index ae08271ee..43138bf94 100644 --- a/src/client/views/nodes/ChatBox/Agent.ts +++ b/src/client/views/nodes/ChatBox/Agent.ts @@ -55,13 +55,23 @@ export class Agent { const systemPrompt = getReactPrompt(Object.values(this.tools), this._summaries, chatHistory); this.interMessages = [{ role: 'system', content: systemPrompt }]; this.interMessages.push({ role: 'user', content: `<stage number="1" role="user"><query>${question}</query></stage>` }); - const parser = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: '@_' }); + const parser = new XMLParser({ + ignoreAttributes: false, + attributeNamePrefix: '@_', + textNodeName: '_text', + isArray: (name, jpath, isLeafNode, isAttribute) => { + // Convert tags with the same name to arrays + return ['query', 'url'].indexOf(name) !== -1; + }, + }); const builder = new XMLBuilder({ ignoreAttributes: false, attributeNamePrefix: '@_' }); + let currentAction: string | undefined; this.processingInfo = []; for (let i = 2; i < maxTurns; i += 2) { + console.log(this.interMessages); console.log(`Turn ${i}/${maxTurns}`); const result = await this.execute(onUpdate); @@ -102,11 +112,14 @@ export class Agent { break; } } else if (key === 'action_input') { - const actionInput = builder.build({ action_input: stage[key] }); - console.log(`Action input: ${actionInput}`); + const actionInput = stage[key]; + console.log(`Action input:`, actionInput); if (currentAction) { try { - const observation = await this.processAction(currentAction, stage[key].inputs); + // Parse the inputs + //const parsedInputs = this.parseActionInputs(actionInput.inputs); + //console.log(`Parsed inputs:`, parsedInputs); + const observation = await this.processAction(currentAction, actionInput.inputs); const nextPrompt = [{ type: 'text', text: `<stage number="${i + 1}" role="user"> <observation>` }, ...observation, { type: 'text', text: '</observation></stage>' }]; console.log(observation); this.interMessages.push({ role: 'user', content: nextPrompt }); @@ -198,9 +211,26 @@ export class Agent { const tool = this.tools[action]; const args: Record<string, any> = {}; + for (const paramName in tool.parameters) { if (actionInput[paramName] !== undefined) { - args[paramName] = actionInput[paramName]; + if (Array.isArray(actionInput[paramName])) { + // If the input is already an array, use it as is + args[paramName] = actionInput[paramName]; + } else if (typeof actionInput[paramName] === 'object' && actionInput[paramName] !== null) { + // If the input is an object, check if it has multiple of the same tag + const values = Object.values(actionInput[paramName]); + if (values.length > 1) { + // If there are multiple values, convert to an array + args[paramName] = values; + } else { + // If there's only one value, use it directly + args[paramName] = values[0]; + } + } else { + // For single values, use them as is + args[paramName] = actionInput[paramName]; + } } else if (tool.parameters[paramName].required === 'true') { throw new Error(`Missing required parameter '${paramName}' for action '${action}'`); } @@ -208,4 +238,16 @@ export class Agent { return await tool.execute(args); } + + private parseActionInputs(inputs: any): Record<string, string | string[]> { + const parsedInputs: Record<string, string | string[]> = {}; + for (const key in inputs) { + if (Array.isArray(inputs[key])) { + parsedInputs[key] = inputs[key].map((item: any) => item._text); + } else { + parsedInputs[key] = inputs[key]._text; + } + } + return parsedInputs; + } } diff --git a/src/client/views/nodes/ChatBox/prompts.ts b/src/client/views/nodes/ChatBox/prompts.ts index 200a0fa75..845b4d255 100644 --- a/src/client/views/nodes/ChatBox/prompts.ts +++ b/src/client/views/nodes/ChatBox/prompts.ts @@ -56,15 +56,15 @@ export function getReactPrompt(tools: Tool[], summaries: () => string, chatHisto <step>Grounded text can be as short as a few words or as long as several sentences.</step> <step>Avoid overlapping or nesting <grounded_text> tags; use sequential tags instead.</step> <step>Grounded text tags should always have a citation_index attribute that references a citation index number that the text is grounded in.</step> - <step>Should be in Markdown format.</step> + <step>Content within the <grounded_text> tags should be in Markdown format.</step> </grounded_text_guidelines> <normal_text_guidelines> - <step>Wrap all information that is not derived from tools or chunks in <normal_text> tags.</step> + <step>Wrap all text that is not derived from tools or chunks in <normal_text> tags (any text outputted in the answer that is not in a <grounded_text> tag should be within a normal text tag).</step> <step>Ensure that these tags are used for your reasoning, background knowledge, or general information that does not require a citation.</step> <step>Do not use <normal_text> tags for information that needs grounding or citation.</step> <step>Anything that is in any user docs should be grounded text and cited, not normal text, even if it is background or general information.</step> - <step>Should be in Markdown format.</step> + <step>Content within the <normal_text> tags should be in Markdown format.</step> </normal_text_guidelines> <citation_guidelines> @@ -87,6 +87,7 @@ export function getReactPrompt(tools: Tool[], summaries: () => string, chatHisto <substep>Use the <action> tag to specify the tool.</substep> <substep>End your response after the <action> tag and wait for action rules to be provided.</substep> <substep>Based on the action rules, provide the necessary tool parameters within the <inputs>. The <inputs> tag should be within the <action_input> tag, and should follow an <action_description> tag that contains a brief description of what you're doing with the action.</substep> + <substep>For each input, you may provide as many different iterations of the same tag (i.e. to provide multiple inputs to the tool) as is specified in the input's max_input's field.</substep> <substep>End your response again and wait for the observation from the tool.</substep> </substeps> <step>If no tool is needed, use the 'no_tool' action but still follow the same response structure.</step> @@ -169,7 +170,7 @@ export function getReactPrompt(tools: Tool[], summaries: () => string, chatHisto <stage number="6" role="assistant"> <thought> - With information on key moments from the press release, I will now analyze the medal count data to compare how different countries performed during the games. + With information on key moments from the press release, I will now analyze the medal count data and economic impact data to provide a comprehensive overview of the 2010 Vancouver Winter Olympics's impact. </thought> <action>dataAnalysis</action> </stage> @@ -180,9 +181,10 @@ export function getReactPrompt(tools: Tool[], summaries: () => string, chatHisto <stage number="8" role="assistant"> <action_input> - <action_input_description>Analyzing the medal count data for the 2010 Vancouver Winter Olympics to compare country performances.</action_input_description> + <action_input_description>Analyzing the medal count data and economic impact data for the 2010 Vancouver Winter Olympics to compare country performances and assess the games' overall impact.</action_input_description> <inputs> <csv_file_name>2010_Vancouver_Olympics_Medal_Count.csv</csv_file_name> + <csv_file_name>2010_Vancouver_Olympics_Economic_Impact.csv</csv_file_name> </inputs> </action_input> </stage> @@ -194,234 +196,236 @@ export function getReactPrompt(tools: Tool[], summaries: () => string, chatHisto Germany,10,13,7,30 Canada,14,7,5,26 Norway,9,8,6,23 + Russia,3,5,7,15 + South Korea,6,6,2,14 + China,5,2,4,11 + Sweden,5,2,4,11 + France,2,3,6,11 + Austria,4,6,6,16 + </chunk> + <chunk chunk_id="bcde5678-f901-2345-gh67-89ijklmnopq0" chunk_type="csv"> + Category,Value + Total Cost (CAD),7.7 billion + Revenue Generated (CAD),2.5 billion + Jobs Created,45000 + Tourism Increase (%),35 + Infrastructure Investment (CAD),1.9 billion + Post-Olympic Annual Tourism Revenue Increase (CAD),220 million + Venues Repurposed,8 + Carbon Footprint Offset (%),118 </chunk> </stage> <stage number="10" role="assistant"> <thought> - Now that I have gathered comprehensive information from the official press release and the medal count data, I will provide a detailed answer to the user's query. + Now that I have gathered comprehensive information from the official press release, medal count data, and economic impact data, I will provide a detailed answer to the user's query, incorporating all aspects of the 2010 Vancouver Winter Olympics's impact. </thought> <answer> <grounded_text citation_index="1"> The 2010 Winter Olympics, officially known as the XXI Olympic Winter Games, took place in Vancouver, British Columbia, Canada, from February 12 to 28, 2010. It featured 86 events in 15 disciplines across 7 sports, with 2,566 athletes from 82 National Olympic Committees participating. </grounded_text> + <grounded_text citation_index="2"> The Opening Ceremony was one of the most spectacular in Olympic history, celebrating Canadian culture and heritage. A significant highlight for the host nation was the victory of the Canadian men's and women's ice hockey teams, both securing gold medals, which was a source of immense national pride. </grounded_text> + <grounded_text citation_index="3"> - In terms of medal performance, the United States led the overall tally with 37 medals, followed by Germany with 30 medals. Canada, while placing third in total medals, achieved a record number of 14 gold medals, the highest of any country in the 2010 games. + In terms of medal performance, the United States led the overall tally with 37 medals (9 gold, 15 silver, 13 bronze), followed by Germany with 30 medals (10 gold, 13 silver, 7 bronze). Canada, while placing third in total medals with 26, achieved a record number of 14 gold medals, the highest of any country in the 2010 games. Other notable performances came from Norway (23 medals), Russia (15 medals), and South Korea (14 medals). </grounded_text> + <grounded_text citation_index="4"> - However, the games were also marked by tragedy with the unfortunate death of Georgian luger Nodar Kumaritashvili during a training run, which deeply affected the Olympic community. + The economic impact of the 2010 Vancouver Winter Olympics was significant. The total cost of hosting the games was approximately 7.7 billion CAD, while generating revenue of 2.5 billion CAD. The games created about 45,000 jobs and led to a 35% increase in tourism during the event. The long-term benefits include an annual increase of 220 million CAD in tourism revenue and 1.9 billion CAD invested in infrastructure. </grounded_text> - <citations> - <citation index="1" chunk_id="123e4567-e89b-12d3-a456-426614174000" type="text"></citation> - <citation index="2" chunk_id="987f6543-e21b-43c9-a987-654321fedcba" type="text"> - Vancouver, BC - The 2010 Winter Olympics have been hailed as a monumental success, showcasing the best of Canadian culture and athletic prowess. The Opening Ceremony, held on February 12, 2010, was a spectacular celebration of the nation's history and diversity... - Key Moments: - - The Canadian men's and women's ice hockey teams both claimed gold medals, an achievement that brought immense pride to the host nation. - </citation> + <grounded_text citation_index="5"> + From an environmental perspective, the Vancouver Olympics made efforts to be sustainable, with 118% of the carbon footprint offset and 8 venues repurposed after the games, demonstrating a commitment to leaving a positive legacy. + </grounded_text> + + <grounded_text citation_index="6"> + However, the games were also marked by tragedy with the unfortunate death of Georgian luger Nodar Kumaritashvili during a training run, which deeply affected the Olympic community and led to increased scrutiny of safety measures across all events. + </grounded_text> + + <grounded_text citation_index="7"> + Despite this tragedy, the 2010 Vancouver Winter Olympics were generally hailed as a monumental success, showcasing the best of Canadian culture and athletic prowess. The games concluded on February 28, 2010, with a memorable Closing Ceremony that highlighted the achievements of the athletes and the spirit of unity that defined these Olympics. + </grounded_text> + + <citations> + <citation index="1" chunk_id="987f6543-e21b-43c9-a987-654321fedcba" type="text"></citation> + <citation index="2" chunk_id="987f6543-e21b-43c9-a987-654321fedcba" type="text"></citation> <citation index="3" chunk_id="789a1234-e567-890f-gh12-34567ijklmn8" type="csv"></citation> - <citation index="4" chunk_id="987f6543-e21b-43c9-a987-654321fedcba" type="text"> - Tragedy struck early in the games with the death of Georgian luger Nodar Kumaritashvili during a training run. - </citation> + <citation index="4" chunk_id="bcde5678-f901-2345-gh67-89ijklmnopq0" type="csv"></citation> + <citation index="5" chunk_id="bcde5678-f901-2345-gh67-89ijklmnopq0" type="csv"></citation> + <citation index="6" chunk_id="987f6543-e21b-43c9-a987-654321fedcba" type="text"></citation> + <citation index="7" chunk_id="987f6543-e21b-43c9-a987-654321fedcba" type="text"></citation> </citations> <follow_up_questions> - <question>What were the economic impacts on Vancouver after hosting the 2010 Winter Olympics?</question> - <question>How did the tragic accident of Nodar Kumaritashvili influence safety protocols in luge and other winter sports?</question> - <question>Can you provide more information on other significant performances by athletes during the 2010 Winter Olympics?</question> + <question>How did the 2010 Vancouver Winter Olympics compare to previous Winter Olympics in terms of economic impact and sustainability efforts?</question> + <question>What specific infrastructure improvements were made in Vancouver as a result of hosting the 2010 Winter Olympics?</question> + <question>How did the performance of Canadian athletes in the 2010 Vancouver Winter Olympics compare to their performance in previous Winter Olympics?</question> </follow_up_questions> </answer> </stage> </interaction> <interaction description="multistep web-scrape example"> + <system_message> + ***SYSTEM MESSAGE ELIDED*** + </system_message> <stage number="1" role="user"> - <query>What are the best hiking trails in Yosemite National Park?</query> + <query>What are the best hiking trails in Yosemite National Park? And which are the safest?</query> </stage> - <stage number="2" role="assistant"> <thought> - To provide comprehensive information about the best hiking trails in Yosemite National Park, I'll use the search tool to find relevant websites with hiking recommendations and park information. + To provide comprehensive information about the best hiking trails in Yosemite National Park, I'll use the search tool to find relevant websites with hiking recommendations, safety information, and general park information. </thought> <action>searchTool</action> </stage> - <stage number="3" role="user"> <action_rules>***Action rules elided***</action_rules> </stage> - <stage number="4" role="assistant"> <action_input> - <action_input_description>Searching the web for information about the best hiking trails in Yosemite National Park.</action_input_description> + <action_input_description>Searching the web for information about the best and safest hiking trails in Yosemite National Park.</action_input_description> <inputs> <query>Best hiking trails Yosemite National Park</query> + <query>Safest hiking trails Yosemite National Park</query> + <query>Information about hiking in Yosemite National Park</query> </inputs> </action_input> </stage> - <stage number="5" role="user"> <observation> - <chunk chunk_id="a1b2c3d4-e5f6-7g8h-9i10-j11k12l13m14" chunk_type="text"> + <chunk chunk_id="a1b2c3d4-e5f6-7g8h-9i10-j11k12l13m14" chunk_type="url"> <url>https://www.nps.gov/yose/planyourvisit/hiking.htm</url> <overview>Official National Park Service website with hiking information for Yosemite</overview> </chunk> - <chunk chunk_id="n15o16p17-q18r-19s20-t21u-v22w23x24y25" chunk_type="text"> + <chunk chunk_id="n15o16p17-q18r-19s20-t21u-v22w23x24y25" chunk_type="url"> <url>https://www.alltrails.com/parks/us/california/yosemite-national-park</url> <overview>AllTrails page featuring user-rated hiking trails in Yosemite</overview> </chunk> - <chunk chunk_id="z26a27b28-c29d-30e31-f32g-h33i34j35k36" chunk_type="text"> + <chunk chunk_id="z26a27b28-c29d-30e31-f32g-h33i34j35k36" chunk_type="url"> <url>https://www.yosemitehikes.com/</url> <overview>Comprehensive guide to Yosemite hikes with detailed trail information</overview> </chunk> - ***7 more search results elided*** </observation> </stage> - <stage number="6" role="assistant"> <thought> - I've found several relevant websites about hiking in Yosemite National Park. I'll start by scraping content from the official National Park Service website for the most reliable information. + I've found several relevant websites about hiking in Yosemite National Park. I'll start by scraping content from the official National Park Service website for the most reliable information, then move on to AllTrails for user ratings and reviews, and finally to YosemiteHikes.com for more detailed trail descriptions. </thought> <action>websiteInfoScraper</action> </stage> - <stage number="7" role="user"> <action_rules>***Action rules elided***</action_rules> </stage> - <stage number="8" role="assistant"> <action_input> - <action_input_description>Scraping information about hiking trails from the official Yosemite National Park website.</action_input_description> + <action_input_description>Scraping information from three websites about hiking trails in Yosemite National Park.</action_input_description> <inputs> <url>https://www.nps.gov/yose/planyourvisit/hiking.htm</url> + <url>https://www.alltrails.com/parks/us/california/yosemite-national-park</url> + <url>https://www.yosemitehikes.com/</url> </inputs> </action_input> </stage> - <stage number="9" role="user"> <observation> <chunk chunk_id="l37m38n39-o40p-41q42-r43s-t44u45v46w47" chunk_type="url"> - ***Website image elided*** - ***Scraped content from NPS website*** + ***NPS general planning website image elided*** + </chunk> + <chunk chunk_id="x48y49z50-a51b-52c53-d54e-f55g56h57i58" chunk_type="url"> + ***AllTrails website image elided*** + </chunk> + <chunk chunk_id="j59k60l61-m62n-63o64-p65q-r66s67t68u69" chunk_type="url"> + ***YosemiteHikes.com website image elided*** </chunk> </observation> </stage> - <stage number="10" role="assistant"> <thought> - The information from the National Park Service website was helpful, but it lacks user reviews and ratings. I'll check AllTrails for this additional perspective, although it may not provide as much official information. + The information gathered from the three websites provides a good overview of the best hiking trails and safety considerations in Yosemite National Park. However, I noticed that there's limited information about seasonal trail conditions and closures, which could be crucial for planning a safe hike. To address this, I'll scrape additional information from the Yosemite National Park's current conditions page. </thought> <action>websiteInfoScraper</action> </stage> - <stage number="11" role="user"> <action_rules>***Action rules elided***</action_rules> </stage> - <stage number="12" role="assistant"> <action_input> - <action_input_description>Scraping user reviews and ratings for Yosemite hiking trails from AllTrails.</action_input_description> + <action_input_description>Scraping information about current trail conditions and closures in Yosemite National Park.</action_input_description> <inputs> - <url>https://www.alltrails.com/parks/us/california/yosemite-national-park</url> + <url>https://www.nps.gov/yose/planyourvisit/conditions.htm</url> </inputs> </action_input> </stage> - <stage number="13" role="user"> <observation> - <chunk chunk_id="x48y49z50-a51b-52c53-d54e-f55g56h57i58" chunk_type="url"> - ***Website image elided*** - ***Scraped content from AllTrails*** + <chunk chunk_id="k70l71m72-n73o-74p75-q76r-s77t78u79v80" chunk_type="url"> + ***NPS conditions website image elided*** </chunk> </observation> </stage> - <stage number="14" role="assistant"> <thought> - The AllTrails website didn't provide as much detailed information as I had hoped. To ensure a comprehensive answer, I'll scrape YosemiteHikes.com for additional details and trail descriptions. + Now that I have additional information about current trail conditions and seasonal closures, I can provide a more comprehensive and up-to-date answer to the user's query about the best and safest hiking trails in Yosemite National Park. </thought> - <action>websiteInfoScraper</action> - </stage> - - <stage number="15" role="user"> - <action_rules>***Action rules elided***</action_rules> - </stage> + <answer> + <grounded_text citation_index="1"> + Yosemite National Park offers a wide range of hiking trails suitable for various skill levels. Some of the best hiking trails in Yosemite, based on the information gathered, include: - <stage number="16" role="assistant"> - <action_input> - <action_input_description>Gathering detailed trail descriptions and hiking information from YosemiteHikes.com.</action_input_description> - <inputs> - <url>https://www.yosemitehikes.com/</url> - </inputs> - </action_input> - </stage> + 1. Mist Trail to Vernal Fall: A moderate 3-mile round-trip hike in Yosemite Valley, offering close-up views of waterfalls... ***REST ELIDED FOR BREVITY*** </grounded_text> - <stage number="17" role="user"> - <observation> - <chunk chunk_id="j59k60l61-m62n-63o64-p65q-r66s67t68u69" chunk_type="url"> - ***Website image elided*** - ***Scraped content from YosemiteHikes.com*** - </chunk> - </observation> - </stage> - - <stage number="18" role="assistant"> - <thought> - I have successfully scraped information from all three websites. Now, I'll synthesize this information to provide a comprehensive answer about the best hiking trails in Yosemite National Park. - </thought> - <answer> - <normal_text> - Yosemite National Park is renowned for its breathtaking landscapes and diverse hiking opportunities. The park spans nearly 1,200 square miles of wilderness in California's Sierra Nevada mountains, offering trails suitable for all skill levels. - </normal_text> + <grounded_text citation_index="2"> + ***CONTENT ELIDED FOR BREVITY*** + </grounded_text> + <grounded_text citation_index="3"> + ***CONTENT ELIDED FOR BREVITY*** + </grounded_text> <normal_text> - Based on the information gathered from multiple sources, here are some of the best hiking trails in Yosemite: + Regarding safety, some of the safest trails for hikers of all skill levels include: </normal_text> + <grounded_text citation_index="1,2"> + 1. Lower Yosemite Fall Trail: An easy 1-mile loop in Yosemite Valley... ***REST ELIDED FOR BREVITY*** + </grounded_text> - 1. <grounded_text citation_index="2">Half Dome: This strenuous 14-16 mile round trip hike is one of Yosemite's most iconic and challenging trails, requiring a permit for the cable section.</grounded_text> - - 2. <grounded_text citation_index="3">Mist Trail to Vernal and Nevada Falls: A popular 6.4-mile round trip hike offering close-up views of two spectacular waterfalls.</grounded_text> - - 3. <grounded_text citation_index="4">Yosemite Falls Trail: A strenuous 7.2-mile round trip hike to the top of North America's tallest waterfall.</grounded_text> - - 4. <grounded_text citation_index="5">Bridalveil Fall Trail: An easy 0.5-mile round trip walk to the base of this iconic Yosemite waterfall.</grounded_text> - - 5. <grounded_text citation_index="6">Mirror Lake Trail: A moderate 2-5 mile round trip hike to a lake that reflects surrounding cliffs and Half Dome.</grounded_text> - + <grounded_text citation_index="4"> + ***CONTENT ELIDED FOR BREVITY*** + </grounded_text> <normal_text> - These trails offer a range of difficulties and showcase the park's diverse natural beauty, from towering waterfalls to panoramic valley views. + To ensure a safe hiking experience in Yosemite, regardless of the trail you choose, follow these safety tips: </normal_text> - - <grounded_text citation_index="7"> - It's important to note that trail conditions can vary depending on the season, and some trails may require permits or have specific regulations. Always check the official Yosemite National Park website for the most up-to-date information before planning your hike. + <grounded_text citation_index="1,2,3,4"> + 1. Stay on marked trails at all times... + ***REST ELIDED FOR BREVITY*** </grounded_text> - <normal_text> - Remember to practice Leave No Trace principles, stay on designated trails, and come prepared with appropriate gear, water, and snacks for your hike. + Remember that even the "safest" trails can pose risks if proper precautions are not taken. Always hike within your ability level and be prepared for the specific conditions of the trail you choose. It's essential to check for daily updates on trail conditions before starting your hike, as they can change rapidly, especially during spring and fall. </normal_text> - <citations> - <citation index="1" chunk_id="l37m38n39-o40p-41q42-r43s-t44u45v46w47" type="url"></citation> - <citation index="2" chunk_id="x48y49z50-a51b-52c53-d54e-f55g56h57i58" type="url"></citation> - <citation index="3" chunk_id="j59k60l61-m62n-63o64-p65q-r66s67t68u69" type="url"></citation> - <citation index="4" chunk_id="l37m38n39-o40p-41q42-r43s-t44u45v46w47" type="url"></citation> - <citation index="5" chunk_id="x48y49z50-a51b-52c53-d54e-f55g56h57i58" type="url"></citation> - <citation index="6" chunk_id="j59k60l61-m62n-63o64-p65q-r66s67t68u69" type="url"></citation> - <citation index="7" chunk_id="l37m38n39-o40p-41q42-r43s-t44u45v46w47" type="url"></citation> + <citation index="1" chunk_id="l37m38n39-o40p-41q42-r43s-t44u45v46w47" type="url"> + https://www.nps.gov/yose/planyourvisit/hiking.htm + </citation> + <citation index="2" chunk_id="x48y49z50-a51b-52c53-d54e-f55g56h57i58" type="url"> + https://www.alltrails.com/parks/us/california/yosemite-national-park + </citation> + <citation index="3" chunk_id="j59k60l61-m62n-63o64-p65q-r66s67t68u69" type="url"> + https://www.yosemitehikes.com/ + </citation> + <citation index="4" chunk_id="k70l71m72-n73o-74p75-q76r-s77t78u79v80" type="url"> + https://www.nps.gov/yose/planyourvisit/conditions.htm + </citation> </citations> - <follow_up_questions> <question>What is the best time of year to hike in Yosemite National Park?</question> - <question>Are there any beginner-friendly trails in Yosemite that offer scenic views?</question> - <question>What safety precautions should hikers take when exploring Yosemite's trails?</question> + <question>Are there any special permits required for hiking certain trails in Yosemite?</question> + <question>What wildlife might I encounter while hiking in Yosemite, and how should I prepare for potential encounters?</question> </follow_up_questions> </answer> </stage> </interaction> </example_interactions> - <chat_history> ${chatHistory} <note>Use this history for context when appropriate.</note> diff --git a/src/client/views/nodes/ChatBox/tools/CalculateTool.ts b/src/client/views/nodes/ChatBox/tools/CalculateTool.ts index 818332c44..74b7ca27b 100644 --- a/src/client/views/nodes/ChatBox/tools/CalculateTool.ts +++ b/src/client/views/nodes/ChatBox/tools/CalculateTool.ts @@ -10,6 +10,7 @@ export class CalculateTool extends BaseTool<{ expression: string }> { type: 'string', description: 'The mathematical expression to evaluate', required: 'true', + max_inputs: '1', }, }, 'Provide a mathematical expression to calculate that would work with JavaScript eval().', diff --git a/src/client/views/nodes/ChatBox/tools/CreateCollectionTool.ts b/src/client/views/nodes/ChatBox/tools/CreateCollectionTool.ts index 26ac0d7cc..573428179 100644 --- a/src/client/views/nodes/ChatBox/tools/CreateCollectionTool.ts +++ b/src/client/views/nodes/ChatBox/tools/CreateCollectionTool.ts @@ -16,6 +16,7 @@ export class GetDocsContentTool extends BaseTool<{ title: string; document_ids: type: 'string', description: 'the title of the collection that you will be making', required: 'true', + max_inputs: '1', }, }, 'Provide a mathematical expression to calculate that would work with JavaScript eval().', diff --git a/src/client/views/nodes/ChatBox/tools/DataAnalysisTool.ts b/src/client/views/nodes/ChatBox/tools/DataAnalysisTool.ts index b45733639..a12ee46e5 100644 --- a/src/client/views/nodes/ChatBox/tools/DataAnalysisTool.ts +++ b/src/client/views/nodes/ChatBox/tools/DataAnalysisTool.ts @@ -1,21 +1,22 @@ import { BaseTool } from './BaseTool'; -export class DataAnalysisTool extends BaseTool<{ csv_file_name: string }> { +export class DataAnalysisTool extends BaseTool<{ csv_file_name: string | string[] }> { private csv_files_function: () => { filename: string; id: string; text: string }[]; constructor(csv_files: () => { filename: string; id: string; text: string }[]) { super( 'dataAnalysis', - 'Analyzes, and provides insights, from a CSV file', + 'Analyzes, and provides insights, from one or more CSV files', { csv_file_name: { type: 'string', - description: 'Name of the CSV file to analyze', + description: 'Name(s) of the CSV file(s) to analyze', required: 'true', + max_inputs: '3', }, }, - 'Provide the name of the CSV file to analyze based on the user query and whichever available CSV file may be relevant.', - 'Provides the full CSV file text for your analysis based on the user query and the available CSV file. ' + 'Provide the name(s) of up to 3 CSV files to analyze based on the user query and whichever available CSV files may be relevant.', + 'Provides the full CSV file text for your analysis based on the user query and the available CSV file(s). ' ); this.csv_files_function = csv_files; } @@ -32,8 +33,27 @@ export class DataAnalysisTool extends BaseTool<{ csv_file_name: string }> { return file?.id; } - async execute(args: { csv_file_name: string }): Promise<any> { - console.log(this.csv_files_function()); - return [{ type: 'text', text: `<chunk chunk_id=${this.getFileID(args.csv_file_name)} chunk_type=csv}>` + this.getFileContent(args.csv_file_name) + '</chunk>' }]; + async execute(args: { csv_file_name: string | string[] }): Promise<any> { + const filenames = Array.isArray(args.csv_file_name) ? args.csv_file_name : [args.csv_file_name]; + const results = []; + + for (const filename of filenames) { + const fileContent = this.getFileContent(filename); + const fileID = this.getFileID(filename); + + if (fileContent && fileID) { + results.push({ + type: 'text', + text: `<chunk chunk_id=${fileID} chunk_type=csv>${fileContent}</chunk>`, + }); + } else { + results.push({ + type: 'text', + text: `File not found: ${filename}`, + }); + } + } + + return results; } } diff --git a/src/client/views/nodes/ChatBox/tools/SearchTool.ts b/src/client/views/nodes/ChatBox/tools/SearchTool.ts index 6523fd11c..b926cbadc 100644 --- a/src/client/views/nodes/ChatBox/tools/SearchTool.ts +++ b/src/client/views/nodes/ChatBox/tools/SearchTool.ts @@ -1,47 +1,54 @@ +import { max } from 'lodash'; import { Networking } from '../../../../Network'; import { BaseTool } from './BaseTool'; import { v4 as uuidv4 } from 'uuid'; -export class SearchTool extends BaseTool<{ query: string }> { +export class SearchTool extends BaseTool<{ query: string | string[] }> { private _addLinkedUrlDoc: (url: string, id: string) => void; - - constructor(addLinkedUrlDoc: (url: string, id: string) => void) { + private _max_results: number; + constructor(addLinkedUrlDoc: (url: string, id: string) => void, max_results: number = 5) { super( 'searchTool', - 'Search the web to find a wide range of websites related to a query', + 'Search the web to find a wide range of websites related to a query or multiple queries', { query: { type: 'string', - description: 'The search query to use for finding websites', - required: true, + description: 'The search query or queries to use for finding websites', + required: 'true', + max_inputs: '3', }, }, - 'Provide a search query to find a broad range of websites. This tool is intended to help you identify relevant websites, but not to be used for providing the final answer. Use this information to determine which specific website to investigate further.', - 'Returns a list of websites and their overviews based on the search query, helping to identify which website might contain the most relevant information.' + 'Provide up to 3 search queries to find a broad range of websites. This tool is intended to help you identify relevant websites, but not to be used for providing the final answer. Use this information to determine which specific website to investigate further.', + 'Returns a list of websites and their overviews based on the search queries, helping to identify which websites might contain relevant information.' ); this._addLinkedUrlDoc = addLinkedUrlDoc; + this._max_results = max_results; } - async execute(args: { query: string }): Promise<any> { - try { - const { results } = await Networking.PostToServer('/getWebSearchResults', { query: args.query }); - console.log(results); - const data: { type: string; text: string }[] = results.map((result: { url: string; snippet: string }) => { - console.log; - const id = uuidv4(); - //this._addLinkedUrlDoc(result.url, id); //not needed right now because it shouldn't use this information to ground responses and should scrape afterwards - return { - type: 'text', - text: `<chunk chunk_id="${id}" chunk_type="text"> - <url>${result.url}</url> - <overview>${result.snippet}</overview> - </chunk>`, - }; - }); - return data; - } catch (error) { - console.log(error); - return [{ type: 'text', text: 'An error occurred while performing the web search.' }]; + async execute(args: { query: string | string[] }): Promise<any> { + const queries = Array.isArray(args.query) ? args.query : [args.query]; + const allResults = []; + + for (const query of queries) { + try { + const { results } = await Networking.PostToServer('/getWebSearchResults', { query, max_results: this._max_results }); + const data: { type: string; text: string }[] = results.map((result: { url: string; snippet: string }) => { + const id = uuidv4(); + return { + type: 'text', + text: `<chunk chunk_id="${id}" chunk_type="text"> + <url>${result.url}</url> + <overview>${result.snippet}</overview> + </chunk>`, + }; + }); + allResults.push(...data); + } catch (error) { + console.log(error); + allResults.push({ type: 'text', text: `An error occurred while performing the web search for query: ${query}` }); + } } + + return allResults; } } diff --git a/src/client/views/nodes/ChatBox/tools/WebsiteInfoScraperTool.ts b/src/client/views/nodes/ChatBox/tools/WebsiteInfoScraperTool.ts index c59afefbd..739329bea 100644 --- a/src/client/views/nodes/ChatBox/tools/WebsiteInfoScraperTool.ts +++ b/src/client/views/nodes/ChatBox/tools/WebsiteInfoScraperTool.ts @@ -2,43 +2,51 @@ import { Networking } from '../../../../Network'; import { BaseTool } from './BaseTool'; import { v4 as uuidv4 } from 'uuid'; -export class WebsiteInfoScraperTool extends BaseTool<{ url: string }> { +export class WebsiteInfoScraperTool extends BaseTool<{ url: string | string[] }> { private _addLinkedUrlDoc: (url: string, id: string) => void; constructor(addLinkedUrlDoc: (url: string, id: string) => void) { super( 'websiteInfoScraper', - 'Scrape detailed information from a specific website identified as the most relevant', + 'Scrape detailed information from specific websites identified as relevant to the user query', { url: { type: 'string', - description: 'The URL of the website to scrape', - required: true, + description: 'The URL(s) of the website(s) to scrape', + required: 'true', + max_inputs: '3', }, }, - 'Provide the URL of the website that you have identified as the most relevant from the previous search. This tool will scrape and process detailed information from that specific website. It will also create a document from the scraped content for future reference.', - 'Returns the full HTML content from the provided URL and creates a document from the content for further analysis.' + 'Provide up to 3 URLs of websites that you have identified as the most relevant from the previous search. This tool will provide screenshots of those specific websites. It will also create a document from the scraped content for future reference. When providing a response to the user, ideally reference as many of the websites as possible in order to provide a well grounded result.', + 'Returns the full content of the webpages as images for analysis.' ); this._addLinkedUrlDoc = addLinkedUrlDoc; } - async execute(args: { url: string }): Promise<any> { - try { - const { website_image_base64 } = await Networking.PostToServer('/scrapeWebsite', { url: args.url }); - const id = uuidv4(); - this._addLinkedUrlDoc(args.url, id); - return [ - { type: 'text', text: `<chunk chunk_id=${id} chunk_type=url> ` }, - { - type: 'image_url', - image_url: { - url: `data:image/jpeg;base64,${website_image_base64}`, + async execute(args: { url: string | string[] }): Promise<any> { + const urls = Array.isArray(args.url) ? args.url : [args.url]; + const results = []; + + for (const url of urls) { + try { + const { website_image_base64 } = await Networking.PostToServer('/scrapeWebsite', { url }); + const id = uuidv4(); + this._addLinkedUrlDoc(url, id); + results.push( + { type: 'text', text: `<chunk chunk_id=${id} chunk_type=url> ` }, + { + type: 'image_url', + image_url: { + url: `data:image/jpeg;base64,${website_image_base64}`, + }, }, - }, - { type: 'text', text: `</chunk>\n` }, - ]; - } catch (error) { - return [{ type: 'text', text: 'An error occurred while scraping the website.' }]; + { type: 'text', text: `</chunk>\n` } + ); + } catch (error) { + results.push({ type: 'text', text: `An error occurred while scraping the website: ${url}` }); + } } + + return results; } } diff --git a/src/server/ApiManagers/AssistantManager.ts b/src/server/ApiManagers/AssistantManager.ts index 9b85dbbe8..afaeaf961 100644 --- a/src/server/ApiManagers/AssistantManager.ts +++ b/src/server/ApiManagers/AssistantManager.ts @@ -90,13 +90,14 @@ export default class AssistantManager extends ApiManager { method: Method.POST, subscription: '/getWebSearchResults', secureHandler: async ({ req, res }) => { - const { query } = req.body; + const { query, max_results } = req.body; try { const response = await customsearch.cse.list({ q: query, cx: process.env._CLIENT_GOOGLE_SEARCH_ENGINE_ID, key: process.env._CLIENT_GOOGLE_API_KEY, safe: 'active', + num: max_results, }); const results = |