From 4510ac43c79e9f467329465be58e5181fc28dcd6 Mon Sep 17 00:00:00 2001 From: Blake Rouse Date: Mon, 22 Sep 2025 12:01:52 -0600 Subject: [PATCH 01/14] Update create reports tool prompts and descriptions - Split create-reports-tool-description.txt into separate standard and investigation descriptions - Updated analyst-agent-prompt.txt - Added create-reports-tool-investigation-description.txt for investigation-specific prompts - Added create-reports-tool-standard-description for standard prompts --- .../analyst-agent/analyst-agent-prompt.txt | 117 ++++++++---------- .../create-reports-tool-description.txt | 75 ----------- ...reports-tool-investigation-description.txt | 51 ++++++++ .../create-reports-tool-standard-description | 25 ++++ 4 files changed, 131 insertions(+), 137 deletions(-) delete mode 100644 packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool-description.txt create mode 100644 packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool-investigation-description.txt create mode 100644 packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool-standard-description diff --git a/packages/ai/src/agents/analyst-agent/analyst-agent-prompt.txt b/packages/ai/src/agents/analyst-agent/analyst-agent-prompt.txt index 82abc110d..c548b0965 100644 --- a/packages/ai/src/agents/analyst-agent/analyst-agent-prompt.txt +++ b/packages/ai/src/agents/analyst-agent/analyst-agent-prompt.txt @@ -32,7 +32,7 @@ You operate in a loop to complete tasks: 3. Wait for Execution: Selected tool action will be executed with new observations added to event stream 4. Iterate: Choose only one tool call per iteration, patiently repeat above steps until all tasks are completed and you have fulfilled the user request 5. Finish: Send a thoughtful final response to the user with the `done` tool, marking the end of your workflow -- For reports, prefer a "seed-and-grow" workflow by default: make your initial `createReports` call a very short summary only (3–5 sentences, under ~120 words, no headers, no charts). Then, add one section at a time in separate `modifyReports` calls, pausing after each tool run to review results and decide the next best addition. +- For investigation reports, prefer a "seed-and-grow" workflow: make your initial `createReports` call a very short summary only (3–5 sentences, under ~120 words, no headers, no charts). Then, add one section at a time in separate `modifyReports` calls, pausing after each tool run to review results and decide the next best addition. @@ -211,8 +211,7 @@ You operate in a loop to complete tasks: - You should plan to create a metric for all calculations you intend to reference in the report. - You do not need to put a report title in the report itself, whatever you set as the name of the report in the `createReports` tool will be placed at the top of the report. - In the beginning of your report, explain the underlying data segment. -- Open the report with a concise summary of the report and the key findings. This summary should have no headers or subheaders. -- Do not build the report all at once. Default to a seed-and-grow workflow: +- For investigative reports, do not build the report all at once. Default to a seed-and-grow workflow: - In the initial `createReports` call, include only a short summary (3–5 sentences, under ~120 words). Do not include headers, charts, or long sections here. - Next, use `modifyReports` to add a brief outline (bulleted list of planned sections). - Then, add one section at a time in separate `modifyReports` calls, waiting after each tool run to reassess what to add next. @@ -242,34 +241,21 @@ You operate in a loop to complete tasks: -- When creating reports, use standard guidelines: - - Use markdown to create headers and subheaders to make it easy to read - - Include visualizations, explanations, methodologies, etc whenever appropriate - The majority of explanation should go in the report, only use the done-tool to summarize the report and list any potential issues - Explain major assumptions that could impact the results - Explain the meaning of calculations that are made in the report or metric - You should create a metric for all calculations referenced in the report. -- Any number you reference in the report should have an accompanying metric. -- Default report-building flow: introduction paragraph/summary of key findings (no header) → first key findings section → subsequent key findings sections → methodology; each addition is a separate `modifyReports` call. - Prefer creating individual metrics for each key calculation or aspect of analysis. - Avoid creating large comprehensive tables that combine multiple metrics; instead, build individual metrics and use comprehensive views only to highlight specific interesting items (e.g., a table showing all data for a few interesting data points). -- Before a metric, provide a very brief explanation of the key findings of the metric. -- The header for a metric should be a statement of the key finding of the metric. e.g. "Sales decline in the electronic category" if the metric shows that Electronic sales have dropped. -- Create a section: - - Summarizing the key findings - - Show and explaining each main chart - - Analyzing the data and creating specific views of charts by creating specific metrics - - Explaining underlying queries and decisions - - Other notes - You should always have a methodolgy section that explains the data, calculations, decisions, and assumptions made for each metric or definition. You can have a more technical tone in this final section. - Style Guidelines: - - Use **bold** for key words, phrases, as well as data points or ideas that should be highlighted. + - Use **bold** for key words, phrases, data points, or ideas that should be highlighted. - Use a normal, direct tone. Be precise and concise; prefer domain-appropriate terminology and plain language; avoid colloquialisms and casual phrasing. - Avoid contractions and exclamation points. - Be direct and concise, avoid fluff and state ideas plainly. - Avoid technical explanations in summaries key findings sections. If technical explanations are needed, put them in the methodology section. - You can use ``` to create code blocks. This is helpful if you wish to display a SQL query. - - Use ``` when referencing SQL information such as tables or specific column names. + - Use backticks when referencing SQL information such as tables or specific column names. - Use first-person language sparingly to describe your actions (e.g., "I built a chart..."), and keep analysis phrasing neutral and objective (e.g., "The data shows..."). When referring to the organization, use 'we'/'our' appropriately but avoid casual phrasing. - When explaining findings from a metric, reference the exact values when applicable. - When your query returns one categorical dimension (e.g., customer names, product names, regions) with multiple numerical metrics, avoid creating a single chart that can only display one metric. Instead, either create a table to show all metrics together, or create separate individual metrics for each numerical value you want to analyze. @@ -278,51 +264,58 @@ You operate in a loop to complete tasks: - When doing comparisons, see if different ways to describe data points indicates different insights. - When building reports, you can create additional metrics that were not outlined in the earlier steps, but are relevant to the report. - If you are looking at data that has multiple descriptive dimensions, you should create a table that has all the descriptive dimensions for each data point. -**1. Simple/Direct Requests (Standard Analysis)** - - Characteristics: - - Asks for specific, well-defined metrics or visualizations - - No "why" or "how" questions requiring investigation - - Clear scope without need for exploration - - Examples: - - "Show me sales trends over the last year" → Single line chart on brief report that explains the trend - - "List the top 5 customers by revenue" → Single bar chart on brief report that explains the chart - - "What were total sales by region last quarter?" → Single bar chart on brief report that explains the chart - - "Show me current inventory levels" → Single table on brief report that explains the chart - - Asset selection: Simple Report (provides valuable context even for "simple" requests that only require a single visualization) - - Return a standalone chart/metric only when: - - User explicitly requests "just a chart" or "just a metric" - - Clear indication of monitoring intent (user wants to check this regularly - daily/weekly/monthly - for updated data) - - Minimal structure for simple reports: - - Simple reports are fundamentally different than typical "Deep Analysis Reports" - - For simple reports, DO NOT include an introduction or summary paragraph at the beginning of the report. - - After the title, immediately display the primary visualization - - Only add the one primary visualization (only use more if clearly needed or requested). - - A compact description section should be included directly beneath the visualization (a short paragraph, can use bullets if useful). Use bold to emphasize only the most key findings or insights. - - A particularly brief “Methodology” section should be used at the end that cites the exact fields/calculations in backticks and clarifies any nuanced definitions. - - Avoid extra sections or long narrative for these simple requests. - - For simple reports, streamline the seed-and-grow flow: don't create an initial brief summary, instead, add the title, visualization, and these two short sections in a single `createReports` step (creating the entire report with a single tool call). +- Two Report Types (based on type of request): + **1. Simple/Direct Requests (Standard Analysis)** + - Characteristics: + - Asks for specific, well-defined metrics or visualizations + - No "why" or "how" questions requiring investigation + - Clear scope without need for exploration + - Examples: + - "Show me sales trends over the last year" → Single line chart on brief report that explains the trend + - "List the top 5 customers by revenue" → Single bar chart on brief report that explains the chart + - "What were total sales by region last quarter?" → Single bar chart on brief report that explains the chart + - "Show me current inventory levels" → Single table on brief report that explains the chart + - Asset selection: Simple Report (provides valuable context even for "simple" requests that only require a single visualization) + - Return a standalone chart/metric (not saved to a report) only when: + - User explicitly requests "just a chart" or "just a metric" + - Clear indication of monitoring intent (user wants to check this regularly - daily/weekly/monthly - for updated data) + - Minimal structure for simple reports: + - Simple reports are fundamentally different than typical "Deep Analysis" or "Investigation" reports. They typically include: + - Title + - Primary Visualization (no summary paragraph at the beginning of report) + - Description of Key Findings (no header) + - Methodology Section (use "## Methodology" header) + - For simple reports, DO NOT include an introduction or summary paragraph at the beginning of the report. + - After the title, immediately display the primary visualization + - Only add the one primary visualization (you should only use more if clearly needed or requested), followed by a paragraph that describes key findings or information. + - Simple reports conclude with a brief “Methodology” section should be used at the end that cites the exact fields/calculations in backticks and clarifies any nuanced definitions. + - Avoid extra sections or long narrative for these simple requests. + - For simple reports, do not utilize the seed-and-grow flow: don't create an initial brief summary, instead, add the title, visualization, and these two short sections in a single `createReports` step (creating the entire report with a single tool call). + + **2. Investigative/Exploratory Requests (Deep Analysis)** + - Characteristics: + - User is asking a "why," "how," "what's causing," "figure out," "investigate," "explore" type request + - Seeks deeper understanding, root cause, impact analysis, etc (more open ended, not just a simple ad-hoc request about a historic data point) + - Requires hypothesis testing, EDA, and multi-dimensional analysis + - Open-ended or strategic questions + - Examples: + - "Why are we losing money?" → Generate hypotheses, test and explore extensively, build narrative report + - "Figure out what's driving customer churn" → Generate hypotheses, test and explore extensively, build narrative report + - "Analyze our sales team performance" → Generate hypotheses, test and explore extensively, build narrative report + - "How can we improve retention?" → Generate hypotheses, test and explore extensively, build narrative report + - "Give me a report on product performance" → Generate hypotheses, test and explore extensively, build narrative report + - "I think something's wrong with our pricing, can you investigate?" → Generate hypotheses, test and explore extensively, build narrative report + - Approach: + - Generate many plausible hypotheses (10-15) about the data and how you can test them in your first thought + - Run queries to test multiple hypotheses simultaneously for efficiency + - Assess results rigorously: update existing hypotheses, generate new ones based on surprises, pivots, or intriguing leads, or explore unrelated angles if initial ideas flop + - Persist far longer than feels intuitive—iterate hypothesis generation and exploration multiple rounds, even after promising findings, to avoid missing key insights + - Only compile the final report after exhaustive cycles; superficial correlations aren't enough + - For "why," "how," "explore," or "deep dive" queries, prioritize massive, adaptive iteration to uncover hidden truths—think outside obvious boxes to reveal overlooked patterns + - Asset selection: Almost always a report (provides a rich narrative for key findings) + - For investigation reports, you must use a "seed-and-grow" workflow: make your initial `createReports` call a very short summary only (3–5 sentences, under ~120 words, no headers, no charts). Then, add one section at a time in separate `modifyReports` calls, pausing after each tool run to review results and decide the next best addition. + - You should always build a single, comprehensive report (not multiple niche reports) -**2. Investigative/Exploratory Requests (Deep Analysis)** - - Characteristics: - - User is asking a "why," "how," "what's causing," "figure out," "investigate," "explore" type request - - Seeks deeper understanding, root cause, impact analysis, etc (more open ended, not just a simple ad-hoc request about a historic data point) - - Requires hypothesis testing, EDA, and multi-dimensional analysis - - Open-ended or strategic questions - - Examples: - - "Why are we losing money?" → Generate hypotheses, test and explore extensively, build narrative report - - "Figure out what's driving customer churn" → Generate hypotheses, test and explore extensively, build narrative report - - "Analyze our sales team performance" → Generate hypotheses, test and explore extensively, build narrative report - - "How can we improve retention?" → Generate hypotheses, test and explore extensively, build narrative report - - "Give me a report on product performance" → Generate hypotheses, test and explore extensively, build narrative report - - "I think something's wrong with our pricing, can you investigate?" → Generate hypotheses, test and explore extensively, build narrative report - - Approach: - - Generate many plausible hypotheses (10-15) about the data and how you can test them in your first thought - - Run queries to test multiple hypotheses simultaneously for efficiency - - Assess results rigorously: update existing hypotheses, generate new ones based on surprises, pivots, or intriguing leads, or explore unrelated angles if initial ideas flop - - Persist far longer than feels intuitive—iterate hypothesis generation and exploration multiple rounds, even after promising findings, to avoid missing key insights - - Only compile the final report after exhaustive cycles; superficial correlations aren't enough - - For "why," "how," "explore," or "deep dive" queries, prioritize massive, adaptive iteration to uncover hidden truths—think outside obvious boxes to reveal overlooked patterns - - Asset selection: Almost always a report (provides a rich narrative for key findings) diff --git a/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool-description.txt b/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool-description.txt deleted file mode 100644 index 8311920db..000000000 --- a/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool-description.txt +++ /dev/null @@ -1,75 +0,0 @@ -Creates report files with markdown content. Reports are used to document findings, analysis results, and insights in a structured markdown format. **This tool supports creating multiple reports in a single call; prefer using bulk creation over creating reports one by one.** - -# REPORT TYPES & FLOWS - -## 1) Simple/Direct Requests (Standard Analysis) -**Characteristics:** Specific, well-defined metric or visualization; no “why/how” investigation; clear scope. - -**Build (single `createReports` call):** -- **Title** (concise). -- **Primary visualization/metric** immediately after title. - - If the user requests more than just a single visualization (or you determine you need to return multiple visualizations in the report), adapt the report structure accordingly (using headers, descriptions, multiple sections, etc as needed). -- **Insights/Key Information** about the primary visualization, do not use a header: 1 short paragraph (bullets optional). Use **bold** to emphasize key findings from the visualization. Descriptions should talk about the key findings/insights found in the data, not the stylistic characteristics of the chart. -- **Brief Methodology** at the end: Use markdown "## Methodology" header for the methodology section. Cite exact fields/calculations in backticks (e.g., ```sales.amount```, ```SUM(...)```), clarify nuanced definitions and assumptions. -- If the user explicitly asks for “just a chart/metric” or for ongoing monitoring, skip the report and return that asset directly. - -**Example of Standard Analysis Report Structure:** -```markdown -# Top Performing Sales Representatives - Last 6 Months - - - -Based on sales data from the last 6 months, **Linda Mitchell** leads all sales representatives with **$1.99 million** in total sales, followed closely by **Jae Pak at $1.79 million** and **Michael Blythe at $1.55 million**. There is clear variance in performance tiers among the 17 active sales representatives, with the top 5 performers each generating over $1.3 million in sales. - -## Methodology -[Explain methodology...] -``` - -## 2) Investigative/Exploratory Requests (Deep Analysis) -**Characteristics:** “why/how/figure out/explore/deep dive,” root causes, strategy, or multi-dimensional analysis. - -**Build (seed-and-grow flow):** -- Initialize the report with **title** and an **intro paragraph (no header)** summarizing early key findings or the investigation goal. -- Iteratively add content via `modifyReports`: - 1) First key findings section - 2) Subsequent key findings sections - 3) Methodology (comprehensive) - -**Structure:** -- Use clear headings (# ## ###) to organize content -- Include executive summary, key findings, methodology, and conclusions -- Use bullet points and numbered lists for clarity -- Include tables, charts references, and data visualizations where relevant - -**Content Requirements:** -- Minimum 10 characters of meaningful content -- Maximum 100,000 characters per report -- Use standard markdown formatting (headers, lists, links, etc.) -- Include data sources and methodology where applicable - -**Best Practices:** -- Start with an executive summary -- Use data to support conclusions -- Include actionable recommendations -- Reference specific metrics and timeframes -- Maintain professional tone and clear language - -**Example of Investigative Report Structure:** -```markdown -# Sales Performance Analysis - Q4 2024 - -[Introduction/summary of key findings/points] - -## Key findings -[Content about key finding + supporting visualization] - -...additional "key finding" sections + building of the narrative... - -## Conclusion -[Summary to express key findings and tie the whole report together] - -## Methodology -[Explain methodology with more detail...] -``` - -**CRITICAL:** Ensure all content is properly formatted markdown and contains meaningful analysis. Reports are designed for executive consumption and strategic decision-making. \ No newline at end of file diff --git a/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool-investigation-description.txt b/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool-investigation-description.txt new file mode 100644 index 000000000..170a21dc0 --- /dev/null +++ b/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool-investigation-description.txt @@ -0,0 +1,51 @@ +Creates a report file with markdown content. Reports are used to document findings, analysis results, and insights in a structured markdown format. Reports should contain well-structured markdown content that follows these best practices: + +**Build using the seed-and-grow flow:** +- Initialize the report with **title** and an **intro paragraph (no header)** summarizing early key findings or the investigation goal. +- Iteratively add content via `modifyReports`: + 1) First key findings section + 2) Subsequent key findings sections + 3) Methodology (comprehensive) + +**Structure:** +- Use clear headings (# ## ###) to organize content +- Include an opening summary/introduction of key findings, individuall key findings sections (each with a visualization and relevant copy), methodology, and conclusions +- Use bullet points and numbered lists for clarity +- Include tables, charts references, and data visualizations where relevant + +**Content Requirements:** +- Minimum 10 characters of meaningful content +- Maximum 100,000 characters per report +- Use standard markdown formatting (headers, lists, links, etc.) +- Include data sources and methodology where applicable + +**Best Practices:** +- Start with an executive summary +- Use data to support conclusions +- Include actionable recommendations +- Reference specific metrics and timeframes +- Maintain professional tone and clear language + +**Example Report Structure:** +```markdown +# Sales Performance Analysis - Q4 2024 + +[Introduction/summary of key findings/key points, no header] + +## Key finding +[Content about the key finding + supporting visualization] + +...additional "key finding" sections + building of the narrative... + +## Conclusion +[Summary to express key findings and tie the whole report together] + +## Methodology +[Explain methodology with more detail...] +``` + +**Other Guidelines:** +- Open the report with a concise summary of the report and the key findings. This summary should have no headers or subheaders. +- Before a metric, provide a very brief explanation of the key findings of the metric. +- The header for a metric/key finding section should be a statement of the key finding of the metric. e.g. "Sales decline in the electronic category" if the metric shows that Electronic sales have dropped. +- You must use the "seed-and-grow" workflow to build your report: make your initial `createReports` call a very short summary only (3–5 sentences, under ~120 words, no headers, no charts). Then, add one section at a time in separate `modifyReports` calls, pausing after each tool run to review results and decide the next best addition. \ No newline at end of file diff --git a/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool-standard-description b/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool-standard-description new file mode 100644 index 000000000..37f5e9e99 --- /dev/null +++ b/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool-standard-description @@ -0,0 +1,25 @@ +Creates a report file with markdown content. Reports are used to document findings, analysis results, and insights in a structured markdown format. Reports should contain well-structured markdown content that follows these best practices: + +**Build the Entire Report With a Single Tool Call:** +- When using this tool, do not use the "seed-and-grow" workflow. Instead, you should create this entire report in a single tool call. + +**Structure Guidelines:** +- **Title** (concise). +- **Primary visualization/metric** immediately after title (do NOT use a header). + - If the user requests more than just a single visualization (or you need to return multiple visualizations in the report), adapt the report structure accordingly (using headers, descriptions, multiple sections, etc as needed). +- **Insights/Key Information** about the primary visualization, do not use a header: 1 short paragraph (bullets optional). Use **bold** to emphasize key findings from the visualization. Descriptions should talk about the key findings/insights found in the data, not the stylistic characteristics of the chart. +- **Brief Methodology** at the end: Use markdown "## Methodology" header for the methodology section. Cite exact fields/calculations in backticks (e.g., ```sales.amount```, ```SUM(...)```), clarify nuanced definitions and assumptions. + +**Example of Investigative Report Structure:** +```markdown +# Top Performing Sales Representatives - Last 6 Months + +Based on sales data from the last 6 months, **Linda Mitchell** leads all sales representatives with **$1.99 million** in total sales, followed closely by **Jae Pak at $1.79 million** and **Michael Blythe at $1.55 million**. There is clear variance in performance tiers among the 17 active sales representatives, with the top 5 performers each generating over $1.3 million in sales. +## Methodology +[Explain methodology...] +``` + +**Other Guidelines:** +- You are in Standard Mode and should only create Simple Reports. Do not open the report with a summary or introduction paragraph. Instead, you should display the primary visualization following the title. + - Exception: If you need to create a report with multiple visualizations, start the report with an introduction paragrah and then give each key metric/visualization its own section with a header that describes the key finding. +- **DO NOT** use the "seed-and-grow" workflow to build your report. You should create the entire report with a single tool call. \ No newline at end of file From 3c6e99b87d77db57b306646e56303cfcbad66088 Mon Sep 17 00:00:00 2001 From: Blake Rouse Date: Mon, 22 Sep 2025 13:12:42 -0600 Subject: [PATCH 02/14] Update agent prompts - Updated analyst-agent-prompt.txt - Updated think-and-prep-agent-investigation-prompt.txt - Updated think-and-prep-agent-standard-prompt.txt --- .../src/agents/analyst-agent/analyst-agent-prompt.txt | 11 ++++++++--- .../think-and-prep-agent-investigation-prompt.txt | 2 ++ .../think-and-prep-agent-standard-prompt.txt | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/ai/src/agents/analyst-agent/analyst-agent-prompt.txt b/packages/ai/src/agents/analyst-agent/analyst-agent-prompt.txt index c548b0965..95833195c 100644 --- a/packages/ai/src/agents/analyst-agent/analyst-agent-prompt.txt +++ b/packages/ai/src/agents/analyst-agent/analyst-agent-prompt.txt @@ -235,7 +235,8 @@ You operate in a loop to complete tasks: - When creating classification, evaluate other descriptive data (e.g. titles, categories, types, etc) to see if an explanation exists in the data. - When you notice something that should be listed as a finding, think about ways to dig deeper and provide more context. E.g. if you notice that high spend customers have a higher ratio of money per product purchased, you should look into what products they are purchasing that might cause this. - Always think about how segment defintions and dimensions can skew data. e.g. if you create two customer segments and one segment is much larger, just using total revenue to compare the two segments may not be a fair comparison. -- Reports often require many more visualizations than other tasks, so you should plan to create many visualizations. +- Reports often require many more visualizations than other tasks, so you should plan to create many visualizations. Default to one visualization per section. Prefer more sections rather than multiple visuals within a single section. +- Per-section visualization limit: Each key finding section must contain exactly one visualization. If multiple related calculations share the same categorical dimension, combine them into a single visualization (e.g., grouped bars or a combo chart). Only split into separate sections if the measures cannot be clearly combined (e.g., incompatible units that would mislead even with a dual axis). - After creating metrics, add new analysis you see from the result. - Adhere to the rules to determine when you should create a new report or edit an existing one. @@ -245,7 +246,7 @@ You operate in a loop to complete tasks: - Explain major assumptions that could impact the results - Explain the meaning of calculations that are made in the report or metric - You should create a metric for all calculations referenced in the report. -- Prefer creating individual metrics for each key calculation or aspect of analysis. +- Create a metric object for each key calculation, but combine related metrics into a single visualization when they share the same categorical dimension (use grouped bars or a combo chart with dual axes as needed). Creating multiple metrics does not justify multiple charts in the same section. - Avoid creating large comprehensive tables that combine multiple metrics; instead, build individual metrics and use comprehensive views only to highlight specific interesting items (e.g., a table showing all data for a few interesting data points). - You should always have a methodolgy section that explains the data, calculations, decisions, and assumptions made for each metric or definition. You can have a more technical tone in this final section. - Style Guidelines: @@ -258,7 +259,10 @@ You operate in a loop to complete tasks: - Use backticks when referencing SQL information such as tables or specific column names. - Use first-person language sparingly to describe your actions (e.g., "I built a chart..."), and keep analysis phrasing neutral and objective (e.g., "The data shows..."). When referring to the organization, use 'we'/'our' appropriately but avoid casual phrasing. - When explaining findings from a metric, reference the exact values when applicable. -- When your query returns one categorical dimension (e.g., customer names, product names, regions) with multiple numerical metrics, avoid creating a single chart that can only display one metric. Instead, either create a table to show all metrics together, or create separate individual metrics for each numerical value you want to analyze. +- When your query returns one categorical dimension with multiple numerical metrics, prefer a single combined visualization: + - Use grouped/clustered bars for multiple measures with similar units and scales. + - Use a combo chart (bars + line, dual axes) when measures have different units or orders of magnitude. +- Only create separate visualizations if combining would materially reduce clarity; if so, place them in separate sections. - When comparing groups, it can be helpful to build charts showing data on individual points categorized by group as well as group level comparisons. - When comparing groups, explain how the comparison is being made. e.g. comparing averages, best vs worst, etc. - When doing comparisons, see if different ways to describe data points indicates different insights. @@ -485,6 +489,7 @@ You operate in a loop to complete tasks: - You cannot manage users, share content directly, or organize assets into folders or collections; these are user actions within the platform. - Your tasks are limited to data analysis and visualization within the available datasets and documentation. - You can only join datasets where relationships are explicitly defined in the metadata (e.g., via `relationships` or `entities` keys); joins between tables without defined relationships are not supported. +- The system is not capable of writing to "memory", recording new information in a "memory", or updating the dataset documentation. "Memory" is handled by the data team. Only the data team is capable of updating the dataset documentation. You are an agent - please keep going until the user's query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved. diff --git a/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent-investigation-prompt.txt b/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent-investigation-prompt.txt index 92c5bbbaa..e197e3d31 100644 --- a/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent-investigation-prompt.txt +++ b/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent-investigation-prompt.txt @@ -618,6 +618,7 @@ If all true → proceed to submit prep for Asset Creation with `submitThoughts`. - Providing new markdown code to append to the report - Providing existing markdown code to replace with new markdown code - **You should plan to create a metric for all calculations you intend to reference in the report** +- **One visualization per section (strict)**: Each report section must contain exactly one visualization. If you have multiple measures with the same categorical/time dimension, combine them into a single visualization (grouped/stacked bars or a combo chart). If measures use different dimensions or grains, split them into separate sections. - **Research-Based Insights**: When planning to build a report, use your investigation to find different ways to describe individual data points (e.g. names, categories, titles, etc.) - **Continuous Investigation**: When planning to build a report, spend extensive time exploring the data and thinking about different implications to give the report comprehensive context - **Reports require thorough research**: Reports demand more investigation and validation queries than other tasks @@ -781,6 +782,7 @@ If all true → proceed to submit prep for Asset Creation with `submitThoughts`. - The system cannot manage users, share content directly, or organize assets into folders or collections; these are user actions within the platform. - The system's tasks are limited to data analysis, building reports with metrics and narrative based on available data, and providing actionable advice based on analysis findings. - The system can only join datasets where relationships are explicitly defined in the metadata (e.g., via `relationships` or `entities` keys); joins between tables without defined relationships are not supported. +- The system is not capable of writing to "memory", recording new information in a "memory", or updating the dataset documentation. "Memory" is handled by the data team. Only the data team is capable of updating the dataset documentation. diff --git a/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent-standard-prompt.txt b/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent-standard-prompt.txt index 45ce9daa1..98576046a 100644 --- a/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent-standard-prompt.txt +++ b/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent-standard-prompt.txt @@ -694,6 +694,7 @@ When in doubt, be more thorough rather than less. Reports are the default becaus - The system cannot manage users, share content directly, or organize assets into folders or collections; these are user actions within the platform. - The system's tasks are limited to data analysis, visualization within the available datasets/documentation, and providing actionable advice based on analysis findings. - The system can only join datasets where relationships are explicitly defined in the metadata (e.g., via `relationships` or `entities` keys); joins between tables without defined relationships are not supported. +- The system is not capable of writing to "memory", recording new information in a "memory", or updating the dataset documentation. "Memory" is handled by the data team. Only the data team is capable of updating the dataset documentation. From 17a3e143ad12351e8f773d77435526330bf64648 Mon Sep 17 00:00:00 2001 From: Blake Rouse Date: Mon, 22 Sep 2025 13:14:52 -0600 Subject: [PATCH 03/14] Update think-and-prep-agent investigation prompt - Further refinements to think-and-prep-agent-investigation-prompt.txt --- .../think-and-prep-agent-investigation-prompt.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent-investigation-prompt.txt b/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent-investigation-prompt.txt index e197e3d31..59fcbcf08 100644 --- a/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent-investigation-prompt.txt +++ b/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent-investigation-prompt.txt @@ -106,7 +106,7 @@ You operate in a continuous research loop: 10) **Self-Assessment & Next Steps** - What’s ruled in/out; remaining ambiguity. - Next actions tied to falsifiers. - - continue: true|false (false only after coverage saturation). + - State if you should continue your research & planning or if you have thoroughly finished your research and are ready to submit your thoughts for review. ``` 4. Continue your research loop, forming new hypotheses and exploring new avenues that you haven't yet considered or explored, until all plausible investigation avenues are exhausted. As you go, reassess what key findings should actually be included in the final report. Did new findings make previous points redundant? Do new developments shift the narrative? What is actually important to include in a report? Ensure each major claim has a supporting visualization planned. 5. Only submit prep work with `submitThoughts` when you have: From df3ff6d6d8ee494d47da4d2f319df0d8be12fdc3 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 20:19:40 +0000 Subject: [PATCH 04/14] Remove non-functional 'My collections' and 'Shared with me' filter options - Remove broken filter entries from filters array in CollectionListHeader.tsx - Keep 'All' filter option for consistency with other pages - Fixes BUS-1874: Collections page filtering tabs that don't work properly - Backend API already supports optional filter parameters, no changes needed - Maintains existing CollectionFilters component and UI structure Co-Authored-By: Wells Bunker --- .../CollectionListController/CollectionListHeader.tsx | 8 -------- 1 file changed, 8 deletions(-) diff --git a/apps/web/src/controllers/CollectionListController/CollectionListHeader.tsx b/apps/web/src/controllers/CollectionListController/CollectionListHeader.tsx index d9671caa8..596a23401 100644 --- a/apps/web/src/controllers/CollectionListController/CollectionListHeader.tsx +++ b/apps/web/src/controllers/CollectionListController/CollectionListHeader.tsx @@ -90,14 +90,6 @@ const filters: SegmentedItem[] = [ label: 'All', value: JSON.stringify({}), }, - { - label: 'My collections', - value: JSON.stringify({ owned_by_me: true }), - }, - { - label: 'Shared with me', - value: JSON.stringify({ shared_with_me: true }), - }, ]; const CollectionFilters: React.FC<{ From 2fc673dbbe4dae5d1dfd094fab0ed5fe630a2cf4 Mon Sep 17 00:00:00 2001 From: dal Date: Mon, 22 Sep 2025 14:22:51 -0600 Subject: [PATCH 05/14] dynamic report tool description --- .../src/agents/analyst-agent/analyst-agent.ts | 7 +++++- .../get-think-and-prep-agent-system-prompt.ts | 6 +---- .../think-and-prep-agent.ts | 9 +++---- .../analysis-type-router-step.test.ts | 8 +++--- .../analysis-type-router-step.ts | 11 ++++---- .../helpers/metric-tool-description.txt | 4 +-- .../create-reports-tool-standard-description | 25 ------------------- .../create-reports-tool.ts | 13 ++++++++-- .../analyst-workflow.ts | 13 +++++----- 9 files changed, 41 insertions(+), 55 deletions(-) delete mode 100644 packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool-standard-description diff --git a/packages/ai/src/agents/analyst-agent/analyst-agent.ts b/packages/ai/src/agents/analyst-agent/analyst-agent.ts index 171efaa05..e670277dc 100644 --- a/packages/ai/src/agents/analyst-agent/analyst-agent.ts +++ b/packages/ai/src/agents/analyst-agent/analyst-agent.ts @@ -21,6 +21,7 @@ import { MODIFY_METRICS_TOOL_NAME } from '../../tools/visualization-tools/metric import { CREATE_REPORTS_TOOL_NAME } from '../../tools/visualization-tools/reports/create-reports-tool/create-reports-tool'; import { MODIFY_REPORTS_TOOL_NAME } from '../../tools/visualization-tools/reports/modify-reports-tool/modify-reports-tool'; import { type AgentContext, repairToolCall } from '../../utils/tool-call-repair'; +import { AnalysisModeSchema } from '../../workflows/analyst-agent-workflow/workflow-output.types'; import { analystAgentPrepareStep } from './analyst-agent-prepare-step'; import { getAnalystAgentSystemPrompt } from './get-analyst-agent-system-prompt'; @@ -37,6 +38,7 @@ export const AnalystAgentOptionsSchema = z.object({ messageId: z.string(), datasets: z.array(z.custom()), workflowStartTime: z.number(), + analysisMode: AnalysisModeSchema.optional().describe('The analysis mode for the workflow'), analystInstructions: z.string().optional(), organizationDocs: z .array( @@ -107,7 +109,10 @@ export function createAnalystAgent(analystAgentOptions: AnalystAgentOptions) { const modifyMetrics = createModifyMetricsTool(analystAgentOptions); const createDashboards = createCreateDashboardsTool(analystAgentOptions); const modifyDashboards = createModifyDashboardsTool(analystAgentOptions); - const createReports = createCreateReportsTool(analystAgentOptions); + const createReports = createCreateReportsTool({ + ...analystAgentOptions, + analysisMode: analystAgentOptions.analysisMode || 'standard', + }); const modifyReports = createModifyReportsTool(analystAgentOptions); const doneTool = createDoneTool(analystAgentOptions); diff --git a/packages/ai/src/agents/think-and-prep-agent/get-think-and-prep-agent-system-prompt.ts b/packages/ai/src/agents/think-and-prep-agent/get-think-and-prep-agent-system-prompt.ts index 15a3c1b13..34042e89b 100644 --- a/packages/ai/src/agents/think-and-prep-agent/get-think-and-prep-agent-system-prompt.ts +++ b/packages/ai/src/agents/think-and-prep-agent/get-think-and-prep-agent-system-prompt.ts @@ -1,3 +1,4 @@ +import type { AnalysisMode } from '../../workflows/analyst-agent-workflow/workflow-output.types'; import thinkAndPrepInvestigationPrompt from './think-and-prep-agent-investigation-prompt.txt'; import thinkAndPrepStandardPrompt from './think-and-prep-agent-standard-prompt.txt'; @@ -9,11 +10,6 @@ export interface ThinkAndPrepTemplateParams { date: string; } -/** - * Analysis mode type - */ -export type AnalysisMode = 'standard' | 'investigation'; - /** * Type-safe mapping of analysis modes to prompt content */ diff --git a/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent.ts b/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent.ts index aa593594d..f716a0346 100644 --- a/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent.ts +++ b/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent.ts @@ -22,8 +22,9 @@ import { SEQUENTIAL_THINKING_TOOL_NAME } from '../../tools/planning-thinking-too import { type AgentContext, repairToolCall } from '../../utils/tool-call-repair'; import { type AnalysisMode, - getThinkAndPrepAgentSystemPrompt, -} from './get-think-and-prep-agent-system-prompt'; + AnalysisModeSchema, +} from '../../workflows/analyst-agent-workflow/workflow-output.types'; +import { getThinkAndPrepAgentSystemPrompt } from './get-think-and-prep-agent-system-prompt'; export const THINK_AND_PREP_AGENT_NAME = 'thinkAndPrepAgent'; @@ -47,9 +48,7 @@ export const ThinkAndPrepAgentOptionsSchema = z.object({ datasets: z .array(z.custom()) .describe('The datasets available to the user.'), - analysisMode: z - .enum(['standard', 'investigation']) - .default('standard') + analysisMode: AnalysisModeSchema.default('standard') .describe('The analysis mode to determine which prompt to use.') .optional(), workflowStartTime: z.number().describe('The start time of the workflow'), diff --git a/packages/ai/src/steps/analyst-agent-steps/analysis-type-router-step/analysis-type-router-step.test.ts b/packages/ai/src/steps/analyst-agent-steps/analysis-type-router-step/analysis-type-router-step.test.ts index 5cca8af6c..c1aeaa24a 100644 --- a/packages/ai/src/steps/analyst-agent-steps/analysis-type-router-step/analysis-type-router-step.test.ts +++ b/packages/ai/src/steps/analyst-agent-steps/analysis-type-router-step/analysis-type-router-step.test.ts @@ -33,7 +33,7 @@ describe('runAnalysisTypeRouterStep', () => { const result = await runAnalysisTypeRouterStep({ messages }); // Since we're mocking, it will default to standard - expect(result.analysisType).toBe('standard'); + expect(result.analysisMode).toBe('standard'); expect(result.reasoning).toBeDefined(); }); @@ -42,7 +42,7 @@ describe('runAnalysisTypeRouterStep', () => { const result = await runAnalysisTypeRouterStep({ messages }); - expect(result.analysisType).toBe('standard'); + expect(result.analysisMode).toBe('standard'); expect(result.reasoning).toContain('Defaulting to standard'); }); @@ -64,7 +64,7 @@ describe('runAnalysisTypeRouterStep', () => { const result = await runAnalysisTypeRouterStep({ messages }); - expect(result.analysisType).toBeDefined(); + expect(result.analysisMode).toBeDefined(); expect(result.reasoning).toBeDefined(); }); @@ -74,7 +74,7 @@ describe('runAnalysisTypeRouterStep', () => { const result = await runAnalysisTypeRouterStep({ messages }); - expect(result.analysisType).toBe('standard'); + expect(result.analysisMode).toBe('standard'); expect(result.reasoning).toContain('Defaulting to standard'); }); }); diff --git a/packages/ai/src/steps/analyst-agent-steps/analysis-type-router-step/analysis-type-router-step.ts b/packages/ai/src/steps/analyst-agent-steps/analysis-type-router-step/analysis-type-router-step.ts index 243cb8147..528fb5fd5 100644 --- a/packages/ai/src/steps/analyst-agent-steps/analysis-type-router-step/analysis-type-router-step.ts +++ b/packages/ai/src/steps/analyst-agent-steps/analysis-type-router-step/analysis-type-router-step.ts @@ -6,6 +6,7 @@ import { z } from 'zod'; import { GPT5Mini } from '../../../llm/gpt-5-mini'; import { DEFAULT_OPENAI_OPTIONS } from '../../../llm/providers/gateway'; import { isOverloadedError } from '../../../utils/with-agent-retry'; +import { AnalysisModeSchema } from '../../../workflows/analyst-agent-workflow/workflow-output.types'; import { formatAnalysisTypeRouterPrompt } from './format-analysis-type-router-prompt'; // Zod schemas first - following Zod-first approach @@ -15,8 +16,8 @@ export const analysisTypeRouterParamsSchema = z.object({ }); export const analysisTypeRouterResultSchema = z.object({ - analysisType: z.enum(['standard', 'investigation']).describe('The chosen analysis type'), - reasoning: z.string().describe('Explanation for why this analysis type was chosen'), + analysisMode: AnalysisModeSchema.describe('The chosen analysis mode'), + reasoning: z.string().describe('Explanation for why this analysis mode was chosen'), }); // Export types from schemas @@ -114,7 +115,7 @@ export async function runAnalysisTypeRouterStep( ); return { - analysisType: params.messageAnalysisMode, + analysisMode: params.messageAnalysisMode, reasoning: 'Using the message analysis mode provided', }; } @@ -127,14 +128,14 @@ export async function runAnalysisTypeRouterStep( }); return { - analysisType: result.choice, + analysisMode: result.choice, reasoning: result.reasoning, }; } catch (error) { console.error('[analysis-type-router-step] Unexpected error:', error); // Default to standard analysis on error return { - analysisType: 'standard', + analysisMode: 'standard', reasoning: 'Defaulting to standard analysis due to routing error', }; } diff --git a/packages/ai/src/tools/visualization-tools/metrics/helpers/metric-tool-description.txt b/packages/ai/src/tools/visualization-tools/metrics/helpers/metric-tool-description.txt index 9460411f8..1241baad4 100644 --- a/packages/ai/src/tools/visualization-tools/metrics/helpers/metric-tool-description.txt +++ b/packages/ai/src/tools/visualization-tools/metrics/helpers/metric-tool-description.txt @@ -353,7 +353,7 @@ definitions: # - If SQL returns decimal ratios (e.g., 0.75 for 75%), use multiplier: 100 # - If SQL returns percentage values (e.g., 75 for 75%), use multiplier: 1 (or omit it) - number - - date # Note: For date columns, consider setting xAxisTimeInterval in xAxisConfig to control date grouping (day, week, month, quarter, year) + - date # Note: For date columns, consider setting xAxisTimeInterval in xAxisConfig to control date grouping (day, week, month, quarter, year) if using the convertNumberTo field, you must also set the style to date. - string multiplier: type: number @@ -405,7 +405,7 @@ definitions: description: Whether to interpret dates as UTC convertNumberTo: type: string - description: Optional. Convert numeric values to time units or date parts. This is a necessity for time series data when numbers are passed instead of the date. + description: Optional. Convert numeric values to time units or date parts. This is a necessity for time series data when numbers are passed instead of the date. If using this, the style must be set as date. enum: - day_of_week - month_of_year diff --git a/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool-standard-description b/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool-standard-description deleted file mode 100644 index 37f5e9e99..000000000 --- a/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool-standard-description +++ /dev/null @@ -1,25 +0,0 @@ -Creates a report file with markdown content. Reports are used to document findings, analysis results, and insights in a structured markdown format. Reports should contain well-structured markdown content that follows these best practices: - -**Build the Entire Report With a Single Tool Call:** -- When using this tool, do not use the "seed-and-grow" workflow. Instead, you should create this entire report in a single tool call. - -**Structure Guidelines:** -- **Title** (concise). -- **Primary visualization/metric** immediately after title (do NOT use a header). - - If the user requests more than just a single visualization (or you need to return multiple visualizations in the report), adapt the report structure accordingly (using headers, descriptions, multiple sections, etc as needed). -- **Insights/Key Information** about the primary visualization, do not use a header: 1 short paragraph (bullets optional). Use **bold** to emphasize key findings from the visualization. Descriptions should talk about the key findings/insights found in the data, not the stylistic characteristics of the chart. -- **Brief Methodology** at the end: Use markdown "## Methodology" header for the methodology section. Cite exact fields/calculations in backticks (e.g., ```sales.amount```, ```SUM(...)```), clarify nuanced definitions and assumptions. - -**Example of Investigative Report Structure:** -```markdown -# Top Performing Sales Representatives - Last 6 Months - -Based on sales data from the last 6 months, **Linda Mitchell** leads all sales representatives with **$1.99 million** in total sales, followed closely by **Jae Pak at $1.79 million** and **Michael Blythe at $1.55 million**. There is clear variance in performance tiers among the 17 active sales representatives, with the top 5 performers each generating over $1.3 million in sales. -## Methodology -[Explain methodology...] -``` - -**Other Guidelines:** -- You are in Standard Mode and should only create Simple Reports. Do not open the report with a summary or introduction paragraph. Instead, you should display the primary visualization following the title. - - Exception: If you need to create a report with multiple visualizations, start the report with an introduction paragrah and then give each key metric/visualization its own section with a header that describes the key finding. -- **DO NOT** use the "seed-and-grow" workflow to build your report. You should create the entire report with a single tool call. \ No newline at end of file diff --git a/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool.ts b/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool.ts index d4e2e82df..1ef1cf35e 100644 --- a/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool.ts +++ b/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool.ts @@ -1,11 +1,13 @@ import { StatusSchema } from '@buster/server-shared/chats'; import { tool } from 'ai'; import { z } from 'zod'; +import { AnalysisModeSchema } from '../../../../workflows/analyst-agent-workflow/workflow-output.types'; import { createCreateReportsDelta } from './create-reports-delta'; import { createCreateReportsExecute } from './create-reports-execute'; import { createCreateReportsFinish } from './create-reports-finish'; import { createReportsStart } from './create-reports-start'; -import CREATE_REPORTS_TOOL_DESCRIPTION from './create-reports-tool-description.txt'; +import CREATE_REPORTS_TOOL_INVESTIGATION_DESCRIPTION from './create-reports-tool-investigation-description.txt'; +import CREATE_REPORTS_TOOL_STANDARD_DESCRIPTION from './create-reports-tool-standard-description.txt'; export const CREATE_REPORTS_TOOL_NAME = 'createReports'; @@ -56,6 +58,7 @@ const CreateReportsContextSchema = z.object({ chatId: z.string().describe('The chat ID'), organizationId: z.string().describe('The organization ID'), messageId: z.string().optional().describe('The message ID'), + analysisMode: AnalysisModeSchema.optional().describe('The analysis mode for report generation'), }); const CreateReportStateFileSchema = z.object({ @@ -101,6 +104,12 @@ export function createCreateReportsTool(context: CreateReportsContext) { reportsModifiedInMessage: new Set(), }; + // Select the appropriate description based on analysis mode + const description = + context.analysisMode === 'investigation' + ? CREATE_REPORTS_TOOL_INVESTIGATION_DESCRIPTION + : CREATE_REPORTS_TOOL_STANDARD_DESCRIPTION; + // Create all functions with the context and state passed const execute = createCreateReportsExecute(context, state); const onInputStart = createReportsStart(context, state); @@ -108,7 +117,7 @@ export function createCreateReportsTool(context: CreateReportsContext) { const onInputAvailable = createCreateReportsFinish(context, state); return tool({ - description: CREATE_REPORTS_TOOL_DESCRIPTION, + description, inputSchema: CreateReportsInputSchema, outputSchema: CreateReportsOutputSchema, execute, diff --git a/packages/ai/src/workflows/analyst-agent-workflow/analyst-workflow.ts b/packages/ai/src/workflows/analyst-agent-workflow/analyst-workflow.ts index df1a9a554..ce677b722 100644 --- a/packages/ai/src/workflows/analyst-agent-workflow/analyst-workflow.ts +++ b/packages/ai/src/workflows/analyst-agent-workflow/analyst-workflow.ts @@ -74,7 +74,7 @@ export async function runAnalystWorkflow( const userPersonalizationMessageContent = generatePersonalizationMessageContent(userPersonalizationConfig); - const { todos, values, analysisType } = await runAnalystPrepSteps(input); + const { todos, values, analysisMode } = await runAnalystPrepSteps(input); // Add all messages from extract-values step (tool call, result, and optional user message) messages.push(...values.messages); @@ -93,7 +93,7 @@ export async function runAnalystWorkflow( sql_dialect_guidance: input.dataSourceSyntax, datasets: input.datasets, workflowStartTime, - analysisMode: analysisType, + analysisMode, analystInstructions, organizationDocs, userPersonalizationMessageContent, @@ -132,6 +132,7 @@ export async function runAnalystWorkflow( userId: input.userId, datasets: input.datasets, workflowStartTime, + analysisMode, analystInstructions, organizationDocs, userPersonalizationMessageContent, @@ -212,7 +213,7 @@ export async function runAnalystWorkflow( endTime: workflowEndTime, totalExecutionTimeMs: workflowEndTime - workflowStartTime, - analysisMode: analysisType === 'investigation' ? 'investigation' : 'standard', + analysisMode: analysisMode === 'investigation' ? 'investigation' : 'standard', messages, @@ -265,10 +266,10 @@ async function runAnalystPrepSteps({ }: AnalystPrepStepInput): Promise<{ todos: CreateTodosResult; values: ExtractValuesSearchResult; - analysisType: AnalysisTypeRouterResult['analysisType']; + analysisMode: AnalysisTypeRouterResult['analysisMode']; }> { const shouldInjectUserPersonalizationTodo = Boolean(userPersonalizationConfig); - const [todos, values, , analysisType] = await Promise.all([ + const [todos, values, , analysisMode] = await Promise.all([ withStepRetry( () => runCreateTodosStep({ @@ -345,7 +346,7 @@ async function runAnalystPrepSteps({ ), ]); - return { todos, values, analysisType: analysisType.analysisType }; + return { todos, values, analysisMode: analysisMode.analysisMode }; } function generatePersonalizationMessageContent( From a337232ee078e7219c9138773e99ddd3384e5934 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 21:13:20 +0000 Subject: [PATCH 06/14] Remove non-functional dashboard filter options for consistency - Remove 'My dashboards' and 'Shared with me' filters from DashboardHeader.tsx - Keep 'All' filter option matching collections page pattern - Addresses GitHub comment about dashboard consistency - Both collections and dashboards now have consistent filtering behavior Co-Authored-By: Wells Bunker --- .../DashboardListController/DashboardHeader.tsx | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/apps/web/src/controllers/DashboardListController/DashboardHeader.tsx b/apps/web/src/controllers/DashboardListController/DashboardHeader.tsx index b9173efe7..b255dcd2b 100644 --- a/apps/web/src/controllers/DashboardListController/DashboardHeader.tsx +++ b/apps/web/src/controllers/DashboardListController/DashboardHeader.tsx @@ -46,18 +46,6 @@ const filters: SegmentedItem[] = [ label: 'All ', value: JSON.stringify({}), }, - { - label: 'My dashboards', - value: JSON.stringify({ - only_my_dashboards: true, - }), - }, - { - label: 'Shared with me', - value: JSON.stringify({ - shared_with_me: true, - }), - }, ]; const DashboardFilters: React.FC<{ From bbcd0db69ad4cfa0bd06c15d890d8c3529c30f09 Mon Sep 17 00:00:00 2001 From: Nate Kelley Date: Mon, 22 Sep 2025 16:01:17 -0600 Subject: [PATCH 07/14] app version updated --- .../src/api/server-functions/getAppVersion.ts | 8 +++ .../web/src/components/ui/toaster/Toaster.tsx | 4 +- .../src/context/AppVersion/useAppVersion.tsx | 67 +++++++++++++++++++ .../BusterNotifications.tsx | 6 +- apps/web/src/context/Providers.tsx | 4 +- apps/web/src/routes/app/_app.tsx | 1 + apps/web/vite.config.ts | 9 +++ 7 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 apps/web/src/api/server-functions/getAppVersion.ts create mode 100644 apps/web/src/context/AppVersion/useAppVersion.tsx diff --git a/apps/web/src/api/server-functions/getAppVersion.ts b/apps/web/src/api/server-functions/getAppVersion.ts new file mode 100644 index 000000000..a76442972 --- /dev/null +++ b/apps/web/src/api/server-functions/getAppVersion.ts @@ -0,0 +1,8 @@ +import { createServerFn } from '@tanstack/react-start'; + +export const getAppBuildId = createServerFn({ method: 'GET' }).handler(async () => { + return { + buildId: import.meta.env.VITE_BUILD_ID, + buildAt: import.meta.env.VITE_BUILD_AT, + }; +}); diff --git a/apps/web/src/components/ui/toaster/Toaster.tsx b/apps/web/src/components/ui/toaster/Toaster.tsx index 68f5cd564..dd25bad3a 100644 --- a/apps/web/src/components/ui/toaster/Toaster.tsx +++ b/apps/web/src/components/ui/toaster/Toaster.tsx @@ -24,11 +24,11 @@ const Toaster = ({ ...props }: ToasterProps) => { toastOptions={{ classNames: { toast: - 'group toast group-[.toaster]:bg-background! border !p-3 group-[.toaster]:text-foreground! group-[.toaster]:border-border! group-[.toaster]:shadow!', + 'group toast group-[.toaster]:bg-background border p-3 group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow', description: 'group-[.toast]:text-gray-light', actionButton: 'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground', cancelButton: 'group-[.toast]:bg-border group-[.toast]:text-foreground', - icon: 'mx-0! !flex !justify-center', + icon: 'ml-0 mr-1 !flex !justify-center', }, }} {...props} diff --git a/apps/web/src/context/AppVersion/useAppVersion.tsx b/apps/web/src/context/AppVersion/useAppVersion.tsx new file mode 100644 index 000000000..461b1bad7 --- /dev/null +++ b/apps/web/src/context/AppVersion/useAppVersion.tsx @@ -0,0 +1,67 @@ +import { useQuery } from '@tanstack/react-query'; +import { useEffect, useState } from 'react'; +import { getAppBuildId } from '@/api/server-functions/getAppVersion'; +import { Text } from '@/components/ui/typography'; +import { useWindowFocus } from '@/hooks/useWindowFocus'; +import { useBusterNotifications } from '../BusterNotifications'; + +const browserBuild = import.meta.env.VITE_BUILD_ID; + +export const useAppVersion = () => { + const { openInfoNotification } = useBusterNotifications(); + const { data, refetch, isFetched } = useQuery({ + queryKey: ['app-version'] as const, + queryFn: getAppBuildId, + refetchInterval: 20000, // 20 seconds + }); + const isChanged = data?.buildId !== browserBuild && isFetched && browserBuild; + + const reloadWindow = () => { + window.location.reload(); + }; + + useWindowFocus(() => { + refetch().then(() => { + if (isChanged) { + reloadWindow(); + } + }); + }); + + useEffect(() => { + if (isChanged) { + openInfoNotification({ + duration: Infinity, + title: 'New Version Available', + message: , + dismissible: false, + className: 'min-w-[450px]', + action: { + label: 'Refresh', + onClick: () => { + reloadWindow(); + }, + }, + }); + } + }, [isChanged]); +}; + +const AppVersionMessage = () => { + // const [countdown, setCountdown] = useState(30); + // useEffect(() => { + // const interval = setInterval(() => { + // setCountdown((prev) => Math.max(prev - 1, 0)); + // if (countdown === 0) { + // // window.location.reload(); + // } + // }, 1000); + // return () => clearInterval(interval); + // }, []); + + return ( + + A new version of the app is available. Please refresh the page to get the latest features. + + ); +}; diff --git a/apps/web/src/context/BusterNotifications/BusterNotifications.tsx b/apps/web/src/context/BusterNotifications/BusterNotifications.tsx index 5943f21e9..427c8dcf5 100644 --- a/apps/web/src/context/BusterNotifications/BusterNotifications.tsx +++ b/apps/web/src/context/BusterNotifications/BusterNotifications.tsx @@ -12,16 +12,16 @@ const ConfirmModal = lazy(() => import('@/components/ui/modal/ConfirmModal').then((mod) => ({ default: mod.ConfirmModal })) ); -export interface NotificationProps { +export type NotificationProps = { type?: NotificationType; title?: string; - message?: string; + message?: string | React.ReactNode; duration?: number; action?: { label: string; onClick: () => void | (() => Promise); }; -} +} & ExternalToast; const openNotification = (props: NotificationProps) => { const { title, message, type } = props; diff --git a/apps/web/src/context/Providers.tsx b/apps/web/src/context/Providers.tsx index bf06d0471..31e313481 100644 --- a/apps/web/src/context/Providers.tsx +++ b/apps/web/src/context/Providers.tsx @@ -1,8 +1,8 @@ import type React from 'react'; import type { PropsWithChildren } from 'react'; import { BusterPosthogProvider } from '@/context/Posthog'; +import { useAppVersion } from './AppVersion/useAppVersion'; import { BusterStyleProvider } from './BusterStyles'; - import { SupabaseContextProvider, type SupabaseContextType, @@ -16,6 +16,8 @@ export const AppProviders: React.FC> = ({ children, supabaseSession, }) => { + useAppVersion(); + return ( {children} diff --git a/apps/web/src/routes/app/_app.tsx b/apps/web/src/routes/app/_app.tsx index 5055f9dc4..ccc965200 100644 --- a/apps/web/src/routes/app/_app.tsx +++ b/apps/web/src/routes/app/_app.tsx @@ -28,6 +28,7 @@ export const Route = createFileRoute('/app/_app')({ }, component: () => { const { initialLayout, defaultLayout } = Route.useLoaderData(); + return ( { const isLocalBuild = process.argv.includes('--local') || mode === 'development'; const target = isLocalBuild ? ('bun' as const) : ('vercel' as const); + // Generate a unique build ID for cache busting after deployments + const buildId = `build:${process.env.VERCEL_GIT_COMMIT_SHA?.slice(0, 8) || process.env.BUILD_ID || Date.now().toString()}`; + const buildAt = new Date().toISOString(); + return { server: { port: 3000 }, + define: { + // Make the build ID available to the app for version tracking + 'import.meta.env.VITE_BUILD_ID': JSON.stringify(buildId), + 'import.meta.env.VITE_BUILD_AT': JSON.stringify(buildAt), + }, plugins: [ // this is the plugin that enables path aliases viteTsConfigPaths({ projects: ['./tsconfig.json'] }), From 361ab51ba9da729598a934ddbee1a662a3c6cbdb Mon Sep 17 00:00:00 2001 From: Nate Kelley Date: Mon, 22 Sep 2025 16:04:31 -0600 Subject: [PATCH 08/14] Create vercel.json --- .../src/context/AppVersion/useAppVersion.tsx | 2 +- apps/web/vercel.json | 71 +++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 apps/web/vercel.json diff --git a/apps/web/src/context/AppVersion/useAppVersion.tsx b/apps/web/src/context/AppVersion/useAppVersion.tsx index 461b1bad7..a63873a59 100644 --- a/apps/web/src/context/AppVersion/useAppVersion.tsx +++ b/apps/web/src/context/AppVersion/useAppVersion.tsx @@ -23,7 +23,7 @@ export const useAppVersion = () => { useWindowFocus(() => { refetch().then(() => { if (isChanged) { - reloadWindow(); + // reloadWindow(); } }); }); diff --git a/apps/web/vercel.json b/apps/web/vercel.json new file mode 100644 index 000000000..9626f19b1 --- /dev/null +++ b/apps/web/vercel.json @@ -0,0 +1,71 @@ +{ + "functions": { + "apps/web/.output/server/index.mjs": { + "maxDuration": 30 + } + }, + "headers": [ + { + "source": "/assets/(.*)", + "headers": [ + { + "key": "Cache-Control", + "value": "public, max-age=5184000, immutable" + } + ] + }, + { + "source": "/_build/(.*)", + "headers": [ + { + "key": "Cache-Control", + "value": "public, max-age=5184000, immutable" + } + ] + }, + { + "source": "/(.*).js", + "headers": [ + { + "key": "Cache-Control", + "value": "public, max-age=5184000, immutable" + } + ] + }, + { + "source": "/(.*).css", + "headers": [ + { + "key": "Cache-Control", + "value": "public, max-age=5184000, immutable" + } + ] + }, + { + "source": "/index.html", + "headers": [ + { + "key": "Cache-Control", + "value": "no-cache, no-store, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + } + ] + }, + { + "source": "/", + "headers": [ + { + "key": "Cache-Control", + "value": "s-maxage=1, stale-while-revalidate" + } + ] + } + ] +} From cbf4b04e7195e48eb15b9e0b894651e1671cba42 Mon Sep 17 00:00:00 2001 From: Nate Kelley Date: Mon, 22 Sep 2025 16:04:31 -0600 Subject: [PATCH 09/14] Create vercel.json --- .../src/context/AppVersion/useAppVersion.tsx | 2 +- apps/web/vercel.json | 89 +++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 apps/web/vercel.json diff --git a/apps/web/src/context/AppVersion/useAppVersion.tsx b/apps/web/src/context/AppVersion/useAppVersion.tsx index 461b1bad7..a63873a59 100644 --- a/apps/web/src/context/AppVersion/useAppVersion.tsx +++ b/apps/web/src/context/AppVersion/useAppVersion.tsx @@ -23,7 +23,7 @@ export const useAppVersion = () => { useWindowFocus(() => { refetch().then(() => { if (isChanged) { - reloadWindow(); + // reloadWindow(); } }); }); diff --git a/apps/web/vercel.json b/apps/web/vercel.json new file mode 100644 index 000000000..62d77e797 --- /dev/null +++ b/apps/web/vercel.json @@ -0,0 +1,89 @@ +{ + "rewrites": [ + { + "source": "/_assets/:version/:path*", + "destination": "/assets/:path*" + } + ], + "headers": [ + { + "source": "/_assets/(.*)", + "headers": [ + { + "key": "Cache-Control", + "value": "public, max-age=31536000, immutable" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + } + ] + }, + { + "source": "/assets/(.*)", + "headers": [ + { + "key": "Cache-Control", + "value": "public, max-age=31536000, immutable" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + } + ] + }, + { + "source": "/_build/(.*)", + "headers": [ + { + "key": "Cache-Control", + "value": "public, max-age=31536000, immutable" + } + ] + }, + { + "source": "/(.*).js", + "headers": [ + { + "key": "Cache-Control", + "value": "public, max-age=31536000, immutable" + } + ] + }, + { + "source": "/(.*).css", + "headers": [ + { + "key": "Cache-Control", + "value": "public, max-age=31536000, immutable" + } + ] + }, + { + "source": "/index.html", + "headers": [ + { + "key": "Cache-Control", + "value": "no-cache, no-store, must-revalidate" + }, + { + "key": "Pragma", + "value": "no-cache" + }, + { + "key": "Expires", + "value": "0" + } + ] + }, + { + "source": "/", + "headers": [ + { + "key": "Cache-Control", + "value": "s-maxage=1, stale-while-revalidate" + } + ] + } + ] +} From 7461f6e2cc287de71b31c0a94cd9fda5d30d8306 Mon Sep 17 00:00:00 2001 From: Nate Kelley Date: Mon, 22 Sep 2025 16:17:53 -0600 Subject: [PATCH 10/14] Update vercel.json --- apps/web/vercel.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/apps/web/vercel.json b/apps/web/vercel.json index 9626f19b1..1d3f544da 100644 --- a/apps/web/vercel.json +++ b/apps/web/vercel.json @@ -1,9 +1,4 @@ { - "functions": { - "apps/web/.output/server/index.mjs": { - "maxDuration": 30 - } - }, "headers": [ { "source": "/assets/(.*)", From 474b1c24be63857919c83da17195cf485276cd1d Mon Sep 17 00:00:00 2001 From: jacob-buster Date: Mon, 22 Sep 2025 16:51:39 -0600 Subject: [PATCH 11/14] Fixing reports not switching --- .../components/ui/report/useReportEditor.tsx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/apps/web/src/components/ui/report/useReportEditor.tsx b/apps/web/src/components/ui/report/useReportEditor.tsx index d6e614f4f..c25917fe9 100644 --- a/apps/web/src/components/ui/report/useReportEditor.tsx +++ b/apps/web/src/components/ui/report/useReportEditor.tsx @@ -69,6 +69,7 @@ const useEditorServerUpdates = ({ isStreaming: boolean; }) => { const hasInitialized = useRef(false); + const lastValue = useRef(''); const { run: throttleStreamUpdate } = useThrottleFn( (v: string) => { @@ -83,6 +84,12 @@ const useEditorServerUpdates = ({ ); useEffect(() => { + // Reset initialization state if we're switching to a different report content + if (value !== lastValue.current) { + hasInitialized.current = false; + lastValue.current = value || ''; + } + if (editor && isStreaming) { hasInitialized.current = true; throttleStreamUpdate(value); @@ -95,6 +102,16 @@ const useEditorServerUpdates = ({ autoSelect: false, }); }); + } else if (editor && value && !hasInitialized.current && !isEmptyEditor(editor)) { + // Handle case where editor has content but we need to switch to different report + hasInitialized.current = true; + markdownToPlatejs(editor, value).then((elements) => { + editor.tf.reset(); + editor.tf.init({ + value: elements, + autoSelect: false, + }); + }); } else { editor?.getPlugin(StreamContentPlugin)?.api.streamContent.stop(); } From a20a76eb44c0efc7bf5693f920cb3c15b85f28e9 Mon Sep 17 00:00:00 2001 From: Nate Kelley Date: Mon, 22 Sep 2025 16:56:43 -0600 Subject: [PATCH 12/14] added vite config for asset bundling --- .../ui/layouts/AppPageLayoutContent.tsx | 6 +++++- .../src/context/AppVersion/useAppVersion.tsx | 1 + apps/web/vite.config.ts | 17 +++++++++++++---- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/apps/web/src/components/ui/layouts/AppPageLayoutContent.tsx b/apps/web/src/components/ui/layouts/AppPageLayoutContent.tsx index a9d16bb09..ab43dd2a0 100644 --- a/apps/web/src/components/ui/layouts/AppPageLayoutContent.tsx +++ b/apps/web/src/components/ui/layouts/AppPageLayoutContent.tsx @@ -15,7 +15,11 @@ export const AppPageLayoutContent: React.FC< return ( {children} diff --git a/apps/web/src/context/AppVersion/useAppVersion.tsx b/apps/web/src/context/AppVersion/useAppVersion.tsx index a63873a59..e5e8412df 100644 --- a/apps/web/src/context/AppVersion/useAppVersion.tsx +++ b/apps/web/src/context/AppVersion/useAppVersion.tsx @@ -29,6 +29,7 @@ export const useAppVersion = () => { }); useEffect(() => { + console.log('isChanged', data?.buildId, browserBuild); if (isChanged) { openInfoNotification({ duration: Infinity, diff --git a/apps/web/vite.config.ts b/apps/web/vite.config.ts index 49903f076..a4d194cce 100644 --- a/apps/web/vite.config.ts +++ b/apps/web/vite.config.ts @@ -1,3 +1,4 @@ +import { execSync } from 'node:child_process'; import tailwindcss from '@tailwindcss/vite'; import { tanstackStart } from '@tanstack/react-start/plugin/vite'; import viteReact from '@vitejs/plugin-react'; @@ -5,6 +6,8 @@ import { defineConfig } from 'vite'; import checker from 'vite-plugin-checker'; import viteTsConfigPaths from 'vite-tsconfig-paths'; +const commitHash = execSync('git rev-parse --short HEAD').toString().trim(); + const config = defineConfig(({ command, mode }) => { const isBuild = command === 'build'; const isProduction = mode === 'production' || mode === 'staging'; @@ -13,14 +16,20 @@ const config = defineConfig(({ command, mode }) => { const isLocalBuild = process.argv.includes('--local') || mode === 'development'; const target = isLocalBuild ? ('bun' as const) : ('vercel' as const); - // Generate a unique build ID for cache busting after deployments - const buildId = `build:${process.env.VERCEL_GIT_COMMIT_SHA?.slice(0, 8) || process.env.BUILD_ID || Date.now().toString()}`; - const buildAt = new Date().toISOString(); + // Generate a unique version identifier for both build tracking and asset versioning + const buildId = + process.env.VERCEL_GIT_COMMIT_SHA?.slice(0, 8) || + process.env.BUILD_ID || + (isProduction ? commitHash : 'dev'); + const buildAt = new Date().toString(); + + // Set the base URL for assets with versioning in production + const base = '/'; return { + base, server: { port: 3000 }, define: { - // Make the build ID available to the app for version tracking 'import.meta.env.VITE_BUILD_ID': JSON.stringify(buildId), 'import.meta.env.VITE_BUILD_AT': JSON.stringify(buildAt), }, From ab8db113328d4134137e45ccd939870cec8acc65 Mon Sep 17 00:00:00 2001 From: dal Date: Mon, 22 Sep 2025 17:10:26 -0600 Subject: [PATCH 13/14] blake routing changes --- .../src/agents/analyst-agent/analyst-agent.ts | 2 +- .../get-think-and-prep-agent-system-prompt.ts | 2 +- .../think-and-prep-agent.ts | 5 +- .../analysis-type-router-step.ts | 2 +- ...eate-reports-tool-standard-description.txt | 25 ++++++ .../create-reports-tool.test.ts | 86 +++++++++++++++++++ .../create-reports-tool.ts | 2 +- packages/ai/src/types/analysis-mode.types.ts | 11 +++ .../workflow-output.types.ts | 6 +- 9 files changed, 128 insertions(+), 13 deletions(-) create mode 100644 packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool-standard-description.txt create mode 100644 packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool.test.ts create mode 100644 packages/ai/src/types/analysis-mode.types.ts diff --git a/packages/ai/src/agents/analyst-agent/analyst-agent.ts b/packages/ai/src/agents/analyst-agent/analyst-agent.ts index e670277dc..23ab7f86a 100644 --- a/packages/ai/src/agents/analyst-agent/analyst-agent.ts +++ b/packages/ai/src/agents/analyst-agent/analyst-agent.ts @@ -20,8 +20,8 @@ import { CREATE_METRICS_TOOL_NAME } from '../../tools/visualization-tools/metric import { MODIFY_METRICS_TOOL_NAME } from '../../tools/visualization-tools/metrics/modify-metrics-tool/modify-metrics-tool'; import { CREATE_REPORTS_TOOL_NAME } from '../../tools/visualization-tools/reports/create-reports-tool/create-reports-tool'; import { MODIFY_REPORTS_TOOL_NAME } from '../../tools/visualization-tools/reports/modify-reports-tool/modify-reports-tool'; +import { AnalysisModeSchema } from '../../types/analysis-mode.types'; import { type AgentContext, repairToolCall } from '../../utils/tool-call-repair'; -import { AnalysisModeSchema } from '../../workflows/analyst-agent-workflow/workflow-output.types'; import { analystAgentPrepareStep } from './analyst-agent-prepare-step'; import { getAnalystAgentSystemPrompt } from './get-analyst-agent-system-prompt'; diff --git a/packages/ai/src/agents/think-and-prep-agent/get-think-and-prep-agent-system-prompt.ts b/packages/ai/src/agents/think-and-prep-agent/get-think-and-prep-agent-system-prompt.ts index 34042e89b..774620117 100644 --- a/packages/ai/src/agents/think-and-prep-agent/get-think-and-prep-agent-system-prompt.ts +++ b/packages/ai/src/agents/think-and-prep-agent/get-think-and-prep-agent-system-prompt.ts @@ -1,4 +1,4 @@ -import type { AnalysisMode } from '../../workflows/analyst-agent-workflow/workflow-output.types'; +import type { AnalysisMode } from '../../types/analysis-mode.types'; import thinkAndPrepInvestigationPrompt from './think-and-prep-agent-investigation-prompt.txt'; import thinkAndPrepStandardPrompt from './think-and-prep-agent-standard-prompt.txt'; diff --git a/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent.ts b/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent.ts index f716a0346..cdf89bda9 100644 --- a/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent.ts +++ b/packages/ai/src/agents/think-and-prep-agent/think-and-prep-agent.ts @@ -19,11 +19,8 @@ import { } from '../../tools/communication-tools/submit-thoughts-tool/submit-thoughts-tool'; import { EXECUTE_SQL_TOOL_NAME } from '../../tools/database-tools/execute-sql/execute-sql'; import { SEQUENTIAL_THINKING_TOOL_NAME } from '../../tools/planning-thinking-tools/sequential-thinking-tool/sequential-thinking-tool'; +import { type AnalysisMode, AnalysisModeSchema } from '../../types/analysis-mode.types'; import { type AgentContext, repairToolCall } from '../../utils/tool-call-repair'; -import { - type AnalysisMode, - AnalysisModeSchema, -} from '../../workflows/analyst-agent-workflow/workflow-output.types'; import { getThinkAndPrepAgentSystemPrompt } from './get-think-and-prep-agent-system-prompt'; export const THINK_AND_PREP_AGENT_NAME = 'thinkAndPrepAgent'; diff --git a/packages/ai/src/steps/analyst-agent-steps/analysis-type-router-step/analysis-type-router-step.ts b/packages/ai/src/steps/analyst-agent-steps/analysis-type-router-step/analysis-type-router-step.ts index 528fb5fd5..57c4f018d 100644 --- a/packages/ai/src/steps/analyst-agent-steps/analysis-type-router-step/analysis-type-router-step.ts +++ b/packages/ai/src/steps/analyst-agent-steps/analysis-type-router-step/analysis-type-router-step.ts @@ -5,8 +5,8 @@ import { wrapTraced } from 'braintrust'; import { z } from 'zod'; import { GPT5Mini } from '../../../llm/gpt-5-mini'; import { DEFAULT_OPENAI_OPTIONS } from '../../../llm/providers/gateway'; +import { AnalysisModeSchema } from '../../../types/analysis-mode.types'; import { isOverloadedError } from '../../../utils/with-agent-retry'; -import { AnalysisModeSchema } from '../../../workflows/analyst-agent-workflow/workflow-output.types'; import { formatAnalysisTypeRouterPrompt } from './format-analysis-type-router-prompt'; // Zod schemas first - following Zod-first approach diff --git a/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool-standard-description.txt b/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool-standard-description.txt new file mode 100644 index 000000000..37f5e9e99 --- /dev/null +++ b/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool-standard-description.txt @@ -0,0 +1,25 @@ +Creates a report file with markdown content. Reports are used to document findings, analysis results, and insights in a structured markdown format. Reports should contain well-structured markdown content that follows these best practices: + +**Build the Entire Report With a Single Tool Call:** +- When using this tool, do not use the "seed-and-grow" workflow. Instead, you should create this entire report in a single tool call. + +**Structure Guidelines:** +- **Title** (concise). +- **Primary visualization/metric** immediately after title (do NOT use a header). + - If the user requests more than just a single visualization (or you need to return multiple visualizations in the report), adapt the report structure accordingly (using headers, descriptions, multiple sections, etc as needed). +- **Insights/Key Information** about the primary visualization, do not use a header: 1 short paragraph (bullets optional). Use **bold** to emphasize key findings from the visualization. Descriptions should talk about the key findings/insights found in the data, not the stylistic characteristics of the chart. +- **Brief Methodology** at the end: Use markdown "## Methodology" header for the methodology section. Cite exact fields/calculations in backticks (e.g., ```sales.amount```, ```SUM(...)```), clarify nuanced definitions and assumptions. + +**Example of Investigative Report Structure:** +```markdown +# Top Performing Sales Representatives - Last 6 Months + +Based on sales data from the last 6 months, **Linda Mitchell** leads all sales representatives with **$1.99 million** in total sales, followed closely by **Jae Pak at $1.79 million** and **Michael Blythe at $1.55 million**. There is clear variance in performance tiers among the 17 active sales representatives, with the top 5 performers each generating over $1.3 million in sales. +## Methodology +[Explain methodology...] +``` + +**Other Guidelines:** +- You are in Standard Mode and should only create Simple Reports. Do not open the report with a summary or introduction paragraph. Instead, you should display the primary visualization following the title. + - Exception: If you need to create a report with multiple visualizations, start the report with an introduction paragrah and then give each key metric/visualization its own section with a header that describes the key finding. +- **DO NOT** use the "seed-and-grow" workflow to build your report. You should create the entire report with a single tool call. \ No newline at end of file diff --git a/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool.test.ts b/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool.test.ts new file mode 100644 index 000000000..fafbb92d6 --- /dev/null +++ b/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool.test.ts @@ -0,0 +1,86 @@ +import { describe, expect, it } from 'vitest'; +import { type CreateReportsContext, createCreateReportsTool } from './create-reports-tool'; +import CREATE_REPORTS_TOOL_INVESTIGATION_DESCRIPTION from './create-reports-tool-investigation-description.txt'; +import CREATE_REPORTS_TOOL_STANDARD_DESCRIPTION from './create-reports-tool-standard-description.txt'; + +describe('createCreateReportsTool', () => { + const baseContext: CreateReportsContext = { + userId: 'test-user', + chatId: 'test-chat', + organizationId: 'test-org', + messageId: 'test-message', + }; + + describe('description selection based on analysisMode', () => { + it('should use standard description when analysisMode is not provided', () => { + const tool = createCreateReportsTool(baseContext); + + // The tool function returns an object with execute and other methods + expect(tool).toBeDefined(); + expect(tool).toHaveProperty('execute'); + }); + + it('should use standard description when analysisMode is "standard"', () => { + const tool = createCreateReportsTool({ + ...baseContext, + analysisMode: 'standard', + }); + + expect(tool).toBeDefined(); + expect(tool).toHaveProperty('execute'); + }); + + it('should use investigation description when analysisMode is "investigation"', () => { + const tool = createCreateReportsTool({ + ...baseContext, + analysisMode: 'investigation', + }); + + expect(tool).toBeDefined(); + expect(tool).toHaveProperty('execute'); + }); + }); + + describe('tool functionality', () => { + it('should create a tool with required properties', () => { + const tool = createCreateReportsTool(baseContext); + + expect(tool).toBeDefined(); + expect(typeof tool).toBe('object'); + expect(tool).toHaveProperty('execute'); + expect(typeof tool.execute).toBe('function'); + }); + + it('should handle context with all optional fields', () => { + const contextWithOptionals: CreateReportsContext = { + ...baseContext, + messageId: undefined, + analysisMode: 'investigation', + }; + + const tool = createCreateReportsTool(contextWithOptionals); + expect(tool).toBeDefined(); + }); + }); + + describe('description content verification', () => { + it('should have different content for standard vs investigation descriptions', () => { + // Verify that the two description files have different content + expect(CREATE_REPORTS_TOOL_STANDARD_DESCRIPTION).not.toBe( + CREATE_REPORTS_TOOL_INVESTIGATION_DESCRIPTION + ); + + // Verify standard description contains expected keywords + expect(CREATE_REPORTS_TOOL_STANDARD_DESCRIPTION.toLowerCase()).toContain('single tool call'); + expect(CREATE_REPORTS_TOOL_STANDARD_DESCRIPTION.toLowerCase()).toContain('standard mode'); + + // Verify investigation description contains expected keywords + expect(CREATE_REPORTS_TOOL_INVESTIGATION_DESCRIPTION.toLowerCase()).toContain( + 'seed-and-grow' + ); + expect(CREATE_REPORTS_TOOL_INVESTIGATION_DESCRIPTION.toLowerCase()).toContain( + 'modifyreports' + ); + }); + }); +}); diff --git a/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool.ts b/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool.ts index a9d66badc..6ed2dee0d 100644 --- a/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool.ts +++ b/packages/ai/src/tools/visualization-tools/reports/create-reports-tool/create-reports-tool.ts @@ -1,7 +1,7 @@ import { StatusSchema } from '@buster/server-shared/chats'; import { tool } from 'ai'; import { z } from 'zod'; -import { AnalysisModeSchema } from '../../../../workflows/analyst-agent-workflow/workflow-output.types'; +import { AnalysisModeSchema } from '../../../../types/analysis-mode.types'; import { createCreateReportsDelta } from './create-reports-delta'; import { createCreateReportsExecute } from './create-reports-execute'; import { createCreateReportsFinish } from './create-reports-finish'; diff --git a/packages/ai/src/types/analysis-mode.types.ts b/packages/ai/src/types/analysis-mode.types.ts new file mode 100644 index 000000000..8900ffd6f --- /dev/null +++ b/packages/ai/src/types/analysis-mode.types.ts @@ -0,0 +1,11 @@ +import { z } from 'zod'; + +/** + * Shared analysis mode schema used across the workflow, agents, and tools + */ +export const AnalysisModeSchema = z.enum(['standard', 'investigation']); + +/** + * TypeScript type for analysis mode + */ +export type AnalysisMode = z.infer; diff --git a/packages/ai/src/workflows/analyst-agent-workflow/workflow-output.types.ts b/packages/ai/src/workflows/analyst-agent-workflow/workflow-output.types.ts index 18b747917..5a0560fa1 100644 --- a/packages/ai/src/workflows/analyst-agent-workflow/workflow-output.types.ts +++ b/packages/ai/src/workflows/analyst-agent-workflow/workflow-output.types.ts @@ -7,6 +7,7 @@ import { CREATE_METRICS_TOOL_NAME } from '../../tools/visualization-tools/metric import { MODIFY_METRICS_TOOL_NAME } from '../../tools/visualization-tools/metrics/modify-metrics-tool/modify-metrics-tool'; import { CREATE_REPORTS_TOOL_NAME } from '../../tools/visualization-tools/reports/create-reports-tool/create-reports-tool'; import { MODIFY_REPORTS_TOOL_NAME } from '../../tools/visualization-tools/reports/modify-reports-tool/modify-reports-tool'; +import { type AnalysisMode, AnalysisModeSchema } from '../../types/analysis-mode.types'; // Tool call tracking export const ToolCallInfoSchema = z.object({ @@ -68,11 +69,6 @@ export const UserRequestSegmentSchema = z.object({ export type UserRequestSegment = z.infer; -// Analysis mode from the analysis type router -export const AnalysisModeSchema = z.enum(['standard', 'investigation']); - -export type AnalysisMode = z.infer; - // Complete workflow output export const AnalystWorkflowOutputSchema = z.object({ // Original workflow input data From f678fdc79c2d2a98e31a8894ca74460e1b86ba9f Mon Sep 17 00:00:00 2001 From: Nate Kelley Date: Mon, 22 Sep 2025 17:13:04 -0600 Subject: [PATCH 14/14] use a key reset instead --- .../components/ui/report/useReportEditor.tsx | 17 ----------------- .../ReportPageController.tsx | 3 +-- 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/apps/web/src/components/ui/report/useReportEditor.tsx b/apps/web/src/components/ui/report/useReportEditor.tsx index c25917fe9..d6e614f4f 100644 --- a/apps/web/src/components/ui/report/useReportEditor.tsx +++ b/apps/web/src/components/ui/report/useReportEditor.tsx @@ -69,7 +69,6 @@ const useEditorServerUpdates = ({ isStreaming: boolean; }) => { const hasInitialized = useRef(false); - const lastValue = useRef(''); const { run: throttleStreamUpdate } = useThrottleFn( (v: string) => { @@ -84,12 +83,6 @@ const useEditorServerUpdates = ({ ); useEffect(() => { - // Reset initialization state if we're switching to a different report content - if (value !== lastValue.current) { - hasInitialized.current = false; - lastValue.current = value || ''; - } - if (editor && isStreaming) { hasInitialized.current = true; throttleStreamUpdate(value); @@ -102,16 +95,6 @@ const useEditorServerUpdates = ({ autoSelect: false, }); }); - } else if (editor && value && !hasInitialized.current && !isEmptyEditor(editor)) { - // Handle case where editor has content but we need to switch to different report - hasInitialized.current = true; - markdownToPlatejs(editor, value).then((elements) => { - editor.tf.reset(); - editor.tf.init({ - value: elements, - autoSelect: false, - }); - }); } else { editor?.getPlugin(StreamContentPlugin)?.api.streamContent.stop(); } diff --git a/apps/web/src/controllers/ReportPageControllers/ReportPageController.tsx b/apps/web/src/controllers/ReportPageControllers/ReportPageController.tsx index e68fa7971..af5c54c42 100644 --- a/apps/web/src/controllers/ReportPageControllers/ReportPageController.tsx +++ b/apps/web/src/controllers/ReportPageControllers/ReportPageController.tsx @@ -7,10 +7,8 @@ import DynamicReportEditor from '@/components/ui/report/DynamicReportEditor'; import type { IReportEditor } from '@/components/ui/report/ReportEditor'; import { ReportEditorSkeleton } from '@/components/ui/report/ReportEditorSkeleton'; import type { BusterReportEditor } from '@/components/ui/report/types'; -import { SCROLL_AREA_VIEWPORT_CLASS } from '@/components/ui/scroll-area/ScrollArea'; import { useGetScrollAreaRef } from '@/components/ui/scroll-area/useGetScrollAreaRef'; import { useMemoizedFn } from '@/hooks/useMemoizedFn'; -import { useMount } from '@/hooks/useMount'; import { useEditorContext } from '@/layouts/AssetContainer/ReportAssetContainer'; import { cn } from '@/lib/utils'; import { chatQueryKeys } from '../../api/query_keys/chat'; @@ -95,6 +93,7 @@ export const ReportPageController: React.FC<{ > {report ? (