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