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.
Files changed (314) hide show
  1. package/README.md +11 -9
  2. package/README.zh.md +11 -9
  3. package/dist/capabilities/body-snippet-search/handler.d.ts +9 -0
  4. package/dist/capabilities/body-snippet-search/handler.d.ts.map +1 -0
  5. package/dist/capabilities/body-snippet-search/handler.js +17 -0
  6. package/dist/capabilities/body-snippet-search/handler.js.map +1 -0
  7. package/dist/capabilities/body-snippet-search/index.d.ts +7 -0
  8. package/dist/capabilities/body-snippet-search/index.d.ts.map +1 -0
  9. package/dist/capabilities/body-snippet-search/index.js +6 -0
  10. package/dist/capabilities/body-snippet-search/index.js.map +1 -0
  11. package/dist/capabilities/body-snippet-search/schemas.d.ts +36 -0
  12. package/dist/capabilities/body-snippet-search/schemas.d.ts.map +1 -0
  13. package/dist/capabilities/body-snippet-search/schemas.js +16 -0
  14. package/dist/capabilities/body-snippet-search/schemas.js.map +1 -0
  15. package/dist/capabilities/body-snippet-search/service.d.ts +4 -0
  16. package/dist/capabilities/body-snippet-search/service.d.ts.map +1 -0
  17. package/dist/capabilities/body-snippet-search/service.js +4 -0
  18. package/dist/capabilities/body-snippet-search/service.js.map +1 -0
  19. package/dist/capabilities/body-snippet-search/tools.d.ts +187 -0
  20. package/dist/capabilities/body-snippet-search/tools.d.ts.map +1 -0
  21. package/dist/capabilities/body-snippet-search/tools.js +49 -0
  22. package/dist/capabilities/body-snippet-search/tools.js.map +1 -0
  23. package/dist/capabilities/body-snippet-search/types.d.ts +14 -0
  24. package/dist/capabilities/body-snippet-search/types.d.ts.map +1 -0
  25. package/dist/capabilities/body-snippet-search/types.js +2 -0
  26. package/dist/capabilities/body-snippet-search/types.js.map +1 -0
  27. package/dist/capabilities/citation-expansion/CitationService.d.ts +47 -0
  28. package/dist/capabilities/citation-expansion/CitationService.d.ts.map +1 -0
  29. package/dist/capabilities/citation-expansion/CitationService.js +243 -0
  30. package/dist/capabilities/citation-expansion/CitationService.js.map +1 -0
  31. package/dist/capabilities/citation-expansion/handler.d.ts +36 -0
  32. package/dist/capabilities/citation-expansion/handler.d.ts.map +1 -0
  33. package/dist/capabilities/citation-expansion/handler.js +44 -0
  34. package/dist/capabilities/citation-expansion/handler.js.map +1 -0
  35. package/dist/capabilities/citation-expansion/index.d.ts +6 -0
  36. package/dist/capabilities/citation-expansion/index.d.ts.map +1 -0
  37. package/dist/capabilities/citation-expansion/index.js +5 -0
  38. package/dist/capabilities/citation-expansion/index.js.map +1 -0
  39. package/dist/capabilities/citation-expansion/schemas.d.ts +28 -0
  40. package/dist/capabilities/citation-expansion/schemas.d.ts.map +1 -0
  41. package/dist/capabilities/citation-expansion/schemas.js +13 -0
  42. package/dist/capabilities/citation-expansion/schemas.js.map +1 -0
  43. package/dist/capabilities/citation-expansion/tools.d.ts +82 -0
  44. package/dist/capabilities/citation-expansion/tools.d.ts.map +1 -0
  45. package/dist/capabilities/citation-expansion/tools.js +48 -0
  46. package/dist/capabilities/citation-expansion/tools.js.map +1 -0
  47. package/dist/capabilities/citation-expansion/types.d.ts +22 -0
  48. package/dist/capabilities/citation-expansion/types.d.ts.map +1 -0
  49. package/dist/capabilities/citation-expansion/types.js +2 -0
  50. package/dist/capabilities/citation-expansion/types.js.map +1 -0
  51. package/dist/capabilities/journal-metrics/JournalMetricsService.d.ts +3 -0
  52. package/dist/capabilities/journal-metrics/JournalMetricsService.d.ts.map +1 -0
  53. package/dist/capabilities/journal-metrics/JournalMetricsService.js +142 -0
  54. package/dist/capabilities/journal-metrics/JournalMetricsService.js.map +1 -0
  55. package/dist/capabilities/journal-metrics/handler.d.ts +12 -0
  56. package/dist/capabilities/journal-metrics/handler.d.ts.map +1 -0
  57. package/dist/capabilities/journal-metrics/handler.js +38 -0
  58. package/dist/capabilities/journal-metrics/handler.js.map +1 -0
  59. package/dist/capabilities/journal-metrics/index.d.ts +6 -0
  60. package/dist/capabilities/journal-metrics/index.d.ts.map +1 -0
  61. package/dist/capabilities/journal-metrics/index.js +5 -0
  62. package/dist/capabilities/journal-metrics/index.js.map +1 -0
  63. package/dist/capabilities/journal-metrics/schemas.d.ts +28 -0
  64. package/dist/capabilities/journal-metrics/schemas.d.ts.map +1 -0
  65. package/dist/capabilities/journal-metrics/schemas.js +13 -0
  66. package/dist/capabilities/journal-metrics/schemas.js.map +1 -0
  67. package/dist/capabilities/journal-metrics/tools.d.ts +67 -0
  68. package/dist/capabilities/journal-metrics/tools.d.ts.map +1 -0
  69. package/dist/capabilities/journal-metrics/tools.js +27 -0
  70. package/dist/capabilities/journal-metrics/tools.js.map +1 -0
  71. package/dist/capabilities/journal-metrics/types.d.ts +36 -0
  72. package/dist/capabilities/journal-metrics/types.d.ts.map +1 -0
  73. package/dist/capabilities/journal-metrics/types.js +2 -0
  74. package/dist/capabilities/journal-metrics/types.js.map +1 -0
  75. package/dist/capabilities/metadata-search/MultiSourceSearchService.d.ts +9 -0
  76. package/dist/capabilities/metadata-search/MultiSourceSearchService.d.ts.map +1 -0
  77. package/dist/capabilities/metadata-search/MultiSourceSearchService.js +78 -0
  78. package/dist/capabilities/metadata-search/MultiSourceSearchService.js.map +1 -0
  79. package/dist/capabilities/metadata-search/handler.d.ts +23 -0
  80. package/dist/capabilities/metadata-search/handler.d.ts.map +1 -0
  81. package/dist/capabilities/metadata-search/handler.js +163 -0
  82. package/dist/capabilities/metadata-search/handler.js.map +1 -0
  83. package/dist/capabilities/metadata-search/index.d.ts +6 -0
  84. package/dist/capabilities/metadata-search/index.d.ts.map +1 -0
  85. package/dist/capabilities/metadata-search/index.js +5 -0
  86. package/dist/capabilities/metadata-search/index.js.map +1 -0
  87. package/dist/capabilities/metadata-search/schemas.d.ts +83 -0
  88. package/dist/capabilities/metadata-search/schemas.d.ts.map +1 -0
  89. package/dist/capabilities/metadata-search/schemas.js +81 -0
  90. package/dist/capabilities/metadata-search/schemas.js.map +1 -0
  91. package/dist/capabilities/metadata-search/tools.d.ts +178 -0
  92. package/dist/capabilities/metadata-search/tools.d.ts.map +1 -0
  93. package/dist/capabilities/metadata-search/tools.js +75 -0
  94. package/dist/capabilities/metadata-search/tools.js.map +1 -0
  95. package/dist/capabilities/metadata-search/types.d.ts +13 -0
  96. package/dist/capabilities/metadata-search/types.d.ts.map +1 -0
  97. package/dist/capabilities/metadata-search/types.js +2 -0
  98. package/dist/capabilities/metadata-search/types.js.map +1 -0
  99. package/dist/capabilities/pdf-discovery/DownloadTier.d.ts +22 -0
  100. package/dist/capabilities/pdf-discovery/DownloadTier.d.ts.map +1 -0
  101. package/dist/capabilities/pdf-discovery/DownloadTier.js +2 -0
  102. package/dist/capabilities/pdf-discovery/DownloadTier.js.map +1 -0
  103. package/dist/capabilities/pdf-discovery/OpenAccessFallbackService.d.ts +10 -0
  104. package/dist/capabilities/pdf-discovery/OpenAccessFallbackService.d.ts.map +1 -0
  105. package/dist/capabilities/pdf-discovery/OpenAccessFallbackService.js +53 -0
  106. package/dist/capabilities/pdf-discovery/OpenAccessFallbackService.js.map +1 -0
  107. package/dist/capabilities/pdf-discovery/handler.d.ts +19 -0
  108. package/dist/capabilities/pdf-discovery/handler.d.ts.map +1 -0
  109. package/dist/capabilities/pdf-discovery/handler.js +56 -0
  110. package/dist/capabilities/pdf-discovery/handler.js.map +1 -0
  111. package/dist/capabilities/pdf-discovery/index.d.ts +7 -0
  112. package/dist/capabilities/pdf-discovery/index.d.ts.map +1 -0
  113. package/dist/capabilities/pdf-discovery/index.js +5 -0
  114. package/dist/capabilities/pdf-discovery/index.js.map +1 -0
  115. package/dist/capabilities/pdf-discovery/schemas.d.ts +37 -0
  116. package/dist/capabilities/pdf-discovery/schemas.d.ts.map +1 -0
  117. package/dist/capabilities/pdf-discovery/schemas.js +22 -0
  118. package/dist/capabilities/pdf-discovery/schemas.js.map +1 -0
  119. package/dist/capabilities/pdf-discovery/tiers/directPdfUrl.d.ts +3 -0
  120. package/dist/capabilities/pdf-discovery/tiers/directPdfUrl.d.ts.map +1 -0
  121. package/dist/capabilities/pdf-discovery/tiers/directPdfUrl.js +27 -0
  122. package/dist/capabilities/pdf-discovery/tiers/directPdfUrl.js.map +1 -0
  123. package/dist/capabilities/pdf-discovery/tiers/primary.d.ts +3 -0
  124. package/dist/capabilities/pdf-discovery/tiers/primary.d.ts.map +1 -0
  125. package/dist/capabilities/pdf-discovery/tiers/primary.js +21 -0
  126. package/dist/capabilities/pdf-discovery/tiers/primary.js.map +1 -0
  127. package/dist/capabilities/pdf-discovery/tiers/repositories.d.ts +3 -0
  128. package/dist/capabilities/pdf-discovery/tiers/repositories.d.ts.map +1 -0
  129. package/dist/capabilities/pdf-discovery/tiers/repositories.js +35 -0
  130. package/dist/capabilities/pdf-discovery/tiers/repositories.js.map +1 -0
  131. package/dist/capabilities/pdf-discovery/tiers/scihub.d.ts +3 -0
  132. package/dist/capabilities/pdf-discovery/tiers/scihub.d.ts.map +1 -0
  133. package/dist/capabilities/pdf-discovery/tiers/scihub.js +21 -0
  134. package/dist/capabilities/pdf-discovery/tiers/scihub.js.map +1 -0
  135. package/dist/capabilities/pdf-discovery/tiers/unpaywall.d.ts +3 -0
  136. package/dist/capabilities/pdf-discovery/tiers/unpaywall.d.ts.map +1 -0
  137. package/dist/capabilities/pdf-discovery/tiers/unpaywall.js +29 -0
  138. package/dist/capabilities/pdf-discovery/tiers/unpaywall.js.map +1 -0
  139. package/dist/capabilities/pdf-discovery/tools.d.ts +114 -0
  140. package/dist/capabilities/pdf-discovery/tools.d.ts.map +1 -0
  141. package/dist/capabilities/pdf-discovery/tools.js +42 -0
  142. package/dist/capabilities/pdf-discovery/tools.js.map +1 -0
  143. package/dist/capabilities/pdf-discovery/types.d.ts +19 -0
  144. package/dist/capabilities/pdf-discovery/types.d.ts.map +1 -0
  145. package/dist/capabilities/pdf-discovery/types.js +2 -0
  146. package/dist/capabilities/pdf-discovery/types.js.map +1 -0
  147. package/dist/cli.js +10 -6
  148. package/dist/cli.js.map +1 -1
  149. package/dist/core/capabilityProfile.d.ts +1 -17
  150. package/dist/core/capabilityProfile.d.ts.map +1 -1
  151. package/dist/core/capabilityProfile.js +1 -152
  152. package/dist/core/capabilityProfile.js.map +1 -1
  153. package/dist/core/diagnostics.d.ts +1 -42
  154. package/dist/core/diagnostics.d.ts.map +1 -1
  155. package/dist/core/diagnostics.js +1 -585
  156. package/dist/core/diagnostics.js.map +1 -1
  157. package/dist/core/handleToolCall.d.ts +1 -0
  158. package/dist/core/handleToolCall.d.ts.map +1 -1
  159. package/dist/core/handleToolCall.js +265 -476
  160. package/dist/core/handleToolCall.js.map +1 -1
  161. package/dist/core/httpPolicies.d.ts +2 -0
  162. package/dist/core/httpPolicies.d.ts.map +1 -0
  163. package/dist/core/httpPolicies.js +2 -0
  164. package/dist/core/httpPolicies.js.map +1 -0
  165. package/dist/core/liveSmoke.d.ts +1 -41
  166. package/dist/core/liveSmoke.d.ts.map +1 -1
  167. package/dist/core/liveSmoke.js +1 -225
  168. package/dist/core/liveSmoke.js.map +1 -1
  169. package/dist/core/platformFactories.d.ts +2 -0
  170. package/dist/core/platformFactories.d.ts.map +1 -0
  171. package/dist/core/platformFactories.js +2 -0
  172. package/dist/core/platformFactories.js.map +1 -0
  173. package/dist/core/platformMetadata.d.ts +1 -27
  174. package/dist/core/platformMetadata.d.ts.map +1 -1
  175. package/dist/core/platformMetadata.js +1 -257
  176. package/dist/core/platformMetadata.js.map +1 -1
  177. package/dist/core/schemas.d.ts +11 -177
  178. package/dist/core/schemas.d.ts.map +1 -1
  179. package/dist/core/schemas.js +14 -107
  180. package/dist/core/schemas.js.map +1 -1
  181. package/dist/core/searchers.d.ts +24 -24
  182. package/dist/core/searchers.d.ts.map +1 -1
  183. package/dist/core/searchers.js +14 -79
  184. package/dist/core/searchers.js.map +1 -1
  185. package/dist/core/textReports.d.ts +1 -20
  186. package/dist/core/textReports.d.ts.map +1 -1
  187. package/dist/core/textReports.js +1 -84
  188. package/dist/core/textReports.js.map +1 -1
  189. package/dist/core/tools.d.ts.map +1 -1
  190. package/dist/core/tools.js +15 -183
  191. package/dist/core/tools.js.map +1 -1
  192. package/dist/infrastructure/cache/RequestCache.d.ts +26 -0
  193. package/dist/infrastructure/cache/RequestCache.d.ts.map +1 -0
  194. package/dist/infrastructure/cache/RequestCache.js +66 -0
  195. package/dist/infrastructure/cache/RequestCache.js.map +1 -0
  196. package/dist/infrastructure/http/ErrorHandler.d.ts +99 -0
  197. package/dist/infrastructure/http/ErrorHandler.d.ts.map +1 -0
  198. package/dist/infrastructure/http/ErrorHandler.js +266 -0
  199. package/dist/infrastructure/http/ErrorHandler.js.map +1 -0
  200. package/dist/infrastructure/http/HttpClient.d.ts +31 -0
  201. package/dist/infrastructure/http/HttpClient.d.ts.map +1 -0
  202. package/dist/infrastructure/http/HttpClient.js +50 -0
  203. package/dist/infrastructure/http/HttpClient.js.map +1 -0
  204. package/dist/infrastructure/pdf/PDFExtractor.d.ts +34 -0
  205. package/dist/infrastructure/pdf/PDFExtractor.d.ts.map +1 -0
  206. package/dist/infrastructure/pdf/PDFExtractor.js +130 -0
  207. package/dist/infrastructure/pdf/PDFExtractor.js.map +1 -0
  208. package/dist/infrastructure/pdf/PdfDownload.d.ts +7 -0
  209. package/dist/infrastructure/pdf/PdfDownload.d.ts.map +1 -0
  210. package/dist/infrastructure/pdf/PdfDownload.js +175 -0
  211. package/dist/infrastructure/pdf/PdfDownload.js.map +1 -0
  212. package/dist/infrastructure/rate-limit/RateLimiter.d.ts +50 -0
  213. package/dist/infrastructure/rate-limit/RateLimiter.d.ts.map +1 -0
  214. package/dist/infrastructure/rate-limit/RateLimiter.js +128 -0
  215. package/dist/infrastructure/rate-limit/RateLimiter.js.map +1 -0
  216. package/dist/infrastructure/security/SecurityUtils.d.ts +80 -0
  217. package/dist/infrastructure/security/SecurityUtils.d.ts.map +1 -0
  218. package/dist/infrastructure/security/SecurityUtils.js +357 -0
  219. package/dist/infrastructure/security/SecurityUtils.js.map +1 -0
  220. package/dist/management/capability-profile/index.d.ts +18 -0
  221. package/dist/management/capability-profile/index.d.ts.map +1 -0
  222. package/dist/management/capability-profile/index.js +167 -0
  223. package/dist/management/capability-profile/index.js.map +1 -0
  224. package/dist/management/config/index.d.ts +2 -0
  225. package/dist/management/config/index.d.ts.map +1 -0
  226. package/dist/management/config/index.js +2 -0
  227. package/dist/management/config/index.js.map +1 -0
  228. package/dist/management/diagnostics/index.d.ts +43 -0
  229. package/dist/management/diagnostics/index.d.ts.map +1 -0
  230. package/dist/management/diagnostics/index.js +586 -0
  231. package/dist/management/diagnostics/index.js.map +1 -0
  232. package/dist/management/reports/index.d.ts +21 -0
  233. package/dist/management/reports/index.d.ts.map +1 -0
  234. package/dist/management/reports/index.js +85 -0
  235. package/dist/management/reports/index.js.map +1 -0
  236. package/dist/management/skills/index.d.ts +2 -0
  237. package/dist/management/skills/index.d.ts.map +1 -0
  238. package/dist/management/skills/index.js +2 -0
  239. package/dist/management/skills/index.js.map +1 -0
  240. package/dist/management/smoke/index.d.ts +42 -0
  241. package/dist/management/smoke/index.d.ts.map +1 -0
  242. package/dist/management/smoke/index.js +226 -0
  243. package/dist/management/smoke/index.js.map +1 -0
  244. package/dist/platforms/BioRxivSearcher.d.ts.map +1 -1
  245. package/dist/platforms/BioRxivSearcher.js +40 -21
  246. package/dist/platforms/BioRxivSearcher.js.map +1 -1
  247. package/dist/platforms/GoogleScholarSearcher.d.ts.map +1 -1
  248. package/dist/platforms/GoogleScholarSearcher.js +3 -2
  249. package/dist/platforms/GoogleScholarSearcher.js.map +1 -1
  250. package/dist/registry/aliases.d.ts +2 -0
  251. package/dist/registry/aliases.d.ts.map +1 -0
  252. package/dist/registry/aliases.js +2 -0
  253. package/dist/registry/aliases.js.map +1 -0
  254. package/dist/registry/httpPolicies.d.ts +3 -0
  255. package/dist/registry/httpPolicies.d.ts.map +1 -0
  256. package/dist/registry/httpPolicies.js +17 -0
  257. package/dist/registry/httpPolicies.js.map +1 -0
  258. package/dist/registry/platformFactories.d.ts +8 -0
  259. package/dist/registry/platformFactories.d.ts.map +1 -0
  260. package/dist/registry/platformFactories.js +55 -0
  261. package/dist/registry/platformFactories.js.map +1 -0
  262. package/dist/registry/platformMetadata.d.ts +39 -0
  263. package/dist/registry/platformMetadata.d.ts.map +1 -0
  264. package/dist/registry/platformMetadata.js +321 -0
  265. package/dist/registry/platformMetadata.js.map +1 -0
  266. package/dist/services/CitationService.d.ts +2 -65
  267. package/dist/services/CitationService.d.ts.map +1 -1
  268. package/dist/services/CitationService.js +1 -236
  269. package/dist/services/CitationService.js.map +1 -1
  270. package/dist/services/JournalMetricsService.d.ts +2 -37
  271. package/dist/services/JournalMetricsService.d.ts.map +1 -1
  272. package/dist/services/JournalMetricsService.js +1 -141
  273. package/dist/services/JournalMetricsService.js.map +1 -1
  274. package/dist/services/MultiSourceSearchService.d.ts +2 -18
  275. package/dist/services/MultiSourceSearchService.d.ts.map +1 -1
  276. package/dist/services/MultiSourceSearchService.js +1 -77
  277. package/dist/services/MultiSourceSearchService.js.map +1 -1
  278. package/dist/services/OpenAccessFallbackService.d.ts +3 -20
  279. package/dist/services/OpenAccessFallbackService.d.ts.map +1 -1
  280. package/dist/services/OpenAccessFallbackService.js +1 -123
  281. package/dist/services/OpenAccessFallbackService.js.map +1 -1
  282. package/dist/utils/ErrorHandler.d.ts +2 -98
  283. package/dist/utils/ErrorHandler.d.ts.map +1 -1
  284. package/dist/utils/ErrorHandler.js +2 -265
  285. package/dist/utils/ErrorHandler.js.map +1 -1
  286. package/dist/utils/HttpClient.d.ts +1 -5
  287. package/dist/utils/HttpClient.d.ts.map +1 -1
  288. package/dist/utils/HttpClient.js +1 -29
  289. package/dist/utils/HttpClient.js.map +1 -1
  290. package/dist/utils/PDFExtractor.d.ts +2 -33
  291. package/dist/utils/PDFExtractor.d.ts.map +1 -1
  292. package/dist/utils/PDFExtractor.js +2 -129
  293. package/dist/utils/PDFExtractor.js.map +1 -1
  294. package/dist/utils/PdfDownload.d.ts +1 -6
  295. package/dist/utils/PdfDownload.d.ts.map +1 -1
  296. package/dist/utils/PdfDownload.js +1 -141
  297. package/dist/utils/PdfDownload.js.map +1 -1
  298. package/dist/utils/RateLimiter.d.ts +1 -49
  299. package/dist/utils/RateLimiter.d.ts.map +1 -1
  300. package/dist/utils/RateLimiter.js +1 -120
  301. package/dist/utils/RateLimiter.js.map +1 -1
  302. package/dist/utils/RequestCache.d.ts +2 -25
  303. package/dist/utils/RequestCache.d.ts.map +1 -1
  304. package/dist/utils/RequestCache.js +2 -65
  305. package/dist/utils/RequestCache.js.map +1 -1
  306. package/dist/utils/SecurityUtils.d.ts +2 -79
  307. package/dist/utils/SecurityUtils.d.ts.map +1 -1
  308. package/dist/utils/SecurityUtils.js +2 -356
  309. package/dist/utils/SecurityUtils.js.map +1 -1
  310. package/package.json +1 -1
  311. package/skills/paper-search/SKILL.md +4 -2
  312. package/skills/paper-search/references/capability-routing.md +15 -2
  313. package/skills/paper-search/references/cli-contract.md +19 -0
  314. 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 { TIMEOUTS } from '../config/constants.js';
