adaptive-memory-multi-model-router 2.14.49 → 2.14.52

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 (605) hide show
  1. package/.dockerignore +82 -0
  2. package/.env.example +303 -0
  3. package/.github/DISCUSSIONS_WELCOME.md +27 -0
  4. package/.github/DISCUSSION_TEMPLATE.yml +5 -0
  5. package/.github/FUNDING.yml +2 -0
  6. package/.github/ISSUE_TEMPLATE/bug_report.md +94 -0
  7. package/.github/ISSUE_TEMPLATE/config.yml +17 -0
  8. package/.github/ISSUE_TEMPLATE/feature_request.md +71 -0
  9. package/.github/PULL_REQUEST_TEMPLATE.md +71 -0
  10. package/.github/dependabot.yml +9 -0
  11. package/.github/workflows/ci.yml +263 -0
  12. package/.github/workflows/codeql.yml +38 -0
  13. package/.github/workflows/npm-publish.yml +20 -0
  14. package/.github/workflows/pages.yml +37 -0
  15. package/.github/workflows/stale.yml +54 -0
  16. package/.publish-tick +1 -0
  17. package/.well-known/ai-plugin.json +16 -0
  18. package/AGENT_COUNCIL_FINDINGS.md +142 -0
  19. package/ARCHITECTURE.md +346 -0
  20. package/AUDIT_REPORT.md +28 -0
  21. package/CODE_OF_CONDUCT.md +128 -0
  22. package/CONTRIBUTING.md +50 -0
  23. package/CONTRIBUTORS.md +20 -0
  24. package/Dockerfile +53 -0
  25. package/Dockerfile.proxy +33 -0
  26. package/HEALTH_REPORT.md +118 -0
  27. package/IMPROVEMENT_PLAN.md +107 -0
  28. package/LANDING.md +43 -0
  29. package/LAUNCH-PAIN-DRIVEN.md +339 -0
  30. package/LAUNCH.md +337 -0
  31. package/LAUNCH_CHECKLIST.md +141 -0
  32. package/LAUNCH_SNAPSHOT.md +260 -0
  33. package/MANIFESTO.md +41 -0
  34. package/POPULARITY_BOOSTERS.md +285 -0
  35. package/PR_STATUS_REPORT.md +148 -0
  36. package/README.md +25 -14
  37. package/REDESIGN.md +95 -0
  38. package/RUNKIT.md +83 -0
  39. package/SECURITY.md +29 -0
  40. package/SUBMISSIONS.md +43 -0
  41. package/_schema.html +53 -0
  42. package/ai-plugin.json +16 -0
  43. package/articles/AI_AGENT_LLM_ROUTING.md +150 -0
  44. package/articles/CHINESE_DIRECTORIES.md +100 -0
  45. package/articles/CHINESE_SUBMISSIONS_READY.md +322 -0
  46. package/articles/COMPETITOR_ALERTS.md +31 -0
  47. package/articles/COMPLETE_POSTING_DIRECTORY.md +147 -0
  48. package/articles/CONTENT_STRUCTURE.md +292 -0
  49. package/articles/DEVTO_COST_GUIDE.md +473 -0
  50. package/articles/DEVTO_FINAL.md +416 -0
  51. package/articles/DEVTO_MULTI_PROVIDER.md +542 -0
  52. package/articles/DEVTO_READY.md +255 -0
  53. package/articles/DEVTO_V2_ANNOUNCEMENT.md +160 -0
  54. package/articles/DEVTO_VIRAL_GROWTH.md +280 -0
  55. package/articles/FRESH_devto.md +460 -0
  56. package/articles/FRESH_devto_2026_05.md +73 -0
  57. package/articles/FRESH_hackernews.md +14 -0
  58. package/articles/FRESH_reddit_ml.md +90 -0
  59. package/articles/FRESH_reddit_node.md +198 -0
  60. package/articles/FRESH_reddit_sideproject.md +72 -0
  61. package/articles/FRESH_reddit_webdev.md +130 -0
  62. package/articles/FROM_ZERO_TO_10K.md +107 -0
  63. package/articles/HN_10X_BETTER.md +430 -0
  64. package/articles/HN_ACCOUNT_GUIDE.md +21 -0
  65. package/articles/HN_CHINESE_STYLE.md +308 -0
  66. package/articles/HN_FINAL.md +148 -0
  67. package/articles/HN_POSTED_VERSION.md +56 -0
  68. package/articles/HN_POST_READY.md +137 -0
  69. package/articles/HN_RESEARCH.md +364 -0
  70. package/articles/HN_SHOW_routerarena.md +17 -0
  71. package/articles/HN_TIMING_GUIDE.md +52 -0
  72. package/articles/INDIEHACKERS_POST.md +52 -0
  73. package/articles/INDIEHACKERS_READY.md +120 -0
  74. package/articles/LLM_BENCHMARK_DEEP_DIVE.md +153 -0
  75. package/articles/MASTER_POSTING_DIRECTORY.md +189 -0
  76. package/articles/NEWSLETTER_SEND_NOW.md +259 -0
  77. package/articles/NEWSLETTER_SUBMISSIONS.md +112 -0
  78. package/articles/PAIN-DRIVEN-devto-v2.md +308 -0
  79. package/articles/PAIN-DRIVEN-devto-v3.md +268 -0
  80. package/articles/PAIN-DRIVEN-devto.md +242 -0
  81. package/articles/PAIN-DRIVEN-hackernews-v2.md +138 -0
  82. package/articles/PAIN-DRIVEN-hackernews-v3.md +151 -0
  83. package/articles/PAIN-DRIVEN-hackernews.md +131 -0
  84. package/articles/PAIN-DRIVEN-reddit-v2.md +301 -0
  85. package/articles/PAIN-DRIVEN-reddit-v3.md +236 -0
  86. package/articles/PAIN-DRIVEN-reddit.md +218 -0
  87. package/articles/PAIN-DRIVEN-twitter-v2.md +110 -0
  88. package/articles/PAIN-DRIVEN-twitter-v3.md +121 -0
  89. package/articles/PAIN-DRIVEN-twitter.md +120 -0
  90. package/articles/PORTKEY_VS_A3M.md +147 -0
  91. package/articles/POSTING_KIT_2026_05.md +67 -0
  92. package/articles/PRESS_KIT_routerarena.md +77 -0
  93. package/articles/PRODUCTHUNT_LISTING.md +48 -0
  94. package/articles/PRODUCTHUNT_READY.md +106 -0
  95. package/articles/PR_PLAN_vault.md +125 -0
  96. package/articles/REDDIT_FINAL.md +232 -0
  97. package/articles/REDDIT_POST.md +67 -0
  98. package/articles/REDDIT_SUBMISSION_READY.md +348 -0
  99. package/articles/ROUTERARENA_9677.md +78 -0
  100. package/articles/ROUTERARENA_LEADER.md +45 -0
  101. package/articles/SHOW_HN_FINAL.md +29 -0
  102. package/articles/TWEETS_10K_DOWNLOADS.md +47 -0
  103. package/articles/TWEETS_BENCHMARK_FIRST.md +46 -0
  104. package/articles/TWEETS_MCP_PLAY.md +51 -0
  105. package/articles/TWEETS_SEQUENTIAL_BROKEN.md +49 -0
  106. package/articles/TWEETS_WHY_BUILD.md +54 -0
  107. package/articles/TWEETS_routerarena_leader.md +53 -0
  108. package/articles/TWEET_STORM_READY.md +165 -0
  109. package/articles/TWITTER_FINAL.md +167 -0
  110. package/articles/WHY_10X_BETTER.md +261 -0
  111. package/articles/WHY_CHINESE_STYLE_BETTER.md +323 -0
  112. package/articles/ai-discoverability-llm-routing.md +210 -0
  113. package/articles/devto-llm-routing.md +138 -0
  114. package/articles/hackernews-show-hn.md +54 -0
  115. package/articles/hashnode-llm-cost-optimization.md +125 -0
  116. package/articles/hn_show_2026_05.md +11 -0
  117. package/articles/medium-building-llm-router.md +205 -0
  118. package/articles/reddit-ml.md +76 -0
  119. package/articles/twitter-thread-cost-savings.md +50 -0
  120. package/articles/youtube-tutorial-script.md +262 -0
  121. package/assets/a3m_3blue1brown.mp4 +0 -0
  122. package/assets/banner.svg +109 -0
  123. package/assets/chart-cost-v2.svg +91 -0
  124. package/assets/chart-cost-v3.svg +143 -0
  125. package/assets/chart-features-v2.svg +132 -0
  126. package/assets/chart-features-v3.svg +211 -0
  127. package/assets/chart-growth-v2.svg +122 -0
  128. package/assets/chart-growth-v3.svg +189 -0
  129. package/assets/cost-comparison.svg +134 -0
  130. package/assets/cost-simple.svg +64 -0
  131. package/assets/demo-hn.gif +0 -0
  132. package/assets/feature-matrix.svg +136 -0
  133. package/assets/growth-chart-animated.svg +76 -0
  134. package/assets/growth-chart.svg +82 -0
  135. package/assets/growth-simple.svg +69 -0
  136. package/assets/hero-diagram.svg +81 -0
  137. package/assets/logo-new.svg +21 -0
  138. package/assets/logo.svg +68 -0
  139. package/assets/provider-comparison.svg +121 -0
  140. package/assets/social-preview-new.svg +100 -0
  141. package/assets/social-preview.svg +194 -0
  142. package/assets/social-v2.svg +130 -0
  143. package/assets/social-v3.svg +212 -0
  144. package/benchmark-provider-results.json +245 -0
  145. package/benchmark-results.json +54 -0
  146. package/council-votes/architecture-vote.md +121 -0
  147. package/council-votes/coverage-vote.md +93 -0
  148. package/data/adaptive-benchmark.json +92 -0
  149. package/data/benchmark-results.json +47 -0
  150. package/data/labeled-benchmark.json +88 -0
  151. package/demo/3blue1brown_video.py +285 -0
  152. package/demo/3blue1brown_video_v2.py +310 -0
  153. package/demo/IMPROVED_PROMPTS.md +229 -0
  154. package/demo/VEO3_PROMPTS.md +269 -0
  155. package/demo/VIDEO_PRODUCTION_GUIDE.md +333 -0
  156. package/demo/a3m_3blue1brown.mp4 +0 -0
  157. package/demo/asciinema-demo.sh +195 -0
  158. package/demo/demo-hn.tape +74 -0
  159. package/demo/demo-script.md +53 -0
  160. package/demo/demo-script.sh +62 -0
  161. package/demo/demo.svg +75 -0
  162. package/demo/frame1_ai_data_center.png +0 -0
  163. package/demo/frame1_sunset_video.mp4 +0 -0
  164. package/demo/frame2_cost_comparison.png +0 -0
  165. package/demo/frame2_cost_comparison_fallback.png +0 -0
  166. package/demo/frame3_parallel_execution.png +0 -0
  167. package/demo/frame3_parallel_execution_fallback.png +0 -0
  168. package/demo/frame4_providers.png +0 -0
  169. package/demo/frame4_providers_fallback.png +0 -0
  170. package/demo/frame5_endcard.png +0 -0
  171. package/demo/frame5_endcard_fallback.png +0 -0
  172. package/demo/new_frame1_hook.png +0 -0
  173. package/demo/new_frame2_proof.png +0 -0
  174. package/demo/new_frame3_wow.png +0 -0
  175. package/demo/new_frame4_social.png +0 -0
  176. package/demo/new_frame5_cta.png +0 -0
  177. package/demo/package.json +13 -0
  178. package/demo/product-video-final.mp4 +0 -0
  179. package/demo/product-video-hype-v1.mp4 +0 -0
  180. package/demo/product-video-v1.mp4 +0 -0
  181. package/demo/public/index.html +762 -0
  182. package/demo/recording.cast +55 -0
  183. package/demo/server.js +405 -0
  184. package/demo-new.tape +71 -0
  185. package/demo-real.sh +198 -0
  186. package/demo-simple.tape +205 -0
  187. package/demo.html +520 -0
  188. package/demo.sh +85 -0
  189. package/demo.tape +259 -0
  190. package/dist/analytics/costAnalytics.d.ts.map +1 -0
  191. package/dist/analytics/costAnalytics.js.map +1 -0
  192. package/dist/benchmark/comprehensive.js.map +1 -0
  193. package/dist/benchmark/reproducible.d.ts.map +1 -0
  194. package/dist/benchmark/reproducible.js.map +1 -0
  195. package/dist/cache/prefixCache.d.ts.map +1 -0
  196. package/dist/cache/prefixCache.js.map +1 -0
  197. package/dist/cache/responseCache.d.ts.map +1 -0
  198. package/dist/cache/responseCache.js.map +1 -0
  199. package/dist/cache/semanticCache.d.ts.map +1 -0
  200. package/dist/cache/semanticCache.js.map +1 -0
  201. package/dist/cli/setupWizard.d.ts.map +1 -0
  202. package/dist/cli/setupWizard.js.map +1 -0
  203. package/dist/cost/budgetEnforcer.d.ts.map +1 -0
  204. package/dist/cost/budgetEnforcer.js.map +1 -0
  205. package/dist/cost/costTracker.d.ts.map +1 -0
  206. package/dist/cost/costTracker.js.map +1 -0
  207. package/dist/ensemble/multiRoundDialog.js.map +1 -0
  208. package/dist/ensemble/shapleyValue.js.map +1 -0
  209. package/dist/integrations/langchainAdapter.d.ts.map +1 -0
  210. package/dist/integrations/langchainAdapter.js.map +1 -0
  211. package/dist/integrations/oauth.d.ts.map +1 -0
  212. package/dist/integrations/oauth.js.map +1 -0
  213. package/dist/integrations/scienceAdapter.js.map +1 -0
  214. package/dist/memory/autoFetch.d.ts.map +1 -0
  215. package/dist/memory/autoFetch.js.map +1 -0
  216. package/dist/memory/episodicMemory.d.ts.map +1 -0
  217. package/dist/memory/episodicMemory.js.map +1 -0
  218. package/dist/memory/hybridMemory.js.map +1 -0
  219. package/dist/memory/memoryTree.d.ts.map +1 -0
  220. package/dist/memory/memoryTree.js.map +1 -0
  221. package/dist/memory/obsidianVault.d.ts.map +1 -0
  222. package/dist/memory/obsidianVault.js.map +1 -0
  223. package/dist/memory/reasoningBank.js.map +1 -0
  224. package/dist/observability/changeWatch.d.ts.map +1 -0
  225. package/dist/observability/changeWatch.js.map +1 -0
  226. package/dist/observability/fatigueDetector.d.ts.map +1 -0
  227. package/dist/observability/fatigueDetector.js.map +1 -0
  228. package/dist/observability/index.d.ts.map +1 -0
  229. package/dist/observability/index.js.map +1 -0
  230. package/dist/observability/metrics.d.ts.map +1 -0
  231. package/dist/observability/metrics.js.map +1 -0
  232. package/dist/observability/middleware.d.ts.map +1 -0
  233. package/dist/observability/middleware.js.map +1 -0
  234. package/dist/observability/tracer.d.ts.map +1 -0
  235. package/dist/observability/tracer.js.map +1 -0
  236. package/dist/observability/types.d.ts.map +1 -0
  237. package/dist/observability/types.js.map +1 -0
  238. package/dist/orchestration/haloOrchestrator.d.ts.map +1 -0
  239. package/dist/orchestration/haloOrchestrator.js.map +1 -0
  240. package/dist/orchestration/mctsWorkflow.d.ts.map +1 -0
  241. package/dist/orchestration/mctsWorkflow.js.map +1 -0
  242. package/dist/providers/localProvider.d.ts.map +1 -0
  243. package/dist/providers/localProvider.js.map +1 -0
  244. package/dist/providers/providerConfig.d.ts.map +1 -0
  245. package/dist/providers/providerConfig.js.map +1 -0
  246. package/dist/providers/registry.d.ts.map +1 -0
  247. package/dist/providers/registry.js.map +1 -0
  248. package/dist/routing/advancedRouter.d.ts.map +1 -0
  249. package/dist/routing/advancedRouter.js +1 -1
  250. package/dist/routing/advancedRouter.js.map +1 -0
  251. package/dist/routing/crossModelValidation.d.ts.map +1 -0
  252. package/dist/routing/crossModelValidation.js.map +1 -0
  253. package/dist/routing/providerHealth.d.ts.map +1 -0
  254. package/dist/routing/providerHealth.js.map +1 -0
  255. package/dist/routing/providerRetry.d.ts.map +1 -0
  256. package/dist/routing/providerRetry.js.map +1 -0
  257. package/dist/scripts/banner.js +29 -0
  258. package/dist/security/guardrails.d.ts.map +1 -0
  259. package/dist/security/guardrails.js.map +1 -0
  260. package/dist/server/dashboard.d.ts.map +1 -0
  261. package/dist/server/dashboard.js.map +1 -0
  262. package/dist/server/modelMapper.d.ts.map +1 -0
  263. package/dist/server/modelMapper.js.map +1 -0
  264. package/dist/server/proxyServer.d.ts.map +1 -0
  265. package/dist/server/proxyServer.js.map +1 -0
  266. package/dist/skills/__tests__/skill_manager.test.d.ts +2 -0
  267. package/dist/skills/__tests__/skill_manager.test.d.ts.map +1 -0
  268. package/dist/skills/__tests__/skill_manager.test.js +268 -0
  269. package/dist/skills/__tests__/skill_manager.test.js.map +1 -0
  270. package/dist/tools/tmlpdTools.d.ts.map +1 -0
  271. package/dist/tools/tmlpdTools.js.map +1 -0
  272. package/dist/tui/dashboard.d.ts.map +1 -0
  273. package/dist/tui/dashboard.js.map +1 -0
  274. package/dist/tui/index.d.ts.map +1 -0
  275. package/dist/tui/index.js.map +1 -0
  276. package/dist/utils/batchProcessor.d.ts.map +1 -0
  277. package/dist/utils/batchProcessor.js.map +1 -0
  278. package/dist/utils/compression.d.ts.map +1 -0
  279. package/dist/utils/compression.js.map +1 -0
  280. package/dist/utils/costUtils.d.ts.map +1 -0
  281. package/dist/utils/costUtils.js.map +1 -0
  282. package/dist/utils/reliability.d.ts.map +1 -0
  283. package/dist/utils/reliability.js.map +1 -0
  284. package/dist/utils/sorting.d.ts.map +1 -0
  285. package/dist/utils/sorting.js.map +1 -0
  286. package/dist/utils/speculativeDecoding.d.ts.map +1 -0
  287. package/dist/utils/speculativeDecoding.js.map +1 -0
  288. package/dist/utils/tokenUtils.d.ts.map +1 -0
  289. package/dist/utils/tokenUtils.js.map +1 -0
  290. package/docs/.nojekyll +0 -0
  291. package/docs/ANALYSIS_PRINCIPLES.md +162 -0
  292. package/docs/API.md +855 -0
  293. package/docs/ARCHITECTURAL-IMPROVEMENTS-2025.md +1391 -0
  294. package/docs/ARCHITECTURAL-IMPROVEMENTS-REVISED-2025.md +1051 -0
  295. package/docs/BENCHMARK.md +170 -0
  296. package/docs/CHINESE_PROVIDER_RELIABILITY.md +37 -0
  297. package/docs/CITATIONS.md +74 -0
  298. package/docs/CLAIMS_AND_EVIDENCE.md +58 -0
  299. package/docs/CONFIGURATION.md +476 -0
  300. package/docs/COUNCIL_DECISION.json +816 -0
  301. package/docs/COUNCIL_SUMMARY.md +319 -0
  302. package/docs/COUNCIL_V2.2_DECISION.md +416 -0
  303. package/docs/ENGINEERING_SPEC.md +55 -0
  304. package/docs/FACTORY_RESET.md +34 -0
  305. package/docs/GEO.md +66 -0
  306. package/docs/GEO_OPTIMIZATION.md +30 -0
  307. package/docs/GEO_ROOT_CAUSE.md +136 -0
  308. package/docs/GEO_STATUS.md +85 -0
  309. package/docs/GEO_TEST_RESULTS.md +176 -0
  310. package/docs/HN_CHECKLIST.md +38 -0
  311. package/docs/HN_FOUNDER_COMMENT.md +17 -0
  312. package/docs/HN_SUBMISSION_FINAL.md +180 -0
  313. package/docs/HN_SUBMISSION_V3.md +56 -0
  314. package/docs/IMPROVEMENT_ROADMAP.md +515 -0
  315. package/docs/INTEGRATIONS.md +420 -0
  316. package/docs/LANGCHAIN_INTEGRATION.md +147 -0
  317. package/docs/LLM_COUNCIL_DECISION.md +508 -0
  318. package/docs/MIDDLEWARE_CHAIN.md +35 -0
  319. package/docs/PROMO_CHECKLIST.md +200 -0
  320. package/docs/QUICKSTART.md +271 -0
  321. package/docs/QUICK_START.md +43 -0
  322. package/docs/QUICK_START_VISIBILITY.md +782 -0
  323. package/docs/REDDIT_GAP_ANALYSIS.md +299 -0
  324. package/docs/RELEASE_CHECKLIST.md +32 -0
  325. package/docs/REPRODUCIBILITY.md +63 -0
  326. package/docs/RESEARCH_BACKED_IMPROVEMENTS.md +1180 -0
  327. package/docs/ROUTING_RUBRIC.md +197 -0
  328. package/docs/SEO_AUDIT.md +186 -0
  329. package/docs/SOCIAL_LISTENING.md +219 -0
  330. package/docs/TMLPD_QNA.md +751 -0
  331. package/docs/TMLPD_V2.1_COMPLETE.md +763 -0
  332. package/docs/TMLPD_V2.2_RESEARCH_ROADMAP.md +754 -0
  333. package/docs/UPDATE_TOPICS.md +15 -0
  334. package/docs/USE_CASES.md +59 -0
  335. package/docs/V2.2_IMPLEMENTATION_COMPLETE.md +446 -0
  336. package/docs/V2_IMPLEMENTATION_GUIDE.md +388 -0
  337. package/docs/VERCEL_AI_SDK.md +209 -0
  338. package/docs/VISIBILITY_ADOPTION_PLAN.md +1005 -0
  339. package/docs/_config.yml +49 -0
  340. package/docs/ai-plugin.json +16 -0
  341. package/docs/api.html +513 -0
  342. package/docs/architecture-diagram.md +40 -0
  343. package/docs/benchmark-chart.png +0 -0
  344. package/docs/benchmark.html +387 -0
  345. package/docs/blog/routerarena-9677.html +92 -0
  346. package/docs/blog/routerarena-number-one.html +73 -0
  347. package/docs/cli-cheatsheet.md +339 -0
  348. package/docs/compare.md +109 -0
  349. package/docs/comparison-litellm.md +88 -0
  350. package/docs/comparison.md +108 -0
  351. package/docs/cost-chart-ascii.md +42 -0
  352. package/docs/cost-comparison-chart.svg +88 -0
  353. package/docs/curl-examples.md +247 -0
  354. package/docs/demo-auto.html +264 -0
  355. package/docs/demo.html +416 -0
  356. package/docs/geo/GENERATIVE_ENGINE_OPTIMIZATION.md +232 -0
  357. package/docs/index.html +507 -0
  358. package/docs/launch-content/LAUNCH_EXECUTION_CHECKLIST.md +421 -0
  359. package/docs/launch-content/README.md +457 -0
  360. package/docs/launch-content/assets/cost_comparison_100_tasks.png +0 -0
  361. package/docs/launch-content/assets/cumulative_savings.png +0 -0
  362. package/docs/launch-content/assets/parallel_speedup.png +0 -0
  363. package/docs/launch-content/assets/provider_pricing_comparison.png +0 -0
  364. package/docs/launch-content/assets/task_breakdown_comparison.png +0 -0
  365. package/docs/launch-content/generate_charts.py +313 -0
  366. package/docs/launch-content/hn_show_post.md +139 -0
  367. package/docs/launch-content/partner_outreach_templates.md +745 -0
  368. package/docs/launch-content/reddit_posts.md +467 -0
  369. package/docs/launch-content/twitter_thread.txt +460 -0
  370. package/{llms.txt.bak → docs/llms.txt} +6 -6
  371. package/docs/npm-downloads-chart.svg +43 -0
  372. package/docs/openapi.json +139 -0
  373. package/docs/openapi.yaml +1318 -0
  374. package/docs/quick-start.html +366 -0
  375. package/docs/robots.txt +52 -0
  376. package/docs/sitemap.xml +57 -0
  377. package/docs/styles.css +682 -0
  378. package/docs/well-known/ai-plugin.json +16 -0
  379. package/docs/wellknown/ai-plugin.json +16 -0
  380. package/docs-site/assets/og-banner.svg +194 -0
  381. package/docs-site/index.html +632 -0
  382. package/eval/README.md +46 -0
  383. package/eval/baselines/main.json +12 -0
  384. package/eval/benchmark_dataset.jsonl +16 -0
  385. package/eval/check_golden_routes.js +64 -0
  386. package/eval/datasets/catalog.json +33 -0
  387. package/eval/datasets/slices/cn_provider_reliability_v1.jsonl +3 -0
  388. package/eval/datasets/slices/cost_pressure_v1.jsonl +3 -0
  389. package/eval/datasets/slices/safety_guardrails_v1.jsonl +3 -0
  390. package/eval/evals.json +199 -0
  391. package/eval/fault_injection_thresholds.json +3 -0
  392. package/eval/generate_report.js +128 -0
  393. package/eval/golden_routes.json +114 -0
  394. package/eval/lib/experiment_registry.js +24 -0
  395. package/eval/run_eval.js +197 -0
  396. package/eval/run_fault_injection.js +201 -0
  397. package/eval/run_shadow_eval.js +85 -0
  398. package/eval/thresholds.json +9 -0
  399. package/examples/QUICKSTART.md +183 -0
  400. package/examples/README.md +61 -0
  401. package/examples/a3m-sdk.js +124 -0
  402. package/examples/basic-route.js +54 -0
  403. package/examples/chat-loop.js +202 -0
  404. package/examples/classify-then-route.js +102 -0
  405. package/examples/cost-compare.js +120 -0
  406. package/examples/ensemble.js +160 -0
  407. package/examples/whatsapp-telegram-bridge-demo.js +302 -0
  408. package/examples/whatsapp-telegram-bridge.js +269 -0
  409. package/hf-space/README.md +23 -0
  410. package/hf-space/app.py +240 -0
  411. package/hf-space/requirements.txt +1 -0
  412. package/huggingface_space/README.md +35 -0
  413. package/huggingface_space/app.py +126 -0
  414. package/huggingface_space/create_space.py +208 -0
  415. package/huggingface_space/requirements.txt +1 -0
  416. package/index.html +1 -1
  417. package/mcp-server/README.md +188 -0
  418. package/mcp-server/package.json +29 -0
  419. package/mcp-server/src/index.ts +744 -0
  420. package/mcp-server/tsconfig.json +19 -0
  421. package/openclaw-alexa-bridge/ALL_REMAINING_FIXES_PLAN.md +313 -0
  422. package/openclaw-alexa-bridge/REMAINING_FIXES_SUMMARY.md +277 -0
  423. package/openclaw-alexa-bridge/src/alexa_handler_no_tmlpd.js +1234 -0
  424. package/openclaw-alexa-bridge/test_fixes.js +77 -0
  425. package/package.json +76 -272
  426. package/playground/README.md +51 -0
  427. package/playground/codesandbox.json +12 -0
  428. package/playground/index.js +39 -0
  429. package/proxy/README.md +227 -0
  430. package/proxy/package-lock.json +831 -0
  431. package/proxy/package.json +17 -0
  432. package/proxy/rate-limit.js +145 -0
  433. package/proxy/rate-limit.test.js +311 -0
  434. package/proxy/server.js +970 -0
  435. package/python/README.md +102 -0
  436. package/python/a3m/__init__.py +6 -0
  437. package/python/a3m/client.py +190 -0
  438. package/python/a3m/models.py +40 -0
  439. package/python/a3m/sync_client.py +61 -0
  440. package/python/examples.py +53 -0
  441. package/python/integrations.py +330 -0
  442. package/python/pyproject.toml +23 -0
  443. package/python/setup.py +28 -0
  444. package/python/tmlpd.py +369 -0
  445. package/qna/REDDIT_GAP_ANALYSIS.md +299 -0
  446. package/qna/TMLPD_QNA.md +751 -0
  447. package/research/FINDING_001_safety.md +28 -0
  448. package/research/FINDING_002_error_diversity.md +32 -0
  449. package/research/FINDING_003_confidence_weighted_voting.md +32 -0
  450. package/research/FINDING_004_cross_model_semantic_detection.md +37 -0
  451. package/research/FINDING_005_knowledge_gap_orthogonality.md +34 -0
  452. package/research/HALLUCINATION_RESEARCH.md +27 -0
  453. package/research/ensemble-voting.md +324 -0
  454. package/research/loss-functions.md +545 -0
  455. package/research-log.md +49 -0
  456. package/scripts/banner.js +29 -0
  457. package/scripts/benchmark-local-routerarena.ts +176 -0
  458. package/scripts/benchmark.js +145 -0
  459. package/scripts/benchmark.sh +61 -0
  460. package/scripts/compare-providers.sh +230 -0
  461. package/scripts/content-planner.js +25 -0
  462. package/scripts/create-labeled-benchmark.ts +105 -0
  463. package/scripts/cross_post.py +443 -0
  464. package/scripts/local-router-benchmark.ts +154 -0
  465. package/scripts/post-all.sh +41 -0
  466. package/scripts/publish_fcc.py +106 -0
  467. package/scripts/push-to-gitee.sh +25 -0
  468. package/scripts/routerarena_ensemble.js +144 -0
  469. package/scripts/routing-benchmark-v2.js +373 -0
  470. package/scripts/routing-benchmark-v3.js +118 -0
  471. package/scripts/routing-benchmark.js +462 -0
  472. package/scripts/run-labeled-benchmark.mjs +104 -0
  473. package/scripts/run-mmlu-benchmark.js +176 -0
  474. package/scripts/run-provider-benchmark.js +244 -0
  475. package/scripts/update-npm-badges.js +158 -0
  476. package/skill/SKILL.md +238 -0
  477. package/src/__tests__/integration/tmpld_integration.test.py +540 -0
  478. package/src/ensemble.ts +2 -0
  479. package/src/routing/advancedRouter.ts +1 -1
  480. package/src/skills/__tests__/skill_manager.test.ts +328 -0
  481. package/submissions/benchmarks/ALL_PLATFORMS_SUBMISSION.md +94 -0
  482. package/submissions/benchmarks/LLMROUTERBENCH_SUBMISSION.md +121 -0
  483. package/submissions/benchmarks/MMRBENCH_SUBMISSION.md +94 -0
  484. package/submissions/benchmarks/ROUTERARENA_UPDATE.md +83 -0
  485. package/submissions/benchmarks/ROUTERBENCH_SUBMISSION.md +225 -0
  486. package/test-council/1-structure-tests.test.js +353 -0
  487. package/test-council/1-structure-tests.test.ts +353 -0
  488. package/test-council/2-edge-case-tests.test.ts +361 -0
  489. package/test-council/3-performance-tests.test.ts +652 -0
  490. package/test-council/4-integration-tests.test.ts +391 -0
  491. package/test-council/5-agent-council-eval.test.ts +413 -0
  492. package/test-council/AGENT_COUNCIL_ARCHITECTURE.md +349 -0
  493. package/test-council/TEST_COUNCIL_REPORT.md +201 -0
  494. package/test-council/agents/edge-case-agent.ts +363 -0
  495. package/test-council/agents/performance-agent.ts +426 -0
  496. package/test-council/agents/structure-agent.ts +227 -0
  497. package/test-council/council.md +183 -0
  498. package/tests/__mocks__/tokenUtils.ts +8 -0
  499. package/tests/memory/episodicMemory.test.ts +227 -0
  500. package/tests/package-lock.json +1785 -0
  501. package/tests/package.json +19 -0
  502. package/tests/routing/ensembleVoting.test.ts +236 -0
  503. package/tests/routing/providerRetry.test.ts +360 -0
  504. package/tests/routing/queryTypePresets.test.ts +208 -0
  505. package/tests/security/guardrailEngine.test.ts +700 -0
  506. package/tests/tsconfig.json +21 -0
  507. package/tests/vitest.config.ts +18 -0
  508. package/tmlpd-pi-extension/README.md +66 -0
  509. package/tmlpd-pi-extension/dist/cache/prefixCache.d.ts +114 -0
  510. package/tmlpd-pi-extension/dist/cache/prefixCache.d.ts.map +1 -0
  511. package/tmlpd-pi-extension/dist/cache/prefixCache.js +285 -0
  512. package/tmlpd-pi-extension/dist/cache/prefixCache.js.map +1 -0
  513. package/tmlpd-pi-extension/dist/cache/responseCache.d.ts +58 -0
  514. package/tmlpd-pi-extension/dist/cache/responseCache.d.ts.map +1 -0
  515. package/tmlpd-pi-extension/dist/cache/responseCache.js +153 -0
  516. package/tmlpd-pi-extension/dist/cache/responseCache.js.map +1 -0
  517. package/tmlpd-pi-extension/dist/cli.js +59 -0
  518. package/tmlpd-pi-extension/dist/cost/costTracker.d.ts +95 -0
  519. package/tmlpd-pi-extension/dist/cost/costTracker.d.ts.map +1 -0
  520. package/tmlpd-pi-extension/dist/cost/costTracker.js +240 -0
  521. package/tmlpd-pi-extension/dist/cost/costTracker.js.map +1 -0
  522. package/tmlpd-pi-extension/dist/index.d.ts +723 -0
  523. package/tmlpd-pi-extension/dist/index.d.ts.map +1 -0
  524. package/tmlpd-pi-extension/dist/index.js +239 -0
  525. package/tmlpd-pi-extension/dist/index.js.map +1 -0
  526. package/tmlpd-pi-extension/dist/memory/episodicMemory.d.ts +82 -0
  527. package/tmlpd-pi-extension/dist/memory/episodicMemory.d.ts.map +1 -0
  528. package/tmlpd-pi-extension/dist/memory/episodicMemory.js +145 -0
  529. package/tmlpd-pi-extension/dist/memory/episodicMemory.js.map +1 -0
  530. package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.d.ts +102 -0
  531. package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.d.ts.map +1 -0
  532. package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.js +207 -0
  533. package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.js.map +1 -0
  534. package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.d.ts +85 -0
  535. package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.d.ts.map +1 -0
  536. package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.js +210 -0
  537. package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.js.map +1 -0
  538. package/tmlpd-pi-extension/dist/providers/localProvider.d.ts +102 -0
  539. package/tmlpd-pi-extension/dist/providers/localProvider.d.ts.map +1 -0
  540. package/tmlpd-pi-extension/dist/providers/localProvider.js +338 -0
  541. package/tmlpd-pi-extension/dist/providers/localProvider.js.map +1 -0
  542. package/tmlpd-pi-extension/dist/providers/registry.d.ts +55 -0
  543. package/tmlpd-pi-extension/dist/providers/registry.d.ts.map +1 -0
  544. package/tmlpd-pi-extension/dist/providers/registry.js +138 -0
  545. package/tmlpd-pi-extension/dist/providers/registry.js.map +1 -0
  546. package/tmlpd-pi-extension/dist/routing/advancedRouter.d.ts +68 -0
  547. package/tmlpd-pi-extension/dist/routing/advancedRouter.d.ts.map +1 -0
  548. package/tmlpd-pi-extension/dist/routing/advancedRouter.js +332 -0
  549. package/tmlpd-pi-extension/dist/routing/advancedRouter.js.map +1 -0
  550. package/tmlpd-pi-extension/dist/tools/tmlpdTools.d.ts +101 -0
  551. package/tmlpd-pi-extension/dist/tools/tmlpdTools.d.ts.map +1 -0
  552. package/tmlpd-pi-extension/dist/tools/tmlpdTools.js +368 -0
  553. package/tmlpd-pi-extension/dist/tools/tmlpdTools.js.map +1 -0
  554. package/tmlpd-pi-extension/dist/utils/batchProcessor.d.ts +96 -0
  555. package/tmlpd-pi-extension/dist/utils/batchProcessor.d.ts.map +1 -0
  556. package/tmlpd-pi-extension/dist/utils/batchProcessor.js +170 -0
  557. package/tmlpd-pi-extension/dist/utils/batchProcessor.js.map +1 -0
  558. package/tmlpd-pi-extension/dist/utils/compression.d.ts +61 -0
  559. package/tmlpd-pi-extension/dist/utils/compression.d.ts.map +1 -0
  560. package/tmlpd-pi-extension/dist/utils/compression.js +281 -0
  561. package/tmlpd-pi-extension/dist/utils/compression.js.map +1 -0
  562. package/tmlpd-pi-extension/dist/utils/reliability.d.ts +74 -0
  563. package/tmlpd-pi-extension/dist/utils/reliability.d.ts.map +1 -0
  564. package/tmlpd-pi-extension/dist/utils/reliability.js +177 -0
  565. package/tmlpd-pi-extension/dist/utils/reliability.js.map +1 -0
  566. package/tmlpd-pi-extension/dist/utils/speculativeDecoding.d.ts +117 -0
  567. package/tmlpd-pi-extension/dist/utils/speculativeDecoding.d.ts.map +1 -0
  568. package/tmlpd-pi-extension/dist/utils/speculativeDecoding.js +246 -0
  569. package/tmlpd-pi-extension/dist/utils/speculativeDecoding.js.map +1 -0
  570. package/tmlpd-pi-extension/dist/utils/tokenUtils.d.ts +50 -0
  571. package/tmlpd-pi-extension/dist/utils/tokenUtils.d.ts.map +1 -0
  572. package/tmlpd-pi-extension/dist/utils/tokenUtils.js +124 -0
  573. package/tmlpd-pi-extension/dist/utils/tokenUtils.js.map +1 -0
  574. package/tmlpd-pi-extension/examples/QUICKSTART.md +183 -0
  575. package/tmlpd-pi-extension/package-lock.json +79 -0
  576. package/tmlpd-pi-extension/package.json +172 -0
  577. package/tmlpd-pi-extension/python/examples.py +53 -0
  578. package/tmlpd-pi-extension/python/integrations.py +330 -0
  579. package/tmlpd-pi-extension/python/setup.py +28 -0
  580. package/tmlpd-pi-extension/python/tmlpd.py +369 -0
  581. package/tmlpd-pi-extension/qna/REDDIT_GAP_ANALYSIS.md +299 -0
  582. package/tmlpd-pi-extension/qna/TMLPD_QNA.md +751 -0
  583. package/tmlpd-pi-extension/skill/SKILL.md +238 -0
  584. package/tmlpd-pi-extension/src/cache/responseCache.ts +147 -0
  585. package/tmlpd-pi-extension/src/cost/costTracker.ts +302 -0
  586. package/tmlpd-pi-extension/src/index.ts +232 -0
  587. package/tmlpd-pi-extension/src/memory/episodicMemory.ts +257 -0
  588. package/tmlpd-pi-extension/src/orchestration/haloOrchestrator.ts +266 -0
  589. package/tmlpd-pi-extension/src/orchestration/mctsWorkflow.ts +262 -0
  590. package/tmlpd-pi-extension/src/providers/localProvider.ts +406 -0
  591. package/tmlpd-pi-extension/src/providers/registry.ts +164 -0
  592. package/tmlpd-pi-extension/src/routing/ensembleVoting.ts +159 -0
  593. package/tmlpd-pi-extension/src/routing/queryTypePresets.ts +136 -0
  594. package/tmlpd-pi-extension/src/tools/tmlpdTools.ts +433 -0
  595. package/tmlpd-pi-extension/src/utils/batchProcessor.ts +232 -0
  596. package/tmlpd-pi-extension/src/utils/compression.ts +325 -0
  597. package/tmlpd-pi-extension/src/utils/reliability.ts +221 -0
  598. package/tmlpd-pi-extension/src/utils/tokenUtils.ts +145 -0
  599. package/tmlpd-pi-extension/tsconfig.json +18 -0
  600. package/tsconfig.build.json +29 -0
  601. package/tsconfig.json +18 -0
  602. package/README.md.bak +0 -1185
  603. package/src/routing/advancedRouter.ts.bak +0 -650
  604. package/test.js.bak +0 -376
  605. /package/{llms-full.txt.bak → docs/llms-full.txt} +0 -0
