@elizaos/plugin-research 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +400 -0
  2. package/dist/index.cjs +9366 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.js +9284 -0
  5. package/dist/index.js.map +1 -0
  6. package/package.json +80 -0
  7. package/src/__tests__/action-chaining.test.ts +532 -0
  8. package/src/__tests__/actions.test.ts +118 -0
  9. package/src/__tests__/cache-rate-limiter.test.ts +303 -0
  10. package/src/__tests__/content-extractors.test.ts +26 -0
  11. package/src/__tests__/deepresearch-bench-integration.test.ts +520 -0
  12. package/src/__tests__/deepresearch-bench-simplified.e2e.test.ts +290 -0
  13. package/src/__tests__/deepresearch-bench.e2e.test.ts +376 -0
  14. package/src/__tests__/e2e.test.ts +1870 -0
  15. package/src/__tests__/multi-benchmark-runner.ts +427 -0
  16. package/src/__tests__/providers.test.ts +156 -0
  17. package/src/__tests__/real-world.e2e.test.ts +788 -0
  18. package/src/__tests__/research-scenarios.test.ts +755 -0
  19. package/src/__tests__/research.e2e.test.ts +704 -0
  20. package/src/__tests__/research.test.ts +174 -0
  21. package/src/__tests__/search-providers.test.ts +174 -0
  22. package/src/__tests__/single-benchmark-runner.ts +735 -0
  23. package/src/__tests__/test-search-providers.ts +171 -0
  24. package/src/__tests__/verify-apis.test.ts +82 -0
  25. package/src/actions.ts +1677 -0
  26. package/src/benchmark/deepresearch-benchmark.ts +369 -0
  27. package/src/evaluation/research-evaluator.ts +444 -0
  28. package/src/examples/api-integration.md +498 -0
  29. package/src/examples/browserbase-integration.md +132 -0
  30. package/src/examples/debug-research-query.ts +162 -0
  31. package/src/examples/defi-code-scenarios.md +536 -0
  32. package/src/examples/defi-implementation-guide.md +454 -0
  33. package/src/examples/eliza-research-example.ts +142 -0
  34. package/src/examples/fix-renewable-energy-research.ts +209 -0
  35. package/src/examples/research-scenarios.md +408 -0
  36. package/src/examples/run-complete-renewable-research.ts +303 -0
  37. package/src/examples/run-deep-research.ts +352 -0
  38. package/src/examples/run-logged-research.ts +304 -0
  39. package/src/examples/run-real-research.ts +151 -0
  40. package/src/examples/save-research-output.ts +133 -0
  41. package/src/examples/test-file-logging.ts +199 -0
  42. package/src/examples/test-real-research.ts +67 -0
  43. package/src/examples/test-renewable-energy-research.ts +229 -0
  44. package/src/index.ts +28 -0
  45. package/src/integrations/cache.ts +128 -0
  46. package/src/integrations/content-extractors/firecrawl.ts +314 -0
  47. package/src/integrations/content-extractors/pdf-extractor.ts +350 -0
  48. package/src/integrations/content-extractors/playwright.ts +420 -0
  49. package/src/integrations/factory.ts +419 -0
  50. package/src/integrations/index.ts +18 -0
  51. package/src/integrations/rate-limiter.ts +181 -0
  52. package/src/integrations/search-providers/academic.ts +290 -0
  53. package/src/integrations/search-providers/exa.ts +205 -0
  54. package/src/integrations/search-providers/npm.ts +330 -0
  55. package/src/integrations/search-providers/pypi.ts +211 -0
  56. package/src/integrations/search-providers/serpapi.ts +277 -0
  57. package/src/integrations/search-providers/serper.ts +358 -0
  58. package/src/integrations/search-providers/stagehand-google.ts +87 -0
  59. package/src/integrations/search-providers/tavily.ts +187 -0
  60. package/src/processing/relevance-analyzer.ts +353 -0
  61. package/src/processing/research-logger.ts +450 -0
  62. package/src/processing/result-processor.ts +372 -0
  63. package/src/prompts/research-prompts.ts +419 -0
  64. package/src/providers/cacheProvider.ts +164 -0
  65. package/src/providers.ts +173 -0
  66. package/src/service.ts +2588 -0
  67. package/src/services/swe-bench.ts +286 -0
  68. package/src/strategies/research-strategies.ts +790 -0
  69. package/src/types/pdf-parse.d.ts +34 -0
  70. package/src/types.ts +551 -0
  71. package/src/verification/claim-verifier.ts +443 -0
