paper-search-cli 0.3.1 → 0.3.2
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.
- package/README.md +1 -1
- package/README.zh.md +1 -1
- package/dist/capabilities/body-snippet-search/handler.d.ts +9 -0
- package/dist/capabilities/body-snippet-search/handler.d.ts.map +1 -0
- package/dist/capabilities/body-snippet-search/handler.js +17 -0
- package/dist/capabilities/body-snippet-search/handler.js.map +1 -0
- package/dist/capabilities/body-snippet-search/index.d.ts +7 -0
- package/dist/capabilities/body-snippet-search/index.d.ts.map +1 -0
- package/dist/capabilities/body-snippet-search/index.js +6 -0
- package/dist/capabilities/body-snippet-search/index.js.map +1 -0
- package/dist/capabilities/body-snippet-search/schemas.d.ts +36 -0
- package/dist/capabilities/body-snippet-search/schemas.d.ts.map +1 -0
- package/dist/capabilities/body-snippet-search/schemas.js +16 -0
- package/dist/capabilities/body-snippet-search/schemas.js.map +1 -0
- package/dist/capabilities/body-snippet-search/service.d.ts +4 -0
- package/dist/capabilities/body-snippet-search/service.d.ts.map +1 -0
- package/dist/capabilities/body-snippet-search/service.js +4 -0
- package/dist/capabilities/body-snippet-search/service.js.map +1 -0
- package/dist/capabilities/body-snippet-search/tools.d.ts +187 -0
- package/dist/capabilities/body-snippet-search/tools.d.ts.map +1 -0
- package/dist/capabilities/body-snippet-search/tools.js +49 -0
- package/dist/capabilities/body-snippet-search/tools.js.map +1 -0
- package/dist/capabilities/body-snippet-search/types.d.ts +14 -0
- package/dist/capabilities/body-snippet-search/types.d.ts.map +1 -0
- package/dist/capabilities/body-snippet-search/types.js +2 -0
- package/dist/capabilities/body-snippet-search/types.js.map +1 -0
- package/dist/capabilities/citation-expansion/CitationService.d.ts +47 -0
- package/dist/capabilities/citation-expansion/CitationService.d.ts.map +1 -0
- package/dist/capabilities/citation-expansion/CitationService.js +243 -0
- package/dist/capabilities/citation-expansion/CitationService.js.map +1 -0
- package/dist/capabilities/citation-expansion/handler.d.ts +36 -0
- package/dist/capabilities/citation-expansion/handler.d.ts.map +1 -0
- package/dist/capabilities/citation-expansion/handler.js +44 -0
- package/dist/capabilities/citation-expansion/handler.js.map +1 -0
- package/dist/capabilities/citation-expansion/index.d.ts +6 -0
- package/dist/capabilities/citation-expansion/index.d.ts.map +1 -0
- package/dist/capabilities/citation-expansion/index.js +5 -0
- package/dist/capabilities/citation-expansion/index.js.map +1 -0
- package/dist/capabilities/citation-expansion/schemas.d.ts +28 -0
- package/dist/capabilities/citation-expansion/schemas.d.ts.map +1 -0
- package/dist/capabilities/citation-expansion/schemas.js +13 -0
- package/dist/capabilities/citation-expansion/schemas.js.map +1 -0
- package/dist/capabilities/citation-expansion/tools.d.ts +82 -0
- package/dist/capabilities/citation-expansion/tools.d.ts.map +1 -0
- package/dist/capabilities/citation-expansion/tools.js +48 -0
- package/dist/capabilities/citation-expansion/tools.js.map +1 -0
- package/dist/capabilities/citation-expansion/types.d.ts +22 -0
- package/dist/capabilities/citation-expansion/types.d.ts.map +1 -0
- package/dist/capabilities/citation-expansion/types.js +2 -0
- package/dist/capabilities/citation-expansion/types.js.map +1 -0
- package/dist/capabilities/journal-metrics/JournalMetricsService.d.ts +3 -0
- package/dist/capabilities/journal-metrics/JournalMetricsService.d.ts.map +1 -0
- package/dist/capabilities/journal-metrics/JournalMetricsService.js +142 -0
- package/dist/capabilities/journal-metrics/JournalMetricsService.js.map +1 -0
- package/dist/capabilities/journal-metrics/handler.d.ts +12 -0
- package/dist/capabilities/journal-metrics/handler.d.ts.map +1 -0
- package/dist/capabilities/journal-metrics/handler.js +38 -0
- package/dist/capabilities/journal-metrics/handler.js.map +1 -0
- package/dist/capabilities/journal-metrics/index.d.ts +6 -0
- package/dist/capabilities/journal-metrics/index.d.ts.map +1 -0
- package/dist/capabilities/journal-metrics/index.js +5 -0
- package/dist/capabilities/journal-metrics/index.js.map +1 -0
- package/dist/capabilities/journal-metrics/schemas.d.ts +28 -0
- package/dist/capabilities/journal-metrics/schemas.d.ts.map +1 -0
- package/dist/capabilities/journal-metrics/schemas.js +13 -0
- package/dist/capabilities/journal-metrics/schemas.js.map +1 -0
- package/dist/capabilities/journal-metrics/tools.d.ts +67 -0
- package/dist/capabilities/journal-metrics/tools.d.ts.map +1 -0
- package/dist/capabilities/journal-metrics/tools.js +27 -0
- package/dist/capabilities/journal-metrics/tools.js.map +1 -0
- package/dist/capabilities/journal-metrics/types.d.ts +36 -0
- package/dist/capabilities/journal-metrics/types.d.ts.map +1 -0
- package/dist/capabilities/journal-metrics/types.js +2 -0
- package/dist/capabilities/journal-metrics/types.js.map +1 -0
- package/dist/capabilities/metadata-search/MultiSourceSearchService.d.ts +9 -0
- package/dist/capabilities/metadata-search/MultiSourceSearchService.d.ts.map +1 -0
- package/dist/capabilities/metadata-search/MultiSourceSearchService.js +78 -0
- package/dist/capabilities/metadata-search/MultiSourceSearchService.js.map +1 -0
- package/dist/capabilities/metadata-search/handler.d.ts +23 -0
- package/dist/capabilities/metadata-search/handler.d.ts.map +1 -0
- package/dist/capabilities/metadata-search/handler.js +163 -0
- package/dist/capabilities/metadata-search/handler.js.map +1 -0
- package/dist/capabilities/metadata-search/index.d.ts +6 -0
- package/dist/capabilities/metadata-search/index.d.ts.map +1 -0
- package/dist/capabilities/metadata-search/index.js +5 -0
- package/dist/capabilities/metadata-search/index.js.map +1 -0
- package/dist/capabilities/metadata-search/schemas.d.ts +83 -0
- package/dist/capabilities/metadata-search/schemas.d.ts.map +1 -0
- package/dist/capabilities/metadata-search/schemas.js +81 -0
- package/dist/capabilities/metadata-search/schemas.js.map +1 -0
- package/dist/capabilities/metadata-search/tools.d.ts +178 -0
- package/dist/capabilities/metadata-search/tools.d.ts.map +1 -0
- package/dist/capabilities/metadata-search/tools.js +75 -0
- package/dist/capabilities/metadata-search/tools.js.map +1 -0
- package/dist/capabilities/metadata-search/types.d.ts +13 -0
- package/dist/capabilities/metadata-search/types.d.ts.map +1 -0
- package/dist/capabilities/metadata-search/types.js +2 -0
- package/dist/capabilities/metadata-search/types.js.map +1 -0
- package/dist/capabilities/pdf-discovery/DownloadTier.d.ts +22 -0
- package/dist/capabilities/pdf-discovery/DownloadTier.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/DownloadTier.js +2 -0
- package/dist/capabilities/pdf-discovery/DownloadTier.js.map +1 -0
- package/dist/capabilities/pdf-discovery/OpenAccessFallbackService.d.ts +10 -0
- package/dist/capabilities/pdf-discovery/OpenAccessFallbackService.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/OpenAccessFallbackService.js +53 -0
- package/dist/capabilities/pdf-discovery/OpenAccessFallbackService.js.map +1 -0
- package/dist/capabilities/pdf-discovery/handler.d.ts +19 -0
- package/dist/capabilities/pdf-discovery/handler.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/handler.js +56 -0
- package/dist/capabilities/pdf-discovery/handler.js.map +1 -0
- package/dist/capabilities/pdf-discovery/index.d.ts +7 -0
- package/dist/capabilities/pdf-discovery/index.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/index.js +5 -0
- package/dist/capabilities/pdf-discovery/index.js.map +1 -0
- package/dist/capabilities/pdf-discovery/schemas.d.ts +37 -0
- package/dist/capabilities/pdf-discovery/schemas.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/schemas.js +22 -0
- package/dist/capabilities/pdf-discovery/schemas.js.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/directPdfUrl.d.ts +3 -0
- package/dist/capabilities/pdf-discovery/tiers/directPdfUrl.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/directPdfUrl.js +27 -0
- package/dist/capabilities/pdf-discovery/tiers/directPdfUrl.js.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/primary.d.ts +3 -0
- package/dist/capabilities/pdf-discovery/tiers/primary.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/primary.js +21 -0
- package/dist/capabilities/pdf-discovery/tiers/primary.js.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/repositories.d.ts +3 -0
- package/dist/capabilities/pdf-discovery/tiers/repositories.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/repositories.js +35 -0
- package/dist/capabilities/pdf-discovery/tiers/repositories.js.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/scihub.d.ts +3 -0
- package/dist/capabilities/pdf-discovery/tiers/scihub.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/scihub.js +21 -0
- package/dist/capabilities/pdf-discovery/tiers/scihub.js.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/unpaywall.d.ts +3 -0
- package/dist/capabilities/pdf-discovery/tiers/unpaywall.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/unpaywall.js +29 -0
- package/dist/capabilities/pdf-discovery/tiers/unpaywall.js.map +1 -0
- package/dist/capabilities/pdf-discovery/tools.d.ts +114 -0
- package/dist/capabilities/pdf-discovery/tools.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/tools.js +42 -0
- package/dist/capabilities/pdf-discovery/tools.js.map +1 -0
- package/dist/capabilities/pdf-discovery/types.d.ts +19 -0
- package/dist/capabilities/pdf-discovery/types.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/types.js +2 -0
- package/dist/capabilities/pdf-discovery/types.js.map +1 -0
- package/dist/cli.js +6 -6
- package/dist/cli.js.map +1 -1
- package/dist/core/capabilityProfile.d.ts +1 -17
- package/dist/core/capabilityProfile.d.ts.map +1 -1
- package/dist/core/capabilityProfile.js +1 -166
- package/dist/core/capabilityProfile.js.map +1 -1
- package/dist/core/diagnostics.d.ts +1 -42
- package/dist/core/diagnostics.d.ts.map +1 -1
- package/dist/core/diagnostics.js +1 -585
- package/dist/core/diagnostics.js.map +1 -1
- package/dist/core/handleToolCall.d.ts +1 -0
- package/dist/core/handleToolCall.d.ts.map +1 -1
- package/dist/core/handleToolCall.js +265 -509
- package/dist/core/handleToolCall.js.map +1 -1
- package/dist/core/httpPolicies.d.ts +2 -0
- package/dist/core/httpPolicies.d.ts.map +1 -0
- package/dist/core/httpPolicies.js +2 -0
- package/dist/core/httpPolicies.js.map +1 -0
- package/dist/core/liveSmoke.d.ts +1 -41
- package/dist/core/liveSmoke.d.ts.map +1 -1
- package/dist/core/liveSmoke.js +1 -225
- package/dist/core/liveSmoke.js.map +1 -1
- package/dist/core/platformFactories.d.ts +2 -0
- package/dist/core/platformFactories.d.ts.map +1 -0
- package/dist/core/platformFactories.js +2 -0
- package/dist/core/platformFactories.js.map +1 -0
- package/dist/core/platformMetadata.d.ts +1 -27
- package/dist/core/platformMetadata.d.ts.map +1 -1
- package/dist/core/platformMetadata.js +1 -257
- package/dist/core/platformMetadata.js.map +1 -1
- package/dist/core/schemas.d.ts +10 -202
- package/dist/core/schemas.d.ts.map +1 -1
- package/dist/core/schemas.js +11 -118
- package/dist/core/schemas.js.map +1 -1
- package/dist/core/searchers.d.ts +24 -24
- package/dist/core/searchers.d.ts.map +1 -1
- package/dist/core/searchers.js +14 -79
- package/dist/core/searchers.js.map +1 -1
- package/dist/core/textReports.d.ts +1 -20
- package/dist/core/textReports.d.ts.map +1 -1
- package/dist/core/textReports.js +1 -84
- package/dist/core/textReports.js.map +1 -1
- package/dist/core/tools.d.ts.map +1 -1
- package/dist/core/tools.js +15 -237
- package/dist/core/tools.js.map +1 -1
- package/dist/infrastructure/cache/RequestCache.d.ts +26 -0
- package/dist/infrastructure/cache/RequestCache.d.ts.map +1 -0
- package/dist/infrastructure/cache/RequestCache.js +66 -0
- package/dist/infrastructure/cache/RequestCache.js.map +1 -0
- package/dist/infrastructure/http/ErrorHandler.d.ts +99 -0
- package/dist/infrastructure/http/ErrorHandler.d.ts.map +1 -0
- package/dist/infrastructure/http/ErrorHandler.js +266 -0
- package/dist/infrastructure/http/ErrorHandler.js.map +1 -0
- package/dist/infrastructure/http/HttpClient.d.ts +31 -0
- package/dist/infrastructure/http/HttpClient.d.ts.map +1 -0
- package/dist/infrastructure/http/HttpClient.js +50 -0
- package/dist/infrastructure/http/HttpClient.js.map +1 -0
- package/dist/infrastructure/pdf/PDFExtractor.d.ts +34 -0
- package/dist/infrastructure/pdf/PDFExtractor.d.ts.map +1 -0
- package/dist/infrastructure/pdf/PDFExtractor.js +130 -0
- package/dist/infrastructure/pdf/PDFExtractor.js.map +1 -0
- package/dist/infrastructure/pdf/PdfDownload.d.ts +7 -0
- package/dist/infrastructure/pdf/PdfDownload.d.ts.map +1 -0
- package/dist/infrastructure/pdf/PdfDownload.js +175 -0
- package/dist/infrastructure/pdf/PdfDownload.js.map +1 -0
- package/dist/infrastructure/rate-limit/RateLimiter.d.ts +50 -0
- package/dist/infrastructure/rate-limit/RateLimiter.d.ts.map +1 -0
- package/dist/infrastructure/rate-limit/RateLimiter.js +128 -0
- package/dist/infrastructure/rate-limit/RateLimiter.js.map +1 -0
- package/dist/infrastructure/security/SecurityUtils.d.ts +80 -0
- package/dist/infrastructure/security/SecurityUtils.d.ts.map +1 -0
- package/dist/infrastructure/security/SecurityUtils.js +357 -0
- package/dist/infrastructure/security/SecurityUtils.js.map +1 -0
- package/dist/management/capability-profile/index.d.ts +18 -0
- package/dist/management/capability-profile/index.d.ts.map +1 -0
- package/dist/management/capability-profile/index.js +167 -0
- package/dist/management/capability-profile/index.js.map +1 -0
- package/dist/management/config/index.d.ts +2 -0
- package/dist/management/config/index.d.ts.map +1 -0
- package/dist/management/config/index.js +2 -0
- package/dist/management/config/index.js.map +1 -0
- package/dist/management/diagnostics/index.d.ts +43 -0
- package/dist/management/diagnostics/index.d.ts.map +1 -0
- package/dist/management/diagnostics/index.js +586 -0
- package/dist/management/diagnostics/index.js.map +1 -0
- package/dist/management/reports/index.d.ts +21 -0
- package/dist/management/reports/index.d.ts.map +1 -0
- package/dist/management/reports/index.js +85 -0
- package/dist/management/reports/index.js.map +1 -0
- package/dist/management/skills/index.d.ts +2 -0
- package/dist/management/skills/index.d.ts.map +1 -0
- package/dist/management/skills/index.js +2 -0
- package/dist/management/skills/index.js.map +1 -0
- package/dist/management/smoke/index.d.ts +42 -0
- package/dist/management/smoke/index.d.ts.map +1 -0
- package/dist/management/smoke/index.js +226 -0
- package/dist/management/smoke/index.js.map +1 -0
- package/dist/registry/aliases.d.ts +2 -0
- package/dist/registry/aliases.d.ts.map +1 -0
- package/dist/registry/aliases.js +2 -0
- package/dist/registry/aliases.js.map +1 -0
- package/dist/registry/httpPolicies.d.ts +3 -0
- package/dist/registry/httpPolicies.d.ts.map +1 -0
- package/dist/registry/httpPolicies.js +17 -0
- package/dist/registry/httpPolicies.js.map +1 -0
- package/dist/registry/platformFactories.d.ts +8 -0
- package/dist/registry/platformFactories.d.ts.map +1 -0
- package/dist/registry/platformFactories.js +55 -0
- package/dist/registry/platformFactories.js.map +1 -0
- package/dist/registry/platformMetadata.d.ts +39 -0
- package/dist/registry/platformMetadata.d.ts.map +1 -0
- package/dist/registry/platformMetadata.js +321 -0
- package/dist/registry/platformMetadata.js.map +1 -0
- package/dist/services/CitationService.d.ts +2 -65
- package/dist/services/CitationService.d.ts.map +1 -1
- package/dist/services/CitationService.js +1 -242
- package/dist/services/CitationService.js.map +1 -1
- package/dist/services/JournalMetricsService.d.ts +2 -37
- package/dist/services/JournalMetricsService.d.ts.map +1 -1
- package/dist/services/JournalMetricsService.js +1 -141
- package/dist/services/JournalMetricsService.js.map +1 -1
- package/dist/services/MultiSourceSearchService.d.ts +2 -18
- package/dist/services/MultiSourceSearchService.d.ts.map +1 -1
- package/dist/services/MultiSourceSearchService.js +1 -77
- package/dist/services/MultiSourceSearchService.js.map +1 -1
- package/dist/services/OpenAccessFallbackService.d.ts +3 -40
- package/dist/services/OpenAccessFallbackService.d.ts.map +1 -1
- package/dist/services/OpenAccessFallbackService.js +1 -146
- package/dist/services/OpenAccessFallbackService.js.map +1 -1
- package/dist/utils/ErrorHandler.d.ts +2 -98
- package/dist/utils/ErrorHandler.d.ts.map +1 -1
- package/dist/utils/ErrorHandler.js +2 -265
- package/dist/utils/ErrorHandler.js.map +1 -1
- package/dist/utils/HttpClient.d.ts +1 -5
- package/dist/utils/HttpClient.d.ts.map +1 -1
- package/dist/utils/HttpClient.js +1 -29
- package/dist/utils/HttpClient.js.map +1 -1
- package/dist/utils/PDFExtractor.d.ts +2 -33
- package/dist/utils/PDFExtractor.d.ts.map +1 -1
- package/dist/utils/PDFExtractor.js +2 -129
- package/dist/utils/PDFExtractor.js.map +1 -1
- package/dist/utils/PdfDownload.d.ts +1 -6
- package/dist/utils/PdfDownload.d.ts.map +1 -1
- package/dist/utils/PdfDownload.js +1 -141
- package/dist/utils/PdfDownload.js.map +1 -1
- package/dist/utils/RateLimiter.d.ts +1 -49
- package/dist/utils/RateLimiter.d.ts.map +1 -1
- package/dist/utils/RateLimiter.js +1 -127
- package/dist/utils/RateLimiter.js.map +1 -1
- package/dist/utils/RequestCache.d.ts +2 -25
- package/dist/utils/RequestCache.d.ts.map +1 -1
- package/dist/utils/RequestCache.js +2 -65
- package/dist/utils/RequestCache.js.map +1 -1
- package/dist/utils/SecurityUtils.d.ts +2 -79
- package/dist/utils/SecurityUtils.d.ts.map +1 -1
- package/dist/utils/SecurityUtils.js +2 -356
- package/dist/utils/SecurityUtils.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { parseToolArgs } from './schemas.js';
|
|
2
2
|
import { PaperFactory } from '../models/Paper.js';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
9
|
-
import { withTimeout } from '../utils/SecurityUtils.js';
|
|
10
|
-
import { getGenericSearchToolPlatform, getPlatformMetadata, isPlatformAlias, resolvePlatformId } from './platformMetadata.js';
|
|
3
|
+
import { handleSemanticSnippets } from '../capabilities/body-snippet-search/handler.js';
|
|
4
|
+
import { handleGetPaperCitations, handleGetPaperReferences } from '../capabilities/citation-expansion/handler.js';
|
|
5
|
+
import { handleGenericSearch, handleGetPaperByDoi, handleSearchPapers } from '../capabilities/metadata-search/handler.js';
|
|
6
|
+
import { handleJournalMetrics } from '../capabilities/journal-metrics/handler.js';
|
|
7
|
+
import { handleDownloadPaper, handleDownloadWithFallback } from '../capabilities/pdf-discovery/handler.js';
|
|
8
|
+
import { getGenericSearchToolPlatform, isPlatformAlias } from './platformMetadata.js';
|
|
11
9
|
function jsonTextResponse(text) {
|
|
12
10
|
return {
|
|
13
11
|
content: [
|
|
@@ -18,526 +16,284 @@ function jsonTextResponse(text) {
|
|
|
18
16
|
]
|
|
19
17
|
};
|
|
20
18
|
}
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
.map(item => item.trim())
|
|
40
|
-
.filter(Boolean);
|
|
41
|
-
}
|
|
42
|
-
function normalizeDoi(value) {
|
|
43
|
-
return value
|
|
44
|
-
.trim()
|
|
45
|
-
.replace(/^https?:\/\/(?:dx\.)?doi\.org\//i, '')
|
|
46
|
-
.toLowerCase();
|
|
47
|
-
}
|
|
48
|
-
function paperMatchesDoi(paper, doi) {
|
|
49
|
-
return normalizeDoi(paper.doi || '') === normalizeDoi(doi);
|
|
50
|
-
}
|
|
51
|
-
function resolveCitationTarget(args) {
|
|
52
|
-
if (args.paperId)
|
|
53
|
-
return args.paperId;
|
|
54
|
-
if (args.doi)
|
|
55
|
-
return `DOI:${args.doi}`;
|
|
56
|
-
if (args.arxivId)
|
|
57
|
-
return `ARXIV:${args.arxivId}`;
|
|
58
|
-
throw new Error('Provide paperId, doi, or arxivId');
|
|
59
|
-
}
|
|
60
|
-
function citationResponse(target, relation, papers) {
|
|
61
|
-
return {
|
|
62
|
-
target,
|
|
63
|
-
relation,
|
|
64
|
-
provider: 'semantic_scholar',
|
|
65
|
-
total: papers.length,
|
|
66
|
-
papers
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
async function handleGenericSearch(platform, args, searchers) {
|
|
70
|
-
const resolvedPlatform = resolvePlatformId(platform);
|
|
71
|
-
const searcher = searchers[resolvedPlatform];
|
|
72
|
-
if (!searcher) {
|
|
73
|
-
throw new Error(`Unsupported platform: ${platform}`);
|
|
74
|
-
}
|
|
75
|
-
const { query, ...searchOptions } = args;
|
|
76
|
-
const results = await searcher.search(query, searchOptions);
|
|
77
|
-
const displayName = getPlatformMetadata(platform)?.displayName || platform;
|
|
78
|
-
return jsonTextResponse(`Found ${results.length} ${displayName} papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
79
|
-
}
|
|
80
|
-
export async function handleToolCall(toolNameRaw, rawArgs, searchers) {
|
|
81
|
-
const toolName = toolNameRaw;
|
|
82
|
-
const args = parseToolArgs(toolName, rawArgs);
|
|
83
|
-
const genericSearchPlatform = getGenericSearchToolPlatform(toolNameRaw);
|
|
84
|
-
if (genericSearchPlatform) {
|
|
85
|
-
return handleGenericSearch(genericSearchPlatform, args, searchers);
|
|
86
|
-
}
|
|
87
|
-
switch (toolName) {
|
|
88
|
-
case 'search_papers': {
|
|
89
|
-
const { query, platform, sources, maxResults, year, author, journal, category, days, fetchDetails, fieldsOfStudy, sortBy, sortOrder } = args;
|
|
90
|
-
const results = [];
|
|
91
|
-
const searchOptions = {
|
|
92
|
-
maxResults,
|
|
93
|
-
year,
|
|
94
|
-
author,
|
|
95
|
-
journal,
|
|
96
|
-
category,
|
|
97
|
-
days,
|
|
98
|
-
fetchDetails,
|
|
99
|
-
fieldsOfStudy,
|
|
100
|
-
sortBy,
|
|
101
|
-
sortOrder
|
|
102
|
-
};
|
|
103
|
-
if (platform === 'all') {
|
|
104
|
-
const result = await searchMultipleSources(searchers, query, sources || 'all', searchOptions);
|
|
105
|
-
return jsonTextResponse(`Found ${result.total} papers across ${result.sources_used.length} source(s).\n\n${JSON.stringify(result, null, 2)}`);
|
|
106
|
-
}
|
|
107
|
-
else if (sources) {
|
|
108
|
-
const result = await searchMultipleSources(searchers, query, sources, searchOptions);
|
|
109
|
-
return jsonTextResponse(`Found ${result.total} papers across ${result.sources_used.length} source(s).\n\n${JSON.stringify(result, null, 2)}`);
|
|
110
|
-
}
|
|
111
|
-
else {
|
|
112
|
-
const resolvedPlatform = resolvePlatformId(platform);
|
|
113
|
-
const searcher = searchers[resolvedPlatform];
|
|
114
|
-
if (!searcher) {
|
|
115
|
-
throw new Error(`Unsupported platform: ${platform}`);
|
|
116
|
-
}
|
|
117
|
-
const platformResults = await searcher.search(query, searchOptions);
|
|
118
|
-
results.push(...platformResults.map((paper) => PaperFactory.toDict(paper)));
|
|
119
|
-
}
|
|
120
|
-
return jsonTextResponse(`Found ${results.length} papers.\n\n${JSON.stringify(results, null, 2)}`);
|
|
19
|
+
const TOOL_HANDLERS = {
|
|
20
|
+
search_papers: async (args, searchers) => handleSearchPapers(args, searchers),
|
|
21
|
+
search_arxiv: async (args, searchers) => {
|
|
22
|
+
const { query, maxResults, category, author, year, sortBy, sortOrder } = args;
|
|
23
|
+
const results = await searchers.arxiv.search(query, {
|
|
24
|
+
maxResults,
|
|
25
|
+
category,
|
|
26
|
+
author,
|
|
27
|
+
year,
|
|
28
|
+
sortBy,
|
|
29
|
+
sortOrder
|
|
30
|
+
});
|
|
31
|
+
return jsonTextResponse(`Found ${results.length} arXiv papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
32
|
+
},
|
|
33
|
+
search_webofscience: async (args, searchers) => {
|
|
34
|
+
const { query, maxResults, year, author, journal, sortBy, sortOrder } = args;
|
|
35
|
+
if (!process.env.WOS_API_KEY) {
|
|
36
|
+
throw new Error('Web of Science API key not configured. Please set WOS_API_KEY environment variable.');
|
|
121
37
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
38
|
+
const results = await searchers.webofscience.search(query, {
|
|
39
|
+
maxResults,
|
|
40
|
+
year,
|
|
41
|
+
author,
|
|
42
|
+
journal,
|
|
43
|
+
sortBy,
|
|
44
|
+
sortOrder
|
|
45
|
+
});
|
|
46
|
+
return jsonTextResponse(`Found ${results.length} Web of Science papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
47
|
+
},
|
|
48
|
+
search_pubmed: async (args, searchers) => {
|
|
49
|
+
const { query, maxResults, year, author, journal, publicationType, sortBy } = args;
|
|
50
|
+
const results = await searchers.pubmed.search(query, {
|
|
51
|
+
maxResults,
|
|
52
|
+
year,
|
|
53
|
+
author,
|
|
54
|
+
journal,
|
|
55
|
+
publicationType,
|
|
56
|
+
sortBy
|
|
57
|
+
});
|
|
58
|
+
const rateStatus = searchers.pubmed.getRateLimiterStatus();
|
|
59
|
+
const apiKeyStatus = searchers.pubmed.hasApiKey() ? 'configured' : 'not configured';
|
|
60
|
+
const rateLimit = searchers.pubmed.hasApiKey() ? '10 requests/second' : '3 requests/second';
|
|
61
|
+
return jsonTextResponse(`Found ${results.length} PubMed papers.\n\nAPI Status: ${apiKeyStatus} (${rateLimit})\nRate Limiter: ${rateStatus.availableTokens}/${rateStatus.maxTokens} tokens available\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
62
|
+
},
|
|
63
|
+
search_biorxiv: async (args, searchers) => {
|
|
64
|
+
const { query, maxResults, days, category } = args;
|
|
65
|
+
const results = await searchers.biorxiv.search(query, {
|
|
66
|
+
maxResults,
|
|
67
|
+
days,
|
|
68
|
+
category
|
|
69
|
+
});
|
|
70
|
+
return jsonTextResponse(`Found ${results.length} bioRxiv papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
71
|
+
},
|
|
72
|
+
search_medrxiv: async (args, searchers) => {
|
|
73
|
+
const { query, maxResults, days, category } = args;
|
|
74
|
+
const results = await searchers.medrxiv.search(query, {
|
|
75
|
+
maxResults,
|
|
76
|
+
days,
|
|
77
|
+
category
|
|
78
|
+
});
|
|
79
|
+
return jsonTextResponse(`Found ${results.length} medRxiv papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
80
|
+
},
|
|
81
|
+
search_semantic_scholar: async (args, searchers) => {
|
|
82
|
+
const { query, maxResults, year, fieldsOfStudy } = args;
|
|
83
|
+
const results = await searchers.semantic.search(query, {
|
|
84
|
+
maxResults,
|
|
85
|
+
year,
|
|
86
|
+
fieldsOfStudy
|
|
87
|
+
});
|
|
88
|
+
const rateStatus = searchers.semantic.getRateLimiterStatus();
|
|
89
|
+
const apiKeyStatus = searchers.semantic.hasApiKey()
|
|
90
|
+
? 'configured'
|
|
91
|
+
: 'not configured (using free tier)';
|
|
92
|
+
const rateLimit = searchers.semantic.hasApiKey() ? '200 requests/minute' : '20 requests/minute';
|
|
93
|
+
return jsonTextResponse(`Found ${results.length} Semantic Scholar papers.\n\nAPI Status: ${apiKeyStatus} (${rateLimit})\nRate Limiter: ${rateStatus.availableTokens}/${rateStatus.maxTokens} tokens available\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
94
|
+
},
|
|
95
|
+
search_semantic_snippets: async (args, searchers) => handleSemanticSnippets(args, searchers),
|
|
96
|
+
get_paper_citations: async (args) => handleGetPaperCitations(args),
|
|
97
|
+
get_paper_references: async (args) => handleGetPaperReferences(args),
|
|
98
|
+
search_iacr: async (args, searchers) => {
|
|
99
|
+
const { query, maxResults, fetchDetails } = args;
|
|
100
|
+
const results = await searchers.iacr.search(query, { maxResults, fetchDetails });
|
|
101
|
+
return jsonTextResponse(`Found ${results.length} IACR ePrint papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
102
|
+
},
|
|
103
|
+
download_paper: async (args, searchers) => handleDownloadPaper(args, searchers),
|
|
104
|
+
download_with_fallback: async (args, searchers) => handleDownloadWithFallback(args, searchers),
|
|
105
|
+
query_journal_metrics: async (args) => handleJournalMetrics(args),
|
|
106
|
+
search_google_scholar: async (args, searchers) => {
|
|
107
|
+
const { query, maxResults, yearLow, yearHigh, author } = args;
|
|
108
|
+
const results = await searchers.googlescholar.search(query, {
|
|
109
|
+
maxResults,
|
|
110
|
+
yearLow,
|
|
111
|
+
yearHigh,
|
|
112
|
+
author
|
|
113
|
+
});
|
|
114
|
+
return jsonTextResponse(`Found ${results.length} Google Scholar papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
115
|
+
},
|
|
116
|
+
get_paper_by_doi: async (args, searchers) => handleGetPaperByDoi(args, searchers),
|
|
117
|
+
search_scihub: async (args, searchers) => {
|
|
118
|
+
const { doiOrUrl, downloadPdf, savePath } = args;
|
|
119
|
+
const resolvedSavePath = savePath || './downloads';
|
|
120
|
+
const results = await searchers.scihub.search(doiOrUrl);
|
|
121
|
+
if (results.length === 0) {
|
|
122
|
+
return jsonTextResponse(`No paper found on Sci-Hub for: ${doiOrUrl}`);
|
|
133
123
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
throw new Error('Web of Science API key not configured. Please set WOS_API_KEY environment variable.');
|
|
138
|
-
}
|
|
139
|
-
const results = await searchers.webofscience.search(query, {
|
|
140
|
-
maxResults,
|
|
141
|
-
year,
|
|
142
|
-
author,
|
|
143
|
-
journal,
|
|
144
|
-
sortBy,
|
|
145
|
-
sortOrder
|
|
146
|
-
});
|
|
147
|
-
return jsonTextResponse(`Found ${results.length} Web of Science papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
148
|
-
}
|
|
149
|
-
case 'search_pubmed': {
|
|
150
|
-
const { query, maxResults, year, author, journal, publicationType, sortBy } = args;
|
|
151
|
-
const results = await searchers.pubmed.search(query, {
|
|
152
|
-
maxResults,
|
|
153
|
-
year,
|
|
154
|
-
author,
|
|
155
|
-
journal,
|
|
156
|
-
publicationType,
|
|
157
|
-
sortBy
|
|
158
|
-
});
|
|
159
|
-
const rateStatus = searchers.pubmed.getRateLimiterStatus();
|
|
160
|
-
const apiKeyStatus = searchers.pubmed.hasApiKey() ? 'configured' : 'not configured';
|
|
161
|
-
const rateLimit = searchers.pubmed.hasApiKey() ? '10 requests/second' : '3 requests/second';
|
|
162
|
-
return jsonTextResponse(`Found ${results.length} PubMed papers.\n\nAPI Status: ${apiKeyStatus} (${rateLimit})\nRate Limiter: ${rateStatus.availableTokens}/${rateStatus.maxTokens} tokens available\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
163
|
-
}
|
|
164
|
-
case 'search_biorxiv': {
|
|
165
|
-
const { query, maxResults, days, category } = args;
|
|
166
|
-
const results = await searchers.biorxiv.search(query, {
|
|
167
|
-
maxResults,
|
|
168
|
-
days,
|
|
169
|
-
category
|
|
170
|
-
});
|
|
171
|
-
return jsonTextResponse(`Found ${results.length} bioRxiv papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
172
|
-
}
|
|
173
|
-
case 'search_medrxiv': {
|
|
174
|
-
const { query, maxResults, days, category } = args;
|
|
175
|
-
const results = await searchers.medrxiv.search(query, {
|
|
176
|
-
maxResults,
|
|
177
|
-
days,
|
|
178
|
-
category
|
|
179
|
-
});
|
|
180
|
-
return jsonTextResponse(`Found ${results.length} medRxiv papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
181
|
-
}
|
|
182
|
-
case 'search_semantic_scholar': {
|
|
183
|
-
const { query, maxResults, year, fieldsOfStudy } = args;
|
|
184
|
-
const results = await searchers.semantic.search(query, {
|
|
185
|
-
maxResults,
|
|
186
|
-
year,
|
|
187
|
-
fieldsOfStudy
|
|
188
|
-
});
|
|
189
|
-
const rateStatus = searchers.semantic.getRateLimiterStatus();
|
|
190
|
-
const apiKeyStatus = searchers.semantic.hasApiKey()
|
|
191
|
-
? 'configured'
|
|
192
|
-
: 'not configured (using free tier)';
|
|
193
|
-
const rateLimit = searchers.semantic.hasApiKey() ? '200 requests/minute' : '20 requests/minute';
|
|
194
|
-
return jsonTextResponse(`Found ${results.length} Semantic Scholar papers.\n\nAPI Status: ${apiKeyStatus} (${rateLimit})\nRate Limiter: ${rateStatus.availableTokens}/${rateStatus.maxTokens} tokens available\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
195
|
-
}
|
|
196
|
-
case 'search_semantic_snippets': {
|
|
197
|
-
const results = await searchers.semantic.searchSnippets(args);
|
|
198
|
-
const bodyCount = results.filter(result => result.snippet.snippetKind === 'body').length;
|
|
199
|
-
return jsonTextResponse(`Found ${results.length} Semantic Scholar snippet(s), including ${bodyCount} body snippet(s).\n\n${JSON.stringify(results, null, 2)}`);
|
|
200
|
-
}
|
|
201
|
-
case 'get_paper_citations': {
|
|
202
|
-
const target = resolveCitationTarget(args);
|
|
203
|
-
const service = new CitationService();
|
|
204
|
-
const papers = await service.getCitations(target, args.limit);
|
|
205
|
-
const result = citationResponse(target, 'citations', papers);
|
|
206
|
-
return jsonTextResponse(`Found ${papers.length} citing paper(s).\n\n${JSON.stringify(result, null, 2)}`);
|
|
207
|
-
}
|
|
208
|
-
case 'get_paper_references': {
|
|
209
|
-
const target = resolveCitationTarget(args);
|
|
210
|
-
const service = new CitationService();
|
|
211
|
-
const papers = await service.getReferences(target, args.limit);
|
|
212
|
-
const result = citationResponse(target, 'references', papers);
|
|
213
|
-
return jsonTextResponse(`Found ${papers.length} cited reference(s).\n\n${JSON.stringify(result, null, 2)}`);
|
|
214
|
-
}
|
|
215
|
-
case 'search_iacr': {
|
|
216
|
-
const { query, maxResults, fetchDetails } = args;
|
|
217
|
-
const results = await searchers.iacr.search(query, { maxResults, fetchDetails });
|
|
218
|
-
return jsonTextResponse(`Found ${results.length} IACR ePrint papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
219
|
-
}
|
|
220
|
-
case 'download_paper': {
|
|
221
|
-
const { paperId, platform, savePath } = args;
|
|
222
|
-
const resolvedSavePath = savePath || './downloads';
|
|
223
|
-
const resolvedPlatform = resolvePlatformId(platform);
|
|
224
|
-
const searcher = searchers[resolvedPlatform];
|
|
225
|
-
if (!searcher) {
|
|
226
|
-
throw new Error(`Unsupported platform for download: ${platform}`);
|
|
227
|
-
}
|
|
228
|
-
if (!searcher.getCapabilities().download) {
|
|
229
|
-
const result = await downloadWithFallback(searchers, {
|
|
230
|
-
source: resolvedPlatform,
|
|
231
|
-
paperId,
|
|
232
|
-
doi: paperId,
|
|
233
|
-
savePath: resolvedSavePath,
|
|
234
|
-
useSciHub: true
|
|
235
|
-
});
|
|
236
|
-
if (result.status === 'ok') {
|
|
237
|
-
return jsonTextResponse(`PDF downloaded successfully via fallback to: ${result.path}\n\n${JSON.stringify(result, null, 2)}`);
|
|
238
|
-
}
|
|
239
|
-
return jsonTextResponse(`PDF download failed via fallback.\n\n${JSON.stringify(result, null, 2)}`);
|
|
240
|
-
}
|
|
124
|
+
const paper = results[0];
|
|
125
|
+
let responseText = `Found paper on Sci-Hub:\n\n${JSON.stringify(PaperFactory.toDict(paper), null, 2)}`;
|
|
126
|
+
if (downloadPdf && paper.pdfUrl) {
|
|
241
127
|
try {
|
|
242
|
-
const filePath = await
|
|
243
|
-
|
|
128
|
+
const filePath = await searchers.scihub.downloadPdf(doiOrUrl, { savePath: resolvedSavePath });
|
|
129
|
+
responseText += `\n\nPDF downloaded successfully to: ${filePath}`;
|
|
244
130
|
}
|
|
245
|
-
catch (
|
|
246
|
-
|
|
247
|
-
source: resolvedPlatform,
|
|
248
|
-
paperId,
|
|
249
|
-
doi: paperId,
|
|
250
|
-
savePath: resolvedSavePath,
|
|
251
|
-
useSciHub: true
|
|
252
|
-
});
|
|
253
|
-
if (result.status === 'ok') {
|
|
254
|
-
return jsonTextResponse(`Primary download failed; PDF downloaded successfully via fallback to: ${result.path}\n\n${JSON.stringify(result, null, 2)}`);
|
|
255
|
-
}
|
|
256
|
-
throw error;
|
|
131
|
+
catch (downloadError) {
|
|
132
|
+
responseText += `\n\nFailed to download PDF: ${downloadError.message}`;
|
|
257
133
|
}
|
|
258
134
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
135
|
+
return jsonTextResponse(responseText);
|
|
136
|
+
},
|
|
137
|
+
check_scihub_mirrors: async (args, searchers) => {
|
|
138
|
+
const { forceCheck } = args;
|
|
139
|
+
if (forceCheck) {
|
|
140
|
+
await searchers.scihub.forceHealthCheck();
|
|
262
141
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
.split(/\r?\n/)
|
|
271
|
-
.map(line => line.trim())
|
|
272
|
-
.filter(line => line && !line.startsWith('#'))
|
|
273
|
-
: [])
|
|
274
|
-
];
|
|
275
|
-
const rows = await queryJournalMetrics({ journals, includeRaw: args.includeRaw });
|
|
276
|
-
const found = rows.filter(row => row.status === 'found').length;
|
|
277
|
-
return jsonTextResponse(`Found journal metrics for ${found}/${rows.length} journal(s).\n\n${JSON.stringify(rows, null, 2)}`);
|
|
142
|
+
const mirrorStatus = searchers.scihub.getMirrorStatus();
|
|
143
|
+
return jsonTextResponse(`Sci-Hub Mirror Status:\n\n${JSON.stringify(mirrorStatus, null, 2)}`);
|
|
144
|
+
},
|
|
145
|
+
search_sciencedirect: async (args, searchers) => {
|
|
146
|
+
const { query, maxResults, year, author, journal, openAccess } = args;
|
|
147
|
+
if (!process.env.ELSEVIER_API_KEY) {
|
|
148
|
+
throw new Error('Elsevier API key not configured. Please set ELSEVIER_API_KEY environment variable.');
|
|
278
149
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
150
|
+
const results = await searchers.sciencedirect.search(query, {
|
|
151
|
+
maxResults,
|
|
152
|
+
year,
|
|
153
|
+
author,
|
|
154
|
+
journal,
|
|
155
|
+
openAccess
|
|
156
|
+
});
|
|
157
|
+
return jsonTextResponse(`Found ${results.length} ScienceDirect papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
158
|
+
},
|
|
159
|
+
search_springer: async (args, searchers) => {
|
|
160
|
+
const { query, maxResults, year, author, journal, subject, openAccess, type } = args;
|
|
161
|
+
if (!process.env.SPRINGER_API_KEY) {
|
|
162
|
+
throw new Error('Springer API key not configured. Please set SPRINGER_API_KEY environment variable.');
|
|
288
163
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
logDebug(`Error getting paper by DOI from ${source}:`, result.reason);
|
|
310
|
-
continue;
|
|
311
|
-
}
|
|
312
|
-
const paper = result.value.paper;
|
|
313
|
-
if (!paper) {
|
|
314
|
-
sourceResults[source] = 0;
|
|
315
|
-
continue;
|
|
316
|
-
}
|
|
317
|
-
if (!paperMatchesDoi(paper, doi)) {
|
|
318
|
-
sourceResults[source] = 0;
|
|
319
|
-
errors[source] = `Returned DOI ${paper.doi || '(missing)'} did not match requested DOI ${doi}`;
|
|
320
|
-
failedSources.push(source);
|
|
321
|
-
continue;
|
|
322
|
-
}
|
|
323
|
-
sourceResults[source] = 1;
|
|
324
|
-
results.push(PaperFactory.toDict(paper));
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
else {
|
|
328
|
-
const searcher = searchers[resolvePlatformId(platform)];
|
|
329
|
-
if (!searcher) {
|
|
330
|
-
throw new Error(`Unsupported platform: ${platform}`);
|
|
331
|
-
}
|
|
332
|
-
const paper = await searcher.getPaperByDoi(doi);
|
|
333
|
-
if (paper) {
|
|
334
|
-
results.push(PaperFactory.toDict(paper));
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
if (results.length === 0) {
|
|
338
|
-
if (platform === 'all') {
|
|
339
|
-
const result = {
|
|
340
|
-
doi,
|
|
341
|
-
sources_requested: 'all',
|
|
342
|
-
sources_used: DOI_LOOKUP_SOURCES.filter(source => source in searchers),
|
|
343
|
-
source_results: sourceResults,
|
|
344
|
-
errors,
|
|
345
|
-
failed_sources: failedSources,
|
|
346
|
-
warnings: failedSources.map(source => `${source}: ${errors[source]}`),
|
|
347
|
-
total: 0,
|
|
348
|
-
papers: []
|
|
349
|
-
};
|
|
350
|
-
return jsonTextResponse(`No paper found with DOI: ${doi}\n\n${JSON.stringify(result, null, 2)}`);
|
|
351
|
-
}
|
|
352
|
-
return jsonTextResponse(`No paper found with DOI: ${doi}`);
|
|
353
|
-
}
|
|
354
|
-
if (platform === 'all') {
|
|
355
|
-
const result = {
|
|
356
|
-
doi,
|
|
357
|
-
sources_requested: 'all',
|
|
358
|
-
sources_used: DOI_LOOKUP_SOURCES.filter(source => source in searchers),
|
|
359
|
-
source_results: sourceResults,
|
|
360
|
-
errors,
|
|
361
|
-
failed_sources: failedSources,
|
|
362
|
-
warnings: failedSources.map(source => `${source}: ${errors[source]}`),
|
|
363
|
-
total: results.length,
|
|
364
|
-
papers: results
|
|
365
|
-
};
|
|
366
|
-
return jsonTextResponse(`Found ${results.length} paper(s) with DOI ${doi} across ${result.sources_used.length} source(s).\n\n${JSON.stringify(result, null, 2)}`);
|
|
367
|
-
}
|
|
368
|
-
return jsonTextResponse(`Found ${results.length} paper(s) with DOI ${doi}:\n\n${JSON.stringify(results, null, 2)}`);
|
|
369
|
-
}
|
|
370
|
-
case 'search_scihub': {
|
|
371
|
-
const { doiOrUrl, downloadPdf, savePath } = args;
|
|
372
|
-
const resolvedSavePath = savePath || './downloads';
|
|
373
|
-
const results = await searchers.scihub.search(doiOrUrl);
|
|
374
|
-
if (results.length === 0) {
|
|
375
|
-
return jsonTextResponse(`No paper found on Sci-Hub for: ${doiOrUrl}`);
|
|
376
|
-
}
|
|
377
|
-
const paper = results[0];
|
|
378
|
-
let responseText = `Found paper on Sci-Hub:\n\n${JSON.stringify(PaperFactory.toDict(paper), null, 2)}`;
|
|
379
|
-
if (downloadPdf && paper.pdfUrl) {
|
|
380
|
-
try {
|
|
381
|
-
const filePath = await searchers.scihub.downloadPdf(doiOrUrl, { savePath: resolvedSavePath });
|
|
382
|
-
responseText += `\n\nPDF downloaded successfully to: ${filePath}`;
|
|
383
|
-
}
|
|
384
|
-
catch (downloadError) {
|
|
385
|
-
responseText += `\n\nFailed to download PDF: ${downloadError.message}`;
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
return jsonTextResponse(responseText);
|
|
389
|
-
}
|
|
390
|
-
case 'check_scihub_mirrors': {
|
|
391
|
-
const { forceCheck } = args;
|
|
392
|
-
if (forceCheck) {
|
|
393
|
-
await searchers.scihub.forceHealthCheck();
|
|
394
|
-
}
|
|
395
|
-
const mirrorStatus = searchers.scihub.getMirrorStatus();
|
|
396
|
-
return jsonTextResponse(`Sci-Hub Mirror Status:\n\n${JSON.stringify(mirrorStatus, null, 2)}`);
|
|
397
|
-
}
|
|
398
|
-
case 'search_sciencedirect': {
|
|
399
|
-
const { query, maxResults, year, author, journal, openAccess } = args;
|
|
400
|
-
if (!process.env.ELSEVIER_API_KEY) {
|
|
401
|
-
throw new Error('Elsevier API key not configured. Please set ELSEVIER_API_KEY environment variable.');
|
|
402
|
-
}
|
|
403
|
-
const results = await searchers.sciencedirect.search(query, {
|
|
404
|
-
maxResults,
|
|
405
|
-
year,
|
|
406
|
-
author,
|
|
407
|
-
journal,
|
|
408
|
-
openAccess
|
|
409
|
-
});
|
|
410
|
-
return jsonTextResponse(`Found ${results.length} ScienceDirect papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
411
|
-
}
|
|
412
|
-
case 'search_springer': {
|
|
413
|
-
const { query, maxResults, year, author, journal, subject, openAccess, type } = args;
|
|
414
|
-
if (!process.env.SPRINGER_API_KEY) {
|
|
415
|
-
throw new Error('Springer API key not configured. Please set SPRINGER_API_KEY environment variable.');
|
|
416
|
-
}
|
|
417
|
-
const results = await searchers.springer.search(query, {
|
|
418
|
-
maxResults,
|
|
419
|
-
year,
|
|
420
|
-
author,
|
|
421
|
-
journal,
|
|
422
|
-
subject,
|
|
423
|
-
openAccess,
|
|
424
|
-
type
|
|
425
|
-
});
|
|
426
|
-
return jsonTextResponse(`Found ${results.length} Springer papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
427
|
-
}
|
|
428
|
-
case 'search_wiley': {
|
|
429
|
-
return jsonTextResponse(`DEPRECATED: Wiley TDM API does not support keyword search.\n\n` +
|
|
430
|
-
`To access Wiley content:\n` +
|
|
431
|
-
`1. Use search_crossref to find Wiley articles (filter by publisher if needed)\n` +
|
|
432
|
-
`2. Use download_paper with platform="wiley" and the DOI to download the PDF\n\n` +
|
|
433
|
-
`Example: download_paper(paperId="10.1111/jtsb.12390", platform="wiley")`);
|
|
164
|
+
const results = await searchers.springer.search(query, {
|
|
165
|
+
maxResults,
|
|
166
|
+
year,
|
|
167
|
+
author,
|
|
168
|
+
journal,
|
|
169
|
+
subject,
|
|
170
|
+
openAccess,
|
|
171
|
+
type
|
|
172
|
+
});
|
|
173
|
+
return jsonTextResponse(`Found ${results.length} Springer papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
174
|
+
},
|
|
175
|
+
search_wiley: async () => jsonTextResponse(`DEPRECATED: Wiley TDM API does not support keyword search.\n\n` +
|
|
176
|
+
`To access Wiley content:\n` +
|
|
177
|
+
`1. Use search_crossref to find Wiley articles (filter by publisher if needed)\n` +
|
|
178
|
+
`2. Use download_paper with platform="wiley" and the DOI to download the PDF\n\n` +
|
|
179
|
+
`Example: download_paper(paperId="10.1111/jtsb.12390", platform="wiley")`),
|
|
180
|
+
search_scopus: async (args, searchers) => {
|
|
181
|
+
const { query, maxResults, year, author, journal, affiliation, subject, openAccess, documentType } = args;
|
|
182
|
+
if (!process.env.ELSEVIER_API_KEY) {
|
|
183
|
+
throw new Error('Elsevier API key not configured. Please set ELSEVIER_API_KEY environment variable.');
|
|
434
184
|
}
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
const
|
|
495
|
-
const
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
if (hasApiKey) {
|
|
504
|
-
if (validate) {
|
|
505
|
-
try {
|
|
506
|
-
const isValid = await searcher.validateApiKey();
|
|
507
|
-
apiKeyStatus = isValid ? 'valid' : 'invalid';
|
|
508
|
-
}
|
|
509
|
-
catch {
|
|
510
|
-
apiKeyStatus = 'unknown';
|
|
511
|
-
}
|
|
185
|
+
const results = await searchers.scopus.search(query, {
|
|
186
|
+
maxResults,
|
|
187
|
+
year,
|
|
188
|
+
author,
|
|
189
|
+
journal,
|
|
190
|
+
affiliation,
|
|
191
|
+
subject,
|
|
192
|
+
openAccess,
|
|
193
|
+
documentType
|
|
194
|
+
});
|
|
195
|
+
return jsonTextResponse(`Found ${results.length} Scopus papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
196
|
+
},
|
|
197
|
+
search_crossref: async (args, searchers) => {
|
|
198
|
+
const { query, maxResults, year, author, sortBy, sortOrder } = args;
|
|
199
|
+
const results = await searchers.crossref.search(query, {
|
|
200
|
+
maxResults,
|
|
201
|
+
year,
|
|
202
|
+
author,
|
|
203
|
+
sortBy,
|
|
204
|
+
sortOrder
|
|
205
|
+
});
|
|
206
|
+
return jsonTextResponse(`Found ${results.length} Crossref papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
207
|
+
},
|
|
208
|
+
search_openalex: async (args, searchers) => {
|
|
209
|
+
const { query, maxResults, year } = args;
|
|
210
|
+
const results = await searchers.openalex.search(query, { maxResults, year });
|
|
211
|
+
return jsonTextResponse(`Found ${results.length} OpenAlex papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
212
|
+
},
|
|
213
|
+
search_unpaywall: async (args, searchers) => {
|
|
214
|
+
const { query, maxResults } = args;
|
|
215
|
+
const results = await searchers.unpaywall.search(query, { maxResults });
|
|
216
|
+
return jsonTextResponse(`Found ${results.length} Unpaywall record(s).\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
217
|
+
},
|
|
218
|
+
search_pmc: async (args, searchers) => {
|
|
219
|
+
const { query, maxResults, year } = args;
|
|
220
|
+
const results = await searchers.pmc.search(query, { maxResults, year });
|
|
221
|
+
return jsonTextResponse(`Found ${results.length} PMC papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
222
|
+
},
|
|
223
|
+
search_europepmc: async (args, searchers) => {
|
|
224
|
+
const { query, maxResults, year } = args;
|
|
225
|
+
const results = await searchers.europepmc.search(query, { maxResults, year });
|
|
226
|
+
return jsonTextResponse(`Found ${results.length} Europe PMC papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
227
|
+
},
|
|
228
|
+
search_core: async (args, searchers) => {
|
|
229
|
+
const { query, maxResults, year } = args;
|
|
230
|
+
const results = await searchers.core.search(query, { maxResults, year });
|
|
231
|
+
return jsonTextResponse(`Found ${results.length} CORE papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
232
|
+
},
|
|
233
|
+
search_openaire: async (args, searchers) => {
|
|
234
|
+
const { query, maxResults, year } = args;
|
|
235
|
+
const results = await searchers.openaire.search(query, { maxResults, year });
|
|
236
|
+
return jsonTextResponse(`Found ${results.length} OpenAIRE papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
|
|
237
|
+
},
|
|
238
|
+
get_platform_status: async (args, searchers) => {
|
|
239
|
+
const { validate } = args;
|
|
240
|
+
const statusInfo = [];
|
|
241
|
+
for (const [platformName, searcher] of Object.entries(searchers)) {
|
|
242
|
+
if (isPlatformAlias(platformName))
|
|
243
|
+
continue;
|
|
244
|
+
const capabilities = searcher.getCapabilities();
|
|
245
|
+
const hasApiKey = searcher.hasApiKey();
|
|
246
|
+
let apiKeyStatus = 'not_required';
|
|
247
|
+
if (capabilities.requiresApiKey) {
|
|
248
|
+
if (hasApiKey) {
|
|
249
|
+
if (validate) {
|
|
250
|
+
try {
|
|
251
|
+
const isValid = await searcher.validateApiKey();
|
|
252
|
+
apiKeyStatus = isValid ? 'valid' : 'invalid';
|
|
512
253
|
}
|
|
513
|
-
|
|
514
|
-
apiKeyStatus = '
|
|
254
|
+
catch {
|
|
255
|
+
apiKeyStatus = 'unknown';
|
|
515
256
|
}
|
|
516
257
|
}
|
|
517
258
|
else {
|
|
518
|
-
apiKeyStatus = '
|
|
259
|
+
apiKeyStatus = 'configured';
|
|
519
260
|
}
|
|
520
261
|
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
const mirrorStatus = searchers.scihub.getMirrorStatus();
|
|
524
|
-
additionalInfo = {
|
|
525
|
-
mirrorCount: mirrorStatus.length,
|
|
526
|
-
workingMirrors: mirrorStatus.filter(m => m.status === 'Working').length
|
|
527
|
-
};
|
|
262
|
+
else {
|
|
263
|
+
apiKeyStatus = 'missing';
|
|
528
264
|
}
|
|
529
|
-
statusInfo.push({
|
|
530
|
-
platform: platformName,
|
|
531
|
-
baseUrl: searcher.getBaseUrl(),
|
|
532
|
-
capabilities,
|
|
533
|
-
apiKeyStatus,
|
|
534
|
-
...additionalInfo
|
|
535
|
-
});
|
|
536
265
|
}
|
|
537
|
-
|
|
266
|
+
let additionalInfo = {};
|
|
267
|
+
if (platformName === 'scihub') {
|
|
268
|
+
const mirrorStatus = searchers.scihub.getMirrorStatus();
|
|
269
|
+
additionalInfo = {
|
|
270
|
+
mirrorCount: mirrorStatus.length,
|
|
271
|
+
workingMirrors: mirrorStatus.filter(m => m.status === 'Working').length
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
statusInfo.push({
|
|
275
|
+
platform: platformName,
|
|
276
|
+
baseUrl: searcher.getBaseUrl(),
|
|
277
|
+
capabilities,
|
|
278
|
+
apiKeyStatus,
|
|
279
|
+
...additionalInfo
|
|
280
|
+
});
|
|
538
281
|
}
|
|
539
|
-
|
|
540
|
-
|
|
282
|
+
return jsonTextResponse(`Platform Status:\n\n${JSON.stringify(statusInfo, null, 2)}`);
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
export const TOOL_HANDLER_NAMES = Object.keys(TOOL_HANDLERS).sort();
|
|
286
|
+
export async function handleToolCall(toolNameRaw, rawArgs, searchers) {
|
|
287
|
+
const toolName = toolNameRaw;
|
|
288
|
+
const args = parseToolArgs(toolName, rawArgs);
|
|
289
|
+
const genericSearchPlatform = getGenericSearchToolPlatform(toolNameRaw);
|
|
290
|
+
if (genericSearchPlatform) {
|
|
291
|
+
return handleGenericSearch(genericSearchPlatform, args, searchers);
|
|
292
|
+
}
|
|
293
|
+
const handler = TOOL_HANDLERS[toolNameRaw];
|
|
294
|
+
if (!handler) {
|
|
295
|
+
throw new Error(`Unknown tool: ${toolNameRaw}`);
|
|
541
296
|
}
|
|
297
|
+
return handler(args, searchers);
|
|
542
298
|
}
|
|
543
299
|
//# sourceMappingURL=handleToolCall.js.map
|