lint fixes

This commit is contained in:
Nate Kelley 2025-09-25 22:23:20 -06:00
parent 8ca932b60c
commit 3c11dbf291
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
8 changed files with 70 additions and 55 deletions

View File

@ -2107,20 +2107,20 @@ describe('aggregateAndCreateDatasets', () => {
expect(result.datasets).toHaveLength(4); expect(result.datasets).toHaveLength(4);
// Find sales datasets // Find sales datasets
const salesDatasets = result.datasets.filter(d => d.dataKey === 'sales'); const salesDatasets = result.datasets.filter((d) => d.dataKey === 'sales');
const profitDatasets = result.datasets.filter(d => d.dataKey === 'profit'); const profitDatasets = result.datasets.filter((d) => d.dataKey === 'profit');
expect(salesDatasets).toHaveLength(2); expect(salesDatasets).toHaveLength(2);
expect(profitDatasets).toHaveLength(2); expect(profitDatasets).toHaveLength(2);
// Check labels include both metric and color field // Check labels include both metric and color field
const northSalesDataset = salesDatasets.find(d => d.colors === '#0000ff'); const northSalesDataset = salesDatasets.find((d) => d.colors === '#0000ff');
expect(northSalesDataset?.label).toEqual([ expect(northSalesDataset?.label).toEqual([
{ key: 'sales', value: '' }, { key: 'sales', value: '' },
{ key: 'region', value: 'North' }, { key: 'region', value: 'North' },
]); ]);
const southProfitDataset = profitDatasets.find(d => d.colors === '#ff00ff'); const southProfitDataset = profitDatasets.find((d) => d.colors === '#ff00ff');
expect(southProfitDataset?.label).toEqual([ expect(southProfitDataset?.label).toEqual([
{ key: 'profit', value: '' }, { key: 'profit', value: '' },
{ key: 'region', value: 'South' }, { key: 'region', value: 'South' },
@ -2161,7 +2161,7 @@ describe('aggregateAndCreateDatasets', () => {
// Check that labels include product category AND color field // Check that labels include product category AND color field
const northProductADataset = result.datasets.find( const northProductADataset = result.datasets.find(
d => d.colors === '#aabbcc' && d.label.some(l => l.key === 'product' && l.value === 'A') (d) => d.colors === '#aabbcc' && d.label.some((l) => l.key === 'product' && l.value === 'A')
); );
expect(northProductADataset).toBeDefined(); expect(northProductADataset).toBeDefined();
@ -2172,7 +2172,7 @@ describe('aggregateAndCreateDatasets', () => {
expect(northProductADataset?.data).toEqual([100, 120]); expect(northProductADataset?.data).toEqual([100, 120]);
const southProductADataset = result.datasets.find( const southProductADataset = result.datasets.find(
d => d.colors === '#ddeeff' && d.label.some(l => l.key === 'product' && l.value === 'A') (d) => d.colors === '#ddeeff' && d.label.some((l) => l.key === 'product' && l.value === 'A')
); );
expect(southProductADataset).toBeDefined(); expect(southProductADataset).toBeDefined();
@ -2210,7 +2210,7 @@ describe('aggregateAndCreateDatasets', () => {
expect(result.datasets).toHaveLength(1); expect(result.datasets).toHaveLength(1);
// Dataset A should have real data // Dataset A should have real data
const datasetA = result.datasets.find(d => d.colors === '#ff0000'); const datasetA = result.datasets.find((d) => d.colors === '#ff0000');
expect(datasetA?.data).toEqual([100, 120]); expect(datasetA?.data).toEqual([100, 120]);
expect(datasetA?.label).toEqual([{ key: 'category', value: 'A' }]); expect(datasetA?.label).toEqual([{ key: 'category', value: 'A' }]);

View File

@ -98,10 +98,10 @@ export function createAnalystAgent(analystAgentOptions: AnalystAgentOptions) {
const docsSystemMessage = docsContent const docsSystemMessage = docsContent
? ({ ? ({
role: 'system', role: 'system',
content: `<data_catalog_docs>\n${docsContent}\n</data_catalog_docs>`, content: `<data_catalog_docs>\n${docsContent}\n</data_catalog_docs>`,
providerOptions: DEFAULT_ANTHROPIC_OPTIONS, providerOptions: DEFAULT_ANTHROPIC_OPTIONS,
} as ModelMessage) } as ModelMessage)
: null; : null;
async function stream({ messages }: AnalystStreamOptions) { async function stream({ messages }: AnalystStreamOptions) {
@ -134,19 +134,19 @@ export function createAnalystAgent(analystAgentOptions: AnalystAgentOptions) {
// Create analyst instructions system message with proper escaping // Create analyst instructions system message with proper escaping
const analystInstructionsMessage = analystInstructions const analystInstructionsMessage = analystInstructions
? ({ ? ({
role: 'system', role: 'system',
content: `<organization_instructions>\n${analystInstructions}\n</organization_instructions>`, content: `<organization_instructions>\n${analystInstructions}\n</organization_instructions>`,
providerOptions: DEFAULT_ANTHROPIC_OPTIONS, providerOptions: DEFAULT_ANTHROPIC_OPTIONS,
} as ModelMessage) } as ModelMessage)
: null; : null;
// Create user personalization system message // Create user personalization system message
const userPersonalizationSystemMessage = userPersonalizationMessageContent const userPersonalizationSystemMessage = userPersonalizationMessageContent
? ({ ? ({
role: 'system', role: 'system',
content: userPersonalizationMessageContent, content: userPersonalizationMessageContent,
providerOptions: DEFAULT_ANTHROPIC_OPTIONS, providerOptions: DEFAULT_ANTHROPIC_OPTIONS,
} as ModelMessage) } as ModelMessage)
: null; : null;
return wrapTraced( return wrapTraced(

View File

@ -83,10 +83,14 @@ describe('Analyst Agent Instructions', () => {
expect(result).toContain('MANDATORY SQL NAMING CONVENTIONS'); expect(result).toContain('MANDATORY SQL NAMING CONVENTIONS');
// Ensure table references require full qualification // Ensure table references require full qualification
expect(result).toContain('All Table References: MUST be fully qualified: `DATABASE_NAME.SCHEMA_NAME.TABLE_NAME`'); expect(result).toContain(
'All Table References: MUST be fully qualified: `DATABASE_NAME.SCHEMA_NAME.TABLE_NAME`'
);
// Ensure column references use table aliases (not full qualifiers) // Ensure column references use table aliases (not full qualifiers)
expect(result).toContain('All Column References: MUST be qualified with their table alias (e.g., `c.customerid`)'); expect(result).toContain(
'All Column References: MUST be qualified with their table alias (e.g., `c.customerid`)'
);
// Ensure examples show table alias usage without full qualification // Ensure examples show table alias usage without full qualification
expect(result).toContain('c.customerid'); expect(result).toContain('c.customerid');

View File

@ -151,16 +151,23 @@ describe('Think and Prep Agent Instructions', () => {
['investigation', 'investigation'], ['investigation', 'investigation'],
])('SQL naming conventions in %s mode', (modeName, mode) => { ])('SQL naming conventions in %s mode', (modeName, mode) => {
it(`should contain mandatory SQL naming conventions in ${modeName} mode`, () => { it(`should contain mandatory SQL naming conventions in ${modeName} mode`, () => {
const result = getThinkAndPrepAgentSystemPrompt('Test guidance', mode as 'standard' | 'investigation'); const result = getThinkAndPrepAgentSystemPrompt(
'Test guidance',
mode as 'standard' | 'investigation'
);
// Check for MANDATORY SQL NAMING CONVENTIONS section // Check for MANDATORY SQL NAMING CONVENTIONS section
expect(result).toContain('MANDATORY SQL NAMING CONVENTIONS'); expect(result).toContain('MANDATORY SQL NAMING CONVENTIONS');
// Ensure table references require full qualification // Ensure table references require full qualification
expect(result).toContain('All Table References: MUST be fully qualified: `DATABASE_NAME.SCHEMA_NAME.TABLE_NAME`'); expect(result).toContain(
'All Table References: MUST be fully qualified: `DATABASE_NAME.SCHEMA_NAME.TABLE_NAME`'
);
// Ensure column references use table aliases (not full qualifiers) // Ensure column references use table aliases (not full qualifiers)
expect(result).toContain('All Column References: MUST be qualified with their table alias (e.g., `c.customerid`)'); expect(result).toContain(
'All Column References: MUST be qualified with their table alias (e.g., `c.customerid`)'
);
// Ensure examples show table alias usage without full qualification // Ensure examples show table alias usage without full qualification
expect(result).toContain('c.customerid'); expect(result).toContain('c.customerid');
@ -172,7 +179,10 @@ describe('Think and Prep Agent Instructions', () => {
}); });
it(`should use column names qualified with table aliases in ${modeName} mode`, () => { it(`should use column names qualified with table aliases in ${modeName} mode`, () => {
const result = getThinkAndPrepAgentSystemPrompt('Test guidance', mode as 'standard' | 'investigation'); const result = getThinkAndPrepAgentSystemPrompt(
'Test guidance',
mode as 'standard' | 'investigation'
);
// Check for the updated description // Check for the updated description
expect(result).toContain('Use column names qualified with table aliases'); expect(result).toContain('Use column names qualified with table aliases');

View File

@ -14,7 +14,7 @@ export const DEFAULT_ANTHROPIC_OPTIONS = {
additionalModelRequestFields: { additionalModelRequestFields: {
anthropic_beta: ['fine-grained-tool-streaming-2025-05-14'], anthropic_beta: ['fine-grained-tool-streaming-2025-05-14'],
}, },
} },
}; };
export const DEFAULT_OPENAI_OPTIONS = { export const DEFAULT_OPENAI_OPTIONS = {

View File

@ -97,7 +97,7 @@ async function performUpdate({
/** /**
* Updates message entries with cache-first approach for streaming. * Updates message entries with cache-first approach for streaming.
* Cache is the source of truth during streaming, DB is updated for persistence. * Cache is the source of truth during streaming, DB is updated for persistence.
* *
* Updates are queued per messageId to ensure they execute in order. * Updates are queued per messageId to ensure they execute in order.
* *
* Merge logic: * Merge logic:
@ -109,18 +109,18 @@ export async function updateMessageEntries(
params: UpdateMessageEntriesParams params: UpdateMessageEntriesParams
): Promise<{ success: boolean }> { ): Promise<{ success: boolean }> {
const { messageId } = params; const { messageId } = params;
// Get the current promise for this messageId, or use a resolved promise as the starting point // Get the current promise for this messageId, or use a resolved promise as the starting point
const currentQueue = updateQueues.get(messageId) ?? Promise.resolve({ success: true }); const currentQueue = updateQueues.get(messageId) ?? Promise.resolve({ success: true });
// Chain the new update to run after the current queue completes // Chain the new update to run after the current queue completes
const newQueue = currentQueue const newQueue = currentQueue
.then(() => performUpdate(params)) .then(() => performUpdate(params))
.catch(() => performUpdate(params)); // Still try to run even if previous failed .catch(() => performUpdate(params)); // Still try to run even if previous failed
// Update the queue for this messageId // Update the queue for this messageId
updateQueues.set(messageId, newQueue); updateQueues.set(messageId, newQueue);
// Clean up the queue entry once this update completes // Clean up the queue entry once this update completes
newQueue.finally(() => { newQueue.finally(() => {
// Only remove if this is still the current queue // Only remove if this is still the current queue
@ -128,6 +128,6 @@ export async function updateMessageEntries(
updateQueues.delete(messageId); updateQueues.delete(messageId);
} }
}); });
return newQueue; return newQueue;
} }

View File

@ -32,20 +32,21 @@ type VersionHistoryEntry = {
type VersionHistory = Record<string, VersionHistoryEntry>; type VersionHistory = Record<string, VersionHistoryEntry>;
// Simple in-memory queue for each reportId // Simple in-memory queue for each reportId
const updateQueues = new Map<string, Promise<{ const updateQueues = new Map<
id: string; string,
name: string; Promise<{
content: string; id: string;
versionHistory: VersionHistory | null; name: string;
}>>(); content: string;
versionHistory: VersionHistory | null;
}>
>();
/** /**
* Internal function that performs the actual update logic. * Internal function that performs the actual update logic.
* This is separated so it can be queued. * This is separated so it can be queued.
*/ */
async function performUpdate( async function performUpdate(params: BatchUpdateReportInput): Promise<{
params: BatchUpdateReportInput
): Promise<{
id: string; id: string;
name: string; name: string;
content: string; content: string;
@ -106,7 +107,7 @@ async function performUpdate(
/** /**
* Updates a report with new content, optionally name, and version history in a single operation * Updates a report with new content, optionally name, and version history in a single operation
* This is more efficient than multiple individual updates * This is more efficient than multiple individual updates
* *
* Updates are queued per reportId to ensure they execute in order. * Updates are queued per reportId to ensure they execute in order.
*/ */
export const batchUpdateReport = async ( export const batchUpdateReport = async (
@ -118,23 +119,25 @@ export const batchUpdateReport = async (
versionHistory: VersionHistory | null; versionHistory: VersionHistory | null;
}> => { }> => {
const { reportId } = params; const { reportId } = params;
// Get the current promise for this reportId, or use a resolved promise as the starting point // Get the current promise for this reportId, or use a resolved promise as the starting point
const currentQueue = updateQueues.get(reportId) ?? Promise.resolve({ const currentQueue =
id: '', updateQueues.get(reportId) ??
name: '', Promise.resolve({
content: '', id: '',
versionHistory: null name: '',
}); content: '',
versionHistory: null,
});
// Chain the new update to run after the current queue completes // Chain the new update to run after the current queue completes
const newQueue = currentQueue const newQueue = currentQueue
.then(() => performUpdate(params)) .then(() => performUpdate(params))
.catch(() => performUpdate(params)); // Still try to run even if previous failed .catch(() => performUpdate(params)); // Still try to run even if previous failed
// Update the queue for this reportId // Update the queue for this reportId
updateQueues.set(reportId, newQueue); updateQueues.set(reportId, newQueue);
// Clean up the queue entry once this update completes // Clean up the queue entry once this update completes
newQueue.finally(() => { newQueue.finally(() => {
// Only remove if this is still the current queue // Only remove if this is still the current queue
@ -142,6 +145,6 @@ export const batchUpdateReport = async (
updateQueues.delete(reportId); updateQueues.delete(reportId);
} }
}); });
return newQueue; return newQueue;
}; };

View File

@ -32,13 +32,11 @@ describe('DEFAULT_CHART_CONFIG', () => {
category: [], category: [],
size: [], size: [],
tooltip: null, tooltip: null,
colorBy: null,
}); });
expect(config.pieChartAxis).toEqual({ expect(config.pieChartAxis).toEqual({
x: [], x: [],
y: [], y: [],
tooltip: null, tooltip: null,
colorBy: null,
}); });
// Verify the config is a complete object with all required properties // Verify the config is a complete object with all required properties