adaptive-memory-multi-model-router 2.16.0 → 2.16.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 (248) hide show
  1. package/.github/workflows/adapters-ci.yml +142 -0
  2. package/.github/workflows/auto-submit-sitemap.yml +41 -0
  3. package/.github/workflows/ci.yml +2 -5
  4. package/.github/workflows/mcp-pypi-publish.yml +34 -0
  5. package/.github/workflows/pypi-publish.yml +146 -0
  6. package/.github/workflows/tmlpd-publish.yml +23 -0
  7. package/README.md +245 -148
  8. package/RELEASE_v2.16.0.md +149 -0
  9. package/TECHNICAL_README.md +253 -0
  10. package/adapters/README.md +36 -0
  11. package/adapters/__init__.py +25 -0
  12. package/adapters/a3m_adapter/__init__.py +51 -0
  13. package/adapters/a3m_adapter/adapter/__init__.py +22 -0
  14. package/adapters/a3m_adapter/adapter/autogen.py +169 -0
  15. package/adapters/a3m_adapter/adapter/config.py +100 -0
  16. package/adapters/a3m_adapter/adapter/haystack.py +197 -0
  17. package/adapters/a3m_adapter/adapter/langchain.py +155 -0
  18. package/adapters/a3m_adapter/adapter/langgraph.py +196 -0
  19. package/adapters/a3m_adapter/adapter/llamaindex.py +162 -0
  20. package/adapters/a3m_adapter/adapter/pinecone.py +217 -0
  21. package/adapters/a3m_adapter/adapter/vercel.py +188 -0
  22. package/adapters/a3m_adapter/tests/__init__.py +1 -0
  23. package/adapters/a3m_adapter/tests/test_adapters.py +118 -0
  24. package/adapters/a3m_adapter/tests/test_integration.py +80 -0
  25. package/adapters/requirements-dev.txt +6 -0
  26. package/adapters/requirements.txt +4 -0
  27. package/adapters/setup.py +23 -0
  28. package/demo.py +251 -0
  29. package/discoverability-diagnosis.md +280 -0
  30. package/dist/analytics/costAnalytics.d.ts.map +1 -1
  31. package/dist/benchmark/reproducible.d.ts.map +1 -1
  32. package/dist/cache/semanticCache.d.ts.map +1 -1
  33. package/dist/cli/setupWizard.d.ts +257 -50
  34. package/dist/cli/setupWizard.d.ts.map +1 -1
  35. package/dist/cli/setupWizard.js +419 -109
  36. package/dist/cli/setupWizard.js.map +1 -1
  37. package/dist/cli/tui.d.ts +6 -0
  38. package/dist/cli/tui.js +96 -67
  39. package/dist/cli/tui.js.map +1 -0
  40. package/dist/cli.js +9 -0
  41. package/dist/cost/budgetEnforcer.d.ts.map +1 -1
  42. package/dist/cost/costTracker.d.ts.map +1 -1
  43. package/dist/ensemble/multiRoundDialog.d.ts.map +1 -1
  44. package/dist/ensemble/shapleyValue.d.ts.map +1 -1
  45. package/dist/ensemble.d.ts +1 -1
  46. package/dist/ensemble.js +141 -0
  47. package/dist/integrations/langchainAdapter.d.ts.map +1 -1
  48. package/dist/integrations/langchainAdapter.js +3 -3
  49. package/dist/integrations/langchainAdapter.js.map +1 -1
  50. package/dist/integrations/oauth.d.ts.map +1 -1
  51. package/dist/integrations/scienceAdapter.d.ts.map +1 -1
  52. package/dist/memory/autoFetch.d.ts.map +1 -1
  53. package/dist/memory/hybridMemory.d.ts.map +1 -1
  54. package/dist/memory/memoryTree.d.ts.map +1 -1
  55. package/dist/memory/obsidianVault.d.ts.map +1 -1
  56. package/dist/memory/reasoningBank.d.ts.map +1 -1
  57. package/dist/observability/metrics.d.ts.map +1 -1
  58. package/dist/observability/tracer.d.ts.map +1 -1
  59. package/dist/providers/providerConfig.d.ts.map +1 -1
  60. package/dist/providers/providerConfig.js +32 -17
  61. package/dist/providers/providerConfig.js.map +1 -1
  62. package/dist/routing/advancedRouter.d.ts.map +1 -1
  63. package/dist/routing/advancedRouter.js +106 -14
  64. package/dist/routing/advancedRouter.js.map +1 -1
  65. package/dist/routing/providerHealth.d.ts.map +1 -1
  66. package/dist/routing/providerRetry.d.ts.map +1 -1
  67. package/dist/routing/shadowSampler.d.ts.map +1 -0
  68. package/dist/routing/shadowSampler.js.map +1 -1
  69. package/dist/security/guardrails.d.ts.map +1 -1
  70. package/dist/server/handlers/chatHandler.d.ts.map +1 -1
  71. package/dist/server/handlers/completionsHandler.d.ts.map +1 -1
  72. package/dist/server/handlers/embeddingsHandler.d.ts.map +1 -1
  73. package/dist/server/handlers/healthHandler.d.ts.map +1 -1
  74. package/dist/server/handlers/metricsHandler.d.ts.map +1 -1
  75. package/dist/server/handlers/modelsHandler.d.ts.map +1 -1
  76. package/dist/server/metrics.d.ts.map +1 -1
  77. package/dist/server/proxyServer.d.ts.map +1 -1
  78. package/dist/server/router.d.ts.map +1 -1
  79. package/dist/server/state.d.ts.map +1 -1
  80. package/dist/skills/__tests__/skill_manager.test.js +5 -265
  81. package/dist/skills/__tests__/skill_manager.test.js.map +1 -1
  82. package/dist/utils/tokenUtils.d.ts.map +1 -1
  83. package/docker-compose.yml +84 -60
  84. package/docs/ARTICLE_Biology_Inspired_Routing.md +208 -0
  85. package/docs/ARTICLE_Master.md +78 -0
  86. package/docs/ARTICLE_Master_CN.md +78 -0
  87. package/docs/ARTICLE_OpenRouter_Stripe.md +140 -0
  88. package/docs/DEVPTO_ARTICLE.md +84 -0
  89. package/docs/HUMAN_STYLE_GUIDE.md +75 -0
  90. package/docs/IMPRINT_PLAN.md +88 -0
  91. package/docs/OPENROUTER_ALTERNATIVE.md +184 -0
  92. package/docs/SOCIAL_CAMPAIGN.md +316 -0
  93. package/docs/anthropic.html +45 -0
  94. package/docs/best-llm-routers-2025.html +157 -0
  95. package/docs/cerebras.html +43 -0
  96. package/docs/cli-cheatsheet.md +286 -212
  97. package/docs/comparison.md +2 -2
  98. package/docs/deepseek.html +44 -0
  99. package/docs/google.html +47 -0
  100. package/docs/groq.html +44 -0
  101. package/docs/llms-full.txt +360 -138
  102. package/docs/llms.txt +70 -71
  103. package/docs/mistral.html +43 -0
  104. package/docs/ollama.html +50 -0
  105. package/docs/openai.html +57 -0
  106. package/docs/sitemap.xml +69 -57
  107. package/docs-site/blog/best-llm-routers-2025.html +157 -0
  108. package/docs-site/index.html +68 -9
  109. package/docs-site/providers/anthropic.html +45 -0
  110. package/docs-site/providers/cerebras.html +43 -0
  111. package/docs-site/providers/deepseek.html +44 -0
  112. package/docs-site/providers/google.html +47 -0
  113. package/docs-site/providers/groq.html +44 -0
  114. package/docs-site/providers/index.html +41 -0
  115. package/docs-site/providers/mistral.html +43 -0
  116. package/docs-site/providers/ollama.html +50 -0
  117. package/docs-site/providers/openai.html +57 -0
  118. package/docs-site/sitemap.xml +69 -0
  119. package/llms.txt +70 -62
  120. package/package.json +44 -182
  121. package/packages/agentkit-adapter/LICENSE +21 -0
  122. package/packages/agentkit-adapter/README.md +126 -0
  123. package/packages/agentkit-adapter/examples/agentkit-example.ts +139 -0
  124. package/packages/agentkit-adapter/package.json +57 -0
  125. package/packages/agentkit-adapter/src/adapter.ts +381 -0
  126. package/packages/agentkit-adapter/src/index.ts +36 -0
  127. package/packages/agentkit-adapter/src/types.ts +105 -0
  128. package/packages/agentkit-adapter/src/util.ts +13 -0
  129. package/packages/agentkit-adapter/tsconfig.json +22 -0
  130. package/prometheus.yml +8 -0
  131. package/python/README.md +35 -81
  132. package/python/a3m/__init__.py +32 -3
  133. package/python/a3m/adapters/__init__.py +21 -0
  134. package/python/a3m/adapters/langchain.py +190 -0
  135. package/python/a3m/adapters/llamaindex.py +249 -0
  136. package/python/a3m/adapters/qdrant.py +240 -0
  137. package/python/a3m/adapters/weaviate.py +263 -0
  138. package/python/a3m/client.py +5 -0
  139. package/python/build_verify.sh +32 -0
  140. package/python/mcp-server/README.md +172 -0
  141. package/python/mcp-server/a3m_mcp/__init__.py +25 -0
  142. package/python/mcp-server/a3m_mcp/__main__.py +15 -0
  143. package/python/mcp-server/a3m_mcp/server.py +205 -0
  144. package/python/mcp-server/pyproject.toml +24 -0
  145. package/python/pyproject.toml +60 -6
  146. package/python/setup.py +3 -28
  147. package/scripts/submit-sitemap.sh +52 -0
  148. package/src/__types__/registry.d.ts +14 -0
  149. package/src/cli/setupWizard.ts +443 -112
  150. package/src/cli/tui.ts +159 -0
  151. package/src/ensemble.ts +154 -1
  152. package/src/integrations/langchainAdapter.ts +2 -2
  153. package/src/providers/providerConfig.ts +32 -17
  154. package/src/providers/registry.js +27 -0
  155. package/src/routing/advancedRouter.ts +99 -14
  156. package/src/routing/shadowSampler.ts +1 -1
  157. package/test-install/package.json +12 -0
  158. package/tests/tsconfig.json +0 -1
  159. package/tmlpd-pi-extension/README.md +105 -44
  160. package/tmlpd-pi-extension/docs/demo.svg +33 -0
  161. package/tmlpd-pi-extension/package.json +35 -106
  162. package/tmlpd-pi-extension/src/tokenOptimization/contextStratifier.ts +163 -0
  163. package/tmlpd-pi-extension/src/tokenOptimization/fetchOnceLocal.ts +136 -0
  164. package/tmlpd-pi-extension/src/tokenOptimization/index.ts +197 -0
  165. package/tmlpd-pi-extension/src/tokenOptimization/interAgentCompression.ts +157 -0
  166. package/tmlpd-pi-extension/src/tokenOptimization/schemaContract.ts +101 -0
  167. package/tmlpd-pi-extension/src/tokenOptimization/semanticCache.ts +248 -0
  168. package/tmlpd-pi-extension/src/tokenOptimization/tokenAwareFallback.ts +192 -0
  169. package/tmlpd-pi-extension/test/verify.js +21 -0
  170. package/tsconfig.build.json +3 -2
  171. package/packages/a3m-vercel-ai/dist/a3m-language-model.d.ts +0 -12
  172. package/packages/a3m-vercel-ai/dist/a3m-language-model.d.ts.map +0 -1
  173. package/packages/a3m-vercel-ai/dist/a3m-language-model.js +0 -289
  174. package/packages/a3m-vercel-ai/dist/a3m-language-model.js.map +0 -1
  175. package/packages/a3m-vercel-ai/dist/index.d.ts +0 -82
  176. package/packages/a3m-vercel-ai/dist/index.d.ts.map +0 -1
  177. package/packages/a3m-vercel-ai/dist/index.js +0 -79
  178. package/packages/a3m-vercel-ai/dist/index.js.map +0 -1
  179. package/packages/a3m-vercel-ai/dist/types.d.ts +0 -97
  180. package/packages/a3m-vercel-ai/dist/types.d.ts.map +0 -1
  181. package/packages/a3m-vercel-ai/dist/types.js +0 -5
  182. package/packages/a3m-vercel-ai/dist/types.js.map +0 -1
  183. package/src/skills/__tests__/skill_manager.test.ts +0 -328
  184. package/tmlpd-pi-extension/dist/cache/prefixCache.d.ts +0 -114
  185. package/tmlpd-pi-extension/dist/cache/prefixCache.d.ts.map +0 -1
  186. package/tmlpd-pi-extension/dist/cache/prefixCache.js +0 -285
  187. package/tmlpd-pi-extension/dist/cache/prefixCache.js.map +0 -1
  188. package/tmlpd-pi-extension/dist/cache/responseCache.d.ts +0 -58
  189. package/tmlpd-pi-extension/dist/cache/responseCache.d.ts.map +0 -1
  190. package/tmlpd-pi-extension/dist/cache/responseCache.js +0 -153
  191. package/tmlpd-pi-extension/dist/cache/responseCache.js.map +0 -1
  192. package/tmlpd-pi-extension/dist/cli.js +0 -59
  193. package/tmlpd-pi-extension/dist/cost/costTracker.d.ts +0 -95
  194. package/tmlpd-pi-extension/dist/cost/costTracker.d.ts.map +0 -1
  195. package/tmlpd-pi-extension/dist/cost/costTracker.js +0 -240
  196. package/tmlpd-pi-extension/dist/cost/costTracker.js.map +0 -1
  197. package/tmlpd-pi-extension/dist/index.d.ts +0 -723
  198. package/tmlpd-pi-extension/dist/index.d.ts.map +0 -1
  199. package/tmlpd-pi-extension/dist/index.js +0 -239
  200. package/tmlpd-pi-extension/dist/index.js.map +0 -1
  201. package/tmlpd-pi-extension/dist/memory/episodicMemory.d.ts +0 -82
  202. package/tmlpd-pi-extension/dist/memory/episodicMemory.d.ts.map +0 -1
  203. package/tmlpd-pi-extension/dist/memory/episodicMemory.js +0 -145
  204. package/tmlpd-pi-extension/dist/memory/episodicMemory.js.map +0 -1
  205. package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.d.ts +0 -102
  206. package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.d.ts.map +0 -1
  207. package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.js +0 -207
  208. package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.js.map +0 -1
  209. package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.d.ts +0 -85
  210. package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.d.ts.map +0 -1
  211. package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.js +0 -210
  212. package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.js.map +0 -1
  213. package/tmlpd-pi-extension/dist/providers/localProvider.d.ts +0 -102
  214. package/tmlpd-pi-extension/dist/providers/localProvider.d.ts.map +0 -1
  215. package/tmlpd-pi-extension/dist/providers/localProvider.js +0 -338
  216. package/tmlpd-pi-extension/dist/providers/localProvider.js.map +0 -1
  217. package/tmlpd-pi-extension/dist/providers/registry.d.ts +0 -55
  218. package/tmlpd-pi-extension/dist/providers/registry.d.ts.map +0 -1
  219. package/tmlpd-pi-extension/dist/providers/registry.js +0 -138
  220. package/tmlpd-pi-extension/dist/providers/registry.js.map +0 -1
  221. package/tmlpd-pi-extension/dist/routing/advancedRouter.d.ts +0 -68
  222. package/tmlpd-pi-extension/dist/routing/advancedRouter.d.ts.map +0 -1
  223. package/tmlpd-pi-extension/dist/routing/advancedRouter.js +0 -332
  224. package/tmlpd-pi-extension/dist/routing/advancedRouter.js.map +0 -1
  225. package/tmlpd-pi-extension/dist/tools/tmlpdTools.d.ts +0 -101
  226. package/tmlpd-pi-extension/dist/tools/tmlpdTools.d.ts.map +0 -1
  227. package/tmlpd-pi-extension/dist/tools/tmlpdTools.js +0 -368
  228. package/tmlpd-pi-extension/dist/tools/tmlpdTools.js.map +0 -1
  229. package/tmlpd-pi-extension/dist/utils/batchProcessor.d.ts +0 -96
  230. package/tmlpd-pi-extension/dist/utils/batchProcessor.d.ts.map +0 -1
  231. package/tmlpd-pi-extension/dist/utils/batchProcessor.js +0 -170
  232. package/tmlpd-pi-extension/dist/utils/batchProcessor.js.map +0 -1
  233. package/tmlpd-pi-extension/dist/utils/compression.d.ts +0 -61
  234. package/tmlpd-pi-extension/dist/utils/compression.d.ts.map +0 -1
  235. package/tmlpd-pi-extension/dist/utils/compression.js +0 -281
  236. package/tmlpd-pi-extension/dist/utils/compression.js.map +0 -1
  237. package/tmlpd-pi-extension/dist/utils/reliability.d.ts +0 -74
  238. package/tmlpd-pi-extension/dist/utils/reliability.d.ts.map +0 -1
  239. package/tmlpd-pi-extension/dist/utils/reliability.js +0 -177
  240. package/tmlpd-pi-extension/dist/utils/reliability.js.map +0 -1
  241. package/tmlpd-pi-extension/dist/utils/speculativeDecoding.d.ts +0 -117
  242. package/tmlpd-pi-extension/dist/utils/speculativeDecoding.d.ts.map +0 -1
  243. package/tmlpd-pi-extension/dist/utils/speculativeDecoding.js +0 -246
  244. package/tmlpd-pi-extension/dist/utils/speculativeDecoding.js.map +0 -1
  245. package/tmlpd-pi-extension/dist/utils/tokenUtils.d.ts +0 -50
  246. package/tmlpd-pi-extension/dist/utils/tokenUtils.d.ts.map +0 -1
  247. package/tmlpd-pi-extension/dist/utils/tokenUtils.js +0 -124
  248. package/tmlpd-pi-extension/dist/utils/tokenUtils.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * A3M Router Setup Wizard
