172 lines
5.9 KiB
TypeScript
172 lines
5.9 KiB
TypeScript
import { expect, tap } from '@push.rocks/tapbundle';
|
|
import * as qenv from '@push.rocks/qenv';
|
|
import * as smartai from '../ts/index.js';
|
|
import * as path from 'path';
|
|
import { promises as fs } from 'fs';
|
|
|
|
const testQenv = new qenv.Qenv('./', './.nogit/');
|
|
|
|
// Helper function to save research results
|
|
async function saveResearchResult(testName: string, result: any) {
|
|
const sanitizedName = testName.replace(/[^a-z0-9]/gi, '_').toLowerCase();
|
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
const filename = `openai_${sanitizedName}_${timestamp}.json`;
|
|
const filepath = path.join('.nogit', 'testresults', 'research', filename);
|
|
|
|
await fs.mkdir(path.dirname(filepath), { recursive: true });
|
|
await fs.writeFile(filepath, JSON.stringify(result, null, 2), 'utf-8');
|
|
|
|
console.log(` 💾 Saved to: ${filepath}`);
|
|
}
|
|
|
|
let openaiProvider: smartai.OpenAiProvider;
|
|
|
|
tap.test('OpenAI Research: should initialize provider with research capabilities', async () => {
|
|
openaiProvider = new smartai.OpenAiProvider({
|
|
openaiToken: await testQenv.getEnvVarOnDemand('OPENAI_TOKEN'),
|
|
researchModel: 'o4-mini-deep-research-2025-06-26',
|
|
enableWebSearch: true
|
|
});
|
|
|
|
await openaiProvider.start();
|
|
expect(openaiProvider).toBeInstanceOf(smartai.OpenAiProvider);
|
|
expect(typeof openaiProvider.research).toEqual('function');
|
|
});
|
|
|
|
tap.test('OpenAI Research: should perform basic research query', async () => {
|
|
const result = await openaiProvider.research({
|
|
query: 'What is TypeScript and why is it useful for web development?',
|
|
searchDepth: 'basic'
|
|
});
|
|
|
|
console.log('OpenAI Basic Research:');
|
|
console.log('- Answer length:', result.answer.length);
|
|
console.log('- Sources found:', result.sources.length);
|
|
console.log('- First 200 chars:', result.answer.substring(0, 200));
|
|
|
|
await saveResearchResult('basic_research_typescript', result);
|
|
|
|
expect(result).toBeTruthy();
|
|
expect(result.answer).toBeTruthy();
|
|
expect(result.answer.toLowerCase()).toInclude('typescript');
|
|
expect(result.sources).toBeArray();
|
|
expect(result.metadata).toBeTruthy();
|
|
expect(result.metadata.model).toBeTruthy();
|
|
});
|
|
|
|
tap.test('OpenAI Research: should perform research with web search enabled', async () => {
|
|
const result = await openaiProvider.research({
|
|
query: 'What are the latest features in ECMAScript 2024?',
|
|
searchDepth: 'advanced',
|
|
includeWebSearch: true,
|
|
maxSources: 5
|
|
});
|
|
|
|
console.log('OpenAI Web Search Research:');
|
|
console.log('- Answer length:', result.answer.length);
|
|
console.log('- Sources:', result.sources.length);
|
|
if (result.searchQueries) {
|
|
console.log('- Search queries used:', result.searchQueries);
|
|
}
|
|
|
|
await saveResearchResult('web_search_ecmascript', result);
|
|
|
|
expect(result.answer).toBeTruthy();
|
|
expect(result.answer.toLowerCase()).toInclude('ecmascript');
|
|
|
|
// The model might include sources or search queries
|
|
if (result.sources.length > 0) {
|
|
expect(result.sources[0]).toHaveProperty('url');
|
|
expect(result.sources[0]).toHaveProperty('title');
|
|
}
|
|
});
|
|
|
|
tap.test('OpenAI Research: should handle deep research for complex topics', async () => {
|
|
// Skip this test if it takes too long or costs too much
|
|
// You can enable it for thorough testing
|
|
const skipDeepResearch = true;
|
|
|
|
if (skipDeepResearch) {
|
|
console.log('Skipping deep research test to save API costs');
|
|
return;
|
|
}
|
|
|
|
const result = await openaiProvider.research({
|
|
query: 'Compare the pros and cons of microservices vs monolithic architecture',
|
|
searchDepth: 'deep',
|
|
includeWebSearch: true
|
|
});
|
|
|
|
console.log('OpenAI Deep Research:');
|
|
console.log('- Answer length:', result.answer.length);
|
|
console.log('- Token usage:', result.metadata?.tokensUsed);
|
|
|
|
expect(result.answer).toBeTruthy();
|
|
expect(result.answer.length).toBeGreaterThan(500);
|
|
expect(result.answer.toLowerCase()).toInclude('microservices');
|
|
expect(result.answer.toLowerCase()).toInclude('monolithic');
|
|
});
|
|
|
|
tap.test('OpenAI Research: should extract sources from markdown links', async () => {
|
|
const result = await openaiProvider.research({
|
|
query: 'What is Node.js and provide some official documentation links?',
|
|
searchDepth: 'basic',
|
|
maxSources: 3
|
|
});
|
|
|
|
console.log('OpenAI Source Extraction:');
|
|
console.log('- Sources found:', result.sources.length);
|
|
|
|
await saveResearchResult('source_extraction_nodejs', result);
|
|
|
|
if (result.sources.length > 0) {
|
|
console.log('- Example source:', result.sources[0]);
|
|
expect(result.sources[0].url).toBeTruthy();
|
|
expect(result.sources[0].title).toBeTruthy();
|
|
}
|
|
|
|
expect(result.answer).toInclude('Node.js');
|
|
});
|
|
|
|
tap.test('OpenAI Research: should handle research errors gracefully', async () => {
|
|
// Test with an extremely long query that might cause issues
|
|
const longQuery = 'a'.repeat(10000);
|
|
|
|
let errorCaught = false;
|
|
try {
|
|
await openaiProvider.research({
|
|
query: longQuery,
|
|
searchDepth: 'basic'
|
|
});
|
|
} catch (error) {
|
|
errorCaught = true;
|
|
console.log('Expected error for long query:', error.message.substring(0, 100));
|
|
expect(error.message).toBeTruthy();
|
|
}
|
|
|
|
// OpenAI might handle long queries, so we don't assert the error
|
|
console.log(`Long query error test - Error caught: ${errorCaught}`);
|
|
});
|
|
|
|
tap.test('OpenAI Research: should respect maxSources parameter', async () => {
|
|
const maxSources = 3;
|
|
const result = await openaiProvider.research({
|
|
query: 'List popular JavaScript frameworks',
|
|
searchDepth: 'basic',
|
|
maxSources: maxSources
|
|
});
|
|
|
|
console.log(`OpenAI Max Sources Test - Requested: ${maxSources}, Found: ${result.sources.length}`);
|
|
|
|
// The API might not always return exactly maxSources, but should respect it as a limit
|
|
if (result.sources.length > 0) {
|
|
expect(result.sources.length).toBeLessThanOrEqual(maxSources * 2); // Allow some flexibility
|
|
}
|
|
});
|
|
|
|
tap.test('OpenAI Research: should clean up provider', async () => {
|
|
await openaiProvider.stop();
|
|
console.log('OpenAI research provider stopped successfully');
|
|
});
|
|
|
|
export default tap.start(); |