mcp-sequential-research 1.0.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.
@@ -0,0 +1,871 @@
1
+ /**
2
+ * Research Report Compilation
3
+ *
4
+ * Deterministic compiler that transforms research plan + raw results
5
+ * into a structured markdown report with citations.
6
+ */
7
+ import { generateId, isoNow, formatSourcesList, countWords, deduplicateCitations, renumberCitations, applyCitationMapping, formatBulletList, formatCallout, } from "./format.js";
8
+ /**
9
+ * Section templates by query type
10
+ */
11
+ const SECTION_TEMPLATES = {
12
+ definition: {
13
+ heading: "Overview",
14
+ level: 2,
15
+ formatter: (data, citations) => {
16
+ const parts = [];
17
+ if (data.definition) {
18
+ parts.push(String(data.definition));
19
+ if (citations.length > 0) {
20
+ parts[parts.length - 1] += ` ${formatInlineCitations(citations)}`;
21
+ }
22
+ }
23
+ if (Array.isArray(data.characteristics) && data.characteristics.length > 0) {
24
+ parts.push("\n**Key Characteristics:**");
25
+ parts.push(formatBulletList(data.characteristics.map(String)));
26
+ }
27
+ if (Array.isArray(data.examples) && data.examples.length > 0) {
28
+ parts.push("\n**Examples:**");
29
+ parts.push(formatBulletList(data.examples.map(String)));
30
+ }
31
+ return parts.join("\n");
32
+ },
33
+ },
34
+ comparison: {
35
+ heading: "Comparison",
36
+ level: 2,
37
+ formatter: (data, citations) => {
38
+ const parts = [];
39
+ if (Array.isArray(data.similarities) && data.similarities.length > 0) {
40
+ parts.push("**Similarities:**");
41
+ parts.push(formatBulletList(data.similarities.map(String)));
42
+ }
43
+ if (Array.isArray(data.differences) && data.differences.length > 0) {
44
+ parts.push("\n**Differences:**");
45
+ parts.push(formatBulletList(data.differences.map(String)));
46
+ }
47
+ if (data.recommendation) {
48
+ parts.push(`\n**Recommendation:** ${data.recommendation}`);
49
+ }
50
+ if (citations.length > 0) {
51
+ parts.push(`\n${formatInlineCitations(citations)}`);
52
+ }
53
+ return parts.join("\n");
54
+ },
55
+ },
56
+ enumeration: {
57
+ heading: "Types and Categories",
58
+ level: 2,
59
+ formatter: (data, citations) => {
60
+ const parts = [];
61
+ if (Array.isArray(data.items) && data.items.length > 0) {
62
+ parts.push(formatBulletList(data.items.map(String)));
63
+ }
64
+ if (data.categories && typeof data.categories === "object") {
65
+ for (const [category, items] of Object.entries(data.categories)) {
66
+ parts.push(`\n**${category}:**`);
67
+ if (Array.isArray(items)) {
68
+ parts.push(formatBulletList(items.map(String)));
69
+ }
70
+ }
71
+ }
72
+ if (citations.length > 0) {
73
+ parts.push(`\n${formatInlineCitations(citations)}`);
74
+ }
75
+ return parts.join("\n");
76
+ },
77
+ },
78
+ procedure: {
79
+ heading: "Process",
80
+ level: 2,
81
+ formatter: (data, citations) => {
82
+ const parts = [];
83
+ if (Array.isArray(data.prerequisites) && data.prerequisites.length > 0) {
84
+ parts.push("**Prerequisites:**");
85
+ parts.push(formatBulletList(data.prerequisites.map(String)));
86
+ }
87
+ if (Array.isArray(data.steps) && data.steps.length > 0) {
88
+ parts.push("\n**Steps:**");
89
+ data.steps.forEach((step, i) => {
90
+ parts.push(`${i + 1}. ${step}`);
91
+ });
92
+ }
93
+ if (Array.isArray(data.warnings) && data.warnings.length > 0) {
94
+ parts.push("\n" + formatCallout(data.warnings.join("\n"), "warning"));
95
+ }
96
+ if (citations.length > 0) {
97
+ parts.push(`\n${formatInlineCitations(citations)}`);
98
+ }
99
+ return parts.join("\n");
100
+ },
101
+ },
102
+ causation: {
103
+ heading: "Causes and Factors",
104
+ level: 2,
105
+ formatter: (data, citations) => {
106
+ const parts = [];
107
+ if (Array.isArray(data.primary_causes) && data.primary_causes.length > 0) {
108
+ parts.push("**Primary Causes:**");
109
+ parts.push(formatBulletList(data.primary_causes.map(String)));
110
+ }
111
+ if (Array.isArray(data.contributing_factors) && data.contributing_factors.length > 0) {
112
+ parts.push("\n**Contributing Factors:**");
113
+ parts.push(formatBulletList(data.contributing_factors.map(String)));
114
+ }
115
+ if (data.evidence_quality) {
116
+ parts.push(`\n*Evidence Quality: ${data.evidence_quality}*`);
117
+ }
118
+ if (citations.length > 0) {
119
+ parts.push(`\n${formatInlineCitations(citations)}`);
120
+ }
121
+ return parts.join("\n");
122
+ },
123
+ },
124
+ evidence: {
125
+ heading: "Evidence",
126
+ level: 2,
127
+ formatter: (data, citations) => {
128
+ const parts = [];
129
+ if (Array.isArray(data.supporting_evidence) && data.supporting_evidence.length > 0) {
130
+ parts.push("**Supporting Evidence:**");
131
+ parts.push(formatBulletList(data.supporting_evidence.map(String)));
132
+ }
133
+ if (Array.isArray(data.contrary_evidence) && data.contrary_evidence.length > 0) {
134
+ parts.push("\n**Contrary Evidence:**");
135
+ parts.push(formatBulletList(data.contrary_evidence.map(String)));
136
+ }
137
+ if (data.consensus) {
138
+ parts.push(`\n**Consensus:** ${data.consensus}`);
139
+ }
140
+ if (citations.length > 0) {
141
+ parts.push(`\n${formatInlineCitations(citations)}`);
142
+ }
143
+ return parts.join("\n");
144
+ },
145
+ },
146
+ current_state: {
147
+ heading: "Current State",
148
+ level: 2,
149
+ formatter: (data, citations) => {
150
+ const parts = [];
151
+ if (data.current_status) {
152
+ parts.push(String(data.current_status));
153
+ }
154
+ if (Array.isArray(data.recent_developments) && data.recent_developments.length > 0) {
155
+ parts.push("\n**Recent Developments:**");
156
+ parts.push(formatBulletList(data.recent_developments.map(String)));
157
+ }
158
+ if (Array.isArray(data.key_players) && data.key_players.length > 0) {
159
+ parts.push("\n**Key Players:**");
160
+ parts.push(formatBulletList(data.key_players.map(String)));
161
+ }
162
+ if (citations.length > 0) {
163
+ parts.push(`\n${formatInlineCitations(citations)}`);
164
+ }
165
+ return parts.join("\n");
166
+ },
167
+ },
168
+ historical: {
169
+ heading: "Historical Context",
170
+ level: 2,
171
+ formatter: (data, citations) => {
172
+ const parts = [];
173
+ if (Array.isArray(data.timeline) && data.timeline.length > 0) {
174
+ parts.push("**Timeline:**");
175
+ parts.push(formatBulletList(data.timeline.map(String)));
176
+ }
177
+ if (Array.isArray(data.milestones) && data.milestones.length > 0) {
178
+ parts.push("\n**Key Milestones:**");
179
+ parts.push(formatBulletList(data.milestones.map(String)));
180
+ }
181
+ if (Array.isArray(data.key_figures) && data.key_figures.length > 0) {
182
+ parts.push("\n**Key Figures:**");
183
+ parts.push(formatBulletList(data.key_figures.map(String)));
184
+ }
185
+ if (citations.length > 0) {
186
+ parts.push(`\n${formatInlineCitations(citations)}`);
187
+ }
188
+ return parts.join("\n");
189
+ },
190
+ },
191
+ prediction: {
192
+ heading: "Future Outlook",
193
+ level: 2,
194
+ formatter: (data, citations) => {
195
+ const parts = [];
196
+ if (Array.isArray(data.short_term) && data.short_term.length > 0) {
197
+ parts.push("**Short-term Outlook:**");
198
+ parts.push(formatBulletList(data.short_term.map(String)));
199
+ }
200
+ if (Array.isArray(data.long_term) && data.long_term.length > 0) {
201
+ parts.push("\n**Long-term Outlook:**");
202
+ parts.push(formatBulletList(data.long_term.map(String)));
203
+ }
204
+ if (Array.isArray(data.uncertainties) && data.uncertainties.length > 0) {
205
+ parts.push("\n**Key Uncertainties:**");
206
+ parts.push(formatBulletList(data.uncertainties.map(String)));
207
+ }
208
+ if (citations.length > 0) {
209
+ parts.push(`\n${formatInlineCitations(citations)}`);
210
+ }
211
+ return parts.join("\n");
212
+ },
213
+ },
214
+ opinion: {
215
+ heading: "Expert Perspectives",
216
+ level: 2,
217
+ formatter: (data, citations) => {
218
+ const parts = [];
219
+ if (data.majority_view) {
220
+ parts.push(`**Majority View:** ${data.majority_view}`);
221
+ }
222
+ if (Array.isArray(data.alternative_views) && data.alternative_views.length > 0) {
223
+ parts.push("\n**Alternative Views:**");
224
+ parts.push(formatBulletList(data.alternative_views.map(String)));
225
+ }
226
+ if (Array.isArray(data.key_debates) && data.key_debates.length > 0) {
227
+ parts.push("\n**Key Debates:**");
228
+ parts.push(formatBulletList(data.key_debates.map(String)));
229
+ }
230
+ if (citations.length > 0) {
231
+ parts.push(`\n${formatInlineCitations(citations)}`);
232
+ }
233
+ return parts.join("\n");
234
+ },
235
+ },
236
+ // Patent-grade section templates
237
+ patent_broad: {
238
+ heading: "Patent Landscape",
239
+ level: 2,
240
+ formatter: (data, citations) => {
241
+ const parts = [];
242
+ if (Array.isArray(data.patents) && data.patents.length > 0) {
243
+ parts.push("**Relevant Patents:**");
244
+ parts.push(formatBulletList(data.patents.map(String)));
245
+ }
246
+ if (Array.isArray(data.key_claims) && data.key_claims.length > 0) {
247
+ parts.push("\n**Key Claim Language:**");
248
+ parts.push(formatBulletList(data.key_claims.map(String)));
249
+ }
250
+ if (Array.isArray(data.classifications) && data.classifications.length > 0) {
251
+ parts.push("\n**Technology Classifications:** " + data.classifications.join(", "));
252
+ }
253
+ if (Array.isArray(data.assignees) && data.assignees.length > 0) {
254
+ parts.push("\n**Major Assignees:** " + data.assignees.join(", "));
255
+ }
256
+ if (citations.length > 0) {
257
+ parts.push(`\n${formatInlineCitations(citations)}`);
258
+ }
259
+ return parts.join("\n");
260
+ },
261
+ },
262
+ patent_synonyms: {
263
+ heading: "Terminology Analysis",
264
+ level: 2,
265
+ formatter: (data, citations) => {
266
+ const parts = [];
267
+ if (Array.isArray(data.synonyms) && data.synonyms.length > 0) {
268
+ parts.push("**Alternative Terms:**");
269
+ parts.push(formatBulletList(data.synonyms.map(String)));
270
+ }
271
+ if (Array.isArray(data.patent_language) && data.patent_language.length > 0) {
272
+ parts.push("\n**Patent Language:**");
273
+ parts.push(formatBulletList(data.patent_language.map(String)));
274
+ }
275
+ if (citations.length > 0) {
276
+ parts.push(`\n${formatInlineCitations(citations)}`);
277
+ }
278
+ return parts.join("\n");
279
+ },
280
+ },
281
+ patent_problem_benefit: {
282
+ heading: "Problem-Solution Analysis",
283
+ level: 2,
284
+ formatter: (data, citations) => {
285
+ const parts = [];
286
+ if (Array.isArray(data.problems) && data.problems.length > 0) {
287
+ parts.push("**Problems Addressed:**");
288
+ parts.push(formatBulletList(data.problems.map(String)));
289
+ }
290
+ if (Array.isArray(data.benefits) && data.benefits.length > 0) {
291
+ parts.push("\n**Claimed Benefits:**");
292
+ parts.push(formatBulletList(data.benefits.map(String)));
293
+ }
294
+ if (Array.isArray(data.technical_effects) && data.technical_effects.length > 0) {
295
+ parts.push("\n**Technical Effects:**");
296
+ parts.push(formatBulletList(data.technical_effects.map(String)));
297
+ }
298
+ if (data.prior_art_gap) {
299
+ parts.push(`\n**Gap in Prior Art:** ${data.prior_art_gap}`);
300
+ }
301
+ if (citations.length > 0) {
302
+ parts.push(`\n${formatInlineCitations(citations)}`);
303
+ }
304
+ return parts.join("\n");
305
+ },
306
+ },
307
+ patent_competitor: {
308
+ heading: "Competitor Analysis",
309
+ level: 2,
310
+ formatter: (data, citations) => {
311
+ const parts = [];
312
+ if (Array.isArray(data.assignees) && data.assignees.length > 0) {
313
+ parts.push("**Key Patent Holders:**");
314
+ parts.push(formatBulletList(data.assignees.map(String)));
315
+ }
316
+ if (Array.isArray(data.recent_filings) && data.recent_filings.length > 0) {
317
+ parts.push("\n**Recent Filing Activity:**");
318
+ parts.push(formatBulletList(data.recent_filings.map(String)));
319
+ }
320
+ if (Array.isArray(data.key_patents) && data.key_patents.length > 0) {
321
+ parts.push("\n**Most Cited Patents:**");
322
+ parts.push(formatBulletList(data.key_patents.map(String)));
323
+ }
324
+ if (citations.length > 0) {
325
+ parts.push(`\n${formatInlineCitations(citations)}`);
326
+ }
327
+ return parts.join("\n");
328
+ },
329
+ },
330
+ patent_limitation: {
331
+ heading: "Claim Limitations",
332
+ level: 2,
333
+ formatter: (data, citations) => {
334
+ const parts = [];
335
+ if (Array.isArray(data.claim_elements) && data.claim_elements.length > 0) {
336
+ parts.push("**Claim Elements:**");
337
+ parts.push(formatBulletList(data.claim_elements.map(String)));
338
+ }
339
+ if (Array.isArray(data.limitations) && data.limitations.length > 0) {
340
+ parts.push("\n**Technical Limitations:**");
341
+ parts.push(formatBulletList(data.limitations.map(String)));
342
+ }
343
+ if (data.parameters && typeof data.parameters === "object") {
344
+ parts.push("\n**Parameter Ranges:**");
345
+ for (const [param, value] of Object.entries(data.parameters)) {
346
+ parts.push(`- ${param}: ${value}`);
347
+ }
348
+ }
349
+ if (citations.length > 0) {
350
+ parts.push(`\n${formatInlineCitations(citations)}`);
351
+ }
352
+ return parts.join("\n");
353
+ },
354
+ },
355
+ // Web query section templates
356
+ web_academic: {
357
+ heading: "Academic Research",
358
+ level: 2,
359
+ formatter: (data, citations) => {
360
+ const parts = [];
361
+ if (Array.isArray(data.papers) && data.papers.length > 0) {
362
+ parts.push("**Academic Publications:**");
363
+ parts.push(formatBulletList(data.papers.map(String)));
364
+ }
365
+ if (Array.isArray(data.authors) && data.authors.length > 0) {
366
+ parts.push("\n**Key Researchers:** " + data.authors.join(", "));
367
+ }
368
+ if (Array.isArray(data.institutions) && data.institutions.length > 0) {
369
+ parts.push("\n**Research Institutions:** " + data.institutions.join(", "));
370
+ }
371
+ if (citations.length > 0) {
372
+ parts.push(`\n${formatInlineCitations(citations)}`);
373
+ }
374
+ return parts.join("\n");
375
+ },
376
+ },
377
+ web_vendor: {
378
+ heading: "Commercial Implementations",
379
+ level: 2,
380
+ formatter: (data, citations) => {
381
+ const parts = [];
382
+ if (Array.isArray(data.products) && data.products.length > 0) {
383
+ parts.push("**Commercial Products:**");
384
+ parts.push(formatBulletList(data.products.map(String)));
385
+ }
386
+ if (Array.isArray(data.vendors) && data.vendors.length > 0) {
387
+ parts.push("\n**Vendors:** " + data.vendors.join(", "));
388
+ }
389
+ if (data.availability) {
390
+ parts.push(`\n**Market Availability:** ${data.availability}`);
391
+ }
392
+ if (citations.length > 0) {
393
+ parts.push(`\n${formatInlineCitations(citations)}`);
394
+ }
395
+ return parts.join("\n");
396
+ },
397
+ },
398
+ web_opensource: {
399
+ heading: "Open Source Implementations",
400
+ level: 2,
401
+ formatter: (data, citations) => {
402
+ const parts = [];
403
+ if (Array.isArray(data.repositories) && data.repositories.length > 0) {
404
+ parts.push("**Repositories:**");
405
+ parts.push(formatBulletList(data.repositories.map(String)));
406
+ }
407
+ if (Array.isArray(data.implementations) && data.implementations.length > 0) {
408
+ parts.push("\n**Implementations:**");
409
+ parts.push(formatBulletList(data.implementations.map(String)));
410
+ }
411
+ if (Array.isArray(data.licenses) && data.licenses.length > 0) {
412
+ parts.push("\n**Licenses:** " + data.licenses.join(", "));
413
+ }
414
+ if (citations.length > 0) {
415
+ parts.push(`\n${formatInlineCitations(citations)}`);
416
+ }
417
+ return parts.join("\n");
418
+ },
419
+ },
420
+ web_conference: {
421
+ heading: "Conference Papers",
422
+ level: 2,
423
+ formatter: (data, citations) => {
424
+ const parts = [];
425
+ if (Array.isArray(data.papers) && data.papers.length > 0) {
426
+ parts.push("**Papers:**");
427
+ parts.push(formatBulletList(data.papers.map(String)));
428
+ }
429
+ if (Array.isArray(data.conferences) && data.conferences.length > 0) {
430
+ parts.push("\n**Conferences:** " + data.conferences.join(", "));
431
+ }
432
+ if (Array.isArray(data.preprints) && data.preprints.length > 0) {
433
+ parts.push("\n**Preprints:**");
434
+ parts.push(formatBulletList(data.preprints.map(String)));
435
+ }
436
+ if (citations.length > 0) {
437
+ parts.push(`\n${formatInlineCitations(citations)}`);
438
+ }
439
+ return parts.join("\n");
440
+ },
441
+ },
442
+ };
443
+ /**
444
+ * Format inline citation references
445
+ */
446
+ function formatInlineCitations(citations) {
447
+ if (citations.length === 0)
448
+ return "";
449
+ return citations.map((c) => `[${c.id}]`).join(", ");
450
+ }
451
+ /**
452
+ * Build a report section from a query result
453
+ */
454
+ function buildSection(plan, result) {
455
+ // Find the query in the plan
456
+ const query = plan.queries.find((q) => q.query_id === result.query_id);
457
+ if (!query)
458
+ return null;
459
+ // Skip failed queries
460
+ if (!result.success || !result.data)
461
+ return null;
462
+ // Get template for query type
463
+ const template = SECTION_TEMPLATES[query.query_type];
464
+ if (!template) {
465
+ // Fallback for unknown types
466
+ return {
467
+ heading: query.query_text,
468
+ level: 2,
469
+ content: JSON.stringify(result.data, null, 2),
470
+ citations_used: result.sources?.map((s) => s.id) ?? [],
471
+ };
472
+ }
473
+ const content = template.formatter(result.data, result.sources ?? []);
474
+ return {
475
+ heading: template.heading,
476
+ level: template.level,
477
+ content,
478
+ citations_used: result.sources?.map((s) => s.id) ?? [],
479
+ };
480
+ }
481
+ /**
482
+ * Generate executive summary from sections
483
+ */
484
+ function generateExecutiveSummary(topic, sections, stats) {
485
+ const parts = [];
486
+ parts.push(`This report presents research findings on **${topic}**.`);
487
+ if (stats.succeeded > 0) {
488
+ parts.push(`The analysis covers ${stats.succeeded} research queries across ${sections.length} sections.`);
489
+ }
490
+ if (stats.failed > 0) {
491
+ parts.push(`Note: ${stats.failed} queries could not be completed.`);
492
+ }
493
+ // Add brief description of each section
494
+ const sectionNames = sections.map((s) => s.heading).slice(0, 5);
495
+ if (sectionNames.length > 0) {
496
+ parts.push(`Key topics include: ${sectionNames.join(", ")}.`);
497
+ }
498
+ return parts.join(" ");
499
+ }
500
+ /**
501
+ * Build the full markdown report
502
+ */
503
+ function buildMarkdownReport(title, summary, sections, sources, includeSources, includeMethodology, citationStyle) {
504
+ const parts = [];
505
+ // Title
506
+ parts.push(`# ${title}`);
507
+ parts.push("");
508
+ // Executive Summary
509
+ parts.push("## Executive Summary");
510
+ parts.push("");
511
+ parts.push(summary);
512
+ parts.push("");
513
+ // Methodology (optional)
514
+ if (includeMethodology) {
515
+ parts.push("## Methodology");
516
+ parts.push("");
517
+ parts.push("This report was compiled using a sequential research approach:");
518
+ parts.push("1. Research queries were generated based on the topic and focus areas");
519
+ parts.push("2. Each query was executed to gather relevant information");
520
+ parts.push("3. Results were compiled and organized into thematic sections");
521
+ parts.push("4. Sources were consolidated and citations were verified");
522
+ parts.push("");
523
+ }
524
+ // Content sections
525
+ for (const section of sections) {
526
+ parts.push("#".repeat(section.level) + " " + section.heading);
527
+ parts.push("");
528
+ parts.push(section.content);
529
+ parts.push("");
530
+ }
531
+ // Sources
532
+ if (includeSources && sources.length > 0) {
533
+ parts.push(formatSourcesList(sources, citationStyle));
534
+ }
535
+ return parts.join("\n");
536
+ }
537
+ /**
538
+ * Check if this is a patent-focused research plan
539
+ */
540
+ function isPatentFocused(plan) {
541
+ return plan.queries.some((q) => q.query_type.startsWith("patent_") || q.query_type.startsWith("web_"));
542
+ }
543
+ /**
544
+ * Generate prior art clusters from sources
545
+ */
546
+ function generatePriorArtClusters(sources, _results, _plan) {
547
+ const clusters = [];
548
+ // Group by source type
549
+ const patentSources = sources.filter((s) => s.source_type === "patent" || s.source_type === "document");
550
+ const webSources = sources.filter((s) => s.source_type === "web");
551
+ const academicSources = sources.filter((s) => s.url?.includes(".edu") || s.url?.includes("arxiv") || s.url?.includes("ieee"));
552
+ if (patentSources.length > 0) {
553
+ clusters.push({
554
+ cluster_id: generateId("cluster"),
555
+ theme: "Patent Prior Art",
556
+ source_ids: patentSources.map((s) => s.id),
557
+ relevance: "high",
558
+ overlap_notes: `${patentSources.length} patent documents identified as potential prior art`,
559
+ });
560
+ }
561
+ if (academicSources.length > 0) {
562
+ clusters.push({
563
+ cluster_id: generateId("cluster"),
564
+ theme: "Academic Publications",
565
+ source_ids: academicSources.map((s) => s.id),
566
+ relevance: "medium",
567
+ overlap_notes: `${academicSources.length} academic sources may establish prior knowledge`,
568
+ });
569
+ }
570
+ const commercialSources = webSources.filter((s) => !s.url?.includes(".edu") && !s.url?.includes("arxiv") && !s.url?.includes("github"));
571
+ if (commercialSources.length > 0) {
572
+ clusters.push({
573
+ cluster_id: generateId("cluster"),
574
+ theme: "Commercial Prior Art",
575
+ source_ids: commercialSources.map((s) => s.id),
576
+ relevance: "medium",
577
+ overlap_notes: `${commercialSources.length} commercial sources showing market implementation`,
578
+ });
579
+ }
580
+ const ossSources = webSources.filter((s) => s.url?.includes("github") || s.url?.includes("gitlab"));
581
+ if (ossSources.length > 0) {
582
+ clusters.push({
583
+ cluster_id: generateId("cluster"),
584
+ theme: "Open Source Prior Art",
585
+ source_ids: ossSources.map((s) => s.id),
586
+ relevance: "low",
587
+ overlap_notes: `${ossSources.length} open source implementations may affect novelty`,
588
+ });
589
+ }
590
+ return clusters;
591
+ }
592
+ /**
593
+ * Generate claim risk flags based on results
594
+ */
595
+ function generateClaimRiskFlags(sources, results, plan) {
596
+ const risks = [];
597
+ // Check for potential anticipation
598
+ const patentResults = results.filter((r) => {
599
+ const query = plan.queries.find((q) => q.query_id === r.query_id);
600
+ return query?.query_type.startsWith("patent_");
601
+ });
602
+ if (patentResults.length > 0) {
603
+ const patentCount = sources.filter((s) => s.source_type === "patent" || s.source_type === "document").length;
604
+ if (patentCount > 5) {
605
+ risks.push({
606
+ risk_id: generateId("risk"),
607
+ severity: "high",
608
+ category: "anticipation",
609
+ description: `${patentCount} potentially relevant patents identified. Review each for anticipation of core claims.`,
610
+ blocking_sources: sources
611
+ .filter((s) => s.source_type === "patent" || s.source_type === "document")
612
+ .slice(0, 5)
613
+ .map((s) => s.id),
614
+ mitigation: "Conduct detailed claim-by-claim analysis against top 5 most relevant patents",
615
+ });
616
+ }
617
+ }
618
+ // Check for obviousness risk
619
+ const problemBenefitResults = results.filter((r) => {
620
+ const query = plan.queries.find((q) => q.query_id === r.query_id);
621
+ return query?.query_type === "patent_problem_benefit";
622
+ });
623
+ if (problemBenefitResults.length > 0 && sources.length > 3) {
624
+ risks.push({
625
+ risk_id: generateId("risk"),
626
+ severity: "medium",
627
+ category: "obviousness",
628
+ description: "Multiple sources address similar problems. Combination of references may render claims obvious.",
629
+ mitigation: "Identify unexpected results or synergistic effects to overcome obviousness",
630
+ });
631
+ }
632
+ // Check for academic prior art
633
+ const academicCount = sources.filter((s) => s.url?.includes(".edu") || s.url?.includes("arxiv") || s.url?.includes("ieee")).length;
634
+ if (academicCount > 3) {
635
+ risks.push({
636
+ risk_id: generateId("risk"),
637
+ severity: "medium",
638
+ category: "anticipation",
639
+ description: `${academicCount} academic publications found. Academic literature often predates patent filings.`,
640
+ blocking_sources: sources
641
+ .filter((s) => s.url?.includes(".edu") || s.url?.includes("arxiv"))
642
+ .slice(0, 3)
643
+ .map((s) => s.id),
644
+ mitigation: "Check publication dates against priority date; identify implementation-specific claims",
645
+ });
646
+ }
647
+ return risks;
648
+ }
649
+ /**
650
+ * Generate novelty gap suggestions
651
+ */
652
+ function generateNoveltyGaps(sources, results, plan) {
653
+ const gaps = [];
654
+ // Look for limitation results
655
+ const limitationResults = results.filter((r) => {
656
+ const query = plan.queries.find((q) => q.query_id === r.query_id);
657
+ return query?.query_type === "patent_limitation";
658
+ });
659
+ if (limitationResults.length > 0) {
660
+ for (const result of limitationResults) {
661
+ if (!result.success || !result.data)
662
+ continue;
663
+ const data = result.data;
664
+ // Suggest parameter-based differentiation
665
+ if (data.parameters && typeof data.parameters === "object") {
666
+ const params = Object.keys(data.parameters);
667
+ if (params.length > 0) {
668
+ gaps.push({
669
+ gap_id: generateId("gap"),
670
+ limitation_type: "parameter",
671
+ description: `Consider novel parameter ranges for: ${params.join(", ")}`,
672
+ confidence: "medium",
673
+ claim_language_suggestion: `wherein the ${params[0]} is in a range of [X] to [Y]`,
674
+ });
675
+ }
676
+ }
677
+ // Suggest structural differentiation
678
+ if (Array.isArray(data.claim_elements) && data.claim_elements.length > 0) {
679
+ gaps.push({
680
+ gap_id: generateId("gap"),
681
+ limitation_type: "structural",
682
+ description: "Consider adding structural limitations not found in prior art",
683
+ confidence: "medium",
684
+ claim_language_suggestion: "comprising a [novel component] configured to [novel function]",
685
+ });
686
+ }
687
+ }
688
+ }
689
+ // Look for problem-benefit gaps
690
+ const problemResults = results.filter((r) => {
691
+ const query = plan.queries.find((q) => q.query_id === r.query_id);
692
+ return query?.query_type === "patent_problem_benefit";
693
+ });
694
+ if (problemResults.length > 0) {
695
+ for (const result of problemResults) {
696
+ if (!result.success || !result.data)
697
+ continue;
698
+ const data = result.data;
699
+ if (data.prior_art_gap) {
700
+ gaps.push({
701
+ gap_id: generateId("gap"),
702
+ limitation_type: "functional",
703
+ description: String(data.prior_art_gap),
704
+ confidence: "high",
705
+ claim_language_suggestion: "wherein [component] is configured to [address identified gap]",
706
+ });
707
+ }
708
+ }
709
+ }
710
+ // Suggest combination novelty if multiple sources
711
+ if (sources.length > 5) {
712
+ gaps.push({
713
+ gap_id: generateId("gap"),
714
+ limitation_type: "combination",
715
+ description: "Consider claiming novel combination of known elements that produces unexpected result",
716
+ confidence: "low",
717
+ claim_language_suggestion: "A system comprising [element A] and [element B] configured to cooperatively [produce unexpected result]",
718
+ });
719
+ }
720
+ return gaps;
721
+ }
722
+ /**
723
+ * Build patent analysis section for markdown report
724
+ */
725
+ function buildPatentAnalysisSection(clusters, risks, gaps) {
726
+ const parts = [];
727
+ if (clusters.length > 0 || risks.length > 0 || gaps.length > 0) {
728
+ parts.push("## Patent Analysis");
729
+ parts.push("");
730
+ }
731
+ if (clusters.length > 0) {
732
+ parts.push("### Prior Art Clusters");
733
+ parts.push("");
734
+ for (const cluster of clusters) {
735
+ parts.push(`**${cluster.theme}** (${cluster.relevance} relevance)`);
736
+ parts.push(`- Sources: ${cluster.source_ids.join(", ")}`);
737
+ if (cluster.overlap_notes) {
738
+ parts.push(`- ${cluster.overlap_notes}`);
739
+ }
740
+ parts.push("");
741
+ }
742
+ }
743
+ if (risks.length > 0) {
744
+ parts.push("### Claim Risk Flags");
745
+ parts.push("");
746
+ for (const risk of risks) {
747
+ const severityIcon = risk.severity === "critical" ? "!!!" :
748
+ risk.severity === "high" ? "!!" : "!";
749
+ parts.push(`**${severityIcon} ${risk.category.toUpperCase()}** (${risk.severity})`);
750
+ parts.push(`- ${risk.description}`);
751
+ if (risk.blocking_sources && risk.blocking_sources.length > 0) {
752
+ parts.push(`- Blocking sources: ${risk.blocking_sources.join(", ")}`);
753
+ }
754
+ if (risk.mitigation) {
755
+ parts.push(`- Mitigation: ${risk.mitigation}`);
756
+ }
757
+ parts.push("");
758
+ }
759
+ }
760
+ if (gaps.length > 0) {
761
+ parts.push("### Novelty Gap Suggestions");
762
+ parts.push("");
763
+ for (const gap of gaps) {
764
+ parts.push(`**${gap.limitation_type.toUpperCase()}** (${gap.confidence} confidence)`);
765
+ parts.push(`- ${gap.description}`);
766
+ if (gap.claim_language_suggestion) {
767
+ parts.push(`- Suggested claim language: \`${gap.claim_language_suggestion}\``);
768
+ }
769
+ parts.push("");
770
+ }
771
+ }
772
+ return parts.join("\n");
773
+ }
774
+ /**
775
+ * Main compile function
776
+ */
777
+ export function compileReport(input) {
778
+ const reportId = generateId("report");
779
+ const warnings = [];
780
+ const patentFocused = isPatentFocused(input.plan);
781
+ // Collect all sources
782
+ const allSources = [];
783
+ for (const result of input.raw_results) {
784
+ if (result.sources) {
785
+ allSources.push(...result.sources);
786
+ }
787
+ }
788
+ // Deduplicate and optionally renumber
789
+ const dedupedSources = deduplicateCitations(allSources);
790
+ const { citations: finalSources, mapping } = renumberCitations(dedupedSources);
791
+ // Build sections
792
+ const sections = [];
793
+ let queriesSucceeded = 0;
794
+ let queriesFailed = 0;
795
+ for (const result of input.raw_results) {
796
+ if (result.success) {
797
+ queriesSucceeded++;
798
+ const section = buildSection(input.plan, result);
799
+ if (section) {
800
+ // Apply citation renumbering
801
+ section.content = applyCitationMapping(section.content, mapping);
802
+ section.citations_used = section.citations_used.map((id) => mapping.get(id) ?? id);
803
+ sections.push(section);
804
+ }
805
+ }
806
+ else {
807
+ queriesFailed++;
808
+ if (result.error) {
809
+ warnings.push(`Query ${result.query_id} failed: ${result.error}`);
810
+ }
811
+ }
812
+ }
813
+ // Generate patent analysis if patent-focused
814
+ let priorArtClusters;
815
+ let claimRiskFlags;
816
+ let noveltyGaps;
817
+ let patentAnalysisSection = "";
818
+ if (patentFocused) {
819
+ priorArtClusters = generatePriorArtClusters(finalSources, input.raw_results, input.plan);
820
+ claimRiskFlags = generateClaimRiskFlags(finalSources, input.raw_results, input.plan);
821
+ noveltyGaps = generateNoveltyGaps(finalSources, input.raw_results, input.plan);
822
+ patentAnalysisSection = buildPatentAnalysisSection(priorArtClusters, claimRiskFlags, noveltyGaps);
823
+ }
824
+ // Generate title
825
+ const title = `Research Report: ${input.plan.topic}`;
826
+ // Generate executive summary
827
+ const executiveSummary = generateExecutiveSummary(input.plan.topic, sections, { succeeded: queriesSucceeded, failed: queriesFailed });
828
+ // Build full markdown report
829
+ let markdownReport = buildMarkdownReport(title, executiveSummary, sections, finalSources, input.include_sources ?? true, input.include_methodology ?? false, input.citation_style ?? "inline");
830
+ // Append patent analysis section if present
831
+ if (patentAnalysisSection) {
832
+ // Insert before sources section
833
+ const sourcesIndex = markdownReport.lastIndexOf("---\n\n### References");
834
+ if (sourcesIndex > 0) {
835
+ markdownReport = markdownReport.slice(0, sourcesIndex) +
836
+ patentAnalysisSection + "\n" +
837
+ markdownReport.slice(sourcesIndex);
838
+ }
839
+ else {
840
+ markdownReport += "\n" + patentAnalysisSection;
841
+ }
842
+ }
843
+ // Calculate statistics
844
+ const wordCount = countWords(markdownReport);
845
+ const patentSourceCount = finalSources.filter((s) => s.source_type === "patent" || s.source_type === "document").length;
846
+ const webSourceCount = finalSources.filter((s) => s.source_type === "web").length;
847
+ return {
848
+ report_id: reportId,
849
+ plan_id: input.plan.plan_id,
850
+ title,
851
+ compiled_at: isoNow(),
852
+ executive_summary: executiveSummary,
853
+ sections,
854
+ markdown_report: markdownReport,
855
+ sources: finalSources,
856
+ statistics: {
857
+ queries_executed: input.raw_results.length,
858
+ queries_succeeded: queriesSucceeded,
859
+ queries_failed: queriesFailed,
860
+ total_sources: finalSources.length,
861
+ word_count: wordCount,
862
+ patent_sources: patentSourceCount > 0 ? patentSourceCount : undefined,
863
+ web_sources: webSourceCount > 0 ? webSourceCount : undefined,
864
+ },
865
+ prior_art_clusters: priorArtClusters && priorArtClusters.length > 0 ? priorArtClusters : undefined,
866
+ claim_risk_flags: claimRiskFlags && claimRiskFlags.length > 0 ? claimRiskFlags : undefined,
867
+ novelty_gaps: noveltyGaps && noveltyGaps.length > 0 ? noveltyGaps : undefined,
868
+ warnings: warnings.length > 0 ? warnings : undefined,
869
+ };
870
+ }
871
+ //# sourceMappingURL=compilers.js.map