3
- * Interactive configuration wizard
3
+ * Interactive configuration wizard with smart defaults
4
4
  */
5
5
 
6
6
  const fs = require('fs');
@@ -8,48 +8,210 @@ const path = require('path');
8
8
  const readline = require('readline');
9
9
 
10
10
  const CONFIG_DIR = path.join(process.env.HOME || '/tmp', '.config', 'a3m-router');
11
- const CONFIG_FILE = path.join(CONFIG_DIR, 'providers.json');
11
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
12
+ const PROVIDERS_FILE = path.join(CONFIG_DIR, 'providers.json');
12
13
 
13
14
  // API key environment variable mappings
14
15
  const API_KEY_ENV_MAP = {
15
- 'GROQ_API_KEY': 'groq',
16
- 'OPENAI_API_KEY': 'openai',
17
- 'ANTHROPIC_API_KEY': 'anthropic',
18
- 'DEEPSEEK_API_KEY': 'deepseek',
19
- 'MISTRAL_API_KEY': 'mistral',
20
- 'GOOGLE_API_KEY': 'google',
21
- 'CEREBRAS_API_KEY': 'cerebras',
22
- 'TOGETHER_API_KEY': 'together',
23
- 'AI21_API_KEY': 'ai21',
24
- 'COHERE_API_KEY': 'cohere',
25
- 'MINIMAX_API_KEY': 'minimax',
26
- 'KIMI_API_KEY': 'kimi',
27
- 'MOONSHOT_API_KEY': 'moonshot',
28
- 'QWEN_API_KEY': 'qwen',
29
- 'ZHIPU_API_KEY': 'zhipu',
30
- 'YI_API_KEY': 'yi',
31
- 'BAICHUAN_API_KEY': 'baichuan',
16
+ // Free tier (recommended first)
17
+ 'GROQ_API_KEY': { id: 'groq', tier: 'free' },
18
+ 'OPENAI_API_KEY': { id: 'openai', tier: 'paid' },
19
+ 'ANTHROPIC_API_KEY': { id: 'anthropic', tier: 'paid' },
20
+ 'DEEPSEEK_API_KEY': { id: 'deepseek', tier: 'cheap' },
21
+ 'MISTRAL_API_KEY': { id: 'mistral', tier: 'cheap' },
22
+ 'GOOGLE_API_KEY': { id: 'google', tier: 'free' },
23
+ 'XAI_API_KEY': { id: 'xai', tier: 'paid' },
24
+ 'FIREWORKS_API_KEY': { id: 'fireworks', tier: 'cheap' },
25
+ 'TOGETHER_API_KEY': { id: 'together', tier: 'cheap' },
26
+ 'CEREBRAS_API_KEY': { id: 'cerebras', tier: 'free' },
27
+ 'AI21_API_KEY': { id: 'ai21', tier: 'paid' },
28
+ 'COHERE_API_KEY': { id: 'cohere', tier: 'cheap' },
29
+ 'PERPLEXITY_API_KEY': { id: 'perplexity', tier: 'paid' },
30
+ // Chinese providers
31
+ 'MINIMAX_API_KEY': { id: 'minimax', tier: 'cheap' },
32
+ 'KIMI_API_KEY': { id: 'kimi', tier: 'cheap' },
33
+ 'MOONSHOT_API_KEY': { id: 'moonshot', tier: 'cheap' },
34
+ 'QWEN_API_KEY': { id: 'qwen', tier: 'cheap' },
35
+ 'ZHIPU_API_KEY': { id: 'zhipu', tier: 'cheap' },
36
+ 'YI_API_KEY': { id: 'yi', tier: 'cheap' },
37
+ 'BAICHUAN_API_KEY': { id: 'baichuan', tier: 'cheap' },
38
+ 'STEPFUN_API_KEY': { id: 'stepfun', tier: 'cheap' },
39
+ // Other providers
40
+ 'REPLICATE_API_KEY': { id: 'replicate', tier: 'cheap' },
41
+ 'HUGGINGFACE_API_KEY': { id: 'huggingface', tier: 'cheap' },
42
+ 'NVIDIA_API_KEY': { id: 'nvidia', tier: 'paid' },
43
+ 'OPENROUTER_API_KEY': { id: 'openrouter', tier: 'mixed' },
44
+ 'AZURE_OPENAI_API_KEY': { id: 'azure', tier: 'paid' },
45
+ 'DEEPINFRA_API_KEY': { id: 'deepinfra', tier: 'cheap' },
46
+ 'SAMBANOVA_API_KEY': { id: 'sambanova', tier: 'cheap' },
47
+ 'ANYSCALE_API_KEY': { id: 'anyscale', tier: 'cheap' },
48
+ 'VOYAGE_API_KEY': { id: 'voyage', tier: 'cheap' },
49
+ 'JINA_API_KEY': { id: 'jina', tier: 'cheap' },
50
+ 'NOVITA_API_KEY': { id: 'novita', tier: 'cheap' },
51
+ 'OCTOAI_API_KEY': { id: 'octoai', tier: 'cheap' },
52
+ 'LAMINAR_API_KEY': { id: 'laminar', tier: 'cheap' },
53
+ 'WRITER_API_KEY': { id: 'writer', tier: 'paid' },
32
54
  };
