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();