@@ -0,0 +1,209 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Script to diagnose and fix renewable energy research issues
4
+ */
5
+
6
+ import dotenv from 'dotenv';
7
+ import path from 'path';
8
+ dotenv.config({ path: path.join(__dirname, '../../.env') });
9
+
10
+ import { ResearchService } from '../service';
11
+ import { elizaLogger, IAgentRuntime, Character, asUUID } from '@elizaos/core';
12
+ import { TavilySearchProvider } from '../integrations/search-providers/tavily';
13
+ import fs from 'fs/promises';
14
+
15
+ async function testTavilyDirectly() {
16
+ elizaLogger.info('=== Testing Tavily Search Directly ===');
17
+
18
+ const apiKey = process.env.TAVILY_API_KEY;
19
+ if (!apiKey) {
20
+ elizaLogger.error('TAVILY_API_KEY not found in environment');
21
+ return;
22
+ }
23
+
24
+ try {
25
+ const tavily = new TavilySearchProvider({ apiKey });
26
+ const query = "renewable energy storage technologies environmental economic impacts grid scale";
27
+
28
+ elizaLogger.info(`Searching Tavily for: "${query}"`);
29
+ const results = await tavily.search(query, 5);
30
+
31
+ elizaLogger.info(`Found ${results.length} results:`);
32
+ results.forEach((result, i) => {
33
+ elizaLogger.info(`${i + 1}. ${result.title}`);
34
+ elizaLogger.info(` URL: ${result.url}`);
35
+ elizaLogger.info(` Score: ${result.score}`);
36
+ elizaLogger.info(` Snippet: ${result.snippet?.substring(0, 100)}...`);
37
+ });
38
+
39
+ // Check if results are relevant
40
+ const relevantResults = results.filter(r =>
41
+ r.title.toLowerCase().includes('energy') ||
42
+ r.title.toLowerCase().includes('storage') ||
43
+ r.snippet?.toLowerCase().includes('battery') ||
44
+ r.snippet?.toLowerCase().includes('renewable')
45
+ );
46
+
47
+ elizaLogger.info(`\n${relevantResults.length} out of ${results.length} results appear relevant`);
48
+
49
+ } catch (error) {
50
+ elizaLogger.error('Tavily search failed:', error);
51
+ }
52
+ }
53
+
54
+ async function testWithMinimalRuntime() {
55
+ elizaLogger.info('\n=== Testing with Minimal Runtime ===');
56
+
57
+ const runtime: IAgentRuntime = {
58
+ agentId: asUUID('11111111-1111-1111-1111-111111111111'),
59
+ character: {
60
+ name: 'ResearchBot',
61
+ bio: ['Research assistant'],
62
+ system: 'You are a research assistant.',
63
+ messageExamples: [],
64
+ postExamples: [],
65
+ topics: [],
66
+ adjectives: [],
67
+ knowledge: [],
68
+ plugins: [],
69
+ },
70
+ getSetting: (key: string) => process.env[key] || null,
71
+ getService: () => null,
72
+ providers: [],
73
+ actions: [],
74
+ evaluators: [],
75
+ plugins: [],
76
+ services: new Map(),
77
+ messageManager: {
78
+ createMemory: async () => asUUID('22222222-2222-2222-2222-222222222222'),
79
+ getMemories: async () => [],
80
+ getMemoriesByRoomIds: async () => [],
81
+ getCachedEmbeddings: async () => [],
82
+ searchMemoriesByEmbedding: async () => [],
83
+ },
84
+ // Add all other required managers
85
+ descriptionManager: {
86
+ createMemory: async () => asUUID('33333333-3333-3333-3333-333333333333'),
87
+ getMemories: async () => [],
88
+ getMemoriesByRoomIds: async () => [],
89
+ getCachedEmbeddings: async () => [],
90
+ searchMemoriesByEmbedding: async () => [],
91
+ },
92
+ documentsManager: {
93
+ createMemory: async () => asUUID('44444444-4444-4444-4444-444444444444'),
94
+ getMemories: async () => [],
95
+ getMemoriesByRoomIds: async () => [],
96
+ getCachedEmbeddings: async () => [],
97
+ searchMemoriesByEmbedding: async () => [],
98
+ },
99
+ knowledgeManager: {
100
+ createMemory: async () => asUUID('55555555-5555-5555-5555-555555555555'),
101
+ getMemories: async () => [],
102
+ getMemoriesByRoomIds: async () => [],
103
+ getCachedEmbeddings: async () => [],
104
+ searchMemoriesByEmbedding: async () => [],
105
+ },
106
+ loreManager: {
107
+ createMemory: async () => asUUID('66666666-6666-6666-6666-666666666666'),
108
+ getMemories: async () => [],
109
+ getMemoriesByRoomIds: async () => [],
110
+ getCachedEmbeddings: async () => [],
111
+ searchMemoriesByEmbedding: async () => [],
112
+ },
113
+ // Add useModel for text generation
114
+ useModel: async (modelType: string, params: any) => {
115
+ elizaLogger.debug(`Mock model called: ${modelType}`);
116
+ // Return simple responses for different types of requests
117
+ return { content: 'Analysis complete.' };
118
+ },
119
+ stop: async () => {},
120
+ } as any;
121
+
122
+ const service = new ResearchService(runtime);
123
+
124
+ try {
125
+ const query = "Compare renewable energy storage technologies environmental economic impacts";
126
+ elizaLogger.info(`Creating research project: "${query}"`);
127
+
128
+ const project = await service.createResearchProject(query, {
129
+ searchProviders: ['web'],
130
+ maxSearchResults: 5,
131
+ maxDepth: 1,
132
+ enableImages: false,
133
+ evaluationEnabled: false,
134
+ timeout: 60000,
135
+ });
136
+
137
+ elizaLogger.info(`Project created: ${project.id}`);
138
+
139
+ // Wait for completion
140
+ let attempts = 0;
141
+ while (attempts < 60) {
142
+ await new Promise(resolve => setTimeout(resolve, 1000));
143
+
144
+ const current = await service.getProject(project.id);
145
+ if (!current) break;
146
+
147
+ if (attempts % 5 === 0) {
148
+ elizaLogger.info(`Status: ${current.status}, Phase: ${current.phase}, Sources: ${current.sources.length}`);
149
+
150
+ // Log first few sources
151
+ if (current.sources.length > 0) {
152
+ elizaLogger.info('First few sources:');
153
+ current.sources.slice(0, 3).forEach((s, i) => {
154
+ elizaLogger.info(` ${i + 1}. ${s.title} (${s.url})`);
155
+ });
156
+ }
157
+ }
158
+
159
+ if (current.status === 'completed' || current.status === 'failed') {
160
+ if (current.status === 'completed' && current.report) {
161
+ const markdown = await service.exportProject(project.id, 'markdown');
162
+ const reportPath = path.join(__dirname, '../../fixed-renewable-energy-report.md');
163
+ await fs.writeFile(reportPath, markdown);
164
+ elizaLogger.info(`✅ Report saved to: ${reportPath}`);
165
+
166
+ // Show preview
167
+ elizaLogger.info('\nReport Preview:');
168
+ elizaLogger.info(markdown.substring(0, 1000) + '...');
169
+
170
+ // Check content
171
+ const hasRelevantContent =
172
+ markdown.toLowerCase().includes('energy') &&
173
+ markdown.toLowerCase().includes('storage') &&
174
+ (markdown.toLowerCase().includes('battery') ||
175
+ markdown.toLowerCase().includes('renewable') ||
176
+ markdown.toLowerCase().includes('environmental'));
177
+
178
+ if (hasRelevantContent) {
179
+ elizaLogger.info('\n✅ SUCCESS: Report contains relevant renewable energy content!');
180
+ } else {
181
+ elizaLogger.error('\n❌ FAIL: Report does NOT contain relevant content');
182
+ elizaLogger.info('\nFirst 2000 chars of report:');
183
+ elizaLogger.info(markdown.substring(0, 2000));
184
+ }
185
+ } else {
186
+ elizaLogger.error(`Research failed: ${current.error}`);
187
+ }
188
+ break;
189
+ }
190
+
191
+ attempts++;
192
+ }
193
+
194
+ await service.stop();
195
+
196
+ } catch (error) {
197
+ elizaLogger.error('Test failed:', error);
198
+ }
199
+ }
200
+
201
+ async function main() {
202
+ // First test Tavily directly
203
+ await testTavilyDirectly();
204
+
205
+ // Then test with minimal runtime
206
+ await testWithMinimalRuntime();
207
+ }
208
+
209
+ main().catch(console.error);
@@ -0,0 +1,408 @@
1
+ # Deep Research Plugin - Example Research Scenarios
2
+
3
+ This document provides real-world examples of how to use the deep research plugin for various research tasks.
4
+
5
+ ## 1. Technical Research Scenario
6
+
7
+ **Topic**: "Performance comparison of Next.js 14 App Router vs Pages Router"
8
+
9
+ ### Expected Research Flow
10
+
11
+ ```typescript
12
+ // User interaction
13
+ User: "Research the performance differences between Next.js 14 App Router and Pages Router"
14
+
15
+ // Agent initiates research
16
+ Agent: "I'll start a deep research project on the performance differences between Next.js 14 App Router and Pages Router."
17
+
18
+ // Research phases:
19
+
20
+ // 1. Planning Phase
21
+ - Identify key performance metrics (FCP, LCP, TTI, Bundle size)
22
+ - Plan to search for benchmarks, case studies, official docs
23
+ - Define comparison criteria
24
+
25
+ // 2. Searching Phase
26
+ - Search for "Next.js 14 App Router performance benchmarks"
27
+ - Search for "Next.js Pages Router vs App Router comparison"
28
+ - Search for "Next.js 14 migration performance impact"
29
+ - Collect 10-15 high-quality sources
30
+
31
+ // 3. Analyzing Phase
32
+ - Extract performance metrics from each source
33
+ - Identify consensus and contradictions
34
+ - Note specific use cases where each excels
35
+
36
+ // 4. Synthesizing Phase
37
+ - Group findings by performance aspect
38
+ - Create comparison tables
39
+ - Identify best practices
40
+
41
+ // 5. Reporting Phase
42
+ - Generate comprehensive report with:
43
+ - Executive summary
44
+ - Detailed performance comparisons
45
+ - Migration considerations
46
+ - Recommendations based on use case
47
+ ```
48
+
49
+ ### Expected Output
50
+
51
+ ```markdown
52
+ # Research Report: Performance comparison of Next.js 14 App Router vs Pages Router
53
+
54
+ ## Executive Summary
55
+ This research analyzed 12 sources to compare the performance characteristics of Next.js 14's App Router versus the traditional Pages Router. Key findings indicate that App Router offers superior performance for dynamic applications with frequent data updates, while Pages Router maintains advantages for static content delivery.
56
+
57
+ ## Key Performance Findings
58
+
59
+ ### 1. Initial Load Performance
60
+ - **App Router**: 15-20% slower initial bundle size due to React Server Components runtime
61
+ - **Pages Router**: Faster initial load for static pages (average 1.2s vs 1.5s)
62
+
63
+ ### 2. Runtime Performance
64
+ - **App Router**: Better runtime performance with streaming SSR
65
+ - **Pages Router**: More predictable performance profile
66
+
67
+ ### 3. Build Performance
68
+ - **App Router**: Faster incremental builds (30% improvement)
69
+ - **Pages Router**: Better full build times for large applications
70
+
71
+ ## Recommendations
72
+ - Use App Router for: Dynamic applications, real-time features, complex data requirements
73
+ - Use Pages Router for: Static sites, blogs, marketing pages
74
+
75
+ ## Sources
76
+ 1. [Vercel Official Benchmarks](https://vercel.com/blog/next-14-performance) - Official performance metrics
77
+ 2. [Web.dev Case Study](https://web.dev/next-js-performance) - Real-world migration analysis
78
+ [... additional sources ...]
79
+ ```
80
+
81
+ ## 2. Market Research Scenario
82
+
83
+ **Topic**: "AI adoption trends in healthcare industry 2024"
84
+
85
+ ### Research Configuration
86
+
87
+ ```typescript
88
+ const researchConfig = {
89
+ maxSearchResults: 20,
90
+ language: 'en',
91
+ scope: 'Focus on clinical applications, regulatory developments, and market size',
92
+ enableImages: true,
93
+ searchProviders: ['tavily', 'serper']
94
+ };
95
+ ```
96
+
97
+ ### Expected Phases
98
+
99
+ 1. **Planning**: Identify key areas (clinical AI, diagnostic AI, administrative AI)
100
+ 2. **Searching**: Gather data from healthcare journals, industry reports, regulatory filings
101
+ 3. **Analyzing**: Extract adoption rates, use cases, challenges, success stories
102
+ 4. **Synthesizing**: Create industry overview with trends and projections
103
+ 5. **Reporting**: Comprehensive market analysis with data visualizations
104
+
105
+ ## 3. Academic Research Scenario
106
+
107
+ **Topic**: "Recent advances in quantum error correction codes"
108
+
109
+ ### Special Considerations
110
+
111
+ ```typescript
112
+ // Configure for academic research
113
+ const academicConfig = {
114
+ searchProviders: ['arxiv', 'scholar', 'pubmed'],
115
+ enableCitations: true,
116
+ citationStyle: 'APA',
117
+ maxSearchResults: 30,
118
+ prioritizePeerReviewed: true
119
+ };
120
+ ```
121
+
122
+ ### Expected Sources
123
+ - ArXiv preprints
124
+ - Nature/Science publications
125
+ - IEEE Quantum Computing proceedings
126
+ - University research papers
127
+
128
+ ## 4. Competitive Analysis Scenario
129
+
130
+ **Topic**: "Comparison of major LLM providers APIs and pricing models"
131
+
132
+ ### Research Structure
133
+
134
+ ```typescript
135
+ // User request
136
+ User: "Research and compare the APIs and pricing of OpenAI, Anthropic, Google, and Cohere"
137
+
138
+ // Research focus areas
139
+ const competitiveAnalysis = {
140
+ providers: ['OpenAI', 'Anthropic', 'Google Gemini', 'Cohere'],
141
+ aspects: [
142
+ 'API features',
143
+ 'Pricing models',
144
+ 'Rate limits',
145
+ 'Model capabilities',
146
+ 'Documentation quality',
147
+ 'SDK support'
148
+ ]
149
+ };
150
+ ```
151
+
152
+ ### Expected Deliverables
153
+
154
+ 1. **Comparison Matrix**
155
+ - Feature availability across providers
156
+ - Pricing tiers and token costs
157
+ - Rate limits and quotas
158
+
159
+ 2. **Technical Analysis**
160
+ - API design patterns
161
+ - Authentication methods
162
+ - Error handling approaches
163
+
164
+ 3. **Business Insights**
165
+ - Total cost of ownership calculations
166
+ - Use case recommendations
167
+ - Migration considerations
168
+
169
+ ## 5. Real-time Event Research
170
+
171
+ **Topic**: "Impact of recent Federal Reserve rate decision on tech stocks"
172
+
173
+ ### Time-Sensitive Configuration
174
+
175
+ ```typescript
176
+ const realtimeConfig = {
177
+ maxAge: 24, // Only sources from last 24 hours
178
+ searchProviders: ['news', 'financial'],
179
+ updateFrequency: 'hourly',
180
+ alertOnMajorDevelopments: true
181
+ };
182
+ ```
183
+
184
+ ### Expected Workflow
185
+
186
+ 1. **Initial Research**: Gather immediate market reactions
187
+ 2. **Follow-up Analysis**: Track evolving analyst opinions
188
+ 3. **Synthesis**: Connect rate decision to tech valuations
189
+ 4. **Continuous Monitoring**: Update findings as new data emerges
190
+
191
+ ## 6. Product Research Scenario
192
+
193
+ **Topic**: "Best practices for implementing RAG systems in production"
194
+
195
+ ### Implementation Focus
196
+
197
+ ```typescript
198
+ // Research parameters
199
+ const productResearch = {
200
+ scope: `
201
+ - Vector database selection
202
+ - Chunking strategies
203
+ - Retrieval optimization
204
+ - Evaluation metrics
205
+ - Production challenges
206
+ `,
207
+ includeCodeExamples: true,
208
+ prioritizeRecentContent: true
209
+ };
210
+ ```
211
+
212
+ ### Expected Sections
213
+
214
+ 1. **Architecture Patterns**
215
+ - Hybrid search approaches
216
+ - Reranking strategies
217
+ - Cache optimization
218
+
219
+ 2. **Implementation Details**
220
+ - Code examples from GitHub
221
+ - Performance benchmarks
222
+ - Cost analysis
223
+
224
+ 3. **Case Studies**
225
+ - Company implementations
226
+ - Lessons learned
227
+ - Common pitfalls
228
+
229
+ ## Testing Research Quality
230
+
231
+ ### Quality Metrics
232
+
233
+ ```typescript
234
+ interface ResearchQualityMetrics {
235
+ sourceCredibility: number; // 0-1 score
236
+ informationCompleteness: number; // 0-1 score
237
+ findingRelevance: number; // 0-1 score
238
+ citationAccuracy: number; // 0-1 score
239
+ reportCoherence: number; // 0-1 score
240
+ }
241
+
242
+ // Example quality assessment
243
+ const assessQuality = (project: ResearchProject): ResearchQualityMetrics => {
244
+ return {
245
+ sourceCredibility: calculateSourceCredibility(project.sources),
246
+ informationCompleteness: assessTopicCoverage(project.findings),
247
+ findingRelevance: measureRelevanceScore(project.findings, project.query),
248
+ citationAccuracy: verifyCitations(project.report.citations),
249
+ reportCoherence: analyzeReportStructure(project.report)
250
+ };
251
+ };
252
+ ```
253
+
254
+ ## Integration Examples
255
+
256
+ ### 1. Slack Integration
257
+
258
+ ```typescript
259
+ // Respond to Slack message with research
260
+ app.message(/research (.+)/, async ({ message, say }) => {
261
+ const topic = message.text.match(/research (.+)/)[1];
262
+
263
+ const project = await researchService.createProject(topic);
264
+ await say(`Starting research on: ${topic}`);
265
+
266
+ // Send updates as research progresses
267
+ researchService.on('progress', async (update) => {
268
+ await say(`Research update: ${update.phase} - ${update.progress}%`);
269
+ });
270
+
271
+ // Send final report
272
+ researchService.on('complete', async (project) => {
273
+ await say({
274
+ text: 'Research complete!',
275
+ attachments: [{
276
+ title: project.report.title,
277
+ text: project.report.summary,
278
+ fields: project.report.sections.map(s => ({
279
+ title: s.heading,
280
+ value: s.content.substring(0, 500) + '...',
281
+ short: false
282
+ }))
283
+ }]
284
+ });
285
+ });
286
+ });
287
+ ```
288
+
289
+ ### 2. Discord Bot Integration
290
+
291
+ ```typescript
292
+ client.on('messageCreate', async (message) => {
293
+ if (message.content.startsWith('!research')) {
294
+ const topic = message.content.replace('!research', '').trim();
295
+
296
+ const embed = new EmbedBuilder()
297
+ .setTitle('Research Started')
298
+ .setDescription(`Researching: ${topic}`)
299
+ .setColor(0x0099FF);
300
+
301
+ const reply = await message.reply({ embeds: [embed] });
302
+
303
+ const project = await researchService.createProject(topic);
304
+
305
+ // Update embed with progress
306
+ const updateInterval = setInterval(async () => {
307
+ const status = await researchService.getProjectStatus(project.id);
308
+
309
+ embed.setFields([
310
+ { name: 'Status', value: status.status, inline: true },
311
+ { name: 'Phase', value: status.currentPhase, inline: true },
312
+ { name: 'Progress', value: `${status.progress}%`, inline: true }
313
+ ]);
314
+
315
+ await reply.edit({ embeds: [embed] });
316
+
317
+ if (status.status === 'completed') {
318
+ clearInterval(updateInterval);
319
+ // Send full report as file
320
+ const report = await researchService.getReport(project.id);
321
+ const buffer = Buffer.from(report.markdown, 'utf-8');
322
+ await message.channel.send({
323
+ content: 'Research complete! Here\'s your report:',
324
+ files: [{
325
+ attachment: buffer,
326
+ name: `research-${topic.replace(/\s+/g, '-')}.md`
327
+ }]
328
+ });
329
+ }
330
+ }, 5000);
331
+ }
332
+ });
333
+ ```
334
+
335
+ ## Advanced Usage Patterns
336
+
337
+ ### 1. Comparative Research
338
+
339
+ ```typescript
340
+ // Compare multiple topics
341
+ const comparativeResearch = async (topics: string[]) => {
342
+ const projects = await Promise.all(
343
+ topics.map(topic => researchService.createProject(topic))
344
+ );
345
+
346
+ // Wait for all to complete
347
+ await Promise.all(
348
+ projects.map(p => waitForCompletion(p.id))
349
+ );
350
+
351
+ // Generate comparative analysis
352
+ const comparison = await synthesizeComparison(projects);
353
+ return comparison;
354
+ };
355
+
356
+ // Example usage
357
+ const frameworks = ['React', 'Vue', 'Angular', 'Svelte'];
358
+ const comparison = await comparativeResearch(
359
+ frameworks.map(f => `${f} performance benchmarks 2024`)
360
+ );
361
+ ```
362
+
363
+ ### 2. Scheduled Research
364
+
365
+ ```typescript
366
+ // Daily research updates
367
+ const scheduleResearch = (topic: string, schedule: string) => {
368
+ cron.schedule(schedule, async () => {
369
+ const project = await researchService.createProject(
370
+ `${topic} - updates for ${new Date().toDateString()}`
371
+ );
372
+
373
+ await waitForCompletion(project.id);
374
+
375
+ // Send report to stakeholders
376
+ await emailService.send({
377
+ to: stakeholders,
378
+ subject: `Daily Research Update: ${topic}`,
379
+ body: project.report.markdown
380
+ });
381
+ });
382
+ };
383
+
384
+ // Run every day at 9 AM
385
+ scheduleResearch('AI industry news', '0 9 * * *');
386
+ ```
387
+
388
+ ### 3. Research Pipeline
389
+
390
+ ```typescript
391
+ // Multi-stage research pipeline
392
+ const researchPipeline = async (initialTopic: string) => {
393
+ // Stage 1: Broad research
394
+ const overview = await researchService.createProject(initialTopic);
395
+ await waitForCompletion(overview.id);
396
+
397
+ // Stage 2: Deep dive into top findings
398
+ const keyAreas = extractKeyAreas(overview.report);
399
+ const deepDives = await Promise.all(
400
+ keyAreas.map(area => researchService.createProject(area))
401
+ );
402
+
403
+ // Stage 3: Synthesize all research
404
+ const synthesis = await createSynthesisReport([overview, ...deepDives]);
405
+
406
+ return synthesis;
407
+ };
408
+ ```