fix prompts of dashboard and metric tools

This commit is contained in:
dal 2025-08-12 22:42:21 -06:00
parent 5d2631b848
commit 0f0a5ed7d1
No known key found for this signature in database
GPG Key ID: 16F4B0E1E9F61122
7 changed files with 767 additions and 1760 deletions

View File

@ -2,7 +2,7 @@ Creates dashboard configuration files with YAML content following the dashboard
## COMPLETE DASHBOARD YAML SCHEMA
# DASHBOARD CONFIGURATION - YML STRUCTURE
`# DASHBOARD CONFIGURATION - YML STRUCTURE
# ----------------------------------------
# Required fields:
#
@ -32,5 +32,96 @@ Creates dashboard configuration files with YAML content following the dashboard
# 8. String values generally should NOT use quotes unless they contain special characters (like :, {, }, [, ], ,, &, *, #, ?, |, -, <, >, =, !, %, @, `) or start/end with whitespace.
# 9. If a string contains special characters or needs to preserve leading/trailing whitespace, enclose it in double quotes (`"`). Example: `name: "Sales & Marketing Dashboard"`
# 10. Avoid special characters in names and descriptions where possible, but if needed, use quotes as described in rule 9. UUIDs should NEVER be quoted.
# ----------------------------------------
type: object
name: Dashboard Configuration Schema
description: Specifies the structure and constraints of a dashboard config file.
properties:
name:
type: string
description: The title of the dashboard (e.g. Sales & Marketing Dashboard) - do NOT use quotes
description:
type: string
description: A description of the dashboard, its metrics, and its purpose
rows:
type: array
description: Array of row objects, each containing metric items
items:
type: object
properties:
id:
type: integer
description: This is just an integer representing the row number 1 -> n
items:
type: array
description: Array of metrics to display in this row (max 4 items)
maxItems: 4
items:
type: object
properties:
id:
type: string
description: UUIDv4 identifier of an existing metric
required:
- id
column_sizes:
type: array
description: Required array of column sizes (must sum to exactly 12)
items:
type: integer
minimum: 3
maximum: 12
required:
- id
- items
- column_sizes
required:
- name
- description
- rows`
**Key Requirements:**
- `name`: Dashboard title (no underscores, descriptive name)
- `description`: Natural language explanation of the dashboard's purpose and contents
- `rows`: Array of row objects, each with unique ID, items (metric UUIDs), and column_sizes
- Each row must have 1-4 items maximum
- `column_sizes` must sum to exactly 12 and each size must be >= 3
- All metric IDs must be valid UUIDs of existing metrics
- Row IDs must be unique integers (typically 1, 2, 3, etc.)
**Dashboard Layout Rules:**
- Grid system: Each row spans 12 columns total
- Column sizes: [12] = full width, [6,6] = two halves, [4,4,4] = three thirds, [3,3,3,3] = four quarters
- Common layouts: [12], [6,6], [4,8], [3,9], [4,4,4], [3,3,6], [3,3,3,3]
- Each metric item gets the corresponding column size in the same position
**Example Structure:**
```yaml
name: Sales Performance Dashboard
description: Comprehensive overview of sales metrics including revenue, conversions, and geographic performance
rows:
- id: 1
items:
- id: 550e8400-e29b-41d4-a716-446655440001
column_sizes:
- 12
- id: 2
items:
- id: 550e8400-e29b-41d4-a716-446655440002
- id: 550e8400-e29b-41d4-a716-446655440003
column_sizes:
- 6
- 6
- id: 3
items:
- id: 550e8400-e29b-41d4-a716-446655440004
- id: 550e8400-e29b-41d4-a716-446655440005
- id: 550e8400-e29b-41d4-a716-446655440006
column_sizes:
- 4
- 4
- 4
```
**CRITICAL:** Follow the schema exactly - all metric IDs must reference existing metrics, column sizes must sum to 12, and row IDs must be unique. The tool will validate all metric references against the database.

View File

@ -0,0 +1,41 @@
import { describe, expect, it } from 'vitest';
import dashboardToolDescription from './dashboard-tool-description.txt';
import { getDashboardToolDescription } from './get-dashboard-tool-description';
describe('getDashboardToolDescription', () => {
it('should return the dashboard tool description from the .txt file', () => {
const description = getDashboardToolDescription();
// Verify it returns a non-empty string
expect(typeof description).toBe('string');
expect(description.length).toBeGreaterThan(0);
// Verify it contains the expected content from the actual .txt file
expect(description).toContain('Creates dashboard configuration files');
expect(description).toContain('COMPLETE DASHBOARD YAML SCHEMA');
expect(description).toContain('DASHBOARD CONFIGURATION - YML STRUCTURE');
});
it('should have no template variables in the .txt file', () => {
const content = dashboardToolDescription;
// Find any template variables in the file
const templateVariablePattern = /\{\{([^}]+)\}\}/g;
const foundVariables = new Set<string>();
const matches = Array.from(content.matchAll(templateVariablePattern));
for (const match of matches) {
if (match[1]) {
foundVariables.add(match[1]);
}
}
// Should have no template variables since this tool just returns the raw content
expect(foundVariables.size).toBe(0);
// If any variables are found, list them for debugging
if (foundVariables.size > 0) {
console.error('Found unexpected template variables:', Array.from(foundVariables));
}
});
});

View File

@ -1,13 +1,5 @@
import dashboardToolDescription from './dashboard-tool-description.txt';
/**
* Template parameters for the dashboard tool prompt
*/
export interface DashboardToolTemplateParams {
dataSourceSyntax: string;
date: string;
}
/**
* Export the template function for use in dashboard tool
*/

View File

@ -1,46 +0,0 @@
import { describe, expect, it } from 'vitest';
import dashboardToolDescription from './dashboard-tool-description.txt';
import { getDashboardToolDescription } from './get-dashboard-tool-description';
describe('Dashboard Tool Prompt Instructions', () => {
it('should validate template file has no template variables', () => {
const content = dashboardToolDescription;
// Find any template variables in the file
const templateVariablePattern = /\{\{([^}]+)\}\}/g;
const foundVariables = new Set<string>();
const matches = Array.from(content.matchAll(templateVariablePattern));
for (const match of matches) {
if (match[1] && match[1] !== 'variable') {
foundVariables.add(match[1]);
}
}
// Should have no template variables since this tool just fetches the raw content
expect(foundVariables.size).toBe(0);
expect(content.length).toBeGreaterThan(0);
});
it('should load the dashboard tool description correctly', () => {
const result = getDashboardToolDescription();
expect(result).toBeDefined();
expect(typeof result).toBe('string');
expect(result.length).toBeGreaterThan(0);
// Should return the raw content from the text file
expect(result).toBe(dashboardToolDescription);
});
it('should contain expected sections from the dashboard description', () => {
const result = getDashboardToolDescription();
// Check for key sections that should be in the dashboard description
expect(result).toContain('Creates dashboard configuration files');
expect(result).toContain('COMPLETE DASHBOARD YAML SCHEMA');
expect(result).toContain('DASHBOARD CONFIGURATION - YML STRUCTURE');
expect(result).toContain('Required fields:');
expect(result).toContain('Rules:');
});
});

View File

@ -1,78 +1,46 @@
import { describe, expect, it } from 'vitest';
import { getMetricToolDescriptionPrompt } from './get-metric-tool-description';
import { getMetricToolDescription } from './get-metric-tool-description';
import metricToolDescription from './metric-tool-description.txt';
describe('Metric Tool Description Instructions', () => {
it('should validate template file contains expected variables', () => {
describe('getMetricToolDescription', () => {
it('should return the metric tool description from the .txt file', () => {
const description = getMetricToolDescription();
// Verify it returns a non-empty string
expect(typeof description).toBe('string');
expect(description.length).toBeGreaterThan(0);
// Verify it contains the expected content from the actual .txt file
expect(description).toContain('Creates metric configuration files with YAML content');
expect(description).toContain('COMPLETE METRIC YAML SCHEMA SPECIFICATION');
expect(description).toContain('selectedChartType');
expect(description).toContain('columnLabelFormats');
// Verify it has the full schema documentation
expect(description).toContain('# METRIC CONFIGURATION - YML STRUCTURE');
expect(description).toContain('bar, line, scatter, pie, combo, metric, table');
});
it('should have no template variables in the .txt file', () => {
const content = metricToolDescription;
// Expected template variables
const expectedVariables = ['sql_dialect_guidance', 'date'];
// Find all template variables in the file
// Find any template variables in the file
const templateVariablePattern = /\{\{([^}]+)\}\}/g;
const foundVariables = new Set<string>();
const matches = Array.from(content.matchAll(templateVariablePattern));
for (const match of matches) {
if (match[1] && match[1] !== 'variable') {
if (match[1]) {
foundVariables.add(match[1]);
}
}
// Convert to arrays for easier comparison
const foundVariablesArray = Array.from(foundVariables).sort();
const expectedVariablesArray = expectedVariables.sort();
// Should have no template variables since this tool just returns the raw content
expect(foundVariables.size).toBe(0);
// Check that we have exactly the expected variables
expect(foundVariablesArray).toEqual(expectedVariablesArray);
// Also verify each expected variable exists
for (const variable of expectedVariables) {
expect(content).toMatch(new RegExp(`\\{\\{${variable}\\}\\}`));
// If any variables are found, list them for debugging
if (foundVariables.size > 0) {
console.error('Found unexpected template variables:', Array.from(foundVariables));
}
// Ensure no unexpected variables exist
expect(foundVariables.size).toBe(expectedVariables.length);
});
it('should load and process the prompt template correctly', () => {
const sqlDialectGuidance = 'Test SQL guidance for PostgreSQL';
const result = getMetricToolDescriptionPrompt(sqlDialectGuidance);
expect(result).toBeDefined();
expect(typeof result).toBe('string');
expect(result.length).toBeGreaterThan(0);
// Should contain the SQL guidance we provided
expect(result).toContain(sqlDialectGuidance);
// Should not contain any unreplaced template variables
expect(result).not.toMatch(/\{\{sql_dialect_guidance\}\}/);
expect(result).not.toMatch(/\{\{date\}\}/);
// Should contain the current date in YYYY-MM-DD format
const currentDate = new Date().toISOString().split('T')[0];
expect(result).toContain(currentDate);
});
it('should contain expected sections from the prompt template', () => {
const result = getMetricToolDescriptionPrompt('Test guidance');
// Check for key sections that should be in the prompt
// Note: These expectations may need to be adjusted based on the actual content
// of the metric-tool-description.txt file
expect(result.length).toBeGreaterThan(0);
// Additional specific content checks can be added based on the prompt template structure
});
it('should throw an error for empty SQL dialect guidance', () => {
expect(() => {
getMetricToolDescriptionPrompt('');
}).toThrow('SQL dialect guidance is required');
expect(() => {
getMetricToolDescriptionPrompt(' '); // whitespace only
}).toThrow('SQL dialect guidance is required');
});
});

View File

@ -1,40 +1,8 @@
import metricToolDescription from './metric-tool-description.txt';
/**
* Template parameters for the metric tool description prompt
*/
export interface MetricToolTemplateParams {
dataSourceSyntax: string;
date: string;
}
/**
* Loads the metric tool description prompt template and replaces variables
*/
function loadAndProcessPrompt(sqlDialectGuidance: string): string {
if (!sqlDialectGuidance.trim()) {
throw new Error('SQL dialect guidance is required');
}
// Replace template variables
const currentDate = new Date().toISOString().split('T')[0] ?? '';
const processedContent = metricToolDescription
.replace(/\{\{sql_dialect_guidance\}\}/g, sqlDialectGuidance)
.replace(/\{\{date\}\}/g, currentDate);
return processedContent;
}
/**
* Export the template function for use in metric tool
*/
export const getMetricToolDescription = (): string => {
return metricToolDescription;
};
/**
* Export the template function with parameters for use in metric tool
*/
export const getMetricToolDescriptionPrompt = (sqlDialectGuidance: string): string => {
return loadAndProcessPrompt(sqlDialectGuidance);
};