4
- import { logDebug } from '../utils/Logger.js';
5
- import { searchMultipleSources } from '../services/MultiSourceSearchService.js';
6
- import { downloadWithFallback } from '../services/OpenAccessFallbackService.js';
7
- import { queryJournalMetrics } from '../services/JournalMetricsService.js';
8
- import { withTimeout } from '../utils/SecurityUtils.js';
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 DOI_LOOKUP_SOURCES = [
21
- 'crossref',
22
- 'openalex',
23
- 'unpaywall',
24
- 'pubmed',
25
- 'pmc',
26
- 'europepmc',
27
- 'core',
28
- 'webofscience',
29
- 'arxiv'
30
- ];
31
- function parseJournalList(value) {
32
- if (!value)
33
- return [];
34
- if (Array.isArray(value))
35
- return value.map(item => String(item));
36
- return String(value)
37
- .split(/\r?\n|[,;;]/)
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
- case 'search_pubmed': {
131
- const { query, maxResults, year, author, journal, publicationType, sortBy } = args;
132
- const results = await searchers.pubmed.search(query, {
133
- maxResults,
134
- year,
135
- author,
136
- journal,
137
- publicationType,
138
- sortBy
139
- });
140
- const rateStatus = searchers.pubmed.getRateLimiterStatus();
141
- const apiKeyStatus = searchers.pubmed.hasApiKey() ? 'configured' : 'not configured';
142
- const rateLimit = searchers.pubmed.hasApiKey() ? '10 requests/second' : '3 requests/second';
143
- 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)}`);
144
- }
145
- case 'search_biorxiv': {
146
- const { query, maxResults, days, category } = args;
147
- const results = await searchers.biorxiv.search(query, {
148
- maxResults,
149
- days,
150
- category
151
- });
152
- return jsonTextResponse(`Found ${results.length} bioRxiv papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
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
- case 'search_medrxiv': {
155
- const { query, maxResults, days, category } = args;
156
- const results = await searchers.medrxiv.search(query, {
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 searcher.downloadPdf(paperId, { savePath: resolvedSavePath });
210
- return jsonTextResponse(`PDF downloaded successfully to: ${filePath}`);
128
+ const filePath = await searchers.scihub.downloadPdf(doiOrUrl, { savePath: resolvedSavePath });
129
+ responseText += `\n\nPDF downloaded successfully to: ${filePath}`;
211
130
  }
212
- catch (error) {
213
- const result = await downloadWithFallback(searchers, {
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
- case 'download_with_fallback': {
227
- const result = await downloadWithFallback(searchers, args);
228
- return jsonTextResponse(`Download with fallback ${result.status}.\n\n${JSON.stringify(result, null, 2)}`);
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
- case 'query_journal_metrics': {
231
- const { readFileSync } = await import('fs');
232
- const journals = [
233
- ...parseJournalList(args.journal),
234
- ...parseJournalList(args.journals),
235
- ...(args.file
236
- ? readFileSync(String(args.file), 'utf8')
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
- case 'search_google_scholar': {
247
- const { query, maxResults, yearLow, yearHigh, author } = args;
248
- const results = await searchers.googlescholar.search(query, {
249
- maxResults,
250
- yearLow,
251
- yearHigh,
252
- author
253
- });
254
- return jsonTextResponse(`Found ${results.length} Google Scholar papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
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
- case 'get_paper_by_doi': {
257
- const { doi, platform } = args;
258
- const results = [];
259
- const sourceResults = {};
260
- const errors = {};
261
- const failedSources = [];
262
- if (platform === 'all') {
263
- const selected = DOI_LOOKUP_SOURCES.filter(source => source in searchers);
264
- const settled = await Promise.allSettled(selected.map(async (source) => {
265
- const searcher = searchers[source];
266
- const paper = await withTimeout(searcher.getPaperByDoi(doi), TIMEOUTS.SOURCE_TASK, `${source} DOI lookup timed out after ${TIMEOUTS.SOURCE_TASK}ms`);
267
- return { source, paper };
268
- }));
269
- for (let i = 0; i < settled.length; i += 1) {
270
- const source = selected[i];
271
- const result = settled[i];
272
- if (result.status === 'rejected') {
273
- sourceResults[source] = 0;
274
- errors[source] = result.reason?.message || String(result.reason);
275
- failedSources.push(source);
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
- case 'search_scihub': {
338
- const { doiOrUrl, downloadPdf, savePath } = args;
339
- const resolvedSavePath = savePath || './downloads';
340
- const results = await searchers.scihub.search(doiOrUrl);
341
- if (results.length === 0) {
342
- return jsonTextResponse(`No paper found on Sci-Hub for: ${doiOrUrl}`);
343
- }
344
- const paper = results[0];
345
- let responseText = `Found paper on Sci-Hub:\n\n${JSON.stringify(PaperFactory.toDict(paper), null, 2)}`;
346
- if (downloadPdf && paper.pdfUrl) {
347
- try {
348
- const filePath = await searchers.scihub.downloadPdf(doiOrUrl, { savePath: resolvedSavePath });
349
- responseText += `\n\nPDF downloaded successfully to: ${filePath}`;
350
- }
351
- catch (downloadError) {
352
- responseText += `\n\nFailed to download PDF: ${downloadError.message}`;
353
- }
354
- }
355
- return jsonTextResponse(responseText);
356
- }
357
- case 'check_scihub_mirrors': {
358
- const { forceCheck } = args;
359
- if (forceCheck) {
360
- await searchers.scihub.forceHealthCheck();
361
- }
362
- const mirrorStatus = searchers.scihub.getMirrorStatus();
363
- return jsonTextResponse(`Sci-Hub Mirror Status:\n\n${JSON.stringify(mirrorStatus, null, 2)}`);
364
- }
365
- case 'search_sciencedirect': {
366
- const { query, maxResults, year, author, journal, openAccess } = args;
367
- if (!process.env.ELSEVIER_API_KEY) {
368
- throw new Error('Elsevier API key not configured. Please set ELSEVIER_API_KEY environment variable.');
369
- }
370
- const results = await searchers.sciencedirect.search(query, {
371
- maxResults,
372
- year,
373
- author,
374
- journal,
375
- openAccess
376
- });
377
- return jsonTextResponse(`Found ${results.length} ScienceDirect papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
378
- }
379
- case 'search_springer': {
380
- const { query, maxResults, year, author, journal, subject, openAccess, type } = args;
381
- if (!process.env.SPRINGER_API_KEY) {
382
- throw new Error('Springer API key not configured. Please set SPRINGER_API_KEY environment variable.');
383
- }
384
- const results = await searchers.springer.search(query, {
385
- maxResults,
386
- year,
387
- author,
388
- journal,
389
- subject,
390
- openAccess,
391
- type
392
- });
393
- return jsonTextResponse(`Found ${results.length} Springer papers.\n\n${JSON.stringify(results.map((paper) => PaperFactory.toDict(paper)), null, 2)}`);
394
- }
395
- case 'search_wiley': {
396
- return jsonTextResponse(`DEPRECATED: Wiley TDM API does not support keyword search.\n\n` +
397
- `To access Wiley content:\n` +
398
- `1. Use search_crossref to find Wiley articles (filter by publisher if needed)\n` +
399
- `2. Use download_paper with platform="wiley" and the DOI to download the PDF\n\n` +
400
- `Example: download_paper(paperId="10.1111/jtsb.12390", platform="wiley")`);
401
- }
402
- case 'search_scopus': {
403
- const { query, maxResults, year, author, journal, affiliation, subject, openAccess, documentType } = args;
404
- if (!process.env.ELSEVIER_API_KEY) {
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
- else {
481
- apiKeyStatus = 'configured';
254
+ catch {
255
+ apiKeyStatus = 'unknown';
482
256
  }
483
257
  }
484
258
  else {
485
- apiKeyStatus = 'missing';
259
+ apiKeyStatus = 'configured';
486
260
  }
487
261
  }
488
- let additionalInfo = {};
489
- if (platformName === 'scihub') {
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
- return jsonTextResponse(`Platform Status:\n\n${JSON.stringify(statusInfo, null, 2)}`);
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
- default:
507
- throw new Error(`Unknown tool: ${toolNameRaw}`);
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