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