@staticn0va/wigolo 0.4.0 → 0.6.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 (138) hide show
  1. package/SKILL.md +279 -68
  2. package/dist/agent/executor.d.ts +13 -0
  3. package/dist/agent/executor.d.ts.map +1 -0
  4. package/dist/agent/executor.js +128 -0
  5. package/dist/agent/executor.js.map +1 -0
  6. package/dist/agent/pipeline.d.ts +5 -0
  7. package/dist/agent/pipeline.d.ts.map +1 -0
  8. package/dist/agent/pipeline.js +198 -0
  9. package/dist/agent/pipeline.js.map +1 -0
  10. package/dist/agent/planner.d.ts +9 -0
  11. package/dist/agent/planner.d.ts.map +1 -0
  12. package/dist/agent/planner.js +190 -0
  13. package/dist/agent/planner.js.map +1 -0
  14. package/dist/cache/db.d.ts.map +1 -1
  15. package/dist/cache/db.js +32 -0
  16. package/dist/cache/db.js.map +1 -1
  17. package/dist/cache/store.d.ts +14 -0
  18. package/dist/cache/store.d.ts.map +1 -1
  19. package/dist/cache/store.js +69 -0
  20. package/dist/cache/store.js.map +1 -1
  21. package/dist/cli/warmup.d.ts +4 -0
  22. package/dist/cli/warmup.d.ts.map +1 -1
  23. package/dist/cli/warmup.js +58 -0
  24. package/dist/cli/warmup.js.map +1 -1
  25. package/dist/config.d.ts +8 -0
  26. package/dist/config.d.ts.map +1 -1
  27. package/dist/config.js +8 -0
  28. package/dist/config.js.map +1 -1
  29. package/dist/embedding/embed.d.ts +19 -0
  30. package/dist/embedding/embed.d.ts.map +1 -0
  31. package/dist/embedding/embed.js +131 -0
  32. package/dist/embedding/embed.js.map +1 -0
  33. package/dist/embedding/key-terms.d.ts +12 -0
  34. package/dist/embedding/key-terms.d.ts.map +1 -0
  35. package/dist/embedding/key-terms.js +138 -0
  36. package/dist/embedding/key-terms.js.map +1 -0
  37. package/dist/embedding/subprocess.d.ts +31 -0
  38. package/dist/embedding/subprocess.d.ts.map +1 -0
  39. package/dist/embedding/subprocess.js +213 -0
  40. package/dist/embedding/subprocess.js.map +1 -0
  41. package/dist/embedding/vector-index.d.ts +26 -0
  42. package/dist/embedding/vector-index.d.ts.map +1 -0
  43. package/dist/embedding/vector-index.js +78 -0
  44. package/dist/embedding/vector-index.js.map +1 -0
  45. package/dist/fetch/browser-pool.d.ts.map +1 -1
  46. package/dist/fetch/browser-pool.js +61 -0
  47. package/dist/fetch/browser-pool.js.map +1 -1
  48. package/dist/fetch/browser-types.js +1 -1
  49. package/dist/fetch/browser-types.js.map +1 -1
  50. package/dist/fetch/lightpanda.d.ts +28 -0
  51. package/dist/fetch/lightpanda.d.ts.map +1 -0
  52. package/dist/fetch/lightpanda.js +177 -0
  53. package/dist/fetch/lightpanda.js.map +1 -0
  54. package/dist/fetch/router.d.ts +1 -0
  55. package/dist/fetch/router.d.ts.map +1 -1
  56. package/dist/fetch/router.js.map +1 -1
  57. package/dist/instructions.d.ts +9 -6
  58. package/dist/instructions.d.ts.map +1 -1
  59. package/dist/instructions.js +111 -21
  60. package/dist/instructions.js.map +1 -1
  61. package/dist/logger.d.ts +1 -1
  62. package/dist/logger.d.ts.map +1 -1
  63. package/dist/repl/commands/agent.d.ts +5 -0
  64. package/dist/repl/commands/agent.d.ts.map +1 -0
  65. package/dist/repl/commands/agent.js +48 -0
  66. package/dist/repl/commands/agent.js.map +1 -0
  67. package/dist/repl/commands/find-similar.d.ts +5 -0
  68. package/dist/repl/commands/find-similar.d.ts.map +1 -0
  69. package/dist/repl/commands/find-similar.js +61 -0
  70. package/dist/repl/commands/find-similar.js.map +1 -0
  71. package/dist/repl/commands/research.d.ts +5 -0
  72. package/dist/repl/commands/research.d.ts.map +1 -0
  73. package/dist/repl/commands/research.js +50 -0
  74. package/dist/repl/commands/research.js.map +1 -0
  75. package/dist/repl/formatters.d.ts +4 -1
  76. package/dist/repl/formatters.d.ts.map +1 -1
  77. package/dist/repl/formatters.js +73 -0
  78. package/dist/repl/formatters.js.map +1 -1
  79. package/dist/repl/shell.d.ts.map +1 -1
  80. package/dist/repl/shell.js +22 -1
  81. package/dist/repl/shell.js.map +1 -1
  82. package/dist/research/decompose.d.ts +7 -0
  83. package/dist/research/decompose.d.ts.map +1 -0
  84. package/dist/research/decompose.js +195 -0
  85. package/dist/research/decompose.js.map +1 -0
  86. package/dist/research/pipeline.d.ts +5 -0
  87. package/dist/research/pipeline.d.ts.map +1 -0
  88. package/dist/research/pipeline.js +135 -0
  89. package/dist/research/pipeline.js.map +1 -0
  90. package/dist/research/synthesize.d.ts +10 -0
  91. package/dist/research/synthesize.d.ts.map +1 -0
  92. package/dist/research/synthesize.js +119 -0
  93. package/dist/research/synthesize.js.map +1 -0
  94. package/dist/search/answer-synthesis.d.ts +13 -0
  95. package/dist/search/answer-synthesis.d.ts.map +1 -0
  96. package/dist/search/answer-synthesis.js +120 -0
  97. package/dist/search/answer-synthesis.js.map +1 -0
  98. package/dist/search/find-similar.d.ts +5 -0
  99. package/dist/search/find-similar.d.ts.map +1 -0
  100. package/dist/search/find-similar.js +436 -0
  101. package/dist/search/find-similar.js.map +1 -0
  102. package/dist/search/multi-query.d.ts +22 -0
  103. package/dist/search/multi-query.d.ts.map +1 -0
  104. package/dist/search/multi-query.js +157 -0
  105. package/dist/search/multi-query.js.map +1 -0
  106. package/dist/search/rrf.d.ts +17 -0
  107. package/dist/search/rrf.d.ts.map +1 -0
  108. package/dist/search/rrf.js +48 -0
  109. package/dist/search/rrf.js.map +1 -0
  110. package/dist/search/sampling.d.ts +25 -0
  111. package/dist/search/sampling.d.ts.map +1 -0
  112. package/dist/search/sampling.js +52 -0
  113. package/dist/search/sampling.js.map +1 -0
  114. package/dist/server.d.ts.map +1 -1
  115. package/dist/server.js +210 -5
  116. package/dist/server.js.map +1 -1
  117. package/dist/tools/agent.d.ts +5 -0
  118. package/dist/tools/agent.d.ts.map +1 -0
  119. package/dist/tools/agent.js +67 -0
  120. package/dist/tools/agent.js.map +1 -0
  121. package/dist/tools/fetch.d.ts.map +1 -1
  122. package/dist/tools/fetch.js +16 -4
  123. package/dist/tools/fetch.js.map +1 -1
  124. package/dist/tools/find-similar.d.ts +5 -0
  125. package/dist/tools/find-similar.d.ts.map +1 -0
  126. package/dist/tools/find-similar.js +48 -0
  127. package/dist/tools/find-similar.js.map +1 -0
  128. package/dist/tools/research.d.ts +5 -0
  129. package/dist/tools/research.d.ts.map +1 -0
  130. package/dist/tools/research.js +50 -0
  131. package/dist/tools/research.js.map +1 -0
  132. package/dist/tools/search.d.ts +3 -2
  133. package/dist/tools/search.d.ts.map +1 -1
  134. package/dist/tools/search.js +217 -14
  135. package/dist/tools/search.js.map +1 -1
  136. package/dist/types.d.ts +108 -3
  137. package/dist/types.d.ts.map +1 -1
  138. package/package.json +10 -3
