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.
- package/.github/workflows/adapters-ci.yml +142 -0
- package/.github/workflows/auto-submit-sitemap.yml +41 -0
- package/.github/workflows/ci.yml +2 -5
- package/.github/workflows/mcp-pypi-publish.yml +34 -0
- package/.github/workflows/pypi-publish.yml +146 -0
- package/.github/workflows/tmlpd-publish.yml +23 -0
- package/README.md +245 -148
- package/RELEASE_v2.16.0.md +149 -0
- package/TECHNICAL_README.md +253 -0
- package/adapters/README.md +36 -0
- package/adapters/__init__.py +25 -0
- package/adapters/a3m_adapter/__init__.py +51 -0
- package/adapters/a3m_adapter/adapter/__init__.py +22 -0
- package/adapters/a3m_adapter/adapter/autogen.py +169 -0
- package/adapters/a3m_adapter/adapter/config.py +100 -0
- package/adapters/a3m_adapter/adapter/haystack.py +197 -0
- package/adapters/a3m_adapter/adapter/langchain.py +155 -0
- package/adapters/a3m_adapter/adapter/langgraph.py +196 -0
- package/adapters/a3m_adapter/adapter/llamaindex.py +162 -0
- package/adapters/a3m_adapter/adapter/pinecone.py +217 -0
- package/adapters/a3m_adapter/adapter/vercel.py +188 -0
- package/adapters/a3m_adapter/tests/__init__.py +1 -0
- package/adapters/a3m_adapter/tests/test_adapters.py +118 -0
- package/adapters/a3m_adapter/tests/test_integration.py +80 -0
- package/adapters/requirements-dev.txt +6 -0
- package/adapters/requirements.txt +4 -0
- package/adapters/setup.py +23 -0
- package/demo.py +251 -0
- package/discoverability-diagnosis.md +280 -0
- package/dist/analytics/costAnalytics.d.ts.map +1 -1
- package/dist/benchmark/reproducible.d.ts.map +1 -1
- package/dist/cache/semanticCache.d.ts.map +1 -1
- package/dist/cli/setupWizard.d.ts +257 -50
- package/dist/cli/setupWizard.d.ts.map +1 -1
- package/dist/cli/setupWizard.js +419 -109
- package/dist/cli/setupWizard.js.map +1 -1
- package/dist/cli/tui.d.ts +6 -0
- package/dist/cli/tui.js +96 -67
- package/dist/cli/tui.js.map +1 -0
- package/dist/cli.js +9 -0
- package/dist/cost/budgetEnforcer.d.ts.map +1 -1
- package/dist/cost/costTracker.d.ts.map +1 -1
- package/dist/ensemble/multiRoundDialog.d.ts.map +1 -1
- package/dist/ensemble/shapleyValue.d.ts.map +1 -1
- package/dist/ensemble.d.ts +1 -1
- package/dist/ensemble.js +141 -0
- package/dist/integrations/langchainAdapter.d.ts.map +1 -1
- package/dist/integrations/langchainAdapter.js +3 -3
- package/dist/integrations/langchainAdapter.js.map +1 -1
- package/dist/integrations/oauth.d.ts.map +1 -1
- package/dist/integrations/scienceAdapter.d.ts.map +1 -1
- package/dist/memory/autoFetch.d.ts.map +1 -1
- package/dist/memory/hybridMemory.d.ts.map +1 -1
- package/dist/memory/memoryTree.d.ts.map +1 -1
- package/dist/memory/obsidianVault.d.ts.map +1 -1
- package/dist/memory/reasoningBank.d.ts.map +1 -1
- package/dist/observability/metrics.d.ts.map +1 -1
- package/dist/observability/tracer.d.ts.map +1 -1
- package/dist/providers/providerConfig.d.ts.map +1 -1
- package/dist/providers/providerConfig.js +32 -17
- package/dist/providers/providerConfig.js.map +1 -1
- package/dist/routing/advancedRouter.d.ts.map +1 -1
- package/dist/routing/advancedRouter.js +106 -14
- package/dist/routing/advancedRouter.js.map +1 -1
- package/dist/routing/providerHealth.d.ts.map +1 -1
- package/dist/routing/providerRetry.d.ts.map +1 -1
- package/dist/routing/shadowSampler.d.ts.map +1 -0
- package/dist/routing/shadowSampler.js.map +1 -1
- package/dist/security/guardrails.d.ts.map +1 -1
- package/dist/server/handlers/chatHandler.d.ts.map +1 -1
- package/dist/server/handlers/completionsHandler.d.ts.map +1 -1
- package/dist/server/handlers/embeddingsHandler.d.ts.map +1 -1
- package/dist/server/handlers/healthHandler.d.ts.map +1 -1
- package/dist/server/handlers/metricsHandler.d.ts.map +1 -1
- package/dist/server/handlers/modelsHandler.d.ts.map +1 -1
- package/dist/server/metrics.d.ts.map +1 -1
- package/dist/server/proxyServer.d.ts.map +1 -1
- package/dist/server/router.d.ts.map +1 -1
- package/dist/server/state.d.ts.map +1 -1
- package/dist/skills/__tests__/skill_manager.test.js +5 -265
- package/dist/skills/__tests__/skill_manager.test.js.map +1 -1
- package/dist/utils/tokenUtils.d.ts.map +1 -1
- package/docker-compose.yml +84 -60
- package/docs/ARTICLE_Biology_Inspired_Routing.md +208 -0
- package/docs/ARTICLE_Master.md +78 -0
- package/docs/ARTICLE_Master_CN.md +78 -0
- package/docs/ARTICLE_OpenRouter_Stripe.md +140 -0
- package/docs/DEVPTO_ARTICLE.md +84 -0
- package/docs/HUMAN_STYLE_GUIDE.md +75 -0
- package/docs/IMPRINT_PLAN.md +88 -0
- package/docs/OPENROUTER_ALTERNATIVE.md +184 -0
- package/docs/SOCIAL_CAMPAIGN.md +316 -0
- package/docs/anthropic.html +45 -0
- package/docs/best-llm-routers-2025.html +157 -0
- package/docs/cerebras.html +43 -0
- package/docs/cli-cheatsheet.md +286 -212
- package/docs/comparison.md +2 -2
- package/docs/deepseek.html +44 -0
- package/docs/google.html +47 -0
- package/docs/groq.html +44 -0
- package/docs/llms-full.txt +360 -138
- package/docs/llms.txt +70 -71
- package/docs/mistral.html +43 -0
- package/docs/ollama.html +50 -0
- package/docs/openai.html +57 -0
- package/docs/sitemap.xml +69 -57
- package/docs-site/blog/best-llm-routers-2025.html +157 -0
- package/docs-site/index.html +68 -9
- package/docs-site/providers/anthropic.html +45 -0
- package/docs-site/providers/cerebras.html +43 -0
- package/docs-site/providers/deepseek.html +44 -0
- package/docs-site/providers/google.html +47 -0
- package/docs-site/providers/groq.html +44 -0
- package/docs-site/providers/index.html +41 -0
- package/docs-site/providers/mistral.html +43 -0
- package/docs-site/providers/ollama.html +50 -0
- package/docs-site/providers/openai.html +57 -0
- package/docs-site/sitemap.xml +69 -0
- package/llms.txt +70 -62
- package/package.json +44 -182
- package/packages/agentkit-adapter/LICENSE +21 -0
- package/packages/agentkit-adapter/README.md +126 -0
- package/packages/agentkit-adapter/examples/agentkit-example.ts +139 -0
- package/packages/agentkit-adapter/package.json +57 -0
- package/packages/agentkit-adapter/src/adapter.ts +381 -0
- package/packages/agentkit-adapter/src/index.ts +36 -0
- package/packages/agentkit-adapter/src/types.ts +105 -0
- package/packages/agentkit-adapter/src/util.ts +13 -0
- package/packages/agentkit-adapter/tsconfig.json +22 -0
- package/prometheus.yml +8 -0
- package/python/README.md +35 -81
- package/python/a3m/__init__.py +32 -3
- package/python/a3m/adapters/__init__.py +21 -0
- package/python/a3m/adapters/langchain.py +190 -0
- package/python/a3m/adapters/llamaindex.py +249 -0
- package/python/a3m/adapters/qdrant.py +240 -0
- package/python/a3m/adapters/weaviate.py +263 -0
- package/python/a3m/client.py +5 -0
- package/python/build_verify.sh +32 -0
- package/python/mcp-server/README.md +172 -0
- package/python/mcp-server/a3m_mcp/__init__.py +25 -0
- package/python/mcp-server/a3m_mcp/__main__.py +15 -0
- package/python/mcp-server/a3m_mcp/server.py +205 -0
- package/python/mcp-server/pyproject.toml +24 -0
- package/python/pyproject.toml +60 -6
- package/python/setup.py +3 -28
- package/scripts/submit-sitemap.sh +52 -0
- package/src/__types__/registry.d.ts +14 -0
- package/src/cli/setupWizard.ts +443 -112
- package/src/cli/tui.ts +159 -0
- package/src/ensemble.ts +154 -1
- package/src/integrations/langchainAdapter.ts +2 -2
- package/src/providers/providerConfig.ts +32 -17
- package/src/providers/registry.js +27 -0
- package/src/routing/advancedRouter.ts +99 -14
- package/src/routing/shadowSampler.ts +1 -1
- package/test-install/package.json +12 -0
- package/tests/tsconfig.json +0 -1
- package/tmlpd-pi-extension/README.md +105 -44
- package/tmlpd-pi-extension/docs/demo.svg +33 -0
- package/tmlpd-pi-extension/package.json +35 -106
- package/tmlpd-pi-extension/src/tokenOptimization/contextStratifier.ts +163 -0
- package/tmlpd-pi-extension/src/tokenOptimization/fetchOnceLocal.ts +136 -0
- package/tmlpd-pi-extension/src/tokenOptimization/index.ts +197 -0
- package/tmlpd-pi-extension/src/tokenOptimization/interAgentCompression.ts +157 -0
- package/tmlpd-pi-extension/src/tokenOptimization/schemaContract.ts +101 -0
- package/tmlpd-pi-extension/src/tokenOptimization/semanticCache.ts +248 -0
- package/tmlpd-pi-extension/src/tokenOptimization/tokenAwareFallback.ts +192 -0
- package/tmlpd-pi-extension/test/verify.js +21 -0
- package/tsconfig.build.json +3 -2
- package/packages/a3m-vercel-ai/dist/a3m-language-model.d.ts +0 -12
- package/packages/a3m-vercel-ai/dist/a3m-language-model.d.ts.map +0 -1
- package/packages/a3m-vercel-ai/dist/a3m-language-model.js +0 -289
- package/packages/a3m-vercel-ai/dist/a3m-language-model.js.map +0 -1
- package/packages/a3m-vercel-ai/dist/index.d.ts +0 -82
- package/packages/a3m-vercel-ai/dist/index.d.ts.map +0 -1
- package/packages/a3m-vercel-ai/dist/index.js +0 -79
- package/packages/a3m-vercel-ai/dist/index.js.map +0 -1
- package/packages/a3m-vercel-ai/dist/types.d.ts +0 -97
- package/packages/a3m-vercel-ai/dist/types.d.ts.map +0 -1
- package/packages/a3m-vercel-ai/dist/types.js +0 -5
- package/packages/a3m-vercel-ai/dist/types.js.map +0 -1
- package/src/skills/__tests__/skill_manager.test.ts +0 -328
- package/tmlpd-pi-extension/dist/cache/prefixCache.d.ts +0 -114
- package/tmlpd-pi-extension/dist/cache/prefixCache.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/cache/prefixCache.js +0 -285
- package/tmlpd-pi-extension/dist/cache/prefixCache.js.map +0 -1
- package/tmlpd-pi-extension/dist/cache/responseCache.d.ts +0 -58
- package/tmlpd-pi-extension/dist/cache/responseCache.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/cache/responseCache.js +0 -153
- package/tmlpd-pi-extension/dist/cache/responseCache.js.map +0 -1
- package/tmlpd-pi-extension/dist/cli.js +0 -59
- package/tmlpd-pi-extension/dist/cost/costTracker.d.ts +0 -95
- package/tmlpd-pi-extension/dist/cost/costTracker.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/cost/costTracker.js +0 -240
- package/tmlpd-pi-extension/dist/cost/costTracker.js.map +0 -1
- package/tmlpd-pi-extension/dist/index.d.ts +0 -723
- package/tmlpd-pi-extension/dist/index.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/index.js +0 -239
- package/tmlpd-pi-extension/dist/index.js.map +0 -1
- package/tmlpd-pi-extension/dist/memory/episodicMemory.d.ts +0 -82
- package/tmlpd-pi-extension/dist/memory/episodicMemory.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/memory/episodicMemory.js +0 -145
- package/tmlpd-pi-extension/dist/memory/episodicMemory.js.map +0 -1
- package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.d.ts +0 -102
- package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.js +0 -207
- package/tmlpd-pi-extension/dist/orchestration/haloOrchestrator.js.map +0 -1
- package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.d.ts +0 -85
- package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.js +0 -210
- package/tmlpd-pi-extension/dist/orchestration/mctsWorkflow.js.map +0 -1
- package/tmlpd-pi-extension/dist/providers/localProvider.d.ts +0 -102
- package/tmlpd-pi-extension/dist/providers/localProvider.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/providers/localProvider.js +0 -338
- package/tmlpd-pi-extension/dist/providers/localProvider.js.map +0 -1
- package/tmlpd-pi-extension/dist/providers/registry.d.ts +0 -55
- package/tmlpd-pi-extension/dist/providers/registry.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/providers/registry.js +0 -138
- package/tmlpd-pi-extension/dist/providers/registry.js.map +0 -1
- package/tmlpd-pi-extension/dist/routing/advancedRouter.d.ts +0 -68
- package/tmlpd-pi-extension/dist/routing/advancedRouter.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/routing/advancedRouter.js +0 -332
- package/tmlpd-pi-extension/dist/routing/advancedRouter.js.map +0 -1
- package/tmlpd-pi-extension/dist/tools/tmlpdTools.d.ts +0 -101
- package/tmlpd-pi-extension/dist/tools/tmlpdTools.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/tools/tmlpdTools.js +0 -368
- package/tmlpd-pi-extension/dist/tools/tmlpdTools.js.map +0 -1
- package/tmlpd-pi-extension/dist/utils/batchProcessor.d.ts +0 -96
- package/tmlpd-pi-extension/dist/utils/batchProcessor.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/utils/batchProcessor.js +0 -170
- package/tmlpd-pi-extension/dist/utils/batchProcessor.js.map +0 -1
- package/tmlpd-pi-extension/dist/utils/compression.d.ts +0 -61
- package/tmlpd-pi-extension/dist/utils/compression.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/utils/compression.js +0 -281
- package/tmlpd-pi-extension/dist/utils/compression.js.map +0 -1
- package/tmlpd-pi-extension/dist/utils/reliability.d.ts +0 -74
- package/tmlpd-pi-extension/dist/utils/reliability.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/utils/reliability.js +0 -177
- package/tmlpd-pi-extension/dist/utils/reliability.js.map +0 -1
- package/tmlpd-pi-extension/dist/utils/speculativeDecoding.d.ts +0 -117
- package/tmlpd-pi-extension/dist/utils/speculativeDecoding.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/utils/speculativeDecoding.js +0 -246
- package/tmlpd-pi-extension/dist/utils/speculativeDecoding.js.map +0 -1
- package/tmlpd-pi-extension/dist/utils/tokenUtils.d.ts +0 -50
- package/tmlpd-pi-extension/dist/utils/tokenUtils.d.ts.map +0 -1
- package/tmlpd-pi-extension/dist/utils/tokenUtils.js +0 -124
- package/tmlpd-pi-extension/dist/utils/tokenUtils.js.map +0 -1
package/src/cli/setupWizard.ts
CHANGED
|
@@ -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, '
|
|
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
|
-
|
|
16
|
-
'
|
|
17
|
-
'
|
|
18
|
-
'
|
|
19
|
-
'
|
|
20
|
-
'
|
|
21
|
-
'
|
|
22
|
-
'
|
|
23
|
-
'
|
|
24
|
-
'
|
|
25
|
-
'
|
|
26
|
-
'
|
|
27
|
-
'
|
|
28
|
-
'
|
|
29
|
-
|
|
30
|
-
'
|
|
31
|
-
'
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
235
|
+
|
|
236
|
+
for (const [envVar, config] of Object.entries(API_KEY_ENV_MAP)) {
|
|
71
237
|
if (process.env[envVar]) {
|
|
72
|
-
|
|
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
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const
|
|
251
|
+
/**
|
|
252
|
+
* Load existing configuration
|
|
253
|
+
*/
|
|
254
|
+
function loadExistingConfig() {
|
|
255
|
+
const config = { providers: {} };
|
|
83
256
|
|
|
84
|
-
//
|
|
85
|
-
if (
|
|
86
|
-
|
|
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
|
-
//
|
|
90
|
-
|
|
91
|
-
if (fs.existsSync(CONFIG_FILE)) {
|
|
268
|
+
// Try legacy providers.json location
|
|
269
|
+
if (fs.existsSync(PROVIDERS_FILE)) {
|
|
92
270
|
try {
|
|
93
|
-
|
|
94
|
-
console.log('✓ Found
|
|
95
|
-
|
|
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
|
-
|
|
275
|
+
// Fall through
|
|
100
276
|
}
|
|
101
277
|
}
|
|
102
278
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const detected = await detectApiKeys();
|
|
279
|
+
return config;
|
|
280
|
+
}
|
|
106
281
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
-
|
|
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
|
-
|
|
120
|
-
|
|
306
|
+
console.log('\n Available providers:\n');
|
|
307
|
+
console.log(' ## Provider Tier Strength');
|
|
308
|
+
console.log(' ──────────────────────────────────────────────────────');
|
|
121
309
|
|
|
122
|
-
|
|
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
|
|
129
|
-
const
|
|
130
|
-
|
|
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 (
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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('
|
|
149
|
-
|
|
150
|
-
|
|
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: '
|
|
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
|
|
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:
|
|
163
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
174
|
-
|
|
175
|
-
console.log(' (Skipped in wizard mode - run "npx a3m-router test" to verify)\n');
|
|
502
|
+
// Tips
|
|
503
|
+
printTips(detected);
|
|
176
504
|
|
|
177
|
-
//
|
|
178
|
-
console.log('
|
|
179
|
-
console.log('✅ A3M Router is ready!');
|
|
180
|
-
console.log('');
|
|
181
|
-
|
|
182
|
-
console.log('
|
|
183
|
-
console.log('
|
|
184
|
-
console.log('
|
|
185
|
-
console.log('');
|
|
186
|
-
console.log('
|
|
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 };
|