33
55
 
34
- // Provider metadata
56
+ // Provider metadata with useful defaults
35
57
  const PROVIDER_INFO = {
36
- groq: { name: 'Groq', models: 'llama-3.3-70b-versatile', tier: 'free', strength: 'Fast, free tier' },
37
- openai: { name: 'OpenAI', models: 'gpt-4o-mini', tier: 'paid', strength: 'GPT-4, most capable' },
38
- anthropic: { name: 'Anthropic', models: 'claude-3.5-haiku', tier: 'paid', strength: 'Claude, best reasoning' },
39
- deepseek: { name: 'DeepSeek', models: 'deepseek-chat-v3', tier: 'cheap', strength: 'Cheap, good code' },
40
- mistral: { name: 'Mistral', models: 'mistral-small-latest', tier: 'cheap', strength: 'European, balanced' },
41
- google: { name: 'Google AI', models: 'gemini-1.5-flash', tier: 'free', strength: 'Gemini, multimodal' },
42
- cerebras: { name: 'Cerebras', models: 'llama-3.3-70b', tier: 'free', strength: 'Fastest inference' },
43
- together: { name: 'Together AI', models: 'Llama-3.3-70B-Instruct', tier: 'cheap', strength: 'Managed, reliable' },
44
- ai21: { name: 'AI21', models: 'jamba-1.5-medium', tier: 'paid', strength: 'Jamba, long context' },
45
- cohere: { name: 'Cohere', models: 'command-r7b', tier: 'cheap', strength: 'Command series, fast' },
46
- minimax: { name: 'MiniMax', models: 'abab6.5s-chat', tier: 'cheap', strength: 'Chinese, cheap' },
47
- kimi: { name: 'Kimi/Moonshot', models: 'moonshot-v1-8k', tier: 'cheap', strength: 'Chinese, 128k context' },
48
- moonshot: { name: 'Moonshot', models: 'moonshot-v1-8k', tier: 'cheap', strength: 'Chinese, good' },
49
- qwen: { name: 'Qwen', models: 'qwen-turbo', tier: 'cheap', strength: 'Alibaba, multilingual' },
50
- zhipu: { name: 'Zhipu GLM', models: 'glm-4', tier: 'cheap', strength: 'Chinese, smart' },
51
- yi: { name: 'Yi', models: 'yi-large', tier: 'cheap', strength: 'Chinese, good reasoning' },
52
- baichuan: { name: 'Baichuan', models: 'baichuan-4', tier: 'cheap', strength: 'Chinese, balanced' },
58
+ // FREE TIER (no cost, start here!)
59
+ groq: {
60
+ name: 'Groq',
61
+ defaultModel: 'llama-3.3-70b-versatile',
62
+ tier: 'free',
63
+ strength: ' Fastest inference, generous free tier',
64
+ specialties: ['code', 'general', 'fast responses'],
65
+ note: 'Best for production free tier'
66
+ },
67
+ cerebras: {
68
+ name: 'Cerebras',
69
+ defaultModel: 'llama-3.3-70b',
70
+ tier: 'free',
71
+ strength: '🚀 Fastest GPU in world',
72
+ specialties: ['code', 'fast inference'],
73
+ note: 'Unique hardware, excellent speed'
74
+ },
75
+ google: {
76
+ name: 'Google AI',
77
+ defaultModel: 'gemini-1.5-flash',
78
+ tier: 'free',
79
+ strength: '🖼️ Multimodal, 1M context',
80
+ specialties: ['multimodal', 'long context', 'vision'],
81
+ note: 'Best free multimodal option'
82
+ },
83
+
84
+ // CHEAP TIER (best cost/speed ratio)
85
+ deepseek: {
86
+ name: 'DeepSeek',
87
+ defaultModel: 'deepseek-chat-v3',
88
+ tier: 'cheap',
89
+ strength: '💰 Best value, excellent code',
90
+ specialties: ['code', 'reasoning', 'math', 'value'],
91
+ note: 'Our top recommendation for cost/quality'
92
+ },
93
+ groq_alt: {
94
+ name: 'Groq (Alt)',
95
+ defaultModel: 'mixtral-8x7b-32768',
96
+ tier: 'cheap',
97
+ strength: '💰 Fast + cheap',
98
+ specialties: ['code', 'fast', 'long context'],
99
+ note: 'Good alternative to paid tiers'
100
+ },
101
+ together: {
102
+ name: 'Together AI',
103
+ defaultModel: 'Llama-3.3-70B-Instruct',
104
+ tier: 'cheap',
105
+ strength: '🏆 Managed, reliable',
106
+ specialties: ['general', 'code', 'reasoning'],
107
+ note: 'Great for production workloads'
108
+ },
109
+ fireworks: {
110
+ name: 'Fireworks AI',
111
+ defaultModel: 'mixtral-8x22b-instruct',
112
+ tier: 'cheap',
113
+ strength: '🔥 Fast inference engine',
114
+ specialties: ['code', 'fast', 'function calling'],
115
+ note: 'Excellent for agentic workflows'
116
+ },
117
+ mistral: {
118
+ name: 'Mistral AI',
119
+ defaultModel: 'mistral-small-latest',
120
+ tier: 'cheap',
121
+ strength: '🇪🇺 European, balanced',
122
+ specialties: ['general', 'code', 'European data'],
123
+ note: 'Great for EU compliance'
124
+ },
125
+ cohere: {
126
+ name: 'Cohere',
127
+ defaultModel: 'command-r7b',
128
+ tier: 'cheap',
129
+ strength: '📊 Great embeddings',
130
+ specialties: ['code', 'embeddings', 'rerank'],
131
+ note: 'Best for RAG workloads'
132
+ },
133
+ qwen: {
134
+ name: 'Qwen (Alibaba)',
135
+ defaultModel: 'qwen-turbo',
136
+ tier: 'cheap',
137
+ strength: '🇨🇳 Best Chinese model',
138
+ specialties: ['chinese', 'multilingual', 'code'],
139
+ note: 'Top Chinese language support'
140
+ },
141
+ zhipu: {
142
+ name: 'Zhipu GLM',
143
+ defaultModel: 'glm-4',
144
+ tier: 'cheap',
145
+ strength: '🇨🇳 Smart Chinese reasoning',
146
+ specialties: ['chinese', 'reasoning', 'code'],
147
+ note: 'Excellent for Chinese language tasks'
148
+ },
149
+ kimi: {
150
+ name: 'Kimi/Moonshot',
151
+ defaultModel: 'moonshot-v1-8k',
152
+ tier: 'cheap',
153
+ strength: '🇨🇳 128k context window',
154
+ specialties: ['long context', 'chinese', 'analysis'],
155
+ note: 'Best for very long documents'
156
+ },
157
+ yi: {
158
+ name: 'Yi (01.AI)',
159
+ defaultModel: 'yi-large',
160
+ tier: 'cheap',
161
+ strength: '🇨🇳 Strong reasoning',
162
+ specialties: ['reasoning', 'chinese', 'english'],
163
+ note: 'Good bilingual support'
164
+ },
165
+ minimax: {
166
+ name: 'MiniMax',
167
+ defaultModel: 'abab6.5s-chat',
168
+ tier: 'cheap',
169
+ strength: '🇨🇳 Fast Chinese responses',
170
+ specialties: ['chinese', 'fast', 'chat'],
171
+ note: 'Great for Chinese chatbots'
172
+ },
173
+ stepfun: {
174
+ name: 'StepFun',
175
+ defaultModel: 'step-1v-8k',
176
+ tier: 'cheap',
177
+ strength: '🇨🇳 Vision + text',
178
+ specialties: ['vision', 'multimodal', 'chinese'],
179
+ note: 'Good for image understanding'
180
+ },
181
+
182
+ // PAID TIER (best quality)
183
+ openai: {
184
+ name: 'OpenAI',
185
+ defaultModel: 'gpt-4o-mini',
186
+ tier: 'paid',
187
+ strength: '🧠 Best overall quality',
188
+ specialties: ['reasoning', 'code', 'general', 'function calling'],
189
+ note: 'Premium quality, higher cost'
190
+ },
191
+ anthropic: {
192
+ name: 'Anthropic',
193
+ defaultModel: 'claude-3.5-haiku',
194
+ tier: 'paid',
195
+ strength: '🛡️ Best reasoning, safest',
196
+ specialties: ['reasoning', 'analysis', 'safety'],
197
+ note: 'Excellent for sensitive tasks'
198
+ },
199
+ xai: {
200
+ name: 'xAI (Grok)',
201
+ defaultModel: 'grok-3',
202
+ tier: 'paid',
203
+ strength: '🤖 Real-time data access',
204
+ specialties: ['real-time', 'web search', 'reasoning'],
205
+ note: 'Accesses real-time information'
206
+ },
207
+ perplexity: {
208
+ name: 'Perplexity',
209
+ defaultModel: 'sonar',
210
+ tier: 'paid',
211
+ strength: '🌐 Online search + reasoning',
212
+ specialties: ['search', 'factual', 'research'],
213
+ note: 'Best for research with web access'
214
+ },
53
215
  };