@@ -0,0 +1,135 @@
1
+ import { createLogger } from '../logger.js';
2
+ import { decomposeQuestion } from './decompose.js';
3
+ import { synthesizeReport } from './synthesize.js';
4
+ import { deduplicateResults } from '../search/dedup.js';
5
+ import { rerankResults } from '../search/rerank.js';
6
+ import { applyAllFilters } from '../search/filters.js';
7
+ import { fanOutSearch } from '../search/multi-query.js';
8
+ import { extractContent } from '../extraction/pipeline.js';
9
+ import { cacheContent } from '../cache/store.js';
10
+ const log = createLogger('research');
11
+ const DEPTH_CONFIG = {
12
+ quick: { subQueries: 2, minSources: 5, maxSources: 8 },
13
+ standard: { subQueries: 4, minSources: 10, maxSources: 15 },
14
+ comprehensive: { subQueries: 7, minSources: 20, maxSources: 25 },
15
+ };
16
+ export async function runResearchPipeline(input, engines, router, server) {
17
+ const start = Date.now();
18
+ const depth = input.depth ?? 'standard';
19
+ const config = DEPTH_CONFIG[depth] ?? DEPTH_CONFIG.standard;
20
+ const maxSources = input.max_sources ?? config.maxSources;
21
+ try {
22
+ // Phase 1: Decompose question into sub-queries
23
+ log.info('research pipeline started', { question: input.question, depth });
24
+ const decomposeResult = await decomposeQuestion(input.question, depth, server);
25
+ const subQueries = decomposeResult.subQueries;
26
+ log.info('decomposition complete', { subQueryCount: subQueries.length, samplingUsed: decomposeResult.samplingUsed });
27
+ // Phase 2: Parallel search across sub-queries via multi-query fan-out
28
+ const { results: allRaw, enginesUsed: enginesUsedArr, errors: searchErrors } = await fanOutSearch(subQueries, engines, {
29
+ maxResults: Math.ceil(maxSources / subQueries.length) * 2,
30
+ includeDomains: input.include_domains,
31
+ excludeDomains: input.exclude_domains,
32
+ });
33
+ if (searchErrors.length > 0) {
34
+ log.warn('some search sub-queries failed', { errors: searchErrors });
35
+ }
36
+ const enginesUsed = new Set(enginesUsedArr);
37
+ log.info('search phase complete', { totalRaw: allRaw.length, engines: [...enginesUsed] });
38
+ // Phase 3: Deduplicate, filter, rerank
39
+ let merged = deduplicateResults(allRaw);
40
+ merged = applyAllFilters(merged, {
41
+ includeDomains: input.include_domains,
42
+ excludeDomains: input.exclude_domains,
43
+ });
44
+ merged = await rerankResults(input.question, merged);
45
+ merged = merged.slice(0, maxSources);
46
+ if (merged.length === 0) {
47
+ return {
48
+ report: `## Research: ${input.question}\n\nNo sources could be found for this query.`,
49
+ citations: [],
50
+ sources: [],
51
+ sub_queries: subQueries,
52
+ depth,
53
+ total_time_ms: Date.now() - start,
54
+ sampling_supported: !!server,
55
+ };
56
+ }
57
+ // Phase 4: Fetch top sources in parallel
58
+ const sources = await fetchSources(merged, router, maxSources);
59
+ log.info('fetch phase complete', {
60
+ fetched: sources.filter((s) => s.fetched).length,
61
+ failed: sources.filter((s) => !s.fetched).length,
62
+ });
63
+ // Phase 5: Synthesize report
64
+ const synthesisResult = await synthesizeReport(input.question, sources, depth, server);
65
+ log.info('synthesis complete', { samplingUsed: synthesisResult.samplingUsed, reportLength: synthesisResult.report.length });
66
+ return {
67
+ report: synthesisResult.report,
68
+ citations: synthesisResult.citations,
69
+ sources,
70
+ sub_queries: subQueries,
71
+ depth,
72
+ total_time_ms: Date.now() - start,
73
+ sampling_supported: !!server,
74
+ };
75
+ }
76
+ catch (err) {
77
+ log.error('research pipeline failed', {
78
+ question: input.question,
79
+ error: err instanceof Error ? err.message : String(err),
80
+ });
81
+ return {
82
+ report: '',
83
+ citations: [],
84
+ sources: [],
85
+ sub_queries: [],
86
+ depth,
87
+ total_time_ms: Date.now() - start,
88
+ sampling_supported: !!server,
89
+ error: err instanceof Error ? err.message : String(err),
90
+ };
91
+ }
92
+ }
93
+ async function fetchSources(merged, router, maxSources) {
94
+ const fetchPromises = merged.slice(0, maxSources).map(async (result) => {
95
+ try {
96
+ const raw = await Promise.race([
97
+ router.fetch(result.url, { renderJs: 'auto' }),
98
+ new Promise((_, reject) => setTimeout(() => reject(new Error('fetch timeout')), 15000)),
99
+ ]);
100
+ const extraction = await extractContent(raw.html, raw.finalUrl, {
101
+ maxChars: 30000,
102
+ contentType: raw.contentType,
103
+ });
104
+ try {
105
+ cacheContent(raw, extraction);
106
+ }
107
+ catch (err) {
108
+ log.debug('failed to cache research source', { url: result.url, error: String(err) });
109
+ }
110
+ return {
111
+ url: result.url,
112
+ title: extraction.title || result.title,
113
+ markdown_content: extraction.markdown,
114
+ relevance_score: result.relevance_score,
115
+ fetched: true,
116
+ };
117
+ }
118
+ catch (err) {
119
+ log.debug('failed to fetch research source', {
120
+ url: result.url,
121
+ error: err instanceof Error ? err.message : String(err),
122
+ });
123
+ return {
124
+ url: result.url,
125
+ title: result.title,
126
+ markdown_content: result.snippet,
127
+ relevance_score: result.relevance_score,
128
+ fetched: false,
129
+ fetch_error: err instanceof Error ? err.message : String(err),
130
+ };
131
+ }
132
+ });
133
+ return Promise.all(fetchPromises);
134
+ }
135
+ //# sourceMappingURL=pipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/research/pipeline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { type SamplingCapableServer } from '../search/sampling.js';
2
+ import type { ResearchSource, Citation } from '../types.js';
3
+ export interface SynthesisResult {
4
+ report: string;
5
+ citations: Citation[];
6
+ samplingUsed: boolean;
7
+ }
8
+ export declare function synthesizeReport(question: string, sources: ResearchSource[], depth: 'quick' | 'standard' | 'comprehensive', server?: SamplingCapableServer): Promise<SynthesisResult>;
9
+ export declare function buildFallbackReport(question: string, sources: ResearchSource[], maxLength: number): string;
10
+ //# sourceMappingURL=synthesize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synthesize.d.ts","sourceRoot":"","sources":["../../src/research/synthesize.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,qBAAqB,EAG3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAU5D,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,EAAE,EACzB,KAAK,EAAE,OAAO,GAAG,UAAU,GAAG,eAAe,EAC7C,MAAM,CAAC,EAAE,qBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC,CAkC1B;AAkED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,EAAE,EACzB,SAAS,EAAE,MAAM,GAChB,MAAM,CAsCR"}
@@ -0,0 +1,119 @@
1
+ import { createLogger } from '../logger.js';
2
+ import { requestSampling, checkSamplingSupport, } from '../search/sampling.js';
3
+ const log = createLogger('research');
4
+ const DEPTH_TOKEN_LIMITS = {
5
+ quick: { reportChars: 2000, perSourceChars: 3000, totalSourceChars: 20000 },
6
+ standard: { reportChars: 4000, perSourceChars: 3000, totalSourceChars: 30000 },
7
+ comprehensive: { reportChars: 6000, perSourceChars: 3000, totalSourceChars: 40000 },
8
+ };
9
+ export async function synthesizeReport(question, sources, depth, server) {
10
+ const limits = DEPTH_TOKEN_LIMITS[depth] ?? DEPTH_TOKEN_LIMITS.standard;
11
+ const fetchedSources = sources.filter((s) => s.fetched && s.markdown_content.length > 0);
12
+ if (fetchedSources.length === 0) {
13
+ return {
14
+ report: `## Research: ${question}\n\nNo sources could be fetched for this query.`,
15
+ citations: [],
16
+ samplingUsed: false,
17
+ };
18
+ }
19
+ const citations = fetchedSources.map((s, i) => ({
20
+ index: i + 1,
21
+ url: s.url,
22
+ title: s.title,
23
+ snippet: s.markdown_content.slice(0, 200),
24
+ }));
25
+ if (server) {
26
+ try {
27
+ const result = await synthesizeWithSampling(question, fetchedSources, citations, limits, server);
28
+ if (result) {
29
+ return { report: result, citations, samplingUsed: true };
30
+ }
31
+ }
32
+ catch (err) {
33
+ log.warn('sampling synthesis failed, using fallback', {
34
+ error: err instanceof Error ? err.message : String(err),
35
+ });
36
+ }
37
+ }
38
+ const report = buildFallbackReport(question, fetchedSources, limits.reportChars);
39
+ return { report, citations, samplingUsed: false };
40
+ }
41
+ async function synthesizeWithSampling(question, sources, citations, limits, server) {
42
+ try {
43
+ if (!checkSamplingSupport(server)) {
44
+ log.debug('client does not support sampling for synthesis');
45
+ return null;
46
+ }
47
+ let totalChars = 0;
48
+ const sourceBlocks = [];
49
+ for (let i = 0; i < sources.length; i++) {
50
+ if (totalChars >= limits.totalSourceChars)
51
+ break;
52
+ const source = sources[i];
53
+ const content = source.markdown_content.slice(0, limits.perSourceChars);
54
+ const block = `[${i + 1}] ${source.title} (${source.url})\n${content}`;
55
+ totalChars += block.length;
56
+ sourceBlocks.push(block);
57
+ }
58
+ const prompt = `You are a research assistant. Synthesize a comprehensive report answering the following question based on the provided sources. Use [N] citation markers to reference sources.
59
+
60
+ Question: ${question}
61
+
62
+ Sources:
63
+ ${sourceBlocks.join('\n\n')}
64
+
65
+ Write a well-structured markdown report of approximately ${limits.reportChars} characters. Include:
66
+ 1. A clear answer to the question
67
+ 2. Key findings from the sources
68
+ 3. Citation markers [1], [2], etc. referencing the source numbers above
69
+ 4. A brief conclusion
70
+
71
+ Report:`;
72
+ const maxTokens = Math.ceil(limits.reportChars / 3);
73
+ const response = await requestSampling(server, [{ role: 'user', content: { type: 'text', text: prompt } }], maxTokens);
74
+ if (!response?.content?.text || response.content.text.trim().length === 0) {
75
+ log.debug('sampling synthesis returned empty response');
76
+ return null;
77
+ }
78
+ return response.content.text.trim();
79
+ }
80
+ catch (err) {
81
+ log.debug('sampling synthesis request failed', {
82
+ error: err instanceof Error ? err.message : String(err),
83
+ });
84
+ return null;
85
+ }
86
+ }
87
+ export function buildFallbackReport(question, sources, maxLength) {
88
+ const fetchedSources = sources.filter((s) => s.markdown_content.length > 0);
89
+ if (fetchedSources.length === 0) {
90
+ return `## Research: ${question}\n\nNo sources available.`;
91
+ }
92
+ const header = `## Research: ${question}\n\nBased on ${fetchedSources.length} source(s):\n\n`;
93
+ let report = header;
94
+ let remaining = maxLength - header.length;
95
+ for (let i = 0; i < fetchedSources.length; i++) {
96
+ if (remaining <= 0)
97
+ break;
98
+ const source = fetchedSources[i];
99
+ const sourceHeader = `### [${i + 1}] ${source.title}\n**URL:** ${source.url}\n\n`;
100
+ if (remaining < sourceHeader.length + 20)
101
+ break;
102
+ report += sourceHeader;
103
+ remaining -= sourceHeader.length;
104
+ const contentBudget = Math.min(remaining - 10, source.markdown_content.length);
105
+ if (contentBudget > 0) {
106
+ let content = source.markdown_content.slice(0, contentBudget);
107
+ if (content.length < source.markdown_content.length) {
108
+ content = content.slice(0, Math.max(contentBudget - 3, 0)) + '...';
109
+ }
110
+ report += content + '\n\n';
111
+ remaining -= content.length + 2;
112
+ }
113
+ }
114
+ if (report.length > maxLength) {
115
+ report = report.slice(0, maxLength - 3) + '...';
116
+ }
117
+ return report.trimEnd();
118
+ }
119
+ //# sourceMappingURL=synthesize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synthesize.js","sourceRoot":"","sources":["../../src/research/synthesize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { SearchResultItem, Citation } from '../types.js';
2
+ import type { SamplingCapableServer } from './sampling.js';
3
+ export interface SynthesisResult {
4
+ answer?: string;
5
+ citations?: Citation[];
6
+ fallback: boolean;
7
+ warning?: string;
8
+ }
9
+ export declare function synthesizeAnswer(results: SearchResultItem[], query: string, server: SamplingCapableServer): Promise<SynthesisResult>;
10
+ export declare function buildSourcesText(results: SearchResultItem[]): string;
11
+ export declare function buildSynthesisPrompt(query: string, sourcesText: string): string;
12
+ export declare function extractCitations(answer: string, results: SearchResultItem[]): Citation[];
13
+ //# sourceMappingURL=answer-synthesis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"answer-synthesis.d.ts","sourceRoot":"","sources":["../../src/search/answer-synthesis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAa3D,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,gBAAgB,EAAE,EAC3B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,eAAe,CAAC,CAwD1B;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,MAAM,CAwBpE;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAc/E;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,gBAAgB,EAAE,GAC1B,QAAQ,EAAE,CA6BZ"}
@@ -0,0 +1,120 @@
1
+ import { checkSamplingSupport, requestSampling, extractTextFromSamplingResponse, } from './sampling.js';
2
+ import { createLogger } from '../logger.js';
3
+ const log = createLogger('search');
4
+ const MAX_CHARS_PER_SOURCE = 3000;
5
+ const MAX_RESPONSE_TOKENS = 1500;
6
+ export async function synthesizeAnswer(results, query, server) {
7
+ try {
8
+ const sourcesText = buildSourcesText(results);
9
+ if (!sourcesText) {
10
+ log.info('no content available for synthesis');
11
+ return {
12
+ fallback: true,
13
+ warning: 'No results with content available for answer synthesis',
14
+ };
15
+ }
16
+ if (!checkSamplingSupport(server)) {
17
+ log.info('sampling not supported by client, falling back to context format');
18
+ return {
19
+ fallback: true,
20
+ warning: 'Client does not support MCP sampling; falling back to context format',
21
+ };
22
+ }
23
+ const prompt = buildSynthesisPrompt(query, sourcesText);
24
+ const response = await requestSampling(server, [{ role: 'user', content: { type: 'text', text: prompt } }], MAX_RESPONSE_TOKENS);
25
+ const answerText = extractTextFromSamplingResponse(response);
26
+ if (!answerText) {
27
+ log.warn('sampling returned empty response');
28
+ return {
29
+ fallback: true,
30
+ warning: 'Sampling returned empty response; falling back to context format',
31
+ };
32
+ }
33
+ const citations = extractCitations(answerText, results);
34
+ log.info('answer synthesis complete', {
35
+ answerLength: answerText.length,
36
+ citationCount: citations.length,
37
+ });
38
+ return {
39
+ answer: answerText,
40
+ citations,
41
+ fallback: false,
42
+ };
43
+ }
44
+ catch (err) {
45
+ log.error('answer synthesis failed', { error: String(err) });
46
+ return {
47
+ fallback: true,
48
+ warning: `Answer synthesis failed: ${err instanceof Error ? err.message : String(err)}; falling back to context format`,
49
+ };
50
+ }
51
+ }
52
+ export function buildSourcesText(results) {
53
+ try {
54
+ const blocks = [];
55
+ let sourceIndex = 1;
56
+ for (const result of results) {
57
+ const content = result.markdown_content || result.snippet || '';
58
+ if (!content.trim())
59
+ continue;
60
+ const truncated = content.length > MAX_CHARS_PER_SOURCE
61
+ ? content.slice(0, MAX_CHARS_PER_SOURCE)
62
+ : content;
63
+ blocks.push(`[${sourceIndex}] ${result.title} (${result.url})\n${truncated}`);
64
+ sourceIndex++;
65
+ }
66
+ if (blocks.length === 0)
67
+ return '';
68
+ return blocks.join('\n\n---\n\n');
69
+ }
70
+ catch (err) {
71
+ log.error('buildSourcesText failed', { error: String(err) });
72
+ return '';
73
+ }
74
+ }
75
+ export function buildSynthesisPrompt(query, sourcesText) {
76
+ return `Based on the following sources, provide a concise and direct answer to the question. Use numbered citations like [1], [2] to reference specific sources.
77
+
78
+ Question: ${query}
79
+
80
+ Sources:
81
+ ${sourcesText}
82
+
83
+ Instructions:
84
+ - Be concise and direct. Answer in 2-4 paragraphs maximum.
85
+ - Cite sources using [1], [2], etc. matching the source numbers above.
86
+ - If sources contain conflicting information, note the discrepancy.
87
+ - If the sources don't adequately answer the question, say so.
88
+ - Do not include information not found in the provided sources.`;
89
+ }
90
+ export function extractCitations(answer, results) {
91
+ try {
92
+ if (!answer || results.length === 0)
93
+ return [];
94
+ const citationRegex = /\[(\d+)\]/g;
95
+ const seen = new Set();
96
+ const citations = [];
97
+ let match;
98
+ while ((match = citationRegex.exec(answer)) !== null) {
99
+ const index = parseInt(match[1], 10);
100
+ if (isNaN(index) || index < 1 || index > results.length)
101
+ continue;
102
+ if (seen.has(index))
103
+ continue;
104
+ seen.add(index);
105
+ const result = results[index - 1];
106
+ citations.push({
107
+ index,
108
+ url: result.url,
109
+ title: result.title,
110
+ snippet: result.snippet,
111
+ });
112
+ }
113
+ return citations;
114
+ }
115
+ catch (err) {
116
+ log.error('citation extraction failed', { error: String(err) });
117
+ return [];
118
+ }
119
+ }
120
+ //# sourceMappingURL=answer-synthesis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"answer-synthesis.js","sourceRoot":"","sources":["../../src/search/answer-synthesis.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { FindSimilarInput, FindSimilarOutput, SearchEngine } from '../types.js';
2
+ import type { SmartRouter } from '../fetch/router.js';
3
+ import type { BackendStatus } from '../server/backend-status.js';
4
+ export declare function findSimilar(input: FindSimilarInput, engines: SearchEngine[], router: SmartRouter, backendStatus?: BackendStatus): Promise<FindSimilarOutput>;
5
+ //# sourceMappingURL=find-similar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-similar.d.ts","sourceRoot":"","sources":["../../src/search/find-similar.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EAEjB,YAAY,EAEb,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAyBjE,wBAAsB,WAAW,CAC/B,KAAK,EAAE,gBAAgB,EACvB,OAAO,EAAE,YAAY,EAAE,EACvB,MAAM,EAAE,WAAW,EACnB,aAAa,CAAC,EAAE,aAAa,GAC5B,OAAO,CAAC,iBAAiB,CAAC,CAqJ5B"}