@@ -0,0 +1,744 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * A3M Router MCP Server
5
+ *
6
+ * Exposes A3M's parallel multi-LLM routing and ensemble execution
7
+ * as MCP tools for any MCP-compatible AI agent (Claude Code, Cursor, etc.).
8
+ *
9
+ * Usage:
10
+ * npx a3m-mcp # Start MCP server via stdio
11
+ * A3M_API_KEY=sk-... npx a3m-mcp # With custom API key
12
+ */
13
+
14
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
15
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
16
+ import {
17
+ CallToolRequestSchema,
18
+ ListToolsRequestSchema,
19
+ ErrorCode,
20
+ McpError,
21
+ } from '@modelcontextprotocol/sdk/types.js';
22
+ import {
23
+ routeQuery,
24
+ extractQueryFeatures,
25
+ getAvailableProviders,
26
+ findCheapestAvailableProvider,
27
+ findFastestAvailableProvider,
28
+ healthCheck,
29
+ } from 'adaptive-memory-multi-model-router';
30
+
31
+ // ============================================================
32
+ // TYPES
33
+ // ============================================================
34
+
35
+ interface ProviderInfo {
36
+ id: string;
37
+ name: string;
38
+ models: string[];
39
+ tier: string;
40
+ costPer1kInput: number;
41
+ costPer1kOutput: number;
42
+ type: string;
43
+ priority: number;
44
+ maxTokens: number;
45
+ enabled: boolean;
46
+ }
47
+
48
+ interface ApiCallResult {
49
+ content: string;
50
+ model: string;
51
+ provider: string;
52
+ totalTokens: number;
53
+ cost: number;
54
+ latencyMs: number;
55
+ }
56
+
57
+ // ============================================================
58
+ // LOGGING
59
+ // ============================================================
60
+
61
+ function log(level: 'info' | 'warn' | 'error', msg: string, ...args: unknown[]): void {
62
+ const prefix = `[A3M-MCP] ${level.toUpperCase()}`;
63
+ process.stderr.write(`${prefix} ${msg}${args.length ? ' ' + JSON.stringify(args) : ''}\n`);
64
+ }
65
+
66
+ // ============================================================
67
+ // PROVIDER HELPERS
68
+ // ============================================================
69
+
70
+ function getFilteredProviders(): Record<string, ProviderInfo> {
71
+ const raw = getAvailableProviders();
72
+ const result: Record<string, ProviderInfo> = {};
73
+
74
+ for (const [id, p] of Object.entries(raw)) {
75
+ const pd = p as Record<string, unknown>;
76
+ result[id] = {
77
+ id: pd.id as string || id,
78
+ name: pd.name as string || id,
79
+ models: (pd.models as string[]) || [],
80
+ tier: pd.tier as string || 'unknown',
81
+ costPer1kInput: ((pd.costPerK as Record<string, number> | undefined)?.input) || 0,
82
+ costPer1kOutput: ((pd.costPerK as Record<string, number> | undefined)?.output) || 0,
83
+ type: pd.type as string || 'api',
84
+ priority: (pd.priority as number) || 999,
85
+ maxTokens: (pd.maxTokens as number) || 4096,
86
+ enabled: !!(pd.apiKey as string | undefined) || pd.type === 'local' || pd.type === 'cli',
87
+ };
88
+ }
89
+ return result;
90
+ }
91
+
92
+ function findEnabledProviders(): Array<{ id: string; info: ProviderInfo }> {
93
+ const providers = getFilteredProviders();
94
+ return Object.entries(providers)
95
+ .filter(([_, info]) => info.enabled)
96
+ .map(([id, info]) => ({ id, info }));
97
+ }
98
+
99
+ // ============================================================
100
+ // API EXECUTION
101
+ // ============================================================
102
+
103
+ async function callProviderApi(
104
+ providerId: string,
105
+ model: string,
106
+ prompt: string,
107
+ maxTokens: number = 2048,
108
+ signal?: AbortSignal,
109
+ ): Promise<ApiCallResult | null> {
110
+ const providers = getAvailableProviders() as Record<string, Record<string, unknown>>;
111
+ const provider = providers[providerId];
112
+
113
+ if (!provider) {
114
+ log('error', `Provider "${providerId}" not found`);
115
+ return null;
116
+ }
117
+
118
+ const apiKey = provider.apiKey as string | undefined;
119
+ const baseUrl = provider.baseUrl as string;
120
+ const type = provider.type as string;
121
+ const format = provider.format as string | undefined;
122
+ const costPerK = provider.costPerK as Record<string, number> | undefined;
123
+
124
+ if (!apiKey && type !== 'local') {
125
+ log('warn', `No API key for provider "${providerId}"`);
126
+ return null;
127
+ }
128
+
129
+ const startTime = Date.now();
130
+
131
+ try {
132
+ if (type === 'cli') {
133
+ // CLI-based providers (CommandCode etc.) — skip for now in MCP context
134
+ log('warn', `CLI provider "${providerId}" not supported in MCP server`);
135
+ return null;
136
+ }
137
+
138
+ let requestUrl = baseUrl;
139
+ let requestBody: Record<string, unknown>;
140
+ let requestHeaders: Record<string, string> = {
141
+ 'Content-Type': 'application/json',
142
+ };
143
+
144
+ if (format === 'google') {
145
+ // Google AI format
146
+ requestUrl = `${baseUrl}/${model}:generateContent?key=${apiKey}`;
147
+ requestBody = {
148
+ contents: [{ parts: [{ text: prompt }] }],
149
+ generationConfig: { maxOutputTokens: maxTokens },
150
+ };
151
+ } else if (format === 'anthropic') {
152
+ requestHeaders['x-api-key'] = apiKey;
153
+ requestHeaders['anthropic-version'] = '2023-06-01';
154
+ requestBody = {
155
+ model,
156
+ messages: [{ role: 'user', content: prompt }],
157
+ max_tokens: maxTokens,
158
+ };
159
+ } else {
160
+ // OpenAI-compatible (default)
161
+ requestHeaders['Authorization'] = `Bearer ${apiKey}`;
162
+ requestBody = {
163
+ model,
164
+ messages: [{ role: 'user', content: prompt }],
165
+ max_tokens: maxTokens,
166
+ };
167
+ }
168
+
169
+ const resp = await fetch(requestUrl, {
170
+ method: 'POST',
171
+ headers: requestHeaders,
172
+ body: JSON.stringify(requestBody),
173
+ signal,
174
+ });
175
+
176
+ const latencyMs = Date.now() - startTime;
177
+ const data = await resp.json() as Record<string, unknown>;
178
+
179
+ if (!resp.ok) {
180
+ const errMsg = (data.error as Record<string, unknown> | undefined)?.message as string
181
+ || (data.error as string | undefined)
182
+ || resp.statusText;
183
+ log('error', `Provider "${providerId}" returned ${resp.status}: ${errMsg}`);
184
+ return null;
185
+ }
186
+
187
+ // Parse response based on format
188
+ let content = '';
189
+ let usage: Record<string, number> = {};
190
+
191
+ if (format === 'google') {
192
+ const candidates = data.candidates as Array<Record<string, unknown>> | undefined;
193
+ if (candidates?.[0]?.content) {
194
+ const parts = (candidates[0].content as Record<string, unknown>).parts as Array<Record<string, unknown>> | undefined;
195
+ content = parts?.map((p) => p.text as string).join('') || '';
196
+ }
197
+ const metadata = data.usageMetadata as Record<string, number> | undefined;
198
+ usage = {
199
+ prompt_tokens: metadata?.promptTokenCount || 0,
200
+ completion_tokens: metadata?.candidatesTokenCount || 0,
201
+ total_tokens: (metadata?.promptTokenCount || 0) + (metadata?.candidatesTokenCount || 0),
202
+ };
203
+ } else if (format === 'anthropic') {
204
+ content = (data.content as Array<Record<string, unknown>> | undefined)
205
+ ?.map((b) => b.text as string)
206
+ .join('') || '';
207
+ usage = {
208
+ prompt_tokens: data.input_tokens as number || 0,
209
+ completion_tokens: data.output_tokens as number || 0,
210
+ total_tokens: ((data.input_tokens as number) || 0) + ((data.output_tokens as number) || 0),
211
+ };
212
+ } else {
213
+ // OpenAI-compatible
214
+ const choices = data.choices as Array<Record<string, unknown>> | undefined;
215
+ content = choices?.[0]?.message
216
+ ? (choices[0].message as Record<string, unknown>).content as string
217
+ : '';
218
+ usage = (data.usage as Record<string, number>) || {};
219
+ }
220
+
221
+ const inputCost = (usage.prompt_tokens || 0) / 1000 * (costPerK?.input || 0) / 1000;
222
+ const outputCost = (usage.completion_tokens || 0) / 1000 * (costPerK?.output || 0) / 1000;
223
+
224
+ return {
225
+ content: content.trim(),
226
+ model: (data.model as string) || model,
227
+ provider: providerId,
228
+ totalTokens: usage.total_tokens || 0,
229
+ cost: inputCost + outputCost,
230
+ latencyMs,
231
+ };
232
+ } catch (err) {
233
+ if (err instanceof DOMException && err.name === 'AbortError') {
234
+ log('warn', `Request to "${providerId}" aborted`);
235
+ return null;
236
+ }
237
+ log('error', `Error calling provider "${providerId}":`, (err as Error).message);
238
+ return null;
239
+ }
240
+ }
241
+
242
+ // ============================================================
243
+ // MCP SERVER
244
+ // ============================================================
245
+
246
+ const server = new Server(
247
+ {
248
+ name: 'a3m-mcp-server',
249
+ version: '0.1.0',
250
+ description: 'A3M Router — parallel multi-LLM execution for AI agents',
251
+ },
252
+ {
253
+ capabilities: {
254
+ tools: {},
255
+ },
256
+ },
257
+ );
258
+
259
+ // ============================================================
260
+ // TOOL: LIST
261
+ // ============================================================
262
+
263
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
264
+ log('info', 'Client requested tool list');
265
+ return {
266
+ tools: [
267
+ {
268
+ name: 'a3m_route',
269
+ description: 'Route a query to the optimal LLM provider. Returns which model/ provider is best suited for the query, with reasoning and cost estimate. Does NOT execute the query — use a3m_ensemble for execution.',
270
+ inputSchema: {
271
+ type: 'object',
272
+ properties: {
273
+ query: {
274
+ type: 'string',
275
+ description: 'The user query to route',
276
+ },
277
+ provider: {
278
+ type: 'string',
279
+ description: 'Optional: Force a specific provider (e.g. "groq", "google", "cerebras")',
280
+ },
281
+ budget_multiplier: {
282
+ type: 'number',
283
+ description: 'Optional: Budget multiplier (default 1.0, lower = cheaper, higher = more capable)',
284
+ default: 1.0,
285
+ },
286
+ },
287
+ required: ['query'],
288
+ },
289
+ },
290
+ {
291
+ name: 'a3m_ensemble',
292
+ description: 'Execute a query across multiple providers in parallel and merge results. Returns individual responses with confidence scores plus a synthesized best answer. This is A3M\'s unique differentiator — no other router does parallel multi-LLM execution with result merging.',
293
+ inputSchema: {
294
+ type: 'object',
295
+ properties: {
296
+ query: {
297
+ type: 'string',
298
+ description: 'The user query to execute in parallel across providers',
299
+ },
300
+ providers: {
301
+ type: 'array',
302
+ items: { type: 'string' },
303
+ description: 'Optional: Specific providers to use (e.g. ["groq", "google", "cerebras"]). Defaults to all enabled providers.',
304
+ },
305
+ max_tokens: {
306
+ type: 'number',
307
+ description: 'Optional: Max tokens per response (default: 2048)',
308
+ default: 2048,
309
+ },
310
+ timeout_ms: {
311
+ type: 'number',
312
+ description: 'Optional: Timeout per provider in ms (default: 30000)',
313
+ default: 30000,
314
+ },
315
+ },
316
+ required: ['query'],
317
+ },
318
+ },
319
+ {
320
+ name: 'a3m_classify',
321
+ description: 'Classify a query by type and get a provider recommendation. Analyzes the query for code, math, creative, reasoning, and domain signals. Returns classification (fast/creative/deep/code) plus a provider recommendation.',
322
+ inputSchema: {
323
+ type: 'object',
324
+ properties: {
325
+ query: {
326
+ type: 'string',
327
+ description: 'The query to classify',
328
+ },
329
+ },
330
+ required: ['query'],
331
+ },
332
+ },
333
+ {
334
+ name: 'a3m_providers',
335
+ description: 'List all configured LLM providers with model info, cost tiers, and availability status.',
336
+ inputSchema: {
337
+ type: 'object',
338
+ properties: {},
339
+ },
340
+ },
341
+ ],
342
+ };
343
+ });
344
+
345
+ // ============================================================
346
+ // TOOL: CALL
347
+ // ============================================================
348
+
349
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
350
+ const { name, arguments: args } = request.params;
351
+
352
+ try {
353
+ switch (name) {
354
+ case 'a3m_route':
355
+ return await handleRoute(args as Record<string, unknown>);
356
+ case 'a3m_ensemble':
357
+ return await handleEnsemble(args as Record<string, unknown>);
358
+ case 'a3m_classify':
359
+ return handleClassify(args as Record<string, unknown>);
360
+ case 'a3m_providers':
361
+ return handleProviders();
362
+ default:
363
+ throw new McpError(
364
+ ErrorCode.MethodNotFound,
365
+ `Unknown tool: ${name}`,
366
+ );
367
+ }
368
+ } catch (err) {
369
+ if (err instanceof McpError) throw err;
370
+ log('error', `Tool "${name}" failed:`, (err as Error).message);
371
+ return {
372
+ content: [
373
+ {
374
+ type: 'text',
375
+ text: `Error: ${(err as Error).message}`,
376
+ },
377
+ ],
378
+ isError: true,
379
+ };
380
+ }
381
+ });
382
+
383
+ // ============================================================
384
+ // HANDLER: a3m_route
385
+ // ============================================================
386
+
387
+ function handleRoute(args: Record<string, unknown>) {
388
+ const query = args.query as string;
389
+ if (!query || typeof query !== 'string' || query.trim().length === 0) {
390
+ throw new McpError(ErrorCode.InvalidParams, 'query must be a non-empty string');
391
+ }
392
+
393
+ const forcedProvider = args.provider as string | undefined;
394
+ const budgetMultiplier = (args.budget_multiplier as number) || 1.0;
395
+
396
+ const features = extractQueryFeatures(query);
397
+ const route = routeQuery(query, forcedProvider ? [forcedProvider] : undefined, budgetMultiplier);
398
+
399
+ // Build enriched response
400
+ let queryType = 'general';
401
+ if (features.has_code) queryType = 'code';
402
+ else if (features.requires_reasoning) queryType = 'deep';
403
+ else if (features.is_creative) queryType = 'creative';
404
+ else if (features.complexity < 0.2) queryType = 'fast';
405
+
406
+ const providers = getFilteredProviders();
407
+ const providerInfo = route.primary_model
408
+ ? providers[route.primary_model.split('/')[0]]
409
+ : null;
410
+
411
+ const result = {
412
+ model: route.primary_model,
413
+ tier: providerInfo?.tier || 'unknown',
414
+ provider: route.primary_model?.split('/')[0] || 'unknown',
415
+ confidence: route.confidence,
416
+ reasoning: route.reasoning,
417
+ estimated_cost: route.estimated_cost,
418
+ estimated_latency_ms: route.estimated_latency_ms,
419
+ fallback_models: route.fallback_models,
420
+ query_features: {
421
+ complexity: features.complexity,
422
+ has_code: features.has_code,
423
+ has_math: features.has_math,
424
+ is_creative: features.is_creative,
425
+ requires_reasoning: features.requires_reasoning,
426
+ is_multilingual: features.is_multilingual,
427
+ },
428
+ classification: queryType,
429
+ suggestion: getSuggestion(queryType, route),
430
+ };
431
+
432
+ return {
433
+ content: [
434
+ {
435
+ type: 'text',
436
+ text: JSON.stringify(result, null, 2),
437
+ },
438
+ ],
439
+ };
440
+ }
441
+
442
+ function getSuggestion(type: string, route: { primary_model: string; estimated_cost: number }): string {
443
+ switch (type) {
444
+ case 'code':
445
+ return `Use "${route.primary_model}" for code. Cost: ~$${(route.estimated_cost || 0).toFixed(6)}`;
446
+ case 'deep':
447
+ return `Use "${route.primary_model}" for reasoning. Cost: ~$${(route.estimated_cost || 0).toFixed(6)}`;
448
+ case 'creative':
449
+ return `Use "${route.primary_model}" for creativity. Cost: ~$${(route.estimated_cost || 0).toFixed(6)}`;
450
+ case 'fast':
451
+ return `Use "${route.primary_model}" for speed. Cost: ~$${(route.estimated_cost || 0).toFixed(6)}`;
452
+ default:
453
+ return `Recommended: "${route.primary_model}" (${route.reasoning || ''})`;
454
+ }
455
+ }
456
+
457
+ // ============================================================
458
+ // HANDLER: a3m_ensemble
459
+ // ============================================================
460
+
461
+ async function handleEnsemble(args: Record<string, unknown>) {
462
+ const query = args.query as string;
463
+ if (!query || typeof query !== 'string' || query.trim().length === 0) {
464
+ throw new McpError(ErrorCode.InvalidParams, 'query must be a non-empty string');
465
+ }
466
+
467
+ const maxTokens = (args.max_tokens as number) || 2048;
468
+ const timeoutMs = (args.timeout_ms as number) || 30000;
469
+
470
+ // Determine which providers to use
471
+ let targetProviders: Array<{ id: string; info: ProviderInfo }>;
472
+
473
+ if (args.providers && Array.isArray(args.providers) && args.providers.length > 0) {
474
+ const requested = args.providers as string[];
475
+ const all = getFilteredProviders();
476
+ targetProviders = requested
477
+ .map((id) => ({ id, info: all[id] }))
478
+ .filter((p) => p.info && p.info.enabled);
479
+ if (targetProviders.length === 0) {
480
+ return {
481
+ content: [
482
+ {
483
+ type: 'text',
484
+ text: JSON.stringify({
485
+ error: 'None of the requested providers are available/enabled',
486
+ requested_providers: requested,
487
+ available: Object.keys(getFilteredProviders()).filter((k) => getFilteredProviders()[k].enabled),
488
+ }, null, 2),
489
+ },
490
+ ],
491
+ isError: true,
492
+ };
493
+ }
494
+ } else {
495
+ targetProviders = findEnabledProviders();
496
+ }
497
+
498
+ if (targetProviders.length === 0) {
499
+ return {
500
+ content: [
501
+ {
502
+ type: 'text',
503
+ text: 'No enabled providers found. Configure API keys via environment variables (e.g. GROQ_API_KEY, GOOGLE_API_KEY, CEREBRAS_API_KEY).',
504
+ },
505
+ ],
506
+ isError: true,
507
+ };
508
+ }
509
+
510
+ // Classify the query first
511
+ const features = extractQueryFeatures(query);
512
+
513
+ // Execute in parallel across all target providers
514
+ const controllers: AbortController[] = [];
515
+ const results = await Promise.all(
516
+ targetProviders.map(async ({ id, info }) => {
517
+ const model = info.models[0];
518
+ if (!model) {
519
+ return { provider: id, model: 'none', error: 'No models configured', content: null };
520
+ }
521
+
522
+ const controller = new AbortController();
523
+ controllers.push(controller);
524
+
525
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
526
+
527
+ try {
528
+ const result = await callProviderApi(id, model, query, maxTokens, controller.signal);
529
+ clearTimeout(timeout);
530
+ return { provider: id, model, error: null, content: result };
531
+ } catch (err) {
532
+ clearTimeout(timeout);
533
+ return { provider: id, model, error: (err as Error).message, content: null };
534
+ }
535
+ }),
536
+ );
537
+
538
+ // Separate successful and failed results
539
+ const successes = results.filter((r): r is typeof r & { content: NonNullable<typeof r.content> } =>
540
+ r.content !== null && r.content.content.length > 0,
541
+ );
542
+ const failures = results.filter((r) => r.error || !r.content || r.content.content.length === 0);
543
+
544
+ // Compute confidence scores based on response quality
545
+ const totalSuccesses = successes.length;
546
+ const scoredResponses = successes.map((r) => {
547
+ const responseLength = r.content.content.length;
548
+ const lengthScore = Math.min(responseLength / 500, 1.0);
549
+ const latencyPenalty = Math.max(0, 1 - r.content.latencyMs / 10000);
550
+ const confidence = Math.round((0.6 * lengthScore + 0.2 * latencyPenalty + 0.2) * 100) / 100;
551
+ return { ...r, confidence: Math.min(confidence, 0.98) };
552
+ }).sort((a, b) => b.confidence - a.confidence);
553
+
554
+ // Synthesize best answer (highest confidence response with context from others)
555
+ let bestAnswer: string;
556
+ if (scoredResponses.length === 0) {
557
+ bestAnswer = 'All providers failed to generate a response.';
558
+ } else if (scoredResponses.length === 1) {
559
+ bestAnswer = scoredResponses[0].content.content;
560
+ } else {
561
+ // Use top response with agreement signal
562
+ const top = scoredResponses[0];
563
+ const agreement = scoredResponses.filter(
564
+ (r) => r.content.content.slice(0, 100).toLowerCase() === top.content.content.slice(0, 100).toLowerCase(),
565
+ ).length;
566
+ const agreementRatio = agreement / totalSuccesses;
567
+ bestAnswer = top.content.content;
568
+ }
569
+
570
+ const ensemble = {
571
+ query,
572
+ query_classification: {
573
+ complexity: features.complexity,
574
+ type: features.has_code ? 'code' : features.requires_reasoning ? 'deep' : features.is_creative ? 'creative' : 'general',
575
+ has_code: features.has_code,
576
+ has_math: features.has_math,
577
+ is_creative: features.is_creative,
578
+ },
579
+ parallel_responses: scoredResponses.map((r) => ({
580
+ provider: r.provider,
581
+ model: r.model,
582
+ confidence: r.confidence,
583
+ latency_ms: r.content.latencyMs,
584
+ cost: r.content.cost,
585
+ tokens: r.content.totalTokens,
586
+ content: r.content.content,
587
+ })),
588
+ failed_providers: failures.map((r) => ({
589
+ provider: r.provider,
590
+ model: r.model,
591
+ error: r.error || 'Empty response',
592
+ })),
593
+ best_answer: bestAnswer,
594
+ stats: {
595
+ total_providers: targetProviders.length,
596
+ successful: successes.length,
597
+ failed: failures.length,
598
+ total_cost: successes.reduce((sum, r) => sum + r.content.cost, 0),
599
+ total_tokens: successes.reduce((sum, r) => sum + r.content.totalTokens, 0),
600
+ avg_latency_ms: successes.length > 0
601
+ ? Math.round(successes.reduce((sum, r) => sum + r.content.latencyMs, 0) / successes.length)
602
+ : 0,
603
+ },
604
+ };
605
+
606
+ return {
607
+ content: [
608
+ {
609
+ type: 'text',
610
+ text: JSON.stringify(ensemble, null, 2),
611
+ },
612
+ ],
613
+ };
614
+ }
615
+
616
+ // ============================================================
617
+ // HANDLER: a3m_classify
618
+ // ============================================================
619
+
620
+ function handleClassify(args: Record<string, unknown>) {
621
+ const query = args.query as string;
622
+ if (!query || typeof query !== 'string' || query.trim().length === 0) {
623
+ throw new McpError(ErrorCode.InvalidParams, 'query must be a non-empty string');
624
+ }
625
+
626
+ const features = extractQueryFeatures(query);
627
+ const route = routeQuery(query);
628
+
629
+ let type: string;
630
+ let recommendation: string;
631
+
632
+ if (features.has_code) {
633
+ type = 'code';
634
+ recommendation = 'Use a fast coding model (Groq, Cerebras) for quick code tasks, or premium (OpenAI, Anthropic) for complex codegen.';
635
+ } else if (features.requires_reasoning && features.complexity > 0.5) {
636
+ type = 'deep';
637
+ recommendation = 'Use a reasoning-capable model (Mistral, premium tier) for deep analytical tasks.';
638
+ } else if (features.is_creative) {
639
+ type = 'creative';
640
+ recommendation = 'Use a creative model (Mistral, Google AI) for open-ended creative work.';
641
+ } else if (features.complexity < 0.2) {
642
+ type = 'fast';
643
+ recommendation = 'Use a fast, cheap model (Groq, Cerebras, free tier) for simple queries.';
644
+ } else {
645
+ type = 'general';
646
+ recommendation = 'Standard routing applies — use the default model selection.';
647
+ }
648
+
649
+ const providers = getFilteredProviders();
650
+ const bestModel = route.primary_model;
651
+ const bestProvider = bestModel ? providers[bestModel.split('/')[0]] : null;
652
+
653
+ return {
654
+ content: [
655
+ {
656
+ type: 'text',
657
+ text: JSON.stringify({
658
+ query,
659
+ classification: {
660
+ type,
661
+ complexity: features.complexity,
662
+ signals: {
663
+ has_code: features.has_code,
664
+ has_math: features.has_math,
665
+ is_creative: features.is_creative,
666
+ requires_reasoning: features.requires_reasoning,
667
+ is_multilingual: features.is_multilingual,
668
+ },
669
+ },
670
+ recommended_provider: bestProvider ? {
671
+ id: bestProvider.id,
672
+ name: bestProvider.name,
673
+ model: bestModel,
674
+ tier: bestProvider.tier,
675
+ cost_per_1k_input: bestProvider.costPer1kInput,
676
+ cost_per_1k_output: bestProvider.costPer1kOutput,
677
+ } : null,
678
+ reasoning: route.reasoning,
679
+ suggestion: recommendation,
680
+ }, null, 2),
681
+ },
682
+ ],
683
+ };
684
+ }
685
+
686
+ // ============================================================
687
+ // HANDLER: a3m_providers
688
+ // ============================================================
689
+
690
+ function handleProviders() {
691
+ const providers = getFilteredProviders();
692
+ const enabled = Object.values(providers).filter((p) => p.enabled);
693
+ const disabled = Object.values(providers).filter((p) => !p.enabled);
694
+
695
+ return {
696
+ content: [
697
+ {
698
+ type: 'text',
699
+ text: JSON.stringify({
700
+ total: Object.keys(providers).length,
701
+ enabled: enabled.length,
702
+ disabled: disabled.length,
703
+ providers: Object.values(providers).sort((a, b) => a.priority - b.priority),
704
+ env_tips: {
705
+ groq: 'GROQ_API_KEY',
706
+ cerebras: 'CEREBRAS_API_KEY',
707
+ mistral: 'MISTRAL_API_KEY',
708
+ google: 'GOOGLE_API_KEY',
709
+ minimax: 'MINIMAX_API_KEY',
710
+ },
711
+ }, null, 2),
712
+ },
713
+ ],
714
+ };
715
+ }
716
+
717
+ // ============================================================
718
+ // STARTUP
719
+ // ============================================================
720
+
721
+ async function main(): Promise<void> {
722
+ const providers = getFilteredProviders();
723
+ const enabledCount = Object.values(providers).filter((p) => p.enabled).length;
724
+ const totalCount = Object.keys(providers).length;
725
+
726
+ log('info', 'A3M Router MCP Server v0.1.0');
727
+ log('info', `Providers: ${totalCount} total, ${enabledCount} enabled`);
728
+ log('info', 'Tools available: a3m_route, a3m_ensemble, a3m_classify, a3m_providers');
729
+ log('info', `Node ${process.version}, ${process.platform}`);
730
+
731
+ for (const [id, info] of Object.entries(providers)) {
732
+ const status = info.enabled ? 'ENABLED' : 'DISABLED';
733
+ log('info', ` ${status.padEnd(8)} ${id.padEnd(12)} ${info.tier.padEnd(8)} ${(info.models[0] || 'no models')}`);
734
+ }
735
+
736
+ const transport = new StdioServerTransport();
737
+ await server.connect(transport);
738
+ log('info', 'MCP server connected via stdio');
739
+ }
740
+
741
+ main().catch((err) => {
742
+ log('error', 'Fatal error:', err);
743
+ process.exit(1);
744
+ });