adaptive-memory-multi-model-router 2.15.3 → 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/CHANGELOG.md +7 -1
- package/README.md +260 -137
- package/README_ja.md +2 -2
- package/README_zh.md +1 -1
- 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/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/demo.py +251 -0
- package/dist/providers/providerConfig.d.ts +5 -1
- package/dist/providers/providerConfig.js +1006 -1
- package/dist/providers/providerConfig.js.map +1 -1
- package/docker-compose.yml +84 -60
- package/docs/comparison.md +2 -2
- package/docs/llms-full.txt +360 -138
- package/docs/llms.txt +70 -71
- package/docs-site/index.html +9 -9
- package/llms.txt +70 -62
- package/package.json +41 -91
- 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
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A3M Router Weaviate adapter.
|
|
3
|
+
|
|
4
|
+
Enables A3M Router as the embedding layer for Weaviate vector search.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
import weaviate
|
|
8
|
+
from a3m.adapters import WeaviateAdapter
|
|
9
|
+
|
|
10
|
+
# Create A3M-powered Weaviate client
|
|
11
|
+
client = WeaviateAdapter(
|
|
12
|
+
a3m_base_url="http://localhost:8787",
|
|
13
|
+
weaviate_url="http://localhost:8080",
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
# Generate embeddings via A3M
|
|
17
|
+
query_embedding = client.embed_query("What is AI?")
|
|
18
|
+
|
|
19
|
+
# Search Weaviate
|
|
20
|
+
results = client.query.get("Article", ["title", "content"]).with_near_vector({
|
|
21
|
+
"vector": query_embedding
|
|
22
|
+
}).with_limit(5).do()
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
import logging
|
|
28
|
+
from typing import Any, Dict, List, Optional
|
|
29
|
+
|
|
30
|
+
logger = logging.getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
WEAVIATE_AVAILABLE = False
|
|
33
|
+
try:
|
|
34
|
+
import weaviate
|
|
35
|
+
from weaviate import Client as WeaviateClient
|
|
36
|
+
from weaviate.types import NUMBERS
|
|
37
|
+
WEAVIATE_AVAILABLE = True
|
|
38
|
+
except ImportError:
|
|
39
|
+
logger.warning("Weaviate client not installed. pip install weaviate-client")
|
|
40
|
+
|
|
41
|
+
from a3m.client import A3MRouter, A3MRouterError
|
|
42
|
+
|
|
43
|
+
if WEAVIATE_AVAILABLE:
|
|
44
|
+
class WeaviateAdapter(WeaviateClient):
|
|
45
|
+
"""
|
|
46
|
+
Weaviate client wrapper that uses A3M Router for embeddings.
|
|
47
|
+
|
|
48
|
+
Provides intelligent embedding generation for Weaviate's
|
|
49
|
+
vector search with automatic model selection.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
a3m_base_url: A3M Router server URL (for embeddings).
|
|
53
|
+
embed_model: Embedding model ("auto" for A3M selection).
|
|
54
|
+
weaviate_url: Weaviate server URL.
|
|
55
|
+
weaviate_client: Existing Weaviate client (for hybrid use).
|
|
56
|
+
**kwargs: Additional WeaviateClient options.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
def __init__(
|
|
60
|
+
self,
|
|
61
|
+
a3m_base_url: str = "http://localhost:8787",
|
|
62
|
+
embed_model: str = "auto",
|
|
63
|
+
weaviate_url: Optional[str] = None,
|
|
64
|
+
weaviate_client: Optional[WeaviateClient] = None,
|
|
65
|
+
**kwargs: Any,
|
|
66
|
+
) -> None:
|
|
67
|
+
# Initialize Weaviate client if URL provided
|
|
68
|
+
if weaviate_client:
|
|
69
|
+
# Copy internal state from provided client
|
|
70
|
+
self._connection = weaviate_client._connection
|
|
71
|
+
self._batch = weaviate_client._batch
|
|
72
|
+
self._schema = weaviate_client._schema
|
|
73
|
+
elif weaviate_url:
|
|
74
|
+
super().__init__(url=weaviate_url, **kwargs)
|
|
75
|
+
else:
|
|
76
|
+
# Initialize with empty client for embedding-only use
|
|
77
|
+
self._connection = None
|
|
78
|
+
self._batch = None
|
|
79
|
+
self._schema = None
|
|
80
|
+
|
|
81
|
+
self._a3m_router = A3MRouter(base_url=a3m_base_url, default_model=embed_model)
|
|
82
|
+
self._embed_model = embed_model
|
|
83
|
+
|
|
84
|
+
def embed_query(
|
|
85
|
+
self,
|
|
86
|
+
query: str,
|
|
87
|
+
**kwargs: Any,
|
|
88
|
+
) -> List[float]:
|
|
89
|
+
"""
|
|
90
|
+
Generate embedding for a query string.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
query: Text to embed.
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
Embedding vector (list of floats).
|
|
97
|
+
"""
|
|
98
|
+
try:
|
|
99
|
+
response = self._a3m_router.embed(texts=[query], model=self._embed_model)
|
|
100
|
+
return response.embedding
|
|
101
|
+
except A3MRouterError as e:
|
|
102
|
+
logger.error(f"A3M Router embedding error: {e}")
|
|
103
|
+
raise
|
|
104
|
+
|
|
105
|
+
def embed_texts(
|
|
106
|
+
self,
|
|
107
|
+
texts: List[str],
|
|
108
|
+
**kwargs: Any,
|
|
109
|
+
) -> List[List[float]]:
|
|
110
|
+
"""
|
|
111
|
+
Generate embeddings for multiple texts.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
texts: List of texts to embed.
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
List of embedding vectors.
|
|
118
|
+
"""
|
|
119
|
+
try:
|
|
120
|
+
response = self._a3m_router.embed(texts=texts, model=self._embed_model)
|
|
121
|
+
if isinstance(response, list):
|
|
122
|
+
return [r.embedding for r in response]
|
|
123
|
+
return [response.embedding]
|
|
124
|
+
except A3MRouterError as e:
|
|
125
|
+
logger.error(f"A3M Router embedding error: {e}")
|
|
126
|
+
raise
|
|
127
|
+
|
|
128
|
+
def with_near_text(
|
|
129
|
+
self,
|
|
130
|
+
query: str,
|
|
131
|
+
**kwargs: Any,
|
|
132
|
+
) -> "WeaviateNearText":
|
|
133
|
+
"""
|
|
134
|
+
Create a near-text search using A3M embeddings.
|
|
135
|
+
|
|
136
|
+
Args:
|
|
137
|
+
query: Text to search for.
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
WeaviateNearText object ready for .do()
|
|
141
|
+
"""
|
|
142
|
+
embedding = self.embed_query(query)
|
|
143
|
+
return WeaviateNearText(
|
|
144
|
+
client=self,
|
|
145
|
+
text=query,
|
|
146
|
+
embedding=embedding,
|
|
147
|
+
**kwargs,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
def rag_search(
|
|
151
|
+
self,
|
|
152
|
+
query: str,
|
|
153
|
+
class_name: str,
|
|
154
|
+
properties: List[str],
|
|
155
|
+
limit: int = 5,
|
|
156
|
+
**kwargs: Any,
|
|
157
|
+
) -> Dict[str, Any]:
|
|
158
|
+
"""
|
|
159
|
+
Perform RAG search: embed query + Weaviate search + context build.
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
query: User query string.
|
|
163
|
+
class_name: Weaviate class to search.
|
|
164
|
+
properties: Properties to return.
|
|
165
|
+
limit: Number of results.
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
Dict with 'chunks', 'context', 'answer', 'provider'.
|
|
169
|
+
"""
|
|
170
|
+
# 1. Embed query via A3M
|
|
171
|
+
query_embedding = self.embed_query(query)
|
|
172
|
+
|
|
173
|
+
# 2. Search Weaviate
|
|
174
|
+
try:
|
|
175
|
+
results = (
|
|
176
|
+
self.query
|
|
177
|
+
.get(class_name, properties)
|
|
178
|
+
.with_near_vector({"vector": query_embedding})
|
|
179
|
+
.with_limit(limit)
|
|
180
|
+
.do()
|
|
181
|
+
)
|
|
182
|
+
except Exception as e:
|
|
183
|
+
logger.warning(f"Weaviate search error: {e}")
|
|
184
|
+
results = {"data": {"Get": {class_name: []}}}
|
|
185
|
+
|
|
186
|
+
# 3. Extract chunks
|
|
187
|
+
data = results.get("data", {}).get("Get", {}).get(class_name, [])
|
|
188
|
+
chunks = []
|
|
189
|
+
for item in data:
|
|
190
|
+
text = " ".join([str(item.get(p, "")) for p in properties if p in item])
|
|
191
|
+
chunks.append(text)
|
|
192
|
+
|
|
193
|
+
context = "\n\n".join(chunks)
|
|
194
|
+
|
|
195
|
+
# 4. Generate answer via A3M
|
|
196
|
+
answer = None
|
|
197
|
+
provider = None
|
|
198
|
+
if chunks:
|
|
199
|
+
try:
|
|
200
|
+
response = self._a3m_router.chat(
|
|
201
|
+
messages=[{
|
|
202
|
+
"role": "user",
|
|
203
|
+
"content": f"Context:\n{context}\n\nQuestion: {query}\n\nAnswer concisely:"
|
|
204
|
+
}],
|
|
205
|
+
model=self._embed_model,
|
|
206
|
+
)
|
|
207
|
+
answer = response.content
|
|
208
|
+
provider = response.provider
|
|
209
|
+
except A3MRouterError:
|
|
210
|
+
answer = chunks[0] if chunks else ""
|
|
211
|
+
provider = "weaviate"
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
"chunks": chunks,
|
|
215
|
+
"context": context,
|
|
216
|
+
"answer": answer,
|
|
217
|
+
"provider": provider,
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
class WeaviateNearText:
|
|
221
|
+
"""Helper class for near-text search with A3M embeddings."""
|
|
222
|
+
|
|
223
|
+
def __init__(
|
|
224
|
+
self,
|
|
225
|
+
client: WeaviateAdapter,
|
|
226
|
+
text: str,
|
|
227
|
+
embedding: List[float],
|
|
228
|
+
certainty: Optional[float] = None,
|
|
229
|
+
distance: Optional[float] = None,
|
|
230
|
+
) -> None:
|
|
231
|
+
self._client = client
|
|
232
|
+
self._text = text
|
|
233
|
+
self._embedding = embedding
|
|
234
|
+
self._certainty = certainty
|
|
235
|
+
self._distance = distance
|
|
236
|
+
|
|
237
|
+
def with_limit(self, limit: int) -> "WeaviateNearText":
|
|
238
|
+
"""Set result limit."""
|
|
239
|
+
self._limit = limit
|
|
240
|
+
return self
|
|
241
|
+
|
|
242
|
+
def do(self) -> Dict[str, Any]:
|
|
243
|
+
"""Execute the search."""
|
|
244
|
+
near_vector = {"vector": self._embedding}
|
|
245
|
+
if self._certainty is not None:
|
|
246
|
+
near_vector["certainty"] = self._certainty
|
|
247
|
+
if self._distance is not None:
|
|
248
|
+
near_vector["distance"] = self._distance
|
|
249
|
+
|
|
250
|
+
return self._client.query.get(
|
|
251
|
+
self._class_name,
|
|
252
|
+
self._properties
|
|
253
|
+
).with_near_vector(near_vector).with_limit(
|
|
254
|
+
getattr(self, "_limit", 10)
|
|
255
|
+
).do()
|
|
256
|
+
|
|
257
|
+
else:
|
|
258
|
+
class WeaviateAdapter:
|
|
259
|
+
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
260
|
+
raise ImportError(
|
|
261
|
+
"Weaviate client not installed. "
|
|
262
|
+
"Install with: pip install weaviate-client"
|
|
263
|
+
)
|
package/python/a3m/client.py
CHANGED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: a3m-router
|
|
3
|
+
Version: 2.2.2
|
|
4
|
+
Summary: Auto-selects cheapest capable LLM from 47+ providers — 70-95% cost savings
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/Das-rebel/a3m-router
|
|
7
|
+
Project-URL: Documentation, https://das-rebel.github.io/a3m-router
|
|
8
|
+
Project-URL: Repository, https://github.com/Das-rebel/a3m-router
|
|
9
|
+
Project-URL: Changelog, https://github.com/Das-rebel/a3m-router/releases
|
|
10
|
+
Keywords: llm,routing,openai,proxy,ai-gateway,routellm,litellm,multi-llm,model-selection,cost-optimization,langchain,llamaindex,rag,vector-search,embeddings,parallel,ensemble,router
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
23
|
+
Requires-Python: >=3.8
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
Requires-Dist: httpx>=0.24.0
|
|
26
|
+
Provides-Extra: langchain
|
|
27
|
+
Requires-Dist: langchain>=0.1.0; extra == "langchain"
|
|
28
|
+
Provides-Extra: llamaindex
|
|
29
|
+
Requires-Dist: llamaindex>=0.9.0; extra == "llamaindex"
|
|
30
|
+
Provides-Extra: qdrant
|
|
31
|
+
Requires-Dist: qdrant-client>=1.7.0; extra == "qdrant"
|
|
32
|
+
Provides-Extra: weaviate
|
|
33
|
+
Requires-Dist: weaviate-client>=4.0.0; extra == "weaviate"
|
|
34
|
+
Provides-Extra: adapters
|
|
35
|
+
Requires-Dist: langchain>=0.1.0; extra == "adapters"
|
|
36
|
+
Requires-Dist: llamaindex>=0.9.0; extra == "adapters"
|
|
37
|
+
Requires-Dist: qdrant-client>=1.7.0; extra == "adapters"
|
|
38
|
+
Requires-Dist: weaviate-client>=4.0.0; extra == "adapters"
|
|
39
|
+
Provides-Extra: dev
|
|
40
|
+
Requires-Dist: pytest>=7.4.0; extra == "dev"
|
|
41
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
42
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
43
|
+
|
|
44
|
+
# A3M Router Python SDK
|
|
45
|
+
|
|
46
|
+
**Intelligent LLM routing — auto-selects the cheapest capable model from 47+ providers.**
|
|
47
|
+
|
|
48
|
+
Routes queries to the best model for your needs — whether it's Groq for simple Q&A ($0.001/1K) or GPT-4o for complex reasoning ($0.15/1K).
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install a3m-router
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quick Start
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from a3m import A3MRouter
|
|
60
|
+
|
|
61
|
+
router = A3MRouter(base_url="http://localhost:8787")
|
|
62
|
+
|
|
63
|
+
# Auto-routes to optimal provider
|
|
64
|
+
response = await router.chat("What is 2+2?")
|
|
65
|
+
# → Routes to Groq, costs ~$0.000001
|
|
66
|
+
|
|
67
|
+
# See routing decision before executing
|
|
68
|
+
decision = await router.route("Explain quantum computing")
|
|
69
|
+
print(f"Model: {decision.model}")
|
|
70
|
+
print(f"Tier: {decision.tier}")
|
|
71
|
+
print(f"Cost: ${decision.cost:.6f}")
|
|
72
|
+
|
|
73
|
+
# Stream responses
|
|
74
|
+
async for token in router.stream_chat("Tell me a story"):
|
|
75
|
+
print(token, end="", flush=True)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Key Features
|
|
79
|
+
|
|
80
|
+
- **Auto-routing**: Picks the right model based on query complexity, budget, and requirements
|
|
81
|
+
- **Cost savings**: 70-95% cheaper than always using premium models
|
|
82
|
+
- **47+ providers**: Groq, DeepSeek, GPT-4o, Claude, Mistral, and more
|
|
83
|
+
- **Framework adapters**: Drop-in for LangChain, LlamaIndex, Qdrant, Weaviate
|
|
84
|
+
- **Health monitoring**: Check provider status and availability
|
|
85
|
+
- **Cost analytics**: Track spending and savings
|
|
86
|
+
|
|
87
|
+
## Framework Adapters
|
|
88
|
+
|
|
89
|
+
| Adapter | Use Case | Install |
|
|
90
|
+
|---------|----------|---------|
|
|
91
|
+
| **LangChain** | Chain-based AI workflows | `pip install a3m-router[langchain]` |
|
|
92
|
+
| **LlamaIndex** | RAG and document QA | `pip install a3m-router[llamaindex]` |
|
|
93
|
+
| **Qdrant** | Vector search + RAG | `pip install a3m-router[qdrant]` |
|
|
94
|
+
| **Weaviate** | Vector search + RAG | `pip install a3m-router[weaviate]` |
|
|
95
|
+
|
|
96
|
+
All adapters:
|
|
97
|
+
```bash
|
|
98
|
+
pip install a3m-router[all]
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Routing Tiers
|
|
102
|
+
|
|
103
|
+
| Tier | Providers | Cost | When Used |
|
|
104
|
+
|------|-----------|------|-----------|
|
|
105
|
+
| **free** | Ollama, vLLM | $0 | Local inference |
|
|
106
|
+
| **cheap** | Groq, DeepSeek | ~$0.001/1K | Simple Q&A, short code |
|
|
107
|
+
| **mid** | GPT-4o-mini, Claude-haiku | ~$0.01/1K | Standard tasks |
|
|
108
|
+
| **premium** | GPT-4o, Claude-sonnet | ~$0.15/1K | Complex reasoning |
|
|
109
|
+
|
|
110
|
+
## API Reference
|
|
111
|
+
|
|
112
|
+
### A3MRouter
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
router = A3MRouter(
|
|
116
|
+
base_url="http://localhost:8787", # A3M Router server URL
|
|
117
|
+
timeout=30.0, # Request timeout
|
|
118
|
+
)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
| Method | Description |
|
|
122
|
+
|--------|-------------|
|
|
123
|
+
| `chat(message)` | Send chat message with auto-routing |
|
|
124
|
+
| `route(query)` | Get routing decision (no execution) |
|
|
125
|
+
| `route_batch(queries)` | Route multiple queries |
|
|
126
|
+
| `stream_chat(message)` | Stream response tokens |
|
|
127
|
+
| `models()` | List all available models |
|
|
128
|
+
| `health()` | Provider health status |
|
|
129
|
+
| `cost_report()` | Cost analytics |
|
|
130
|
+
|
|
131
|
+
### LangChain Example
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
from a3m import LangChainAdapter
|
|
135
|
+
from langchain.schema import HumanMessage
|
|
136
|
+
|
|
137
|
+
llm = LangChainAdapter(base_url="http://localhost:8787")
|
|
138
|
+
response = llm([HumanMessage(content="What is RAG?")])
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### LlamaIndex Example
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
from a3m import LlamaIndexAdapter
|
|
145
|
+
|
|
146
|
+
llm = LlamaIndexAdapter()
|
|
147
|
+
response = llm.complete("Explain transformers")
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Server Setup
|
|
151
|
+
|
|
152
|
+
Start the A3M Router server:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
# Via npm
|
|
156
|
+
npx a3m-router serve
|
|
157
|
+
|
|
158
|
+
# Via Docker
|
|
159
|
+
docker-compose up -d
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Server runs on `http://localhost:8787` by default.
|
|
163
|
+
|
|
164
|
+
## Links
|
|
165
|
+
|
|
166
|
+
- **GitHub**: https://github.com/Das-rebel/a3m-router
|
|
167
|
+
- **npm Package**: https://www.npmjs.com/package/adaptive-memory-multi-model-router
|
|
168
|
+
- **Documentation**: https://das-rebel.github.io/a3m-router
|
|
169
|
+
|
|
170
|
+
## License
|
|
171
|
+
|
|
172
|
+
MIT
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
setup.py
|
|
4
|
+
a3m/__init__.py
|
|
5
|
+
a3m/client.py
|
|
6
|
+
a3m/models.py
|
|
7
|
+
a3m/sync_client.py
|
|
8
|
+
a3m/adapters/__init__.py
|
|
9
|
+
a3m/adapters/langchain.py
|
|
10
|
+
a3m/adapters/llamaindex.py
|
|
11
|
+
a3m/adapters/qdrant.py
|
|
12
|
+
a3m/adapters/weaviate.py
|
|
13
|
+
a3m_router.egg-info/PKG-INFO
|
|
14
|
+
a3m_router.egg-info/SOURCES.txt
|
|
15
|
+
a3m_router.egg-info/dependency_links.txt
|
|
16
|
+
a3m_router.egg-info/requires.txt
|
|
17
|
+
a3m_router.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
httpx>=0.24.0
|
|
2
|
+
|
|
3
|
+
[adapters]
|
|
4
|
+
langchain>=0.1.0
|
|
5
|
+
llamaindex>=0.9.0
|
|
6
|
+
qdrant-client>=1.7.0
|
|
7
|
+
weaviate-client>=4.0.0
|
|
8
|
+
|
|
9
|
+
[dev]
|
|
10
|
+
pytest>=7.4.0
|
|
11
|
+
pytest-asyncio>=0.21.0
|
|
12
|
+
black>=23.0.0
|
|
13
|
+
|
|
14
|
+
[langchain]
|
|
15
|
+
langchain>=0.1.0
|
|
16
|
+
|
|
17
|
+
[llamaindex]
|
|
18
|
+
llamaindex>=0.9.0
|
|
19
|
+
|
|
20
|
+
[qdrant]
|
|
21
|
+
qdrant-client>=1.7.0
|
|
22
|
+
|
|
23
|
+
[weaviate]
|
|
24
|
+
weaviate-client>=4.0.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
a3m
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Build and verify Python SDK
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
echo "=== Building A3M Router Python SDK v2.2.0 ==="
|
|
6
|
+
cd "$(dirname "$0")"
|
|
7
|
+
|
|
8
|
+
echo "1. Installing build dependencies..."
|
|
9
|
+
pip install build twine 2>/dev/null || pip3 install build twine
|
|
10
|
+
|
|
11
|
+
echo "2. Cleaning old builds..."
|
|
12
|
+
rm -rf dist/ build/ *.egg-info
|
|
13
|
+
|
|
14
|
+
echo "3. Building package..."
|
|
15
|
+
python -m build
|
|
16
|
+
|
|
17
|
+
echo "4. Checking package..."
|
|
18
|
+
python -m twine check dist/*
|
|
19
|
+
|
|
20
|
+
echo "5. Listing built files..."
|
|
21
|
+
ls -lh dist/
|
|
22
|
+
|
|
23
|
+
echo ""
|
|
24
|
+
echo "=== Build complete! ==="
|
|
25
|
+
echo "To publish to Test PyPI:"
|
|
26
|
+
echo " cd python && python -m twine upload --repository testpypi dist/*"
|
|
27
|
+
echo ""
|
|
28
|
+
echo "To publish to PyPI:"
|
|
29
|
+
echo " cd python && python -m twine upload dist/*"
|
|
30
|
+
echo ""
|
|
31
|
+
echo "To install locally:"
|
|
32
|
+
echo " pip install dist/a3m_router-*.whl"
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|