54
216
 
55
217
  function createInterface() {
@@ -65,128 +227,297 @@ function question(rl, text) {
65
227
  });
66
228
  }
67
229
 
230
+ /**
231
+ * Detect API keys from environment variables
232
+ */
68
233
  async function detectApiKeys() {
69
234
  const detected = [];
70
- for (const [envVar, providerId] of Object.entries(API_KEY_ENV_MAP)) {
235
+
236
+ for (const [envVar, config] of Object.entries(API_KEY_ENV_MAP)) {
71
237
  if (process.env[envVar]) {
72
- detected.push({ envVar, providerId, info: PROVIDER_INFO[providerId] });
238
+ const info = PROVIDER_INFO[config.id];
239
+ detected.push({
240
+ envVar,
241
+ providerId: config.id,
242
+ tier: config.tier,
243
+ info
244
+ });
73
245
  }
74
246
  }
247
+
75
248
  return detected;
76
249
  }
77
250
 
78
- async function runWizard() {
79
- console.log('\n🔧 A3M Router Setup Wizard');
80
- console.log('━━━━━━━━━━━━━━━━━━━━━━━━━\n');
81
-
82
- const rl = createInterface();
251
+ /**
252
+ * Load existing configuration
253
+ */
254
+ function loadExistingConfig() {
255
+ const config = { providers: {} };
83
256
 
84
- // Ensure config directory exists
85
- if (!fs.existsSync(CONFIG_DIR)) {
86
- fs.mkdirSync(CONFIG_DIR, { recursive: true });
257
+ // Try new config location
258
+ if (fs.existsSync(CONFIG_FILE)) {
259
+ try {
260
+ const data = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
261
+ console.log(' ✓ Found existing config');
262
+ return data;
263
+ } catch (e) {
264
+ // Fall through
265
+ }
87
266
  }
88
267
 
89
- // Check for existing config
90
- let existingConfig = {};
91
- if (fs.existsSync(CONFIG_FILE)) {
268
+ // Try legacy providers.json location
269
+ if (fs.existsSync(PROVIDERS_FILE)) {
92
270
  try {
93
- existingConfig = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
94
- console.log('✓ Found existing config at', CONFIG_FILE);
95
- const providerKeys = Object.keys(existingConfig.providers || {});
96
- console.log(' Providers:', providerKeys.length > 0 ? providerKeys.join(', ') : '(none)');
97
- console.log('');
271
+ const data = JSON.parse(fs.readFileSync(PROVIDERS_FILE, 'utf8'));
272
+ console.log(' ✓ Found legacy config (will migrate)');
273
+ return data;
98
274
  } catch (e) {
99
- console.log('⚠ Could not read existing config, starting fresh\n');
275
+ // Fall through
100
276
  }
101
277
  }
102
278
 
103
- // Auto-detect API keys
104
- console.log('Checking configuration...');
105
- const detected = await detectApiKeys();
279
+ return config;
280
+ }
106
281
 
107
- if (detected.length > 0) {
108
- console.log('✓ Found', detected.length, 'configured provider(s):');
109
- detected.forEach(({ envVar, providerId, info }) => {
110
- console.log(' ✓', info?.name || providerId);
282
+ /**
283
+ * Auto-detect best starter config based on available keys
284
+ */
285
+ function suggestStarterConfig(detected) {
286
+ const suggestions = [];
287
+
288
+ // Priority: Free tier first, then cheap, then paid
289
+ const tierOrder = { free: 1, cheap: 2, paid: 3 };
290
+
291
+ detected
292
+ .sort((a, b) => (tierOrder[a.tier] || 4) - (tierOrder[b.tier] || 4))
293
+ .forEach(({ providerId, info, tier }) => {
294
+ suggestions.push({ providerId, info, tier });
111
295
  });
112
- console.log('');
113
- }
114
296
 
115
- // Provider selection
297
+ return suggestions;
298
+ }
299
+
300
+ /**
301
+ * Print provider list with status
302
+ */
303
+ function printProviderList(selected, detected) {
116
304
  const allProviders = Object.keys(PROVIDER_INFO);
117
- const selected = new Set();
118
305
 
119
- // Pre-select providers with detected keys
120
- detected.forEach(({ providerId }) => selected.add(providerId));
306
+ console.log('\n Available providers:\n');
307
+ console.log(' ## Provider Tier Strength');
308
+ console.log(' ──────────────────────────────────────────────────────');
121
309
 
122
- console.log('📡 Select providers to configure (comma-separated numbers, or "all"):');
123
- console.log('');
124
-
125
- const numbered = allProviders.map((id, i) => ({ id, i }));
126
- numbered.forEach(({ id, i }) => {
310
+ allProviders.forEach((id, i) => {
127
311
  const info = PROVIDER_INFO[id];
128
- const selected_mark = selected.has(id) ? '[x]' : '[ ]';
129
- const tier_mark = info?.tier === 'free' ? '(FREE)' : info?.tier === 'cheap' ? '(cheap)' : '(paid)';
130
- console.log(` ${String(i + 1).padStart(2)}. ${selected_mark} ${id.padEnd(12)} ${tier_mark} - ${info?.strength || ''}`);
312
+ const hasKey = detected.some(d => d.providerId === id);
313
+ const isSelected = selected.has(id);
314
+
315
+ let mark = ' ';
316
+ if (hasKey) mark = '🔑';
317
+ else if (isSelected) mark = '✓ ';
318
+
319
+ const tierIcon = info.tier === 'free' ? '🆓 ' :
320
+ info.tier === 'cheap' ? '💰 ' : '💎 ';
321
+
322
+ const tierStr = info.tier.padEnd(6);
323
+ const name = info.name.padEnd(20);
324
+
325
+ console.log(` ${String(i + 1).padStart(2)}. ${mark} ${name} ${tierIcon}${tierStr} ${info.strength}`);
131
326
  });
132
327
 
328
+ console.log(' ──────────────────────────────────────────────────────');
329
+ console.log(' 🔑 = API key detected in environment');
330
+ }
331
+
332
+ /**
333
+ * Print usage tips
334
+ */
335
+ function printTips(detected) {
336
+ console.log('\n 💡 Pro tips:');
133
337
  console.log('');
134
- const answer = await question(rl, ' Enter numbers or "all" [all with keys detected]: ');
135
338
 
136
- if (answer.toLowerCase().trim() === 'all') {
137
- allProviders.forEach(id => selected.add(id));
138
- } else if (answer.trim()) {
139
- const nums = answer.split(',').map(s => parseInt(s.trim())).filter(n => !isNaN(n));
140
- nums.forEach(n => {
141
- const idx = n - 1;
142
- if (idx >= 0 && idx < allProviders.length) {
143
- selected.add(allProviders[idx]);
144
- }
145
- });
339
+ if (detected.length === 0) {
340
+ console.log(' • Get free API keys at: https://console.groq.com (Groq is free!)');
341
+ console.log(' DeepSeek offers best cost/quality: https://platform.deepseek.com');
342
+ console.log(' A3M works with ANY provider - even 1 key is enough');
343
+ } else {
344
+ // Analyze detected providers
345
+ const tiers = new Set(detected.map(d => d.tier));
346
+
347
+ if (!tiers.has('free') && !tiers.has('cheap')) {
348
+ console.log(' • Consider adding Groq (free tier) for cost savings');
349
+ }
350
+ if (!detected.some(d => d.providerId === 'deepseek')) {
351
+ console.log(' • DeepSeek V3 is excellent and cheap - highly recommended');
352
+ }
353
+ if (detected.length < 3) {
354
+ console.log(' • Adding 3+ providers enables ensemble voting for hallucination detection');
355
+ }
146
356
  }
147
357
 
148
- console.log('\n✓ Selected providers:', Array.from(selected).join(', '));
149
-
150
- // Build config
358
+ console.log(' Run "a3m-router test" after setup to verify connections');
359
+ console.log(' • Ensemble mode (3+ providers) catches hallucinations automatically');
360
+ }
361
+
362
+ /**
363
+ * Build configuration object
364
+ */
365
+ function buildConfig(selected, detected) {
151
366
  const config = {
152
- version: '1.0',
367
+ version: '2.0',
153
368
  providers: {}
154
369
  };
155
370
 
156
371
  selected.forEach(providerId => {
157
372
  const info = PROVIDER_INFO[providerId];
158
- const envKey = Object.entries(API_KEY_ENV_MAP).find(([k, v]) => v === providerId)?.[0];
373
+ const envEntry = Object.entries(API_KEY_ENV_MAP).find(([, v]) => v.id === providerId);
374
+ const envVar = envEntry ? envEntry[0] : null;
159
375
 
160
376
  config.providers[providerId] = {
161
377
  name: info?.name || providerId,
162
- apiKey: envKey ? process.env[envKey] : '',
163
- models: [info?.models || 'default'],
378
+ apiKey: envVar ? process.env[envVar] : '',
379
+ defaultModel: info?.defaultModel || 'auto',
380
+ models: [info?.defaultModel || 'auto'],
164
381
  type: 'api',
165
- enabled: true
382
+ enabled: true,
383
+ tier: info?.tier || 'cheap'
166
384
  };
167
385
  });
168
386
 
169
- // Save config
387
+ return config;
388
+ }
389
+
390
+ /**
391
+ * Main wizard execution
392
+ */
393
+ async function runWizard() {
394
+ console.log('\n ╔═══════════════════════════════════════════════════════════╗');
395
+ console.log(' ║ ║');
396
+ console.log(' ║ 🤖 A3M Router Setup Wizard ║');
397
+ console.log(' ║ The intelligent LLM gateway ║');
398
+ console.log(' ║ ║');
399
+ console.log(' ╚═══════════════════════════════════════════════════════════╝\n');
400
+
401
+ const rl = createInterface();
402
+
403
+ // Ensure config directory exists
404
+ if (!fs.existsSync(CONFIG_DIR)) {
405
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
406
+ console.log(' ✓ Created config directory:', CONFIG_DIR);
407
+ }
408
+
409
+ // Load existing config
410
+ const existingConfig = loadExistingConfig();
411
+ const existingProviders = Object.keys(existingConfig.providers || {});
412
+ if (existingProviders.length > 0) {
413
+ console.log(' ✓ Found', existingProviders.length, 'configured provider(s)');
414
+ }
415
+
416
+ // Detect API keys
417
+ console.log('\n 🔍 Scanning for API keys...\n');
418
+ const detected = await detectApiKeys();
419
+
420
+ if (detected.length > 0) {
421
+ console.log(' ✓ Found', detected.length, 'API key(s) in environment:\n');
422
+ detected.forEach(({ envVar, info, tier }) => {
423
+ const tierMark = tier === 'free' ? '🆓' : tier === 'cheap' ? '💰' : '💎';
424
+ console.log(` ${tierMark} ${info?.name || envVar} (${tier} tier)`);
425
+ });
426
+ } else {
427
+ console.log(' ⚠️ No API keys detected in environment');
428
+ console.log(' You can still configure providers manually or add keys later\n');
429
+ }
430
+
431
+ // Starter suggestions
432
+ const suggestions = suggestStarterConfig(detected);
433
+ const selected = new Set();
434
+
435
+ // Auto-select detected providers
436
+ suggestions.forEach(({ providerId }) => selected.add(providerId));
437
+
438
+ // Print provider list
439
+ printProviderList(selected, detected);
440
+
441
+ // Selection prompt
442
+ console.log('\n 📡 Provider Selection:');
443
+ console.log(' • Enter numbers separated by commas (e.g., 1,3,5)');
444
+ console.log(' • Enter "all" to select all providers');
445
+ console.log(' • Enter "free" for free tier only');
446
+ console.log(' • Enter "min" for minimum viable (1 free + 1 cheap)');
447
+ console.log(' • Press Enter to use detected providers (recommended)\n');
448
+
449
+ const answer = await question(rl, ' Select providers [Enter for detected]: ');
450
+ const trimmed = answer.toLowerCase().trim();
451
+
452
+ if (trimmed === 'all') {
453
+ Object.keys(PROVIDER_INFO).forEach(id => selected.add(id));
454
+ } else if (trimmed === 'free') {
455
+ Object.entries(PROVIDER_INFO)
456
+ .filter(([, info]) => info.tier === 'free')
457
+ .forEach(([id]) => selected.add(id));
458
+ } else if (trimmed === 'min') {
459
+ // One free + one cheap
460
+ const free = Object.entries(PROVIDER_INFO).find(([, info]) => info.tier === 'free');
461
+ const cheap = Object.entries(PROVIDER_INFO).find(([, info]) => info.tier === 'cheap');
462
+ if (free) selected.add(free[0]);
463
+ if (cheap) selected.add(cheap[0]);
464
+ } else if (trimmed) {
465
+ const nums = answer.split(',').map(s => parseInt(s.trim())).filter(n => !isNaN(n));
466
+ selected.clear();
467
+ nums.forEach(n => {
468
+ const idx = n - 1;
469
+ const providers = Object.keys(PROVIDER_INFO);
470
+ if (idx >= 0 && idx < providers.length) {
471
+ selected.add(providers[idx]);
472
+ }
473
+ });
474
+ }
475
+
476
+ // Summary
477
+ console.log('\n ✓ Selected providers:');
478
+ const selectedList = Array.from(selected).map(id => ({
479
+ id,
480
+ info: PROVIDER_INFO[id]
481
+ })).sort((a, b) => {
482
+ const order = { free: 1, cheap: 2, paid: 3 };
483
+ return (order[a.info?.tier] || 4) - (order[b.info?.tier] || 4);
484
+ });
485
+
486
+ selectedList.forEach(({ id, info }) => {
487
+ const tierMark = info.tier === 'free' ? '🆓' : info.tier === 'cheap' ? '💰' : '💎';
488
+ console.log(` ${tierMark} ${info?.name} (${info?.tier} tier) - ${info?.defaultModel}`);
489
+ });
490
+
491
+ // Build and save config
492
+ const config = buildConfig(selected, detected);
493
+
170
494
  fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
171
- console.log('\n✓ Config saved to', CONFIG_FILE);
495
+ console.log('\n ✓ Config saved to:', CONFIG_FILE);
496
+
497
+ // Migration notice
498
+ if (existingProviders.length > 0 && existingProviders.length !== selected.size) {
499
+ console.log(' ℹ️ Note: Legacy config preserved at:', PROVIDERS_FILE);
500
+ }
172
501
 
173
- // Test connections
174
- console.log('\n🧪 Testing connections...');
175
- console.log(' (Skipped in wizard mode - run "npx a3m-router test" to verify)\n');
502
+ // Tips
503
+ printTips(detected);
176
504
 
177
- // Ready message
178
- console.log('━━━━━━━━━━━━━━━━━━━━━━━━━');
179
- console.log('✅ A3M Router is ready!');
180
- console.log('');
181
- console.log(' Next steps:');
182
- console.log(' 1. npx a3m-router serve # Start proxy server');
183
- console.log(' 2. npx a3m-router test # Test provider connections');
184
- console.log(' 3. npx a3m-router route "hi" # Try routing a query');
185
- console.log('');
186
- console.log(' Docs: https://github.com/Das-rebel/a3m-router');
187
- console.log('');
505
+ // Next steps
506
+ console.log('\n ╔═══════════════════════════════════════════════════════════╗');
507
+ console.log('✅ A3M Router is ready!');
508
+ console.log(' ╚═══════════════════════════════════════════════════════════╝\n');
509
+
510
+ console.log(' 📖 Next steps:\n');
511
+ console.log(' 1. Test connections: a3m-router test');
512
+ console.log(' 2. Start proxy: a3m-router serve');
513
+ console.log(' 3. Try routing: a3m-router route "Hello world"');
514
+ console.log(' 4. Open dashboard: a3m-router tui');
515
+ console.log('\n 📚 Docs: https://github.com/Das-rebel/a3m-router');
516
+ console.log(' 📋 Cheat sheet: https://github.com/Das-rebel/a3m-router/blob/main/docs/cli-cheatsheet.md\n');
188
517
 
189
518
  rl.close();
519
+
520
+ return config;
190
521
  }
191
522
 
192
523
  module.exports = { runWizard };