adaptive-memory-multi-model-router 2.15.4 → 2.15.5
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/ci.yml +2 -5
- package/.github/workflows/pypi-publish.yml +102 -0
- package/AGENT_COUNCIL_FINDINGS.md +123 -98
- package/CAMPAIGN_SUMMARY.md +87 -0
- package/CHANGELOG.md +7 -1
- package/ENTERPRISE_INTEGRATIONS.md +94 -0
- package/INTEGRATION_PROGRESS.md +96 -0
- package/OPPORTUNITIES_100.md +277 -0
- package/POPULARITY_BOOSTERS.md +1 -1
- package/README.md +137 -142
- package/README_ja.md +17 -21
- package/README_zh.md +13 -17
- package/TODO_BROWSER_AUTOMATION.md +87 -0
- package/a3m-integrations-summary.md +73 -0
- package/adapters/a3m_adapter/__init__.py +39 -3
- package/adapters/a3m_adapter/adapter/__init__.py +16 -1
- package/adapters/a3m_adapter/adapter/autogen.py +169 -0
- package/adapters/a3m_adapter/adapter/haystack.py +197 -0
- package/adapters/a3m_adapter/adapter/langgraph.py +196 -0
- package/adapters/a3m_adapter/adapter/pinecone.py +217 -0
- package/adapters/a3m_adapter/adapter/vercel.py +188 -0
- package/adapters/a3m_adapter/tests/test_adapters.py +29 -31
- package/adapters/a3m_adapter/tests/test_integration.py +80 -0
- package/adapters/requirements-dev.txt +6 -0
- package/adapters/requirements.txt +4 -0
- package/apps/cost-calculator/README.md +72 -0
- package/apps/cost-calculator/calculator.css +280 -0
- package/apps/cost-calculator/calculator.js +150 -0
- package/apps/cost-calculator/index.html +321 -0
- package/apps/cost-calculator/package.json +13 -0
- package/articles/ANNOUNCEMENT_reddit_ml.md +76 -0
- package/articles/ANNOUNCEMENT_vc/347/244/276/345/214/272.md +71 -0
- package/articles/ANNOUNCEMENT_vercel.md +85 -0
- package/articles/CHINESE_DIRECTORIES.md +2 -2
- package/articles/CHINESE_SUBMISSIONS_READY.md +5 -5
- package/articles/HN_POST_READY.md +16 -20
- package/articles/INDIEHACKERS_READY.md +19 -34
- package/demo.py +251 -0
- package/dist/analytics/costAnalytics.d.ts +0 -1
- package/dist/benchmark/reproducible.d.ts +0 -1
- package/dist/cache/semanticCache.d.ts +0 -1
- package/dist/cost/budgetEnforcer.d.ts +0 -1
- package/dist/cost/costTracker.d.ts +0 -1
- package/dist/ensemble/multiRoundDialog.d.ts +0 -1
- package/dist/ensemble/shapleyValue.d.ts +0 -1
- package/dist/ensemble.d.ts +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/integrations/oauth.d.ts +0 -1
- package/dist/integrations/scienceAdapter.d.ts +0 -1
- package/dist/memory/autoFetch.d.ts +0 -1
- package/dist/memory/hybridMemory.d.ts +0 -1
- package/dist/memory/memoryTree.d.ts +0 -1
- package/dist/memory/obsidianVault.d.ts +0 -1
- package/dist/memory/reasoningBank.d.ts +0 -1
- package/dist/observability/changeWatch.d.ts +0 -1
- package/dist/observability/fatigueDetector.d.ts +0 -1
- package/dist/observability/index.d.ts +0 -1
- package/dist/observability/metrics.d.ts +0 -1
- package/dist/observability/middleware.d.ts +0 -1
- package/dist/observability/tracer.d.ts +0 -1
- package/dist/observability/types.d.ts +0 -1
- package/dist/providers/providerConfig.d.ts +5 -2
- package/dist/providers/providerConfig.js +1006 -1
- package/dist/providers/providerConfig.js.map +1 -1
- package/dist/routing/advancedRouter.d.ts +1 -2
- package/dist/routing/advancedRouter.js +84 -0
- package/dist/routing/advancedRouter.js.map +1 -1
- package/dist/routing/crossModelValidation.d.ts +0 -1
- package/dist/routing/providerHealth.d.ts +77 -2
- package/dist/routing/providerHealth.js +190 -4
- package/dist/routing/providerHealth.js.map +1 -1
- package/dist/routing/providerRetry.d.ts +0 -1
- package/dist/routing/shadowSampler.d.ts +187 -0
- package/dist/routing/shadowSampler.js +306 -0
- package/dist/routing/shadowSampler.js.map +1 -0
- package/dist/sdk.d.ts +0 -1
- package/dist/security/guardrails.d.ts +0 -1
- package/dist/server/dashboard.d.ts +0 -1
- package/dist/server/handlers/chatHandler.d.ts +0 -1
- package/dist/server/handlers/completionsHandler.d.ts +0 -1
- package/dist/server/handlers/embeddingsHandler.d.ts +0 -1
- package/dist/server/handlers/healthHandler.d.ts +0 -1
- package/dist/server/handlers/metricsHandler.d.ts +0 -1
- package/dist/server/handlers/modelsHandler.d.ts +0 -1
- package/dist/server/metrics.d.ts +0 -1
- package/dist/server/modelMapper.d.ts +0 -1
- package/dist/server/proxyServer.d.ts +0 -1
- package/dist/server/router.d.ts +0 -1
- package/dist/server/state.d.ts +0 -1
- package/dist/tui/dashboard.d.ts +0 -1
- package/dist/utils/costUtils.d.ts +0 -1
- package/dist/utils/sorting.d.ts +0 -1
- package/dist/utils/tokenUtils.d.ts +0 -1
- package/docker-compose.yml +84 -60
- package/docs/comparison.md +2 -2
- package/docs/llms-full.txt +89 -0
- package/docs/llms.txt +25 -67
- package/docs-site/index.html +9 -9
- package/integrations/browser-use/README.md +155 -0
- package/integrations/browser-use/examples/form-filling.ts +179 -0
- package/integrations/browser-use/index.ts +145 -0
- package/integrations/browser-use/package.json +34 -0
- package/integrations/browser-use/tsconfig.json +17 -0
- package/integrations/mcp-browser/README.md +177 -0
- package/integrations/mcp-browser/package.json +38 -0
- package/integrations/mcp-browser/src/index.ts +297 -0
- package/integrations/sota-browser/README.md +191 -0
- package/integrations/sota-browser/package.json +34 -0
- package/llms-full.txt +6 -6
- package/llms.txt +25 -67
- package/package.json +34 -5
- package/packages/a3m-vercel-ai/README.md +161 -0
- package/packages/a3m-vercel-ai/dist/a3m-language-model.d.ts +12 -0
- package/packages/a3m-vercel-ai/dist/a3m-language-model.d.ts.map +1 -0
- package/packages/a3m-vercel-ai/dist/a3m-language-model.js +289 -0
- package/packages/a3m-vercel-ai/dist/a3m-language-model.js.map +1 -0
- package/packages/a3m-vercel-ai/dist/index.d.ts +82 -0
- package/packages/a3m-vercel-ai/dist/index.d.ts.map +1 -0
- package/packages/a3m-vercel-ai/dist/index.js +79 -0
- package/packages/a3m-vercel-ai/dist/index.js.map +1 -0
- package/packages/a3m-vercel-ai/dist/types.d.ts +97 -0
- package/packages/a3m-vercel-ai/dist/types.d.ts.map +1 -0
- package/packages/a3m-vercel-ai/dist/types.js +5 -0
- package/packages/a3m-vercel-ai/dist/types.js.map +1 -0
- package/packages/a3m-vercel-ai/package-lock.json +969 -0
- package/packages/a3m-vercel-ai/package.json +46 -0
- package/packages/a3m-vercel-ai/src/a3m-language-model.ts +381 -0
- package/packages/a3m-vercel-ai/src/index.ts +104 -0
- package/packages/a3m-vercel-ai/src/types.ts +116 -0
- package/packages/a3m-vercel-ai/tsconfig.json +20 -0
- 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 +92 -65
- 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/a3m_router.egg-info/PKG-INFO +172 -0
- package/python/a3m_router.egg-info/SOURCES.txt +17 -0
- package/python/a3m_router.egg-info/dependency_links.txt +1 -0
- package/python/a3m_router.egg-info/requires.txt +24 -0
- package/python/a3m_router.egg-info/top_level.txt +1 -0
- package/python/build_verify.sh +32 -0
- package/python/dist/a3m_router-2.2.1-py3-none-any.whl +0 -0
- package/python/dist/a3m_router-2.2.1.tar.gz +0 -0
- package/python/dist/a3m_router-2.2.2-py3-none-any.whl +0 -0
- package/python/dist/a3m_router-2.2.2.tar.gz +0 -0
- package/python/mcp-server/README.md +172 -0
- package/python/mcp-server/a3m_mcp/__init__.py +15 -0
- package/python/mcp-server/a3m_mcp/__main__.py +15 -0
- package/python/mcp-server/a3m_mcp/server.py +339 -0
- package/python/mcp-server/pyproject.toml +24 -0
- package/python/pyproject.toml +56 -5
- package/python/setup.py +3 -28
- package/src/providers/providerConfig.ts +1053 -1
- package/summary.txt +38 -0
- package/tsconfig.build.json +1 -2
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -94
- package/.github/ISSUE_TEMPLATE/config.yml +0 -17
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -71
- package/.well-known/ai-plugin.json +0 -16
package/docs/llms-full.txt
CHANGED
|
@@ -330,3 +330,92 @@ Response:
|
|
|
330
330
|
## License
|
|
331
331
|
|
|
332
332
|
MIT
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## Framework Adapter Details
|
|
337
|
+
|
|
338
|
+
### LangChain Adapter
|
|
339
|
+
|
|
340
|
+
```python
|
|
341
|
+
from a3m_adapter import A3MLangChainAdapter
|
|
342
|
+
|
|
343
|
+
llm = A3MLangChainAdapter(
|
|
344
|
+
model="auto",
|
|
345
|
+
temperature=0.7,
|
|
346
|
+
parallel_ensemble=2
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
# Works with any LangChain chain
|
|
350
|
+
result = llm.invoke("What is RAG?")
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### LlamaIndex Adapter
|
|
354
|
+
|
|
355
|
+
```python
|
|
356
|
+
from a3m_adapter import A3MLlamaIndexAdapter
|
|
357
|
+
|
|
358
|
+
llm = A3MLlamaIndexAdapter(model="auto")
|
|
359
|
+
response = llm.complete("Explain transformers")
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### AutoGen Adapter
|
|
363
|
+
|
|
364
|
+
```python
|
|
365
|
+
from a3m_adapter import A3MAutoGenAdapter
|
|
366
|
+
|
|
367
|
+
llm = A3MAutoGenAdapter(model="auto", parallel_ensemble=2)
|
|
368
|
+
config = llm.create_agent_config()
|
|
369
|
+
|
|
370
|
+
assistant = ConversableAgent(name="assistant", llm_config=config)
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### Vercel AI SDK Adapter
|
|
374
|
+
|
|
375
|
+
```python
|
|
376
|
+
from a3m_adapter import createA3MProvider
|
|
377
|
+
|
|
378
|
+
result = await generateText({
|
|
379
|
+
model: createA3MProvider({"model": "auto", "parallel_ensemble": 2}),
|
|
380
|
+
prompt: "What is 2+2?",
|
|
381
|
+
})
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### Haystack Adapter (RAG)
|
|
385
|
+
|
|
386
|
+
```python
|
|
387
|
+
from a3m_adapter import A3MHaystackAdapter
|
|
388
|
+
|
|
389
|
+
adapter = A3MHaystackAdapter(model="auto")
|
|
390
|
+
result = adapter.predict(query="What is AI?", documents=retrieved_docs)
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
### Pinecone Adapter (Vector Search)
|
|
394
|
+
|
|
395
|
+
```python
|
|
396
|
+
from a3m_adapter import A3MPineconeAdapter
|
|
397
|
+
|
|
398
|
+
adapter = A3MPineconeAdapter(model="auto")
|
|
399
|
+
embedding = adapter.embed_query("quantum computing")
|
|
400
|
+
results = index.query(vector=embedding, top_k=5)
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### LangGraph Adapter (Stateful Agents)
|
|
404
|
+
|
|
405
|
+
```python
|
|
406
|
+
from a3m_adapter import A3MLangGraphAdapter
|
|
407
|
+
|
|
408
|
+
adapter = A3MLangGraphAdapter(model="auto", parallel_ensemble=2)
|
|
409
|
+
agent = create_react_agent(adapter, tools=[...])
|
|
410
|
+
result = agent.invoke({"messages": [{"role": "user", "content": "Hello"}]})
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### CrewAI Adapter (Multi-Agent)
|
|
414
|
+
|
|
415
|
+
```python
|
|
416
|
+
from crewai.llms import A3MCompletion
|
|
417
|
+
|
|
418
|
+
agent = Agent(llm=A3MCompletion(model="auto"))
|
|
419
|
+
crew = Crew(agents=[agent], tasks=[task])
|
|
420
|
+
result = crew.kickoff()
|
|
421
|
+
```
|
package/docs/llms.txt
CHANGED
|
@@ -2,7 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
## What is A3M Router?
|
|
4
4
|
|
|
5
|
-
A3M Router is an intelligent LLM routing proxy that automatically selects the cheapest capable model for each request across 47+ providers.
|
|
5
|
+
A3M Router is an intelligent LLM routing proxy that automatically selects the cheapest capable model for each request across 47+ providers. Saves 70-95% on AI costs.
|
|
6
|
+
|
|
7
|
+
## Framework Adapters (8 Total)
|
|
8
|
+
|
|
9
|
+
| Adapter | Framework | Use Case |
|
|
10
|
+
|---------|-----------|---------|
|
|
11
|
+
| A3MLangChainAdapter | LangChain | Chain-based AI workflows |
|
|
12
|
+
| A3MLlamaIndexAdapter | LlamaIndex | RAG and document qa |
|
|
13
|
+
| A3MAutoGenAdapter | AutoGen | Multi-agent conversations |
|
|
14
|
+
| A3MVercelAdapter | Vercel AI SDK | Next.js apps |
|
|
15
|
+
| A3MHaystackAdapter | Haystack | RAG pipelines |
|
|
16
|
+
| A3MPineconeAdapter | Pinecone | Vector search + RAG |
|
|
17
|
+
| A3MLangGraphAdapter | LangGraph | Stateful agents |
|
|
18
|
+
| A3MCompletion | CrewAI | Multi-agent systems |
|
|
6
19
|
|
|
7
20
|
## Core Capabilities
|
|
8
21
|
|
|
@@ -19,7 +32,7 @@ A3M Router is an intelligent LLM routing proxy that automatically selects the ch
|
|
|
19
32
|
- Use case: "best answer regardless of cost" mode
|
|
20
33
|
|
|
21
34
|
### 3. Biology-Inspired Routing
|
|
22
|
-
- EXP3: Prevents provider monoculture
|
|
35
|
+
- EXP3: Prevents provider monoculture
|
|
23
36
|
- Charnov MVT: Optimal rate-limit rotation timing
|
|
24
37
|
- ODT Shadow Verification: Probabilistic verification for high-stakes queries
|
|
25
38
|
|
|
@@ -31,53 +44,16 @@ A3M Router is an intelligent LLM routing proxy that automatically selects the ch
|
|
|
31
44
|
|
|
32
45
|
## Supported Providers (47+)
|
|
33
46
|
|
|
34
|
-
|
|
35
|
-
|----------|------|---------------|
|
|
36
|
-
| OpenAI | Premium, Mid | gpt-4o, gpt-4o-mini |
|
|
37
|
-
| Anthropic | Premium, Mid | claude-3.5-sonnet, claude-3-haiku |
|
|
38
|
-
| Google | Premium, Mid | gemini-1.5-pro, gemini-1.5-flash |
|
|
39
|
-
| Groq | Cheap | llama-3.3-70b, llama-3.1-8b |
|
|
40
|
-
| DeepSeek | Cheap, Mid | deepseek-chat, deepseek-coder |
|
|
41
|
-
| Mistral | Cheap, Mid | mistral-large, mistral-small |
|
|
42
|
-
| NVIDIA | Premium | nemotron |
|
|
43
|
-
| Ollama | All | Local models |
|
|
44
|
-
| vLLM | All | Self-hosted |
|
|
47
|
+
OpenAI, Anthropic, Google, Groq, DeepSeek, Mistral, NVIDIA, Ollama, vLLM, Azure OpenAI, AWS Bedrock, and 37 more.
|
|
45
48
|
|
|
46
49
|
## API Endpoints
|
|
47
50
|
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
|
|
55
|
-
## Integration Patterns
|
|
56
|
-
|
|
57
|
-
### OpenAI SDK
|
|
58
|
-
```python
|
|
59
|
-
from openai import OpenAI
|
|
60
|
-
client = OpenAI(base_url="http://localhost:8787/v1", api_key="not-needed")
|
|
61
|
-
response = client.chat.completions.create(model="auto", messages=[...])
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### LangChain
|
|
65
|
-
```python
|
|
66
|
-
from a3m_adapter import A3MLangChainAdapter
|
|
67
|
-
llm = A3MLangChainAdapter(model="auto", parallel_ensemble=2)
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### LlamaIndex
|
|
71
|
-
```python
|
|
72
|
-
from a3m_adapter import A3MLlamaIndexAdapter
|
|
73
|
-
llm = A3MLlamaIndexAdapter(model="auto")
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
### CrewAI
|
|
77
|
-
```python
|
|
78
|
-
from crewai.llms import A3MCompletion
|
|
79
|
-
agent = Agent(llm=A3MCompletion(model="auto"))
|
|
80
|
-
```
|
|
51
|
+
- POST /v1/chat/completions — OpenAI-compatible chat
|
|
52
|
+
- POST /v1/completions — Text completions
|
|
53
|
+
- POST /v1/embeddings — Embeddings
|
|
54
|
+
- GET /v1/models — Available models
|
|
55
|
+
- GET /health — Provider health
|
|
56
|
+
- GET /metrics — Prometheus metrics
|
|
81
57
|
|
|
82
58
|
## Cost Savings
|
|
83
59
|
|
|
@@ -87,32 +63,14 @@ agent = Agent(llm=A3MCompletion(model="auto"))
|
|
|
87
63
|
| Code generation | $0.05 | $0.002 | 96% |
|
|
88
64
|
| Complex reasoning | $0.15 | $0.15 | 0% (correct) |
|
|
89
65
|
|
|
90
|
-
## Memory Features
|
|
91
|
-
|
|
92
|
-
- **Semantic Cache**: Instant responses for similar queries
|
|
93
|
-
- **Conversation Context**: Maintains chat history
|
|
94
|
-
- **Cross-Session Memory**: Remembers important facts
|
|
95
|
-
- **Adaptive Forgetting**: Auto-evicts stale info
|
|
96
|
-
|
|
97
|
-
## Benchmark Results
|
|
98
|
-
|
|
99
|
-
RouterArena (8,400 queries):
|
|
100
|
-
- Accuracy: 96.77%
|
|
101
|
-
- Cost: $0.0768/1K
|
|
102
|
-
- Robustness: 1.0000
|
|
103
|
-
|
|
104
66
|
## Installation
|
|
105
67
|
|
|
106
68
|
```bash
|
|
107
69
|
npm install adaptive-memory-multi-model-router
|
|
108
|
-
pip install
|
|
109
|
-
docker
|
|
70
|
+
pip install adapters/
|
|
71
|
+
docker-compose up -d
|
|
110
72
|
```
|
|
111
73
|
|
|
112
74
|
## Keywords
|
|
113
75
|
|
|
114
|
-
llm-router, ai-gateway, model-routing, cost-optimization, multi-provider, openai-compatible, langchain, llamaindex, crewai, parallel-execution, semantic-cache, adaptive-routing, failover, guardrails, cache, budget-alerts, streaming, retries, circuit-breaker
|
|
115
|
-
|
|
116
|
-
## License
|
|
117
|
-
|
|
118
|
-
MIT
|
|
76
|
+
llm-router, ai-gateway, model-routing, cost-optimization, multi-provider, openai-compatible, langchain, llamaindex, autogena, vercel-ai, haystack, pinecone, langgraph, crewai, parallel-execution, semantic-cache, adaptive-routing, failover, guardrails, cache, budget-alerts, streaming, retries, circuit-breaker, multi-agent, rag, embeddings, vector-search
|
package/docs-site/index.html
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
<!-- Primary SEO Meta Tags -->
|
|
8
8
|
<title>A3M Router — Parallel LLM Routing Gateway</title>
|
|
9
|
-
<meta name="description" content="
|
|
9
|
+
<meta name="description" content="Intelligent LLM routing proxy. Routes queries to cheapest capable model across 47+ providers. 96.77% RouterArena accuracy, $0.0768 per 1K tokens. Drop-in OpenAI-compatible API.">
|
|
10
10
|
<meta name="keywords" content="llm router benchmark, llm routing accuracy, routellm alternative, litellm alternative, llm cost optimization, openai proxy free, llm gateway open source, lightweight llm router, keyword-based llm routing, drop-in openai proxy, llm routing without gpu, how to reduce openai api costs">
|
|
11
11
|
<meta name="author" content="A3M Router Team">
|
|
12
12
|
<meta name="robots" content="index, follow, max-snippet:-1, max-image-preview:large">
|
|
@@ -468,20 +468,20 @@
|
|
|
468
468
|
|
|
469
469
|
<div class="stats">
|
|
470
470
|
<div class="stat">
|
|
471
|
-
<div class="stat-value">
|
|
472
|
-
<div class="stat-label">Downloads
|
|
471
|
+
<div class="stat-value">5,400+</div>
|
|
472
|
+
<div class="stat-label">Monthly Downloads</div>
|
|
473
473
|
</div>
|
|
474
474
|
<div class="stat">
|
|
475
|
-
<div class="stat-value">
|
|
476
|
-
<div class="stat-label">
|
|
475
|
+
<div class="stat-value">47+</div>
|
|
476
|
+
<div class="stat-label">LLM Providers</div>
|
|
477
477
|
</div>
|
|
478
478
|
<div class="stat">
|
|
479
|
-
<div class="stat-value">
|
|
480
|
-
<div class="stat-label">
|
|
479
|
+
<div class="stat-value">96.77%</div>
|
|
480
|
+
<div class="stat-label">RouterArena Accuracy</div>
|
|
481
481
|
</div>
|
|
482
482
|
<div class="stat">
|
|
483
|
-
<div class="stat-value"
|
|
484
|
-
<div class="stat-label">
|
|
483
|
+
<div class="stat-value">$0.08</div>
|
|
484
|
+
<div class="stat-label">Per 1K Tokens</div>
|
|
485
485
|
</div>
|
|
486
486
|
</div>
|
|
487
487
|
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# A3M Router + browser-use
|
|
2
|
+
|
|
3
|
+
**Cost-optimized browser automation with intelligent LLM routing.**
|
|
4
|
+
|
|
5
|
+
browser-use (108K GitHub stars) is the leading open-source library for AI-powered browser automation. A3M Router integrates seamlessly to provide:
|
|
6
|
+
|
|
7
|
+
- 💰 **70% cost reduction** vs using GPT-4o for everything
|
|
8
|
+
- 🕵️ **Stealth mode** to minimize bot detection
|
|
9
|
+
- ⚡ **Parallel ensemble** for reliable form filling
|
|
10
|
+
- 🔄 **Automatic fallback** when providers fail
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install adaptive-memory-multi-model-router
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { Agent } from 'browser-use';
|
|
22
|
+
import { A3MRouter } from 'adaptive-memory-multi-model-router';
|
|
23
|
+
|
|
24
|
+
// Configure A3M for browser automation
|
|
25
|
+
const router = new A3MRouter({
|
|
26
|
+
model: 'auto',
|
|
27
|
+
stealth: true,
|
|
28
|
+
parallelEnsemble: 3,
|
|
29
|
+
browserOptimized: true,
|
|
30
|
+
providers: ['openai', 'anthropic', 'google']
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Use with browser-use
|
|
34
|
+
const agent = new Agent({
|
|
35
|
+
task: 'Fill out this job application form with the provided resume data',
|
|
36
|
+
llm: router.getBrowserLLM(), // Optimized LLM wrapper
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const result = await agent.run();
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Why A3M for browser-use?
|
|
43
|
+
|
|
44
|
+
| Feature | A3M + browser-use | browser-use alone |
|
|
45
|
+
|---------|--------------------|--------------------|
|
|
46
|
+
| Form filling cost | $0.002/task | $0.03/task |
|
|
47
|
+
| Stealth mode | ✅ Built-in | ❌ |
|
|
48
|
+
| Automatic fallback | ✅ | Manual |
|
|
49
|
+
| Parallel ensemble | ✅ | ❌ |
|
|
50
|
+
| Anti-detection | ✅ | ❌ |
|
|
51
|
+
|
|
52
|
+
## Browser-Optimized Routing
|
|
53
|
+
|
|
54
|
+
A3M automatically routes browser tasks to the optimal provider:
|
|
55
|
+
|
|
56
|
+
| Task Type | Model Selected | Cost |
|
|
57
|
+
|-----------|-----------------|------|
|
|
58
|
+
| Simple form filling | gpt-4o-mini | $0.001 |
|
|
59
|
+
| Data extraction | claude-sonnet | $0.008 |
|
|
60
|
+
| Complex scraping | gpt-4o | $0.03 |
|
|
61
|
+
| Anti-detection tasks | provider_rotation | $0.005 |
|
|
62
|
+
|
|
63
|
+
## Stealth Mode
|
|
64
|
+
|
|
65
|
+
Enable stealth mode to minimize bot detection:
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
const router = new A3MRouter({
|
|
69
|
+
model: 'auto',
|
|
70
|
+
stealth: true, // Enable anti-detection
|
|
71
|
+
proxyRotation: true, // Rotate proxies automatically
|
|
72
|
+
humanizeTiming: true, // Human-like delays
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Parallel Ensemble
|
|
77
|
+
|
|
78
|
+
For critical tasks, run multiple providers and pick the best result:
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
const router = new A3MRouter({
|
|
82
|
+
model: 'auto',
|
|
83
|
+
parallelEnsemble: 3, // Run 3, vote on result
|
|
84
|
+
ensembleThreshold: 0.8, // Require 80% agreement
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Cost Comparison
|
|
89
|
+
|
|
90
|
+
**Monthly cost for 1000 browser tasks/day:**
|
|
91
|
+
|
|
92
|
+
| Solution | Monthly Cost | Annual Cost |
|
|
93
|
+
|----------|--------------|-------------|
|
|
94
|
+
| GPT-4o for everything | $9,000 | $108,000 |
|
|
95
|
+
| LiteLLM | $3,000 | $36,000 |
|
|
96
|
+
| **A3M + browser-use** | **$450** | **$5,400** |
|
|
97
|
+
|
|
98
|
+
**Savings: 95% vs GPT-4o, 85% vs LiteLLM**
|
|
99
|
+
|
|
100
|
+
## Example: Automated Job Applications
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { A3MRouter } from 'adaptive-memory-multi-model-router';
|
|
104
|
+
import { chromium } from 'playwright';
|
|
105
|
+
|
|
106
|
+
async function applyToJobs(jobs: Job[]) {
|
|
107
|
+
const router = new A3MRouter({
|
|
108
|
+
model: 'auto',
|
|
109
|
+
stealth: true,
|
|
110
|
+
parallelEnsemble: 3,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
for (const job of jobs) {
|
|
114
|
+
const browser = await chromium.launch({ headless: false });
|
|
115
|
+
const page = await browser.newPage();
|
|
116
|
+
|
|
117
|
+
await page.goto(job.url);
|
|
118
|
+
|
|
119
|
+
// A3M analyzes the form and fills it optimally
|
|
120
|
+
const formResult = await router.route({
|
|
121
|
+
task: `Fill this job application. Resume: ${resumeData.stringify()}`,
|
|
122
|
+
context: 'job_application',
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// ... fill form, submit, repeat
|
|
126
|
+
|
|
127
|
+
await browser.close();
|
|
128
|
+
|
|
129
|
+
console.log(`Applied to ${job.company} - Cost: $${formResult.cost}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Integration with Existing Code
|
|
135
|
+
|
|
136
|
+
A3M is a drop-in replacement for browser-use's default LLM:
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
// Before (expensive)
|
|
140
|
+
const agent = new Agent({
|
|
141
|
+
task: 'Extract data from this page',
|
|
142
|
+
llm: new ChatOpenAI({ model: 'gpt-4o' }),
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// After (A3M optimized)
|
|
146
|
+
import { A3MRouter } from 'adaptive-memory-multi-model-router';
|
|
147
|
+
const agent = new Agent({
|
|
148
|
+
task: 'Extract data from this page',
|
|
149
|
+
llm: new A3MRouter({ model: 'auto' }),
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## License
|
|
154
|
+
|
|
155
|
+
MIT - Same as A3M Router
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example: Automated Job Application with A3M + browser-use
|
|
3
|
+
*
|
|
4
|
+
* This example demonstrates:
|
|
5
|
+
* 1. Setting up A3M Router for browser automation
|
|
6
|
+
* 2. Using stealth mode to avoid detection
|
|
7
|
+
* 3. Parallel ensemble for reliable form filling
|
|
8
|
+
* 4. Cost tracking
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { chromium } from 'playwright';
|
|
12
|
+
import { A3MRouter } from 'adaptive-memory-multi-model-router';
|
|
13
|
+
|
|
14
|
+
// Resume data to fill into forms
|
|
15
|
+
const RESUME_DATA = {
|
|
16
|
+
firstName: 'Subhojit',
|
|
17
|
+
lastName: 'Das',
|
|
18
|
+
email: 'subho@example.com',
|
|
19
|
+
phone: '+91-7977110915',
|
|
20
|
+
location: 'Bengaluru, India',
|
|
21
|
+
currentTitle: 'Head of Growth Marketing',
|
|
22
|
+
yearsExperience: '10',
|
|
23
|
+
linkedin: 'https://www.linkedin.com/in/subhajitd/',
|
|
24
|
+
website: 'https://subho.dev',
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
interface JobListing {
|
|
28
|
+
company: string;
|
|
29
|
+
title: string;
|
|
30
|
+
url: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function applyToJob(job: JobListing) {
|
|
34
|
+
// Initialize A3M for browser automation
|
|
35
|
+
const router = new A3MRouter({
|
|
36
|
+
model: 'auto', // Routes to cheapest capable
|
|
37
|
+
stealth: true, // Enable anti-detection
|
|
38
|
+
parallelEnsemble: 3, // Run 3 providers for reliability
|
|
39
|
+
browserOptimized: true,
|
|
40
|
+
providers: ['openai', 'anthropic', 'google'],
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
console.log(`\nApplying to ${job.title} at ${job.company}...`);
|
|
44
|
+
|
|
45
|
+
const browser = await chromium.launch({
|
|
46
|
+
headless: false, // Set to true for production
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
const context = await browser.newContext({
|
|
51
|
+
// Stealth options
|
|
52
|
+
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const page = await context.newPage();
|
|
56
|
+
|
|
57
|
+
// Navigate to job application page
|
|
58
|
+
await page.goto(job.url, { waitUntil: 'networkidle' });
|
|
59
|
+
|
|
60
|
+
// Use A3M to analyze the form
|
|
61
|
+
console.log('Analyzing form structure...');
|
|
62
|
+
const formAnalysis = await router.route({
|
|
63
|
+
task: `Analyze this job application form. List all fields with:
|
|
64
|
+
1. Field name/type
|
|
65
|
+
2. Selector (CSS or XPath)
|
|
66
|
+
3. Whether it's required
|
|
67
|
+
4. Expected format`,
|
|
68
|
+
context: 'form_analysis',
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
console.log(`Found form fields: ${formAnalysis.content.substring(0, 100)}...`);
|
|
72
|
+
|
|
73
|
+
// Fill form fields based on analysis
|
|
74
|
+
const fieldMappings: Record<string, string> = {
|
|
75
|
+
'first name': RESUME_DATA.firstName,
|
|
76
|
+
'last name': RESUME_DATA.lastName,
|
|
77
|
+
'email': RESUME_DATA.email,
|
|
78
|
+
'phone': RESUME_DATA.phone,
|
|
79
|
+
'location': RESUME_DATA.location,
|
|
80
|
+
'current title': RESUME_DATA.currentTitle,
|
|
81
|
+
'years of experience': RESUME_DATA.yearsExperience,
|
|
82
|
+
'linkedin': RESUME_DATA.linkedin,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// Fill text inputs
|
|
86
|
+
for (const [fieldName, value] of Object.entries(fieldMappings)) {
|
|
87
|
+
try {
|
|
88
|
+
// Find the input field by label
|
|
89
|
+
const input = await page.locator(`input[aria-label*="${fieldName}" i], input[name*="${fieldName}" i]`).first();
|
|
90
|
+
|
|
91
|
+
if (await input.isVisible()) {
|
|
92
|
+
await input.fill(value);
|
|
93
|
+
console.log(`Filled: ${fieldName}`);
|
|
94
|
+
}
|
|
95
|
+
} catch (e) {
|
|
96
|
+
console.log(`Could not fill: ${fieldName}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Upload resume if there's a file input
|
|
101
|
+
try {
|
|
102
|
+
const resumeInput = await page.locator('input[type="file"]').first();
|
|
103
|
+
if (await resumeInput.isVisible()) {
|
|
104
|
+
await resumeInput.setInputFiles('/path/to/resume.pdf');
|
|
105
|
+
console.log('Uploaded resume');
|
|
106
|
+
}
|
|
107
|
+
} catch (e) {
|
|
108
|
+
console.log('No file upload field found');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Use A3M to decide if we're ready to submit
|
|
112
|
+
const pageState = await page.content();
|
|
113
|
+
const submitDecision = await router.route({
|
|
114
|
+
task: `Should I submit this form? Review the filled values and check for:
|
|
115
|
+
1. Required fields are filled
|
|
116
|
+
2. Values look correct
|
|
117
|
+
3. No obvious errors
|
|
118
|
+
|
|
119
|
+
Return YES or NO with brief explanation.`,
|
|
120
|
+
context: 'decision_making',
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
if (submitDecision.content.toLowerCase().includes('yes')) {
|
|
124
|
+
// Submit the form
|
|
125
|
+
await page.click('button[type="submit"]');
|
|
126
|
+
console.log('Form submitted!');
|
|
127
|
+
|
|
128
|
+
// Wait for confirmation
|
|
129
|
+
await page.waitForTimeout(2000);
|
|
130
|
+
const confirmation = await page.content();
|
|
131
|
+
|
|
132
|
+
if (confirmation.includes('applied') || confirmation.includes('success')) {
|
|
133
|
+
console.log('✅ Application successful!');
|
|
134
|
+
}
|
|
135
|
+
} else {
|
|
136
|
+
console.log(`❌ Not ready to submit: ${submitDecision.content}`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Get cost stats
|
|
140
|
+
const cost = router.getCost();
|
|
141
|
+
console.log(`Cost for this application: $${cost.total.toFixed(4)}`);
|
|
142
|
+
|
|
143
|
+
} finally {
|
|
144
|
+
await browser.close();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Example usage
|
|
149
|
+
async function main() {
|
|
150
|
+
const jobs: JobListing[] = [
|
|
151
|
+
{
|
|
152
|
+
company: 'TechCorp',
|
|
153
|
+
title: 'Head of Marketing',
|
|
154
|
+
url: 'https://example.com/jobs/123',
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
company: 'StartupXYZ',
|
|
158
|
+
title: 'VP Growth',
|
|
159
|
+
url: 'https://example.com/jobs/456',
|
|
160
|
+
},
|
|
161
|
+
];
|
|
162
|
+
|
|
163
|
+
console.log('🤖 A3M + browser-use Job Application Bot');
|
|
164
|
+
console.log('='.repeat(50));
|
|
165
|
+
console.log(`Applying to ${jobs.length} jobs...\n`);
|
|
166
|
+
|
|
167
|
+
for (const job of jobs) {
|
|
168
|
+
try {
|
|
169
|
+
await applyToJob(job);
|
|
170
|
+
} catch (e) {
|
|
171
|
+
console.error(`Failed to apply to ${job.company}: ${e}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
console.log('\n' + '='.repeat(50));
|
|
176
|
+
console.log('All applications complete!');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
main().catch(console.error);
|