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,306 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* ShadowSampler — Value-Proportional Shadow Verification
|
|
4
|
-
*
|
|
5
|
-
* Implements Optimal Defense Theory (Rhoades 1979; McKey 1974; Zangerl & Bazzaz 1992)
|
|
6
|
-
* from plant ecological economics:
|
|
7
|
-
*
|
|
8
|
-
* "A plant allocates defensive compounds (defense cost) in proportion to
|
|
9
|
-
* tissue value, attack probability, and the marginal cost of defense."
|
|
10
|
-
*
|
|
11
|
-
* Mapped to A3M routing:
|
|
12
|
-
* - Tissue value → query stakes / expected cost of wrong answer
|
|
13
|
-
* - Attack probability → probability that the primary provider fails/misbehaves
|
|
14
|
-
* - Defense cost → cost of the shadow verification call
|
|
15
|
-
* - Marginal return → expected reduction in error rate from verification
|
|
16
|
-
*
|
|
17
|
-
* Instead of binary always-on (wasteful) or always-off (risky), ODT says:
|
|
18
|
-
* Sample shadow verification PROPORTIONALLY to expected value of verification.
|
|
19
|
-
*
|
|
20
|
-
* The sampling probability is:
|
|
21
|
-
* P(shadow) = f(expected_error_cost_reduction, query_risk)
|
|
22
|
-
*
|
|
23
|
-
* This is NOT the Zahavi "shared expert" (which always runs on 100% of queries).
|
|
24
|
-
* ODT shadow runs probabilistically — only on queries where the expected
|
|
25
|
-
* verification benefit exceeds the verification cost.
|
|
26
|
-
*
|
|
27
|
-
* Usage:
|
|
28
|
-
* const sampler = new ShadowSampler();
|
|
29
|
-
* const decision = await sampler.routeWithShadow(query, { strategy: 'auto' });
|
|
30
|
-
* // decision.hasShadow === true iff we sampled a shadow provider
|
|
31
|
-
* // decision.primaryResult and decision.shadowResult are compared automatically
|
|
32
|
-
*/
|
|
33
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
34
|
-
exports.ShadowSampler = void 0;
|
|
35
|
-
const advancedRouter_1 = require("./advancedRouter");
|
|
36
|
-
const providerConfig_1 = require("../providers/providerConfig");
|
|
37
|
-
/**
|
|
38
|
-
* Optimal Defense Theory Shadow Sampler
|
|
39
|
-
*
|
|
40
|
-
* Allocates shadow verification proportionally to query value and risk.
|
|
41
|
-
*
|
|
42
|
-
* The ODT sampling probability:
|
|
43
|
-
* P_shadow = min(maxP, baseP + risk_adj + cost_adj + complexity_adj)
|
|
44
|
-
*
|
|
45
|
-
* where:
|
|
46
|
-
* baseP = baseline verification rate (ODT " constitutive defense")
|
|
47
|
-
* risk_adj = risk_profile scaling (ODT "induced defense")
|
|
48
|
-
* cost_adj = output cost scaling (value of correct answer)
|
|
49
|
-
* complexity_adj = query complexity signal
|
|
50
|
-
*/
|
|
51
|
-
class ShadowSampler {
|
|
52
|
-
config;
|
|
53
|
-
// Cached shadow provider (auto-selected on first call)
|
|
54
|
-
_shadowProvider = null;
|
|
55
|
-
// Counters for sampling statistics
|
|
56
|
-
_shadowCount = 0;
|
|
57
|
-
_totalCount = 0;
|
|
58
|
-
constructor(config = {}) {
|
|
59
|
-
this.config = {
|
|
60
|
-
minQueryStake: config.minQueryStake ?? 0.01,
|
|
61
|
-
maxShadowProbability: config.maxShadowProbability ?? 0.15,
|
|
62
|
-
riskScalingFactor: config.riskScalingFactor ?? 0.5,
|
|
63
|
-
costScalingFactor: config.costScalingFactor ?? 0.3,
|
|
64
|
-
shadowProvider: config.shadowProvider ?? null,
|
|
65
|
-
forceShadowProvider: config.forceShadowProvider ?? false,
|
|
66
|
-
useComplexitySignal: config.useComplexitySignal ?? true,
|
|
67
|
-
forceShadow: config.forceShadow ?? false,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Auto-select the cheapest available provider as the shadow.
|
|
72
|
-
* Excludes the primary provider to ensure diversity.
|
|
73
|
-
*/
|
|
74
|
-
selectShadowProvider(primaryProvider) {
|
|
75
|
-
if (this.config.forceShadowProvider && this.config.shadowProvider) {
|
|
76
|
-
return this.config.shadowProvider;
|
|
77
|
-
}
|
|
78
|
-
if (this._shadowProvider)
|
|
79
|
-
return this._shadowProvider;
|
|
80
|
-
const profiles = (0, providerConfig_1.getAvailableProviders)();
|
|
81
|
-
const candidates = Object.entries(profiles)
|
|
82
|
-
.filter(([name, p]) => {
|
|
83
|
-
// Exclude primary
|
|
84
|
-
if (name === primaryProvider)
|
|
85
|
-
return false;
|
|
86
|
-
// Must be available (has API key) — cost must be finite
|
|
87
|
-
const cost = (p.costPerK.input + p.costPerK.output) / 2;
|
|
88
|
-
return cost < Infinity;
|
|
89
|
-
})
|
|
90
|
-
.sort((a, b) => {
|
|
91
|
-
const costA = (a[1].costPerK.input + a[1].costPerK.output) / 2;
|
|
92
|
-
const costB = (b[1].costPerK.input + b[1].costPerK.output) / 2;
|
|
93
|
-
return costA - costB;
|
|
94
|
-
});
|
|
95
|
-
if (candidates.length === 0) {
|
|
96
|
-
// Fallback: pick any non-primary
|
|
97
|
-
const fallback = Object.keys(profiles).find(n => n !== primaryProvider);
|
|
98
|
-
this._shadowProvider = fallback || primaryProvider;
|
|
99
|
-
}
|
|
100
|
-
else {
|
|
101
|
-
this._shadowProvider = candidates[0][0];
|
|
102
|
-
}
|
|
103
|
-
return this._shadowProvider;
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* Estimate the query "stakes" — the expected cost of a wrong answer.
|
|
107
|
-
*
|
|
108
|
-
* ODT maps this to "tissue value": how much is this asset worth protecting?
|
|
109
|
-
* In routing terms: if this query fails, how much does it cost?
|
|
110
|
-
*
|
|
111
|
-
* We approximate this as:
|
|
112
|
-
* stake ≈ estimated_output_tokens × cost_per_token × criticality_multiplier
|
|
113
|
-
*
|
|
114
|
-
* where criticality is derived from query complexity and risk_profile.
|
|
115
|
-
*/
|
|
116
|
-
estimateQueryStake(features) {
|
|
117
|
-
const estimatedTokens = features.length * 1.5; // rough estimate
|
|
118
|
-
const avgCostPerToken = 0.0001; // roughly $0.10/1K tokens
|
|
119
|
-
const stake = estimatedTokens * avgCostPerToken;
|
|
120
|
-
// Criticality multiplier from risk profile
|
|
121
|
-
const riskMultiplier = {
|
|
122
|
-
high: 10.0, // Wrong answer could cause real harm — worth verifying
|
|
123
|
-
medium: 2.0, // Some cost to wrong answer
|
|
124
|
-
low: 0.5, // Low stakes — skip verification
|
|
125
|
-
};
|
|
126
|
-
const riskMult = riskMultiplier[features.risk_profile || 'medium'] ?? 1.0;
|
|
127
|
-
// Complexity multiplier — complex queries are harder to verify but more valuable
|
|
128
|
-
// We use complexity as a proxy for "correctness is harder to judge"
|
|
129
|
-
const complexityMultiplier = 1 + (features.complexity || 0) * 2;
|
|
130
|
-
return stake * riskMult * complexityMultiplier;
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Compute the ODT sampling probability for this query.
|
|
134
|
-
*
|
|
135
|
-
* ODT principle: defense (shadow) allocation ∝ expected benefit of defense.
|
|
136
|
-
* Expected benefit = P(failure) × cost_of_failure
|
|
137
|
-
*
|
|
138
|
-
* So P(shadow) scales with:
|
|
139
|
-
* 1. Query stake (expected cost of wrong answer)
|
|
140
|
-
* 2. Risk profile (probability of primary failure)
|
|
141
|
-
* 3. Output cost (verification ROI — cheaper outputs need less verification)
|
|
142
|
-
* 4. Complexity (complex queries benefit more from verification)
|
|
143
|
-
*/
|
|
144
|
-
computeShadowProbability(features, stake) {
|
|
145
|
-
// Base probability (ODT "constitutive defense" — baseline verification rate)
|
|
146
|
-
let p = 0.02; // 2% baseline
|
|
147
|
-
// === STAKES ADJUSTMENT (ODT "tissue value") ===
|
|
148
|
-
// Higher stake → proportionally higher verification probability
|
|
149
|
-
// Scale from 2% to maxP as stake goes from minStake to $1.00
|
|
150
|
-
if (stake >= this.config.minQueryStake) {
|
|
151
|
-
const stakeAdj = Math.min((stake - this.config.minQueryStake) / (1.0 - this.config.minQueryStake), 1.0) * (this.config.maxShadowProbability - 0.02);
|
|
152
|
-
p += stakeAdj;
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
// Below minimum stake — no verification regardless
|
|
156
|
-
return 0;
|
|
157
|
-
}
|
|
158
|
-
// === RISK ADJUSTMENT (ODT "attack probability") ===
|
|
159
|
-
// High-risk queries are more likely to have primary failures
|
|
160
|
-
// Scale risk_adj by riskScalingFactor (0.5 = 50% boost for high-risk)
|
|
161
|
-
const riskAdj = {
|
|
162
|
-
high: 0.10 * this.config.riskScalingFactor,
|
|
163
|
-
medium: 0.03 * this.config.riskScalingFactor,
|
|
164
|
-
low: 0.0,
|
|
165
|
-
};
|
|
166
|
-
p += riskAdj[features.risk_profile || 'medium'] ?? 0;
|
|
167
|
-
// === COMPLEXITY ADJUSTMENT (ODT "defense efficacy") ===
|
|
168
|
-
// Complex queries benefit more from verification (more errors to catch)
|
|
169
|
-
// But also harder to verify (requires domain knowledge to judge)
|
|
170
|
-
if (this.config.useComplexitySignal) {
|
|
171
|
-
if (features.has_code) {
|
|
172
|
-
p += 0.05; // Code verification has high ROI (bugs are costly)
|
|
173
|
-
}
|
|
174
|
-
if (features.requires_reasoning) {
|
|
175
|
-
p += 0.03; // Reasoning errors are subtle but costly
|
|
176
|
-
}
|
|
177
|
-
if (features.has_math) {
|
|
178
|
-
p += 0.04; // Math has objective ground truth — easy to verify (note: field is has_math)
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
// === COST SCALING (ODT "marginal defense cost") ===
|
|
182
|
-
// Expensive outputs are harder to produce — verify to avoid waste
|
|
183
|
-
if (this.config.costScalingFactor > 0 && features.length > 500) {
|
|
184
|
-
const costAdj = Math.min((features.length - 500) / 10000, // scale up for very long outputs
|
|
185
|
-
0.05) * this.config.costScalingFactor;
|
|
186
|
-
p += costAdj;
|
|
187
|
-
}
|
|
188
|
-
// Clamp to [0, maxShadowProbability]
|
|
189
|
-
return Math.min(Math.max(p, 0), this.config.maxShadowProbability);
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Route a query, with optional ODT-proportional shadow verification.
|
|
193
|
-
*
|
|
194
|
-
* @param prompt - The user query
|
|
195
|
-
* @param options - Routing options (same as routeQuery)
|
|
196
|
-
* @returns ShadowDecision with shadow metadata
|
|
197
|
-
*/
|
|
198
|
-
routeWithShadow(prompt, options) {
|
|
199
|
-
const features = (0, advancedRouter_1.extractQueryFeatures)(prompt);
|
|
200
|
-
const primaryDecision = (0, advancedRouter_1.routeQuery)(prompt, options?.available_models, options?.budget_multiplier);
|
|
201
|
-
// Compute query stakes and shadow probability
|
|
202
|
-
const stake = this.estimateQueryStake(features);
|
|
203
|
-
const shadowProb = this.computeShadowProbability(features, stake);
|
|
204
|
-
// ODT sampling decision
|
|
205
|
-
const shouldShadow = this.config.forceShadow || Math.random() < shadowProb;
|
|
206
|
-
const shadowProvider = shouldShadow
|
|
207
|
-
? this.selectShadowProvider(primaryDecision.primary_model || '')
|
|
208
|
-
: null;
|
|
209
|
-
if (shouldShadow) {
|
|
210
|
-
this._shadowCount++;
|
|
211
|
-
}
|
|
212
|
-
this._totalCount++;
|
|
213
|
-
const reasoning = shouldShadow
|
|
214
|
-
? `ODT shadow: stake=${stake.toFixed(4)}, risk=${features.risk_profile}, P=${shadowProb.toFixed(3)}, complexity=${features.complexity.toFixed(2)}`
|
|
215
|
-
: `ODT no-shadow: stake=${stake.toFixed(4)} below threshold`;
|
|
216
|
-
return {
|
|
217
|
-
...primaryDecision,
|
|
218
|
-
hasShadow: shouldShadow,
|
|
219
|
-
shadowProvider,
|
|
220
|
-
shadowProbability: shadowProb,
|
|
221
|
-
features,
|
|
222
|
-
shadowReasoning: reasoning,
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Compare primary and shadow outputs.
|
|
227
|
-
* Returns the "better" answer and confidence delta.
|
|
228
|
-
*
|
|
229
|
-
* For production use: this would call both providers in parallel
|
|
230
|
-
* and compare outputs. For now, returns a stub that signals
|
|
231
|
-
* the caller should handle comparison.
|
|
232
|
-
*/
|
|
233
|
-
async compareOutputs(primaryAnswer, shadowAnswer) {
|
|
234
|
-
if (!shadowAnswer) {
|
|
235
|
-
return {
|
|
236
|
-
primary: primaryAnswer,
|
|
237
|
-
shadow: null,
|
|
238
|
-
winner: 'no-shadow',
|
|
239
|
-
confidenceDelta: 0,
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
// Simple comparison: length + character overlap as proxy for agreement
|
|
243
|
-
// In production, this would use a proper semantic similarity check
|
|
244
|
-
const primaryLen = primaryAnswer.length;
|
|
245
|
-
const shadowLen = shadowAnswer.length;
|
|
246
|
-
const lengthRatio = Math.min(primaryLen, shadowLen) / Math.max(primaryLen, shadowLen);
|
|
247
|
-
// Count common bigrams as a simple similarity proxy
|
|
248
|
-
const primaryBigrams = new Set();
|
|
249
|
-
const shadowBigrams = new Set();
|
|
250
|
-
for (let i = 0; i < primaryAnswer.length - 1; i++) {
|
|
251
|
-
primaryBigrams.add(primaryAnswer.slice(i, i + 2));
|
|
252
|
-
}
|
|
253
|
-
for (let i = 0; i < shadowAnswer.length - 1; i++) {
|
|
254
|
-
shadowBigrams.add(shadowAnswer.slice(i, i + 2));
|
|
255
|
-
}
|
|
256
|
-
let intersection = 0;
|
|
257
|
-
for (const bg of primaryBigrams) {
|
|
258
|
-
if (shadowBigrams.has(bg))
|
|
259
|
-
intersection++;
|
|
260
|
-
}
|
|
261
|
-
const union = primaryBigrams.size + shadowBigrams.size - intersection;
|
|
262
|
-
const jaccard = union > 0 ? intersection / union : 0;
|
|
263
|
-
// High agreement (jaccard > 0.8) → trust primary
|
|
264
|
-
// Low agreement → flag for review or prefer primary
|
|
265
|
-
const winner = jaccard > 0.8 ? 'primary'
|
|
266
|
-
: jaccard > 0.5 ? 'tie'
|
|
267
|
-
: 'shadow'; // Low agreement: shadow might have caught something
|
|
268
|
-
const confidenceDelta = jaccard > 0.8 ? 0 : -0.1; // Reduce confidence if they differ
|
|
269
|
-
return {
|
|
270
|
-
primary: primaryAnswer,
|
|
271
|
-
shadow: shadowAnswer,
|
|
272
|
-
winner,
|
|
273
|
-
confidenceDelta,
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
/**
|
|
277
|
-
* Get sampling statistics for monitoring.
|
|
278
|
-
*/
|
|
279
|
-
getStats() {
|
|
280
|
-
return {
|
|
281
|
-
shadowCount: this._shadowCount,
|
|
282
|
-
totalCount: this._totalCount,
|
|
283
|
-
shadowRate: this._totalCount > 0 ? this._shadowCount / this._totalCount : 0,
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
/**
|
|
287
|
-
* Reset statistics counters.
|
|
288
|
-
*/
|
|
289
|
-
resetStats() {
|
|
290
|
-
this._shadowCount = 0;
|
|
291
|
-
this._totalCount = 0;
|
|
292
|
-
}
|
|
293
|
-
/**
|
|
294
|
-
* Update configuration at runtime.
|
|
295
|
-
*/
|
|
296
|
-
configure(config) {
|
|
297
|
-
this.config = { ...this.config, ...config };
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
exports.ShadowSampler = ShadowSampler;
|
|
301
|
-
// ============================================================
|
|
302
|
-
// NOTE: Named exports are at declaration level above.
|
|
303
|
-
// ShadowSampler, ShadowSamplerConfig, ShadowDecision, ShadowedResponse
|
|
304
|
-
// are all exported via 'export interface' / 'export class'
|
|
305
|
-
// ============================================================
|
|
306
|
-
//# sourceMappingURL=shadowSampler.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"shadowSampler.js","sourceRoot":"","sources":["../../src/routing/shadowSampler.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;;;AAEH,qDAAmF;AACnF,gEAAwF;AAiFxF;;;;;;;;;;;;;GAaG;AACH,MAAa,aAAa;IAChB,MAAM,CAAgG;IAE9G,uDAAuD;IAC/C,eAAe,GAAkB,IAAI,CAAC;IAE9C,mCAAmC;IAC3B,YAAY,GAAG,CAAC,CAAC;IACjB,WAAW,GAAG,CAAC,CAAC;IAExB,YAAY,SAA8B,EAAE;QAC1C,IAAI,CAAC,MAAM,GAAG;YACZ,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,IAAI;YAC3C,oBAAoB,EAAE,MAAM,CAAC,oBAAoB,IAAI,IAAI;YACzD,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,IAAI,GAAG;YAClD,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,IAAI,GAAG;YAClD,cAAc,EAAE,MAAM,CAAC,cAAc,IAAI,IAAI;YAC7C,mBAAmB,EAAE,MAAM,CAAC,mBAAmB,IAAI,KAAK;YACxD,mBAAmB,EAAE,MAAM,CAAC,mBAAmB,IAAI,IAAI;YACvD,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,KAAK;SACzC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACK,oBAAoB,CAAC,eAAuB;QAClD,IAAI,IAAI,CAAC,MAAM,CAAC,mBAAmB,IAAI,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;YAClE,OAAO,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC;QACpC,CAAC;QAED,IAAI,IAAI,CAAC,eAAe;YAAE,OAAO,IAAI,CAAC,eAAe,CAAC;QAEtD,MAAM,QAAQ,GAAG,IAAA,sCAAqB,GAAE,CAAC;QACzC,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;aACxC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAA+B,EAAE,EAAE;YAClD,kBAAkB;YAClB,IAAI,IAAI,KAAK,eAAe;gBAAE,OAAO,KAAK,CAAC;YAC3C,wDAAwD;YACxD,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACxD,OAAO,IAAI,GAAG,QAAQ,CAAC;QACzB,CAAC,CAAC;aACD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACb,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC/D,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC/D,OAAO,KAAK,GAAG,KAAK,CAAC;QACvB,CAAC,CAAC,CAAC;QAEL,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,iCAAiC;YACjC,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,eAAe,CAAC,CAAC;YACxE,IAAI,CAAC,eAAe,GAAG,QAAQ,IAAI,eAAe,CAAC;QACrD,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,eAAe,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1C,CAAC;QAED,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;IAED;;;;;;;;;;OAUG;IACK,kBAAkB,CAAC,QAAiD;QAC1E,MAAM,eAAe,GAAG,QAAQ,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,iBAAiB;QAChE,MAAM,eAAe,GAAG,MAAM,CAAC,CAAC,0BAA0B;QAC1D,MAAM,KAAK,GAAG,eAAe,GAAG,eAAe,CAAC;QAEhD,2CAA2C;QAC3C,MAAM,cAAc,GAA2B;YAC7C,IAAI,EAAE,IAAI,EAAK,uDAAuD;YACtE,MAAM,EAAE,GAAG,EAAI,4BAA4B;YAC3C,GAAG,EAAE,GAAG,EAAO,iCAAiC;SACjD,CAAC;QACF,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,YAAY,IAAI,QAAQ,CAAC,IAAI,GAAG,CAAC;QAE1E,iFAAiF;QACjF,oEAAoE;QACpE,MAAM,oBAAoB,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QAEhE,OAAO,KAAK,GAAG,QAAQ,GAAG,oBAAoB,CAAC;IACjD,CAAC;IAED;;;;;;;;;;;OAWG;IACK,wBAAwB,CAC9B,QAAiD,EACjD,KAAa;QAEb,6EAA6E;QAC7E,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,cAAc;QAE5B,iDAAiD;QACjD,gEAAgE;QAChE,6DAA6D;QAC7D,IAAI,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC;YACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CACvB,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,EACvE,GAAG,CACJ,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;YAC9C,CAAC,IAAI,QAAQ,CAAC;QAChB,CAAC;aAAM,CAAC;YACN,mDAAmD;YACnD,OAAO,CAAC,CAAC;QACX,CAAC;QAED,qDAAqD;QACrD,6DAA6D;QAC7D,sEAAsE;QACtE,MAAM,OAAO,GAA2B;YACtC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,iBAAiB;YAC1C,MAAM,EAAE,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,iBAAiB;YAC5C,GAAG,EAAE,GAAG;SACT,CAAC;QACF,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,YAAY,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;QAErD,yDAAyD;QACzD,wEAAwE;QACxE,iEAAiE;QACjE,IAAI,IAAI,CAAC,MAAM,CAAC,mBAAmB,EAAE,CAAC;YACpC,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;gBACtB,CAAC,IAAI,IAAI,CAAC,CAAC,mDAAmD;YAChE,CAAC;YACD,IAAI,QAAQ,CAAC,kBAAkB,EAAE,CAAC;gBAChC,CAAC,IAAI,IAAI,CAAC,CAAC,yCAAyC;YACtD,CAAC;YACD,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;gBACtB,CAAC,IAAI,IAAI,CAAC,CAAC,6EAA6E;YAC1F,CAAC;QACH,CAAC;QAED,qDAAqD;QACrD,kEAAkE;QAClE,IAAI,IAAI,CAAC,MAAM,CAAC,iBAAiB,GAAG,CAAC,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;YAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CACtB,CAAC,QAAQ,CAAC,MAAM,GAAG,GAAG,CAAC,GAAG,KAAK,EAAE,iCAAiC;YAClE,IAAI,CACL,GAAG,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC;YAClC,CAAC,IAAI,OAAO,CAAC;QACf,CAAC;QAED,qCAAqC;QACrC,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IACpE,CAAC;IAED;;;;;;OAMG;IACH,eAAe,CACb,MAAc,EACd,OAAqE;QAErE,MAAM,QAAQ,GAAG,IAAA,qCAAoB,EAAC,MAAM,CAAC,CAAC;QAC9C,MAAM,eAAe,GAAG,IAAA,2BAAU,EAAC,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,iBAAiB,CAAC,CAAC;QAElG,8CAA8C;QAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,UAAU,GAAG,IAAI,CAAC,wBAAwB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAElE,wBAAwB;QACxB,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,IAAI,CAAC,MAAM,EAAE,GAAG,UAAU,CAAC;QAC3E,MAAM,cAAc,GAAG,YAAY;YACjC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,eAAe,CAAC,aAAa,IAAI,EAAE,CAAC;YAChE,CAAC,CAAC,IAAI,CAAC;QAET,IAAI,YAAY,EAAE,CAAC;YACjB,IAAI,CAAC,YAAY,EAAE,CAAC;QACtB,CAAC;QACD,IAAI,CAAC,WAAW,EAAE,CAAC;QAEnB,MAAM,SAAS,GAAG,YAAY;YAC5B,CAAC,CAAC,qBAAqB,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,QAAQ,CAAC,YAAY,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,gBAAgB,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;YAClJ,CAAC,CAAC,wBAAwB,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,kBAAkB,CAAC;QAE/D,OAAO;YACL,GAAG,eAAe;YAClB,SAAS,EAAE,YAAY;YACvB,cAAc;YACd,iBAAiB,EAAE,UAAU;YAC7B,QAAQ;YACR,eAAe,EAAE,SAAS;SAC3B,CAAC;IACJ,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,cAAc,CAClB,aAAqB,EACrB,YAA2B;QAE3B,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,OAAO;gBACL,OAAO,EAAE,aAAa;gBACtB,MAAM,EAAE,IAAI;gBACZ,MAAM,EAAE,WAAW;gBACnB,eAAe,EAAE,CAAC;aACnB,CAAC;QACJ,CAAC;QAED,uEAAuE;QACvE,mEAAmE;QACnE,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC;QACxC,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,CAAC;QACtC,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,SAAS,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;QAEtF,oDAAoD;QACpD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAU,CAAC;QACzC,MAAM,aAAa,GAAG,IAAI,GAAG,EAAU,CAAC;QACxC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAClD,cAAc,CAAC,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACpD,CAAC;QACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACjD,aAAa,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAClD,CAAC;QAED,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,KAAK,MAAM,EAAE,IAAI,cAAc,EAAE,CAAC;YAChC,IAAI,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE,YAAY,EAAE,CAAC;QAC5C,CAAC;QACD,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,GAAG,aAAa,CAAC,IAAI,GAAG,YAAY,CAAC;QACtE,MAAM,OAAO,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAErD,iDAAiD;QACjD,oDAAoD;QACpD,MAAM,MAAM,GACV,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,SAAS;YACzB,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK;gBACvB,CAAC,CAAC,QAAQ,CAAC,CAAC,oDAAoD;QAElE,MAAM,eAAe,GAAG,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,mCAAmC;QAErF,OAAO;YACL,OAAO,EAAE,aAAa;YACtB,MAAM,EAAE,YAAY;YACpB,MAAM;YACN,eAAe;SAChB,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,QAAQ;QACN,OAAO;YACL,WAAW,EAAE,IAAI,CAAC,YAAY;YAC9B,UAAU,EAAE,IAAI,CAAC,WAAW;YAC5B,UAAU,EAAE,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;SAC5E,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,UAAU;QACR,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,MAAoC;QAC5C,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;IAC9C,CAAC;CACF;AApSD,sCAoSC;AAED,+DAA+D;AAC/D,sDAAsD;AACtD,uEAAuE;AACvE,2DAA2D;AAC3D,+DAA+D"}
|
|
@@ -1,155 +0,0 @@
|
|
|
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
|
|
@@ -1,179 +0,0 @@
|
|
|
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);
|