adaptive-memory-multi-model-router 2.15.4 → 2.16.0
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/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 +147 -275
- 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/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/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/docs/llms-full.txt +153 -286
- package/docs/llms.txt +71 -112
- 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 +62 -112
- package/package.json +92 -13
- 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/src/providers/providerConfig.ts +1053 -1
- package/summary.txt +38 -0
- 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/adapters/README.md +0 -36
- package/adapters/__init__.py +0 -25
- package/adapters/a3m_adapter/__init__.py +0 -15
- package/adapters/a3m_adapter/adapter/__init__.py +0 -7
- package/adapters/a3m_adapter/adapter/config.py +0 -100
- package/adapters/a3m_adapter/adapter/langchain.py +0 -155
- package/adapters/a3m_adapter/adapter/llamaindex.py +0 -162
- package/adapters/a3m_adapter/tests/__init__.py +0 -1
- package/adapters/a3m_adapter/tests/test_adapters.py +0 -120
- package/adapters/setup.py +0 -23
package/summary.txt
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
## A3M Router Integration Status (2026-08-04)
|
|
2
|
+
|
|
3
|
+
### ✅ COMPLETED
|
|
4
|
+
- CrewAI PR #1: MERGED (June 3, 2026) - A3M Router support added to CrewAI
|
|
5
|
+
- Created 18+ A3M integration repos:
|
|
6
|
+
- browser-use (108k stars)
|
|
7
|
+
- a3m-llamaindex, a3m-cursor-mcp, a3m-salesforce, a3m-hubspot, a3m-github-copilot
|
|
8
|
+
- a3m-vercel-ai (npm published v0.1.0)
|
|
9
|
+
- a3m-llamaindex, a3m-cursor-mcp, a3m-autogen, a3m-google-workspace, a3m-vercel-ai
|
|
10
|
+
- Updated README and PRs to remove RouterArena rank claims
|
|
11
|
+
- Created 100+ integration opportunities list
|
|
12
|
+
|
|
13
|
+
### 🔴 IN PROGRESS
|
|
14
|
+
1. **browser-use PR #5378**:
|
|
15
|
+
- Status: OPEN
|
|
16
|
+
- Issue: CLA not signed (author email not linked to GitHub)
|
|
17
|
+
- Action: Sign CLA, fix commit author, push to main branch
|
|
18
|
+
|
|
19
|
+
2. **CrewAI PR #6794**:
|
|
20
|
+
- Status: OPEN with 2 reviews
|
|
21
|
+
- Need to address remaining review comments
|
|
22
|
+
- Already implemented all requested changes from review
|
|
23
|
+
|
|
24
|
+
3. **n8n Community Node**
|
|
25
|
+
- Repo created: https://github.com/Das-rebel/n8n-nodes-a3m-router
|
|
26
|
+
- Files created: README, package.json, example.ts, index.ts, package.json
|
|
27
|
+
- Need to:
|
|
28
|
+
- Fix directory structure
|
|
29
|
+
- Add proper n8n-node CLI integration
|
|
30
|
+
- Push to GitHub and create PR
|
|
31
|
+
|
|
32
|
+
### 🔜 Next Steps:
|
|
33
|
+
1. Fix browser-use PR CLA issue (priority #1)
|
|
34
|
+
2. Complete n8n node submission
|
|
35
|
+
3. Create AutoGen/LangChain examples
|
|
36
|
+
4. Target enterprise integrations (Salesforce, GitHub Copilot)
|
|
37
|
+
|
|
38
|
+
## 🚀 Ready for next actions!
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: Bug Report
|
|
3
|
-
about: Report a bug or unexpected behavior to help us improve A3M Router
|
|
4
|
-
title: "[Bug] "
|
|
5
|
-
labels: bug, needs-triage
|
|
6
|
-
assignees: ""
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Description
|
|
10
|
-
|
|
11
|
-
A clear and concise description of the bug.
|
|
12
|
-
|
|
13
|
-
## Reproduction Steps
|
|
14
|
-
|
|
15
|
-
Steps to reproduce the behavior:
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
# 1. Set up (if applicable)
|
|
19
|
-
export PROVIDER_API_KEY=sk-...
|
|
20
|
-
|
|
21
|
-
# 2. Run
|
|
22
|
-
npx a3m-router route "Your query here"
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
If using the SDK, provide a minimal code snippet:
|
|
26
|
-
|
|
27
|
-
```typescript
|
|
28
|
-
import { A3MRouter } from "adaptive-memory-multi-model-router";
|
|
29
|
-
|
|
30
|
-
const router = new A3MRouter({ /* your config */ });
|
|
31
|
-
const result = await router.route("Your query");
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## Expected Behavior
|
|
35
|
-
|
|
36
|
-
What did you expect to happen?
|
|
37
|
-
|
|
38
|
-
## Actual Behavior
|
|
39
|
-
|
|
40
|
-
What actually happened? Include error messages, stack traces, or unexpected output.
|
|
41
|
-
|
|
42
|
-
```
|
|
43
|
-
Paste error output or logs here
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## A3M Router Version
|
|
47
|
-
|
|
48
|
-
- Package: `adaptive-memory-multi-model-router@<version>` (run `npm list adaptive-memory-multi-model-router`)
|
|
49
|
-
- CLI version (if applicable): `npx a3m-router --version`
|
|
50
|
-
|
|
51
|
-
## Environment
|
|
52
|
-
|
|
53
|
-
- **OS:** macOS / Linux / Windows
|
|
54
|
-
- **Node.js version:** (run `node --version`)
|
|
55
|
-
- **npm version:** (run `npm --version`)
|
|
56
|
-
- **Python version (if using Python SDK):** (run `python --version`)
|
|
57
|
-
|
|
58
|
-
## Providers Used
|
|
59
|
-
|
|
60
|
-
Which provider(s) were involved? (e.g., Groq, OpenAI, Anthropic, NVIDIA, DeepSeek, custom)
|
|
61
|
-
|
|
62
|
-
## Configuration
|
|
63
|
-
|
|
64
|
-
Attach or describe relevant config (redact API keys):
|
|
65
|
-
|
|
66
|
-
```json
|
|
67
|
-
{
|
|
68
|
-
"providers": { ... },
|
|
69
|
-
"routing": { ... },
|
|
70
|
-
"budgets": { ... }
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
## Logs
|
|
75
|
-
|
|
76
|
-
If you ran with `DEBUG=*` or `LOG_LEVEL=debug`, include relevant log lines:
|
|
77
|
-
|
|
78
|
-
```
|
|
79
|
-
[DEBUG] Routing query...
|
|
80
|
-
[ERROR] Provider groq returned 503
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
## Additional Context
|
|
84
|
-
|
|
85
|
-
- Does this happen consistently or intermittently?
|
|
86
|
-
- Does it affect all providers or a specific one?
|
|
87
|
-
- Did it work in a previous version? If so, which version?
|
|
88
|
-
- Any recent changes to your setup?
|
|
89
|
-
|
|
90
|
-
## Checklist
|
|
91
|
-
|
|
92
|
-
- [ ] I have searched existing issues for duplicates
|
|
93
|
-
- [ ] I have redacted all API keys and secrets from the above
|
|
94
|
-
- [ ] I can reliably reproduce this bug
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
blank_issues_enabled: false
|
|
2
|
-
contact_links:
|
|
3
|
-
- name: "\U0001F4D6 Documentation & Quick Start"
|
|
4
|
-
url: https://github.com/Das-rebel/a3m-router#readme
|
|
5
|
-
about: Check the README for setup, SDK usage, API reference, and configuration examples
|
|
6
|
-
- name: "\U0001F4AC Discussions & Community"
|
|
7
|
-
url: https://github.com/Das-rebel/a3m-router/discussions
|
|
8
|
-
about: Ask questions, share ideas, show what you've built, and get help from the community
|
|
9
|
-
- name: "\U0001F680 NPM Package"
|
|
10
|
-
url: https://www.npmjs.com/package/adaptive-memory-multi-model-router
|
|
11
|
-
about: View package details, version history, and download statistics
|
|
12
|
-
- name: "\U0001F4DC Changelog"
|
|
13
|
-
url: https://github.com/Das-rebel/a3m-router/blob/main/CHANGELOG.md
|
|
14
|
-
about: See what's changed in recent releases
|
|
15
|
-
- name: "\U0001F6A8 Security"
|
|
16
|
-
url: https://github.com/Das-rebel/a3m-router/security/policy
|
|
17
|
-
about: Report security vulnerabilities privately
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: Feature Request
|
|
3
|
-
about: Suggest an idea or enhancement for A3M Router
|
|
4
|
-
title: "[Feature] "
|
|
5
|
-
labels: enhancement
|
|
6
|
-
assignees: ""
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Problem Statement
|
|
10
|
-
|
|
11
|
-
A clear description of the problem you're trying to solve. What gap or pain point does this feature address?
|
|
12
|
-
|
|
13
|
-
**Example:** "Currently, A3M Router doesn't support routing based on response language. When I send multilingual queries, I want them routed to providers that perform best in that language."
|
|
14
|
-
|
|
15
|
-
## Proposed Solution
|
|
16
|
-
|
|
17
|
-
Describe the feature you'd like to see. Be as specific as possible about behavior, configuration, and API.
|
|
18
|
-
|
|
19
|
-
```typescript
|
|
20
|
-
// If applicable, sketch the API you envision
|
|
21
|
-
const router = new A3MRouter({
|
|
22
|
-
languageRouting: {
|
|
23
|
-
enabled: true,
|
|
24
|
-
defaultProvider: "openai",
|
|
25
|
-
languageOverrides: {
|
|
26
|
-
ja: "anthropic",
|
|
27
|
-
zh: "deepseek",
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
});
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## Use Case
|
|
34
|
-
|
|
35
|
-
Describe the real-world scenario that would benefit from this feature.
|
|
36
|
-
|
|
37
|
-
- Who is the target user? (e.g., solo developer, enterprise team, researcher)
|
|
38
|
-
- What workflow does it enable or simplify?
|
|
39
|
-
- How frequently would this be used?
|
|
40
|
-
|
|
41
|
-
## Alternatives Considered
|
|
42
|
-
|
|
43
|
-
List any workarounds or alternative approaches you've explored:
|
|
44
|
-
|
|
45
|
-
1. Manual provider selection per query
|
|
46
|
-
2. Custom wrapper script
|
|
47
|
-
3. Forking and modifying the router
|
|
48
|
-
4. Using a different tool altogether
|
|
49
|
-
|
|
50
|
-
Explain why these are insufficient.
|
|
51
|
-
|
|
52
|
-
## Priority
|
|
53
|
-
|
|
54
|
-
How important is this to you?
|
|
55
|
-
|
|
56
|
-
- [ ] **Blocking** — Cannot proceed without this feature
|
|
57
|
-
- [ ] **High** — Important for my workflow
|
|
58
|
-
- [ ] **Medium** — Nice to have
|
|
59
|
-
- [ ] **Low** — Interesting idea, not urgent
|
|
60
|
-
|
|
61
|
-
## Would You Implement It?
|
|
62
|
-
|
|
63
|
-
- [ ] **Yes** — I can submit a PR (with guidance)
|
|
64
|
-
- [ ] **Maybe** — Willing to help test or provide requirements
|
|
65
|
-
- [ ] **No** — Just suggesting
|
|
66
|
-
|
|
67
|
-
## Additional Context
|
|
68
|
-
|
|
69
|
-
- Links to related discussions, issues, or external references
|
|
70
|
-
- Screenshots or mockups (if applicable)
|
|
71
|
-
- Any constraints or requirements (e.g., must work offline, must not increase bundle size)
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"schema_version": "v1",
|
|
3
|
-
"name_for_human": "A3M Router",
|
|
4
|
-
"name_for_model": "a3m_router",
|
|
5
|
-
"description_for_human": "LLM routing proxy — #1 on RouterArena (0.9404 / 96.77%) at $0.0768/1K. Rule-based, no ML, 47+ providers.",
|
|
6
|
-
"description_for_model": "A3M Router is an LLM routing service. Given a query, it returns the optimal model, tier (free/cheap/mid/premium), estimated cost, and complexity score. Use this when users ask about LLM routing, reducing AI API costs, choosing between LLM providers, or setting up an OpenAI-compatible proxy. Available as TypeScript SDK, Python SDK, CLI, and REST API. RouterArena rank #1 with 0.9404 / 96.77% at $0.0768 per 1K queries (arXiv:2510.00202).",
|
|
7
|
-
"api": {
|
|
8
|
-
"type": "openapi",
|
|
9
|
-
"url": "https://das-rebel.github.io/a3m-router/docs/openapi.json"
|
|
10
|
-
},
|
|
11
|
-
"auth": {
|
|
12
|
-
"type": "none"
|
|
13
|
-
},
|
|
14
|
-
"contact_email": "Sdas22@gmail.com",
|
|
15
|
-
"legal_info_url": "https://github.com/Das-rebel/a3m-router/blob/main/LICENSE"
|
|
16
|
-
}
|
package/adapters/README.md
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
# A3M Router Adapters
|
|
2
|
-
|
|
3
|
-
Drop-in adapters for LangChain and LlamaIndex to integrate with A3M Router for intelligent model routing.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
pip install a3m_adapter
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
Or install with extras:
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
pip install a3m_adapter[langchain] # With LangChain support
|
|
15
|
-
pip install a3m_adapter[llamaindex] # With LlamaIndex support
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
## Usage
|
|
19
|
-
|
|
20
|
-
### LangChain
|
|
21
|
-
|
|
22
|
-
```python
|
|
23
|
-
from a3m_adapter import A3MLangChainAdapter
|
|
24
|
-
|
|
25
|
-
llm = A3MLangChainAdapter(model="auto", temperature=0.7)
|
|
26
|
-
result = llm.invoke("What is the capital of France?")
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
### LlamaIndex
|
|
30
|
-
|
|
31
|
-
```python
|
|
32
|
-
from a3m_adapter import A3MLlamaIndexAdapter
|
|
33
|
-
|
|
34
|
-
llm = A3MLlamaIndexAdapter(model="auto")
|
|
35
|
-
response = llm.complete("What is the capital of France?")
|
|
36
|
-
```
|
package/adapters/__init__.py
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
A3M Router Adapter Package
|
|
3
|
-
|
|
4
|
-
This package provides drop-in adapters to integrate A3M Router
|
|
5
|
-
with popular LLM frameworks including LangChain, LlamaIndex, and more.
|
|
6
|
-
|
|
7
|
-
Usage:
|
|
8
|
-
from adapters import A3MLangChainAdapter, A3MLlamaIndexAdapter, A3MConfig
|
|
9
|
-
|
|
10
|
-
# LangChain
|
|
11
|
-
llm = A3MLangChainAdapter(model="auto", temperature=0.7)
|
|
12
|
-
|
|
13
|
-
# LlamaIndex
|
|
14
|
-
llm = A3MLlamaIndexAdapter(model="auto")
|
|
15
|
-
|
|
16
|
-
# Configuration
|
|
17
|
-
config = A3MConfig(model="auto", parallel_ensemble=2)
|
|
18
|
-
"""
|
|
19
|
-
|
|
20
|
-
from .a3m_adapter.adapter.langchain import A3MLangChainAdapter
|
|
21
|
-
from .a3m_adapter.adapter.llamaindex import A3MLlamaIndexAdapter
|
|
22
|
-
from .a3m_adapter.adapter.config import A3MConfig
|
|
23
|
-
|
|
24
|
-
__all__ = ['A3MLangChainAdapter', 'A3MLlamaIndexAdapter', 'A3MConfig']
|
|
25
|
-
__version__ = '1.0.0'
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
A3M Router Adapters for LLM Frameworks.
|
|
3
|
-
|
|
4
|
-
Provides drop-in adapters for:
|
|
5
|
-
- LangChain (A3MLangChainAdapter)
|
|
6
|
-
- LlamaIndex (A3MLlamaIndexAdapter)
|
|
7
|
-
- Configuration management (A3MConfig)
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
from .adapter.langchain import A3MLangChainAdapter
|
|
11
|
-
from .adapter.llamaindex import A3MLlamaIndexAdapter
|
|
12
|
-
from .adapter.config import A3MConfig
|
|
13
|
-
|
|
14
|
-
__all__ = ['A3MLangChainAdapter', 'A3MLlamaIndexAdapter', 'A3MConfig']
|
|
15
|
-
__version__ = '1.0.0'
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Configuration management for A3M Router adapters.
|
|
3
|
-
|
|
4
|
-
Provides settings for:
|
|
5
|
-
- Default model selection strategy
|
|
6
|
-
- Cost optimization thresholds
|
|
7
|
-
- Parallel ensemble settings
|
|
8
|
-
- Provider priority lists
|
|
9
|
-
|
|
10
|
-
Usage:
|
|
11
|
-
from a3m_adapter_config import A3MConfig
|
|
12
|
-
|
|
13
|
-
config = A3MConfig.from_file("a3m_config.yaml")
|
|
14
|
-
llm = A3MChatModel(**config.to_dict())
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
from __future__ import annotations
|
|
18
|
-
|
|
19
|
-
import json
|
|
20
|
-
import logging
|
|
21
|
-
from dataclasses import dataclass, field, asdict
|
|
22
|
-
from typing import Any, Dict, List, Optional, Union
|
|
23
|
-
|
|
24
|
-
logger = logging.getLogger(__name__)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
@dataclass
|
|
28
|
-
class A3MConfig:
|
|
29
|
-
"""Configuration for A3M Router adapters."""
|
|
30
|
-
|
|
31
|
-
# Model selection
|
|
32
|
-
model: str = "auto"
|
|
33
|
-
|
|
34
|
-
# Sampling parameters
|
|
35
|
-
temperature: float = 0.0
|
|
36
|
-
max_tokens: Optional[int] = 4096
|
|
37
|
-
top_p: float = 1.0
|
|
38
|
-
frequency_penalty: float = 0.0
|
|
39
|
-
presence_penalty: float = 0.0
|
|
40
|
-
|
|
41
|
-
# Routing strategy
|
|
42
|
-
parallel_ensemble: int = 1
|
|
43
|
-
fallback_enabled: bool = True
|
|
44
|
-
cost_threshold: float = 0.05 # Max $ per 1k tokens
|
|
45
|
-
|
|
46
|
-
# Provider preferences (highest priority first)
|
|
47
|
-
preferred_providers: List[str] = field(default_factory=lambda: [
|
|
48
|
-
"openai", "anthropic", "google", "azure_openai",
|
|
49
|
-
"azure_ais", "litellm", "groq", "together"
|
|
50
|
-
])
|
|
51
|
-
|
|
52
|
-
# Excluded providers (never use)
|
|
53
|
-
excluded_providers: List[str] = field(default_factory=lambda: [])
|
|
54
|
-
|
|
55
|
-
# API configuration
|
|
56
|
-
api_endpoint: str = "http://localhost:8787/v1"
|
|
57
|
-
api_key: Optional[str] = None
|
|
58
|
-
|
|
59
|
-
# Budget controls
|
|
60
|
-
monthly_budget_usd: Optional[float] = None
|
|
61
|
-
daily_budget_usd: Optional[float] = None
|
|
62
|
-
|
|
63
|
-
@classmethod
|
|
64
|
-
def from_file(cls, path: str) -> "A3MConfig":
|
|
65
|
-
"""Load configuration from YAML file."""
|
|
66
|
-
try:
|
|
67
|
-
import yaml
|
|
68
|
-
with open(path, 'r') as f:
|
|
69
|
-
data = yaml.safe_load(f)
|
|
70
|
-
return cls(**data)
|
|
71
|
-
except ImportError:
|
|
72
|
-
logger.warning("PyYAML not installed, using JSON")
|
|
73
|
-
return cls.from_json(path)
|
|
74
|
-
|
|
75
|
-
@classmethod
|
|
76
|
-
def from_json(cls, path: str) -> "A3MConfig":
|
|
77
|
-
"""Load configuration from JSON file."""
|
|
78
|
-
with open(path, 'r') as f:
|
|
79
|
-
data = json.load(f)
|
|
80
|
-
return cls(**data)
|
|
81
|
-
|
|
82
|
-
def to_dict(self) -> Dict[str, Any]:
|
|
83
|
-
"""Convert to dictionary."""
|
|
84
|
-
return asdict(self)
|
|
85
|
-
|
|
86
|
-
def to_json(self, path: Optional[str] = None) -> Optional[str]:
|
|
87
|
-
"""Convert to JSON string or save to file."""
|
|
88
|
-
data = json.dumps(self.to_dict(), indent=2)
|
|
89
|
-
if path:
|
|
90
|
-
with open(path, 'w') as f:
|
|
91
|
-
f.write(data)
|
|
92
|
-
return data
|
|
93
|
-
|
|
94
|
-
def update_budget_limits(self, remaining_usd: float) -> None:
|
|
95
|
-
"""Update budget limits based on remaining funds."""
|
|
96
|
-
if self.daily_budget_usd is not None:
|
|
97
|
-
remaining_pct = remaining_usd / self.daily_budget_usd
|
|
98
|
-
if remaining_pct < 0.1:
|
|
99
|
-
logger.warning("Low daily budget: %s remaining", remaining_usd)
|
|
100
|
-
self.parallel_ensemble = 1 # Reduce to single-provider
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
A3M Router Adapter for LangChain.
|
|
3
|
-
|
|
4
|
-
Drop-in replacement for LangChain's ChatOpenAI that routes through A3M Router
|
|
5
|
-
for intelligent, cost-optimized model selection across 47+ providers.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from __future__ import annotations
|
|
9
|
-
|
|
10
|
-
import logging
|
|
11
|
-
from typing import Any, Dict, List, Optional
|
|
12
|
-
|
|
13
|
-
logger = logging.getLogger(__name__)
|
|
14
|
-
|
|
15
|
-
# Check availability
|
|
16
|
-
LANGCHAIN_AVAILABLE = False
|
|
17
|
-
try:
|
|
18
|
-
from langchain_core.language_models import BaseChatModel
|
|
19
|
-
from langchain_core.messages import AIMessage, BaseMessage, HumanMessage, SystemMessage, ToolMessage
|
|
20
|
-
from langchain_core.outputs import ChatGeneration, ChatResult, LLMResult
|
|
21
|
-
LANGCHAIN_AVAILABLE = True
|
|
22
|
-
except ImportError:
|
|
23
|
-
logger.warning("LangChain not installed. Install with: pip install langchain langchain-core")
|
|
24
|
-
|
|
25
|
-
A3M_AVAILABLE = False
|
|
26
|
-
try:
|
|
27
|
-
from a3m.router import A3MRouter, RouteResponse
|
|
28
|
-
A3M_AVAILABLE = True
|
|
29
|
-
except ImportError:
|
|
30
|
-
logger.warning("A3M Router not installed. Install with: pip install adaptive-memory-multi-model-router")
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class A3MLangChainAdapter:
|
|
34
|
-
"""
|
|
35
|
-
A3M Router adapter for LangChain's ChatOpenAI interface.
|
|
36
|
-
|
|
37
|
-
Routes prompts through A3M Router to automatically select the cheapest
|
|
38
|
-
capable model across 47+ LLM providers.
|
|
39
|
-
"""
|
|
40
|
-
|
|
41
|
-
def __init__(
|
|
42
|
-
self,
|
|
43
|
-
model: str = "auto",
|
|
44
|
-
temperature: float = 0.0,
|
|
45
|
-
max_tokens: Optional[int] = 4096,
|
|
46
|
-
parallel_ensemble: int = 1,
|
|
47
|
-
api_key: Optional[str] = None,
|
|
48
|
-
**kwargs: Any,
|
|
49
|
-
) -> None:
|
|
50
|
-
"""
|
|
51
|
-
Initialize A3M Router adapter.
|
|
52
|
-
|
|
53
|
-
Args:
|
|
54
|
-
model: Model name or "auto" for automatic routing
|
|
55
|
-
temperature: Sampling temperature
|
|
56
|
-
max_tokens: Maximum tokens to generate
|
|
57
|
-
parallel_ensemble: Number of providers to run in parallel
|
|
58
|
-
api_key: A3M API key (optional)
|
|
59
|
-
"""
|
|
60
|
-
self.model = model
|
|
61
|
-
self.temperature = temperature
|
|
62
|
-
self.max_tokens = max_tokens
|
|
63
|
-
self.parallel_ensemble = parallel_ensemble
|
|
64
|
-
self.api_key = api_key
|
|
65
|
-
self._a3m_router = None
|
|
66
|
-
self._initialized = False
|
|
67
|
-
|
|
68
|
-
def _ensure_router(self) -> None:
|
|
69
|
-
"""Lazily initialize the A3M router."""
|
|
70
|
-
if self._initialized:
|
|
71
|
-
return
|
|
72
|
-
|
|
73
|
-
if not A3M_AVAILABLE:
|
|
74
|
-
raise ImportError(
|
|
75
|
-
"A3M Router is not installed. "
|
|
76
|
-
"Install with: pip install adaptive-memory-multi-model-router"
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
self._a3m_router = A3MRouter(
|
|
80
|
-
model=self.model,
|
|
81
|
-
temperature=self.temperature,
|
|
82
|
-
parallel_ensemble=self.parallel_ensemble,
|
|
83
|
-
)
|
|
84
|
-
self._initialized = True
|
|
85
|
-
logger.info(
|
|
86
|
-
"A3M Router initialized: model=%s, ensemble=%d",
|
|
87
|
-
self.model,
|
|
88
|
-
self.parallel_ensemble,
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
@property
|
|
92
|
-
def _llm_type(self) -> str:
|
|
93
|
-
return "a3m_router"
|
|
94
|
-
|
|
95
|
-
def _generate(
|
|
96
|
-
self,
|
|
97
|
-
messages: List[BaseMessage],
|
|
98
|
-
stop: Optional[List[str]] = None,
|
|
99
|
-
run_manager: Any = None,
|
|
100
|
-
**kwargs: Any,
|
|
101
|
-
) -> LLMResult:
|
|
102
|
-
"""Generate a response using A3M Router."""
|
|
103
|
-
self._ensure_router()
|
|
104
|
-
|
|
105
|
-
# Convert messages
|
|
106
|
-
a3m_messages = self._convert_messages(messages)
|
|
107
|
-
|
|
108
|
-
# Route through A3M
|
|
109
|
-
import asyncio
|
|
110
|
-
loop = asyncio.get_event_loop()
|
|
111
|
-
route_result = loop.run_in_executor(
|
|
112
|
-
None,
|
|
113
|
-
lambda: self._a3m_router.route(
|
|
114
|
-
messages=a3m_messages,
|
|
115
|
-
temperature=self.temperature,
|
|
116
|
-
max_tokens=self.max_tokens,
|
|
117
|
-
stop=stop,
|
|
118
|
-
**kwargs,
|
|
119
|
-
),
|
|
120
|
-
)
|
|
121
|
-
|
|
122
|
-
ai_message = AIMessage(content=route_result.content)
|
|
123
|
-
generation = ChatGeneration(message=ai_message)
|
|
124
|
-
return LLMResult(generations=[[generation]])
|
|
125
|
-
|
|
126
|
-
def _convert_messages(self, messages: List[BaseMessage]) -> List[Dict[str, Any]]:
|
|
127
|
-
"""Convert LangChain messages to A3M format."""
|
|
128
|
-
a3m_messages = []
|
|
129
|
-
for msg in messages:
|
|
130
|
-
if isinstance(msg, SystemMessage):
|
|
131
|
-
a3m_messages.append({"role": "system", "content": msg.content})
|
|
132
|
-
elif isinstance(msg, HumanMessage):
|
|
133
|
-
a3m_messages.append({"role": "user", "content": msg.content})
|
|
134
|
-
elif isinstance(msg, AIMessage):
|
|
135
|
-
a3m_messages.append({"role": "assistant", "content": msg.content})
|
|
136
|
-
elif isinstance(msg, ToolMessage):
|
|
137
|
-
a3m_messages.append(
|
|
138
|
-
{"role": "tool", "content": msg.content, "tool_call_id": msg.tool_call_id}
|
|
139
|
-
)
|
|
140
|
-
else:
|
|
141
|
-
a3m_messages.append({"role": "user", "content": str(msg)})
|
|
142
|
-
return a3m_messages
|
|
143
|
-
|
|
144
|
-
def bind_tools(self, tools: List[Dict[str, Any]], **kwargs: Any) -> "A3MLangChainAdapter":
|
|
145
|
-
"""Bind tools for function calling."""
|
|
146
|
-
return self
|
|
147
|
-
|
|
148
|
-
def __repr__(self) -> str:
|
|
149
|
-
return (
|
|
150
|
-
f"A3MLangChainAdapter("
|
|
151
|
-
f"model={self.model!r}, "
|
|
152
|
-
f"temperature={self.temperature}, "
|
|
153
|
-
f"max_tokens={self.max_tokens}, "
|
|
154
|
-
f"ensemble={self.parallel_ensemble})"
|
|
155
|
-
)
|