adaptive-memory-multi-model-router 2.15.3 → 2.15.4
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/ISSUE_TEMPLATE/bug_report.md +94 -0
- package/.github/ISSUE_TEMPLATE/config.yml +17 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +71 -0
- package/.well-known/ai-plugin.json +16 -0
- package/AGENT_COUNCIL_FINDINGS.md +98 -123
- package/POPULARITY_BOOSTERS.md +1 -1
- package/README.md +275 -147
- package/README_ja.md +20 -16
- package/README_zh.md +17 -13
- package/adapters/README.md +36 -0
- package/adapters/__init__.py +25 -0
- package/adapters/a3m_adapter/__init__.py +15 -0
- package/adapters/a3m_adapter/adapter/__init__.py +7 -0
- package/adapters/a3m_adapter/adapter/config.py +100 -0
- package/adapters/a3m_adapter/adapter/langchain.py +155 -0
- package/adapters/a3m_adapter/adapter/llamaindex.py +162 -0
- package/adapters/a3m_adapter/tests/__init__.py +1 -0
- package/adapters/a3m_adapter/tests/test_adapters.py +120 -0
- package/adapters/setup.py +23 -0
- package/articles/CHINESE_DIRECTORIES.md +2 -2
- package/articles/CHINESE_SUBMISSIONS_READY.md +5 -5
- package/articles/HN_POST_READY.md +20 -16
- package/articles/INDIEHACKERS_READY.md +34 -19
- package/dist/analytics/costAnalytics.d.ts +1 -0
- package/dist/benchmark/reproducible.d.ts +1 -0
- package/dist/cache/semanticCache.d.ts +1 -0
- package/dist/cost/budgetEnforcer.d.ts +1 -0
- package/dist/cost/costTracker.d.ts +1 -0
- package/dist/ensemble/multiRoundDialog.d.ts +1 -0
- package/dist/ensemble/shapleyValue.d.ts +1 -0
- package/dist/ensemble.d.ts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/integrations/oauth.d.ts +1 -0
- package/dist/integrations/scienceAdapter.d.ts +1 -0
- package/dist/memory/autoFetch.d.ts +1 -0
- package/dist/memory/hybridMemory.d.ts +1 -0
- package/dist/memory/memoryTree.d.ts +1 -0
- package/dist/memory/obsidianVault.d.ts +1 -0
- package/dist/memory/reasoningBank.d.ts +1 -0
- package/dist/observability/changeWatch.d.ts +1 -0
- package/dist/observability/fatigueDetector.d.ts +1 -0
- package/dist/observability/index.d.ts +1 -0
- package/dist/observability/metrics.d.ts +1 -0
- package/dist/observability/middleware.d.ts +1 -0
- package/dist/observability/tracer.d.ts +1 -0
- package/dist/observability/types.d.ts +1 -0
- package/dist/providers/providerConfig.d.ts +1 -0
- package/dist/routing/advancedRouter.d.ts +2 -1
- package/dist/routing/advancedRouter.js +0 -84
- package/dist/routing/advancedRouter.js.map +1 -1
- package/dist/routing/crossModelValidation.d.ts +1 -0
- package/dist/routing/providerHealth.d.ts +2 -77
- package/dist/routing/providerHealth.js +4 -190
- package/dist/routing/providerHealth.js.map +1 -1
- package/dist/routing/providerRetry.d.ts +1 -0
- package/dist/sdk.d.ts +1 -0
- package/dist/security/guardrails.d.ts +1 -0
- package/dist/server/dashboard.d.ts +1 -0
- package/dist/server/handlers/chatHandler.d.ts +1 -0
- package/dist/server/handlers/completionsHandler.d.ts +1 -0
- package/dist/server/handlers/embeddingsHandler.d.ts +1 -0
- package/dist/server/handlers/healthHandler.d.ts +1 -0
- package/dist/server/handlers/metricsHandler.d.ts +1 -0
- package/dist/server/handlers/modelsHandler.d.ts +1 -0
- package/dist/server/metrics.d.ts +1 -0
- package/dist/server/modelMapper.d.ts +1 -0
- package/dist/server/proxyServer.d.ts +1 -0
- package/dist/server/router.d.ts +1 -0
- package/dist/server/state.d.ts +1 -0
- package/dist/tui/dashboard.d.ts +1 -0
- package/dist/utils/costUtils.d.ts +1 -0
- package/dist/utils/sorting.d.ts +1 -0
- package/dist/utils/tokenUtils.d.ts +1 -0
- package/docs/llms-full.txt +286 -153
- package/docs/llms.txt +112 -71
- package/llms-full.txt +6 -6
- package/llms.txt +112 -62
- package/package.json +12 -91
- package/CAMPAIGN_SUMMARY.md +0 -87
- package/ENTERPRISE_INTEGRATIONS.md +0 -94
- package/INTEGRATION_PROGRESS.md +0 -96
- package/OPPORTUNITIES_100.md +0 -277
- package/TODO_BROWSER_AUTOMATION.md +0 -87
- package/a3m-integrations-summary.md +0 -73
- package/dist/routing/shadowSampler.d.ts +0 -187
- package/dist/routing/shadowSampler.js +0 -306
- package/dist/routing/shadowSampler.js.map +0 -1
- package/integrations/browser-use/README.md +0 -155
- package/integrations/browser-use/examples/form-filling.ts +0 -179
- package/integrations/browser-use/index.ts +0 -145
- package/integrations/browser-use/package.json +0 -34
- package/integrations/browser-use/tsconfig.json +0 -17
- package/integrations/mcp-browser/README.md +0 -177
- package/integrations/mcp-browser/package.json +0 -38
- package/integrations/mcp-browser/src/index.ts +0 -297
- package/integrations/sota-browser/README.md +0 -191
- package/integrations/sota-browser/package.json +0 -34
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A3M Router + browser-use Integration
|
|
3
|
-
*
|
|
4
|
-
* Provides intelligent LLM routing for browser automation tasks.
|
|
5
|
-
* - Routes to cheapest capable model automatically
|
|
6
|
-
* - Stealth mode for anti-detection
|
|
7
|
-
* - Parallel ensemble for reliable extraction
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { A3MRouter, BrowserConfig } from 'adaptive-memory-multi-model-router';
|
|
11
|
-
|
|
12
|
-
export interface BrowserUseA3MConfig extends BrowserConfig {
|
|
13
|
-
/**
|
|
14
|
-
* Enable stealth mode to minimize bot detection
|
|
15
|
-
* @default false
|
|
16
|
-
*/
|
|
17
|
-
stealth?: boolean;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Number of providers to run in parallel for ensemble voting
|
|
21
|
-
* @default 1
|
|
22
|
-
*/
|
|
23
|
-
parallelEnsemble?: number;
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Enable browser-specific optimizations
|
|
27
|
-
* @default true
|
|
28
|
-
*/
|
|
29
|
-
browserOptimized?: boolean;
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Preferred models for browser tasks (in order of preference)
|
|
33
|
-
*/
|
|
34
|
-
preferredBrowserModels?: string[];
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Get a browser-use compatible LLM wrapper from A3M Router
|
|
39
|
-
*/
|
|
40
|
-
export function getBrowserUseLLM(config: BrowserUseA3MConfig) {
|
|
41
|
-
const a3m = new A3MRouter({
|
|
42
|
-
model: config.model || 'auto',
|
|
43
|
-
stealth: config.stealth || false,
|
|
44
|
-
parallelEnsemble: config.parallelEnsemble || 1,
|
|
45
|
-
providers: config.providers,
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
// Return a wrapper that's compatible with browser-use's LLM interface
|
|
49
|
-
return {
|
|
50
|
-
a3m,
|
|
51
|
-
|
|
52
|
-
// Browser-use compatible interface
|
|
53
|
-
async chat(messages: any[]) {
|
|
54
|
-
const lastMessage = messages[messages.length - 1];
|
|
55
|
-
|
|
56
|
-
const result = await a3m.route({
|
|
57
|
-
task: lastMessage.content,
|
|
58
|
-
context: 'browser_automation',
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
return {
|
|
62
|
-
choices: [{
|
|
63
|
-
message: {
|
|
64
|
-
role: 'assistant',
|
|
65
|
-
content: result.content,
|
|
66
|
-
},
|
|
67
|
-
}],
|
|
68
|
-
};
|
|
69
|
-
},
|
|
70
|
-
|
|
71
|
-
// Get routing stats for monitoring
|
|
72
|
-
getStats() {
|
|
73
|
-
return a3m.getStats();
|
|
74
|
-
},
|
|
75
|
-
|
|
76
|
-
// Get cost for last N requests
|
|
77
|
-
getCost() {
|
|
78
|
-
return a3m.getCost();
|
|
79
|
-
},
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Create an A3M Router optimized for browser automation tasks
|
|
85
|
-
*/
|
|
86
|
-
export function createBrowserAutomationRouter(config: BrowserUseA3MConfig) {
|
|
87
|
-
const router = new A3MRouter({
|
|
88
|
-
model: config.model || 'auto',
|
|
89
|
-
stealth: config.stealth || true,
|
|
90
|
-
parallelEnsemble: config.parallelEnsemble || 3,
|
|
91
|
-
browserOptimized: config.browserOptimized !== false,
|
|
92
|
-
providers: config.providers || ['openai', 'anthropic', 'google', 'groq'],
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
return {
|
|
96
|
-
router,
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Route a browser task to the optimal provider
|
|
100
|
-
*/
|
|
101
|
-
async routeTask(task: string, context?: string) {
|
|
102
|
-
return router.route({
|
|
103
|
-
task,
|
|
104
|
-
context: context || 'browser_automation',
|
|
105
|
-
});
|
|
106
|
-
},
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Extract structured data from a page
|
|
110
|
-
*/
|
|
111
|
-
async extractData(pageSchema: any, html: string) {
|
|
112
|
-
return router.route({
|
|
113
|
-
task: `Extract structured data from this HTML matching the schema: ${JSON.stringify(pageSchema)}`,
|
|
114
|
-
context: 'data_extraction',
|
|
115
|
-
});
|
|
116
|
-
},
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Fill a form with optimal model selection
|
|
120
|
-
*/
|
|
121
|
-
async fillForm(formSchema: any, data: any) {
|
|
122
|
-
return router.route({
|
|
123
|
-
task: `Fill this form with data: ${JSON.stringify(data)}. Form schema: ${JSON.stringify(formSchema)}`,
|
|
124
|
-
context: 'form_filling',
|
|
125
|
-
});
|
|
126
|
-
},
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Get stealth routing configuration
|
|
130
|
-
*/
|
|
131
|
-
getStealthConfig() {
|
|
132
|
-
return {
|
|
133
|
-
stealth: config.stealth || true,
|
|
134
|
-
proxyRotation: true,
|
|
135
|
-
humanizeTiming: true,
|
|
136
|
-
randomizeUserAgent: true,
|
|
137
|
-
};
|
|
138
|
-
},
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export default {
|
|
143
|
-
getBrowserUseLLM,
|
|
144
|
-
createBrowserAutomationRouter,
|
|
145
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "a3m-browser-use",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"description": "A3M Router integration for browser-use - cost-optimized browser automation",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"types": "dist/index.d.ts",
|
|
7
|
-
"scripts": {
|
|
8
|
-
"build": "tsc",
|
|
9
|
-
"prepublishOnly": "npm run build"
|
|
10
|
-
},
|
|
11
|
-
"dependencies": {
|
|
12
|
-
"adaptive-memory-multi-model-router": "^2.14.0",
|
|
13
|
-
"browser-use": "^0.12.0"
|
|
14
|
-
},
|
|
15
|
-
"peerDependencies": {
|
|
16
|
-
"browser-use": "^0.12.0"
|
|
17
|
-
},
|
|
18
|
-
"keywords": [
|
|
19
|
-
"browser-use",
|
|
20
|
-
"a3m",
|
|
21
|
-
"llm",
|
|
22
|
-
"router",
|
|
23
|
-
"browser-automation",
|
|
24
|
-
"cost-optimization",
|
|
25
|
-
"stealth",
|
|
26
|
-
"anti-detection"
|
|
27
|
-
],
|
|
28
|
-
"repository": {
|
|
29
|
-
"type": "git",
|
|
30
|
-
"url": "https://github.com/Das-rebel/a3m-router"
|
|
31
|
-
},
|
|
32
|
-
"author": "Subhojit Das",
|
|
33
|
-
"license": "MIT"
|
|
34
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"outDir": "./dist",
|
|
7
|
-
"rootDir": "./src",
|
|
8
|
-
"strict": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"declaration": true,
|
|
12
|
-
"declarationMap": true,
|
|
13
|
-
"sourceMap": true
|
|
14
|
-
},
|
|
15
|
-
"include": ["src/**/*"],
|
|
16
|
-
"exclude": ["node_modules", "dist", "examples"]
|
|
17
|
-
}
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
# A3M Router MCP Server for Browser Automation
|
|
2
|
-
|
|
3
|
-
**Use A3M's intelligent routing as an MCP server for AI agents.**
|
|
4
|
-
|
|
5
|
-
This integration exposes A3M Router's capabilities via the Model Context Protocol (MCP), enabling AI agents (Claude Desktop, Cursor, Codex, n8n, etc.) to use intelligent LLM routing for browser automation tasks.
|
|
6
|
-
|
|
7
|
-
## What is MCP?
|
|
8
|
-
|
|
9
|
-
The [Model Context Protocol](https://modelcontextprotocol.io/) is an open standard for connecting AI assistants to external tools and data sources. MCP servers expose capabilities as "tools" that AI agents can call.
|
|
10
|
-
|
|
11
|
-
## Installation
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
npm install a3m-mcp-browser
|
|
15
|
-
# or
|
|
16
|
-
npx a3m-mcp-browser
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## Setup
|
|
20
|
-
|
|
21
|
-
### Claude Desktop
|
|
22
|
-
|
|
23
|
-
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
24
|
-
|
|
25
|
-
```json
|
|
26
|
-
{
|
|
27
|
-
"mcpServers": {
|
|
28
|
-
"a3m-browser": {
|
|
29
|
-
"command": "npx",
|
|
30
|
-
"args": ["a3m-mcp-browser"]
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
### Cursor
|
|
37
|
-
|
|
38
|
-
Settings → MCP → Add new server:
|
|
39
|
-
|
|
40
|
-
```json
|
|
41
|
-
{
|
|
42
|
-
"name": "a3m-browser",
|
|
43
|
-
"command": "npx",
|
|
44
|
-
"args": ["a3m-mcp-browser"]
|
|
45
|
-
}
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### n8n
|
|
49
|
-
|
|
50
|
-
Add MCP Trigger node with server config above.
|
|
51
|
-
|
|
52
|
-
## Available Tools
|
|
53
|
-
|
|
54
|
-
### `route_for_browser_task`
|
|
55
|
-
|
|
56
|
-
Route a browser task to the optimal LLM provider.
|
|
57
|
-
|
|
58
|
-
```json
|
|
59
|
-
{
|
|
60
|
-
"task": "Extract all job listings from this page including title, company, and apply URL",
|
|
61
|
-
"context": "web_scraping"
|
|
62
|
-
}
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
**Context options:**
|
|
66
|
-
- `web_scraping` - Data extraction from web pages
|
|
67
|
-
- `form_filling` - Filling out web forms
|
|
68
|
-
- `form_analysis` - Analyzing form structure
|
|
69
|
-
- `content_generation` - Generating content for web
|
|
70
|
-
- `decision_making` - Making decisions based on page content
|
|
71
|
-
|
|
72
|
-
### `extract_form_data`
|
|
73
|
-
|
|
74
|
-
Extract structured data from a web page.
|
|
75
|
-
|
|
76
|
-
```json
|
|
77
|
-
{
|
|
78
|
-
"page_html": "<html>...</html>",
|
|
79
|
-
"schema": {
|
|
80
|
-
"name": "string",
|
|
81
|
-
"email": "string",
|
|
82
|
-
"jobs": "array"
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
### `fill_form_intelligently`
|
|
88
|
-
|
|
89
|
-
Get optimal values to fill a form field.
|
|
90
|
-
|
|
91
|
-
```json
|
|
92
|
-
{
|
|
93
|
-
"field_name": "email",
|
|
94
|
-
"field_type": "email",
|
|
95
|
-
"user_profile": {
|
|
96
|
-
"email": "user@example.com"
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
### `get_stealth_routing`
|
|
102
|
-
|
|
103
|
-
Get routing configuration optimized for stealth.
|
|
104
|
-
|
|
105
|
-
```json
|
|
106
|
-
{
|
|
107
|
-
"minimize_detection": true,
|
|
108
|
-
"provider_rotation": true
|
|
109
|
-
}
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
## Example Workflow
|
|
113
|
-
|
|
114
|
-
### Claude Desktop
|
|
115
|
-
|
|
116
|
-
```
|
|
117
|
-
You: Use A3M to extract all job listings from linkedin.com/jobs/search?q=marketing
|
|
118
|
-
|
|
119
|
-
Claude: I'll use the A3M router to extract the job data...
|
|
120
|
-
|
|
121
|
-
[Calls route_for_browser_task with task="Extract all job listings..."]
|
|
122
|
-
|
|
123
|
-
Claude: I found 25 jobs. Here's the first few:
|
|
124
|
-
|
|
125
|
-
1. **Head of Marketing** @ TechCorp
|
|
126
|
-
- URL: https://linkedin.com/jobs/view/123
|
|
127
|
-
- Location: Bengaluru
|
|
128
|
-
- Posted: 2 days ago
|
|
129
|
-
|
|
130
|
-
2. **VP Growth** @ StartupXYZ
|
|
131
|
-
- URL: https://linkedin.com/jobs/view/456
|
|
132
|
-
- Location: Mumbai
|
|
133
|
-
- Posted: 5 days ago
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
### Cursor
|
|
137
|
-
|
|
138
|
-
```
|
|
139
|
-
User: Fill out this job application form using my resume data
|
|
140
|
-
|
|
141
|
-
Cursor: I'll use A3M to intelligently fill the form...
|
|
142
|
-
|
|
143
|
-
[Calls fill_form_intelligently for each field]
|
|
144
|
-
|
|
145
|
-
[Calls route_for_browser_task to verify form completion]
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
## Cost Savings
|
|
149
|
-
|
|
150
|
-
| Task Type | Without A3M | With A3M | Savings |
|
|
151
|
-
|-----------|-------------|----------|---------|
|
|
152
|
-
| Form filling | $0.03/task | $0.002/task | 93% |
|
|
153
|
-
| Data extraction | $0.01/task | $0.003/task | 70% |
|
|
154
|
-
| Page analysis | $0.02/task | $0.005/task | 75% |
|
|
155
|
-
|
|
156
|
-
## Features
|
|
157
|
-
|
|
158
|
-
- **Automatic routing** - Routes to cheapest capable model
|
|
159
|
-
- **Stealth mode** - Minimize bot detection
|
|
160
|
-
- **Parallel ensemble** - Run multiple providers for reliability
|
|
161
|
-
- **Fallback handling** - Automatic retry on failure
|
|
162
|
-
- **Cost tracking** - Monitor spending per task
|
|
163
|
-
|
|
164
|
-
## Configuration
|
|
165
|
-
|
|
166
|
-
```json
|
|
167
|
-
{
|
|
168
|
-
"model": "auto",
|
|
169
|
-
"stealth": true,
|
|
170
|
-
"parallelEnsemble": 3,
|
|
171
|
-
"providers": ["openai", "anthropic", "google", "groq"]
|
|
172
|
-
}
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
## License
|
|
176
|
-
|
|
177
|
-
MIT - Same as A3M Router
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "a3m-mcp-browser",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"description": "A3M Router MCP server for browser automation",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"types": "dist/index.d.ts",
|
|
7
|
-
"bin": {
|
|
8
|
-
"a3m-mcp-browser": "dist/index.js"
|
|
9
|
-
},
|
|
10
|
-
"scripts": {
|
|
11
|
-
"build": "tsc",
|
|
12
|
-
"start": "node dist/index.js",
|
|
13
|
-
"dev": "tsc && node dist/index.js"
|
|
14
|
-
},
|
|
15
|
-
"dependencies": {
|
|
16
|
-
"adaptive-memory-multi-model-router": "^2.14.0",
|
|
17
|
-
"@modelcontextprotocol/sdk": "^0.5.0"
|
|
18
|
-
},
|
|
19
|
-
"engines": {
|
|
20
|
-
"node": ">=18.0.0"
|
|
21
|
-
},
|
|
22
|
-
"keywords": [
|
|
23
|
-
"mcp",
|
|
24
|
-
"model-context-protocol",
|
|
25
|
-
"a3m",
|
|
26
|
-
"browser-automation",
|
|
27
|
-
"llm-routing",
|
|
28
|
-
"claude",
|
|
29
|
-
"cursor",
|
|
30
|
-
"n8n"
|
|
31
|
-
],
|
|
32
|
-
"repository": {
|
|
33
|
-
"type": "git",
|
|
34
|
-
"url": "https://github.com/Das-rebel/a3m-router"
|
|
35
|
-
},
|
|
36
|
-
"author": "Subhojit Das",
|
|
37
|
-
"license": "MIT"
|
|
38
|
-
}
|
|
@@ -1,297 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A3M Router MCP Server for Browser Automation
|
|
3
|
-
*
|
|
4
|
-
* Exposes A3M's intelligent LLM routing as MCP tools for AI agents.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
8
|
-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
9
|
-
import {
|
|
10
|
-
CallToolRequestSchema,
|
|
11
|
-
ListToolsRequestSchema,
|
|
12
|
-
} from '@modelcontextprotocol/sdk/types.js';
|
|
13
|
-
import { A3MRouter } from 'adaptive-memory-multi-model-router';
|
|
14
|
-
|
|
15
|
-
// Initialize A3M Router
|
|
16
|
-
const router = new A3MRouter({
|
|
17
|
-
model: 'auto',
|
|
18
|
-
stealth: true,
|
|
19
|
-
parallelEnsemble: 3,
|
|
20
|
-
browserOptimized: true,
|
|
21
|
-
providers: ['openai', 'anthropic', 'google', 'groq'],
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
// Create MCP server
|
|
25
|
-
const server = new Server(
|
|
26
|
-
{
|
|
27
|
-
name: 'a3m-browser',
|
|
28
|
-
version: '1.0.0',
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
capabilities: {
|
|
32
|
-
tools: {},
|
|
33
|
-
},
|
|
34
|
-
}
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
// Define available tools
|
|
38
|
-
const tools = [
|
|
39
|
-
{
|
|
40
|
-
name: 'route_for_browser_task',
|
|
41
|
-
description: 'Route a browser automation task to the optimal LLM provider. Best for: web scraping, form filling, content extraction, page analysis.',
|
|
42
|
-
inputSchema: {
|
|
43
|
-
type: 'object',
|
|
44
|
-
properties: {
|
|
45
|
-
task: {
|
|
46
|
-
type: 'string',
|
|
47
|
-
description: 'The browser automation task to route',
|
|
48
|
-
},
|
|
49
|
-
context: {
|
|
50
|
-
type: 'string',
|
|
51
|
-
enum: ['web_scraping', 'form_filling', 'form_analysis', 'content_generation', 'decision_making'],
|
|
52
|
-
description: 'Type of browser task',
|
|
53
|
-
default: 'web_scraping',
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
required: ['task'],
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
name: 'extract_form_data',
|
|
61
|
-
description: 'Extract structured data from a web page HTML.',
|
|
62
|
-
inputSchema: {
|
|
63
|
-
type: 'object',
|
|
64
|
-
properties: {
|
|
65
|
-
page_html: {
|
|
66
|
-
type: 'string',
|
|
67
|
-
description: 'The HTML content of the page',
|
|
68
|
-
},
|
|
69
|
-
schema: {
|
|
70
|
-
type: 'object',
|
|
71
|
-
description: 'JSON schema describing what to extract',
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
|
-
required: ['page_html', 'schema'],
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
name: 'fill_form_intelligently',
|
|
79
|
-
description: 'Determine the best value to fill a form field with, based on user profile.',
|
|
80
|
-
inputSchema: {
|
|
81
|
-
type: 'object',
|
|
82
|
-
properties: {
|
|
83
|
-
field_name: {
|
|
84
|
-
type: 'string',
|
|
85
|
-
description: 'Name of the form field',
|
|
86
|
-
},
|
|
87
|
-
field_type: {
|
|
88
|
-
type: 'string',
|
|
89
|
-
description: 'Type of field (text, email, phone, etc.)',
|
|
90
|
-
},
|
|
91
|
-
user_profile: {
|
|
92
|
-
type: 'object',
|
|
93
|
-
description: 'User profile data to fill from',
|
|
94
|
-
},
|
|
95
|
-
},
|
|
96
|
-
required: ['field_name', 'field_type', 'user_profile'],
|
|
97
|
-
},
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
name: 'get_stealth_routing',
|
|
101
|
-
description: 'Get routing configuration optimized for stealth (minimizing bot detection).',
|
|
102
|
-
inputSchema: {
|
|
103
|
-
type: 'object',
|
|
104
|
-
properties: {
|
|
105
|
-
minimize_detection: {
|
|
106
|
-
type: 'boolean',
|
|
107
|
-
description: 'Enable stealth mode',
|
|
108
|
-
default: true,
|
|
109
|
-
},
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
name: 'get_cost_stats',
|
|
115
|
-
description: 'Get cost statistics for routing decisions.',
|
|
116
|
-
inputSchema: {
|
|
117
|
-
type: 'object',
|
|
118
|
-
properties: {},
|
|
119
|
-
},
|
|
120
|
-
},
|
|
121
|
-
];
|
|
122
|
-
|
|
123
|
-
// List tools handler
|
|
124
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
125
|
-
return { tools };
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
// Call tool handler
|
|
129
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
130
|
-
const { name, arguments: args } = request.params;
|
|
131
|
-
|
|
132
|
-
try {
|
|
133
|
-
switch (name) {
|
|
134
|
-
case 'route_for_browser_task': {
|
|
135
|
-
const { task, context = 'web_scraping' } = args as {
|
|
136
|
-
task: string;
|
|
137
|
-
context?: string;
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
const result = await router.route({
|
|
141
|
-
task,
|
|
142
|
-
context: context as any,
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
return {
|
|
146
|
-
content: [
|
|
147
|
-
{
|
|
148
|
-
type: 'text',
|
|
149
|
-
text: JSON.stringify({
|
|
150
|
-
content: result.content,
|
|
151
|
-
provider: result.provider,
|
|
152
|
-
model: result.model,
|
|
153
|
-
cost: result.cost,
|
|
154
|
-
}, null, 2),
|
|
155
|
-
},
|
|
156
|
-
],
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
case 'extract_form_data': {
|
|
161
|
-
const { page_html, schema } = args as {
|
|
162
|
-
page_html: string;
|
|
163
|
-
schema: any;
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
const result = await router.route({
|
|
167
|
-
task: `Extract structured data from this HTML matching the schema: ${JSON.stringify(schema)}`,
|
|
168
|
-
context: 'data_extraction',
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
return {
|
|
172
|
-
content: [
|
|
173
|
-
{
|
|
174
|
-
type: 'text',
|
|
175
|
-
text: result.content,
|
|
176
|
-
},
|
|
177
|
-
],
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
case 'fill_form_intelligently': {
|
|
182
|
-
const { field_name, field_type, user_profile } = args as {
|
|
183
|
-
field_name: string;
|
|
184
|
-
field_type: string;
|
|
185
|
-
user_profile: any;
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
// Map field types to profile keys
|
|
189
|
-
const fieldMappings: Record<string, string> = {
|
|
190
|
-
'first name': 'firstName',
|
|
191
|
-
'last name': 'lastName',
|
|
192
|
-
'email': 'email',
|
|
193
|
-
'phone': 'phone',
|
|
194
|
-
'name': 'fullName',
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
const profileKey = fieldMappings[field_name.toLowerCase()] || field_name.toLowerCase();
|
|
198
|
-
let value = user_profile[profileKey];
|
|
199
|
-
|
|
200
|
-
if (!value) {
|
|
201
|
-
// Try common variations
|
|
202
|
-
const variations = [
|
|
203
|
-
field_name.replace(/\s+/g, ''),
|
|
204
|
-
field_name.replace(/\s+/g, '_'),
|
|
205
|
-
field_name.toLowerCase(),
|
|
206
|
-
];
|
|
207
|
-
for (const v of variations) {
|
|
208
|
-
if (user_profile[v]) {
|
|
209
|
-
value = user_profile[v];
|
|
210
|
-
break;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
return {
|
|
216
|
-
content: [
|
|
217
|
-
{
|
|
218
|
-
type: 'text',
|
|
219
|
-
text: JSON.stringify({
|
|
220
|
-
field: field_name,
|
|
221
|
-
suggested_value: value || '',
|
|
222
|
-
provider: 'profile_lookup',
|
|
223
|
-
}, null, 2),
|
|
224
|
-
},
|
|
225
|
-
],
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
case 'get_stealth_routing': {
|
|
230
|
-
return {
|
|
231
|
-
content: [
|
|
232
|
-
{
|
|
233
|
-
type: 'text',
|
|
234
|
-
text: JSON.stringify({
|
|
235
|
-
stealth: true,
|
|
236
|
-
proxy_rotation: true,
|
|
237
|
-
humanize_timing: true,
|
|
238
|
-
randomize_user_agent: true,
|
|
239
|
-
recommended_providers: ['anthropic', 'google'],
|
|
240
|
-
avoid_providers: ['openai-gpt4'], // Rate limited sites
|
|
241
|
-
}, null, 2),
|
|
242
|
-
},
|
|
243
|
-
],
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
case 'get_cost_stats': {
|
|
248
|
-
const stats = router.getStats();
|
|
249
|
-
const cost = router.getCost();
|
|
250
|
-
|
|
251
|
-
return {
|
|
252
|
-
content: [
|
|
253
|
-
{
|
|
254
|
-
type: 'text',
|
|
255
|
-
text: JSON.stringify({
|
|
256
|
-
total_requests: stats.totalRequests,
|
|
257
|
-
total_cost: cost.total,
|
|
258
|
-
average_cost_per_request: cost.total / (stats.totalRequests || 1),
|
|
259
|
-
by_provider: cost.byProvider,
|
|
260
|
-
}, null, 2),
|
|
261
|
-
},
|
|
262
|
-
],
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
default:
|
|
267
|
-
return {
|
|
268
|
-
content: [
|
|
269
|
-
{
|
|
270
|
-
type: 'text',
|
|
271
|
-
text: `Unknown tool: ${name}`,
|
|
272
|
-
},
|
|
273
|
-
],
|
|
274
|
-
isError: true,
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
} catch (error) {
|
|
278
|
-
return {
|
|
279
|
-
content: [
|
|
280
|
-
{
|
|
281
|
-
type: 'text',
|
|
282
|
-
text: `Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
283
|
-
},
|
|
284
|
-
],
|
|
285
|
-
isError: true,
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
// Start server
|
|
291
|
-
async function main() {
|
|
292
|
-
const transport = new StdioServerTransport();
|
|
293
|
-
await server.connect(transport);
|
|
294
|
-
console.error('A3M Browser MCP Server running on stdio');
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
main().catch(console.error);
|