adaptive-memory-multi-model-router 2.16.1 → 2.16.3

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.
@@ -0,0 +1,49 @@
1
+ /**
2
+ * JevRouter — System One routing for A3M.
3
+ *
4
+ * Replaces the autoregressive/heuristic routing loop with a single-pass
5
+ * calibrated decision (Jev interface pattern):
6
+ *
7
+ * prompt ──► OptionAttention engine ──► { provider choice, complexity score,
8
+ * capability noul flags }
9
+ *
10
+ * The engine is distilled from A3M's own System 2 router (advancedRouter.ts):
11
+ * tools/distill.mjs runs routeQuery over a synthetic prompt corpus and
12
+ * tools/train_jev.py trains the ~25k-parameter option-attention weights.
13
+ *
14
+ * Confidence guard: if the top provider probability is below MIN_CONFIDENCE,
15
+ * we fall back to the full heuristic router (System 2) — Jev decides the easy
16
+ * 90%, the heavy router handles the hard 10%.
17
+ */
18
+ import { type RouteDecision } from "../advancedRouter";
19
+ import { type OptionAttentionWeights } from "./optionAttention";
20
+ import type { JevResponse } from "./types";
21
+ /** Below this top-probability, defer to the System 2 heuristic router. */
22
+ export declare const MIN_CONFIDENCE = 0.22;
23
+ export declare function loadWeights(): OptionAttentionWeights | null;
24
+ /** For tests / hot-reload of retrained weights. */
25
+ export declare function resetWeightsCache(): void;
26
+ /**
27
+ * Build the option text for a model profile. Option text is what the engine
28
+ * embeds — providers unseen at training time are still scored through their
29
+ * strengths/tier description.
30
+ */
31
+ export declare function optionTextForModel(model: string, profile: {
32
+ providerName?: string;
33
+ strengths?: string[];
34
+ quality_score?: number;
35
+ cost_per_1k_input?: number;
36
+ cost_per_1k_output?: number;
37
+ type?: string;
38
+ }): string;
39
+ /**
40
+ * Single-pass Jev routing decision. Returns a RouteDecision shaped exactly
41
+ * like advancedRouter.routeQuery so it is a drop-in replacement.
42
+ */
43
+ export declare function jevRoute(prompt: string, available_models?: string[], budget_multiplier?: number): RouteDecision & {
44
+ jev?: JevResponse;
45
+ };
46
+ /** Async variant with remote backend support. */
47
+ export declare function jevRouteAsync(prompt: string, available_models?: string[], budget_multiplier?: number): Promise<RouteDecision & {
48
+ jev?: JevResponse;
49
+ }>;
@@ -0,0 +1,231 @@
1
+ "use strict";
2
+ /**
3
+ * JevRouter — System One routing for A3M.
4
+ *
5
+ * Replaces the autoregressive/heuristic routing loop with a single-pass
6
+ * calibrated decision (Jev interface pattern):
7
+ *
8
+ * prompt ──► OptionAttention engine ──► { provider choice, complexity score,
9
+ * capability noul flags }
10
+ *
11
+ * The engine is distilled from A3M's own System 2 router (advancedRouter.ts):
12
+ * tools/distill.mjs runs routeQuery over a synthetic prompt corpus and
13
+ * tools/train_jev.py trains the ~25k-parameter option-attention weights.
14
+ *
15
+ * Confidence guard: if the top provider probability is below MIN_CONFIDENCE,
16
+ * we fall back to the full heuristic router (System 2) — Jev decides the easy
17
+ * 90%, the heavy router handles the hard 10%.
18
+ */
19
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ var desc = Object.getOwnPropertyDescriptor(m, k);
22
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
23
+ desc = { enumerable: true, get: function() { return m[k]; } };
24
+ }
25
+ Object.defineProperty(o, k2, desc);
26
+ }) : (function(o, m, k, k2) {
27
+ if (k2 === undefined) k2 = k;
28
+ o[k2] = m[k];
29
+ }));
30
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
31
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
32
+ }) : function(o, v) {
33
+ o["default"] = v;
34
+ });
35
+ var __importStar = (this && this.__importStar) || (function () {
36
+ var ownKeys = function(o) {
37
+ ownKeys = Object.getOwnPropertyNames || function (o) {
38
+ var ar = [];
39
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
40
+ return ar;
41
+ };
42
+ return ownKeys(o);
43
+ };
44
+ return function (mod) {
45
+ if (mod && mod.__esModule) return mod;
46
+ var result = {};
47
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
48
+ __setModuleDefault(result, mod);
49
+ return result;
50
+ };
51
+ })();
52
+ Object.defineProperty(exports, "__esModule", { value: true });
53
+ exports.MIN_CONFIDENCE = void 0;
54
+ exports.loadWeights = loadWeights;
55
+ exports.resetWeightsCache = resetWeightsCache;
56
+ exports.optionTextForModel = optionTextForModel;
57
+ exports.jevRoute = jevRoute;
58
+ exports.jevRouteAsync = jevRouteAsync;
59
+ const fs = __importStar(require("fs"));
60
+ const path = __importStar(require("path"));
61
+ const advancedRouter_1 = require("../advancedRouter");
62
+ const optionAttention_1 = require("./optionAttention");
63
+ const remote_1 = require("./remote");
64
+ const WEIGHTS_PATHS = [
65
+ path.join(__dirname, "weights", "jev-router-weights.json"), // dist copy
66
+ path.join(__dirname, "..", "..", "..", "src", "routing", "jev", "weights", "jev-router-weights.json"), // repo fallback
67
+ ];
68
+ /** Below this top-probability, defer to the System 2 heuristic router. */
69
+ exports.MIN_CONFIDENCE = 0.22;
70
+ let cachedWeights;
71
+ function loadWeights() {
72
+ if (cachedWeights !== undefined)
73
+ return cachedWeights;
74
+ try {
75
+ for (const p of WEIGHTS_PATHS) {
76
+ if (fs.existsSync(p)) {
77
+ cachedWeights = JSON.parse(fs.readFileSync(p, "utf8"));
78
+ return cachedWeights;
79
+ }
80
+ }
81
+ cachedWeights = null;
82
+ }
83
+ catch {
84
+ cachedWeights = null;
85
+ }
86
+ return cachedWeights;
87
+ }
88
+ /** For tests / hot-reload of retrained weights. */
89
+ function resetWeightsCache() {
90
+ cachedWeights = undefined;
91
+ (0, optionAttention_1.resetQueryCache)();
92
+ }
93
+ /**
94
+ * Build the option text for a model profile. Option text is what the engine
95
+ * embeds — providers unseen at training time are still scored through their
96
+ * strengths/tier description.
97
+ */
98
+ function optionTextForModel(model, profile) {
99
+ const strengths = (profile.strengths || []).slice(0, 6).join(",");
100
+ const cost = profile.cost_per_1k_input != null
101
+ ? ((profile.cost_per_1k_input + (profile.cost_per_1k_output || 0)) / 2).toFixed(4)
102
+ : "?";
103
+ return `${model} provider:${profile.providerName || "?"} type:${profile.type || "api"} strengths:${strengths} quality:${profile.quality_score ?? "?"} cost:${cost}`;
104
+ }
105
+ /**
106
+ * Single-pass Jev routing decision. Returns a RouteDecision shaped exactly
107
+ * like advancedRouter.routeQuery so it is a drop-in replacement.
108
+ */
109
+ function jevRoute(prompt, available_models, budget_multiplier = 1.0) {
110
+ // 1. Remote backend (openjev-sglang / typesafe) takes precedence if configured
111
+ if ((0, remote_1.remoteConfigured)()) {
112
+ // remoteDecide is async; jevRoute is sync to match routeQuery's contract.
113
+ // Remote mode is exposed via jevRouteAsync below.
114
+ }
115
+ const weights = loadWeights();
116
+ if (!weights)
117
+ return fallbackRoute(prompt, available_models, budget_multiplier, "no weights");
118
+ // 2. Candidate pool — mirror routeQuery's candidate selection
119
+ const profiles = getModelProfilesSafe();
120
+ const candidateNames = (available_models && available_models.length
121
+ ? available_models
122
+ : Object.keys(profiles)).filter((n) => profiles[n]);
123
+ if (candidateNames.length === 0)
124
+ return fallbackRoute(prompt, available_models, budget_multiplier, "no candidates");
125
+ const t0 = Date.now();
126
+ const options = candidateNames.map((m) => optionTextForModel(m, profiles[m]));
127
+ const { probs, top } = (0, optionAttention_1.scoreOptions)(prompt, options, weights);
128
+ const complexity = (0, optionAttention_1.scoreScalar)(prompt, weights);
129
+ const { value: needsCode, prob: codeProb } = (0, optionAttention_1.scoreNoul)(prompt, "requires code generation", weights);
130
+ const elapsed = Date.now() - t0;
131
+ const bestIdx = top[0]?.index ?? -1;
132
+ const bestProb = top[0]?.prob ?? 0;
133
+ const jev = {
134
+ answers: [
135
+ {
136
+ type: "choice",
137
+ key: "provider",
138
+ value: bestIdx >= 0 ? candidateNames[bestIdx] : "",
139
+ prob: bestProb,
140
+ top: top.map((t) => ({ option: candidateNames[t.index], prob: t.prob })),
141
+ },
142
+ { type: "score", key: "complexity", value: complexity },
143
+ { type: "noul", key: "needs_code", value: needsCode, prob: codeProb },
144
+ ],
145
+ elapsed_ms: elapsed,
146
+ backend: "local-weights",
147
+ };
148
+ // 3. Confidence guard → System 2 fallback
149
+ if (bestProb < exports.MIN_CONFIDENCE || bestIdx < 0) {
150
+ const fb = fallbackRoute(prompt, available_models, budget_multiplier, `low confidence ${bestProb.toFixed(2)}`);
151
+ return { ...fb, jev };
152
+ }
153
+ const primary = candidateNames[bestIdx];
154
+ const profile = profiles[primary];
155
+ const fallbacks = top.slice(1, 3).map((t) => candidateNames[t.index]);
156
+ return {
157
+ primary_model: primary,
158
+ fallback_models: fallbacks,
159
+ confidence: bestProb,
160
+ reasoning: `jev single-pass (distilled): p=${bestProb.toFixed(3)} complexity=${complexity.toFixed(2)} needs_code=${needsCode}(${codeProb.toFixed(2)}) [${elapsed}ms]`,
161
+ estimated_cost: ((profile.cost_per_1k_input || 0) + (profile.cost_per_1k_output || 0)) / 2,
162
+ estimated_latency_ms: profile.latency_ms || 500,
163
+ provider_type: profile.type,
164
+ jev,
165
+ };
166
+ }
167
+ /** Async variant with remote backend support. */
168
+ async function jevRouteAsync(prompt, available_models, budget_multiplier = 1.0) {
169
+ if ((0, remote_1.remoteConfigured)()) {
170
+ const profiles = getModelProfilesSafe();
171
+ const candidates = (available_models && available_models.length
172
+ ? available_models
173
+ : Object.keys(profiles)).filter((n) => profiles[n]);
174
+ const remote = await (0, remote_1.remoteDecide)({
175
+ state: prompt,
176
+ questions: [
177
+ {
178
+ type: "choice",
179
+ key: "provider",
180
+ description: "best model for this query",
181
+ options: candidates.map((m) => optionTextForModel(m, profiles[m])),
182
+ },
183
+ ],
184
+ });
185
+ if (remote) {
186
+ const choice = remote.answers[0];
187
+ if (choice && choice.type === "choice") {
188
+ // map option text back to model name
189
+ const idx = candidates.findIndex((m) => choice.value.startsWith(m + " "));
190
+ const primary = idx >= 0 ? candidates[idx] : candidates.find((c) => choice.value.includes(c));
191
+ if (primary) {
192
+ const profile = profiles[primary];
193
+ return {
194
+ primary_model: primary,
195
+ fallback_models: [],
196
+ confidence: choice.prob,
197
+ reasoning: `jev remote (${remote.backend}) [${remote.elapsed_ms}ms]`,
198
+ estimated_cost: ((profile.cost_per_1k_input || 0) + (profile.cost_per_1k_output || 0)) / 2,
199
+ estimated_latency_ms: profile.latency_ms || 500,
200
+ provider_type: profile.type,
201
+ jev: remote,
202
+ };
203
+ }
204
+ }
205
+ }
206
+ }
207
+ return jevRoute(prompt, available_models, budget_multiplier);
208
+ }
209
+ // ---------------------------------------------------------------------------
210
+ // internals
211
+ // ---------------------------------------------------------------------------
212
+ const advancedRouter_2 = require("../advancedRouter");
213
+ function getModelProfilesSafe() {
214
+ // MODEL_PROFILES is populated by the first routeQuery call (profile cache).
215
+ if (Object.keys(advancedRouter_2.MODEL_PROFILES).length === 0)
216
+ (0, advancedRouter_1.routeQuery)("warmup");
217
+ return advancedRouter_2.MODEL_PROFILES;
218
+ }
219
+ function fallbackRoute(prompt, available_models, budget_multiplier, why) {
220
+ const d = (0, advancedRouter_1.routeQuery)(prompt, available_models, budget_multiplier);
221
+ return {
222
+ ...d,
223
+ reasoning: `system2-fallback (${why}): ${d.reasoning}`,
224
+ jev: {
225
+ answers: [],
226
+ elapsed_ms: 0,
227
+ backend: "fallback-heuristic",
228
+ },
229
+ };
230
+ }
231
+ //# sourceMappingURL=jevRouter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jevRouter.js","sourceRoot":"","sources":["../../../src/routing/jev/jevRouter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * OptionAttention — a pure-TypeScript System One decision engine.
3
+ *
4
+ * Port of the architecture popularized by vinnylarouge/jevlike (835★):
5
+ *
6
+ * Each option becomes a query vector. The query assigns attention weights
7
+ * to the context tokens; those weights produce one attended context vector
8
+ * per option. A shared dot product turns each (option, context) pair into
9
+ * one score. A softmax across options yields calibrated probabilities —
10
+ * all in a single forward pass, no autoregressive generation.
11
+ *
12
+ * Why this architecture for A3M:
13
+ * - Dynamic option sets: providers come and go; unseen options are scored
14
+ * through their text (name + strengths + tier), so the engine generalizes
15
+ * to providers it was never trained on.
16
+ * - Zero dependencies: byte-level embeddings, ~25k parameters, weights ship
17
+ * as JSON inside the npm package.
18
+ * - CPU-fast: single matmul chain, sub-millisecond for 100+ options.
19
+ */
20
+ export interface OptionAttentionWeights {
21
+ /** Hashed trigram embedding table: VOCAB × D. */
22
+ emb: number[][];
23
+ /** Option projection: D × D. */
24
+ wq: number[][];
25
+ bq: number[];
26
+ /** Shared scoring vector: D. */
27
+ w: number[];
28
+ b: number[];
29
+ /** Score head (context pooled → sigmoid): D + 2. */
30
+ ws: number[];
31
+ bs: number[];
32
+ /** Temperature for calibrated softmax. */
33
+ temperature: number;
34
+ dim: number;
35
+ }
36
+ /** Number of trigram hash buckets (must match tools/train_jev.py). */
37
+ export declare const VOCAB = 2048;
38
+ /**
39
+ * Hashed trigram tokenization — character trigrams give much sharper text
40
+ * discrimination than raw bytes ("chat" vs "code" produce disjoint buckets).
41
+ */
42
+ export declare function tokenize(text: string): number[];
43
+ export declare function resetQueryCache(): void;
44
+ export interface ChoiceResult {
45
+ probs: number[];
46
+ top: Array<{
47
+ index: number;
48
+ prob: number;
49
+ }>;
50
+ }
51
+ /**
52
+ * Score N options against a context in one pass.
53
+ * Attention: a_ij = softmax_j( q_i · E_j / √D ), c_i = Σ_j a_ij E_j
54
+ * Score: s_i = w · (q_i ⊙ c_i) + b, probs = softmax(s / T)
55
+ */
56
+ export declare function scoreOptions(context: string, options: string[], weights: OptionAttentionWeights): ChoiceResult;
57
+ /** Context → scalar in [0,1] via sigmoid(w_s · meanPool + b_s). */
58
+ export declare function scoreScalar(context: string, weights: OptionAttentionWeights): number;
59
+ /** Boolean decision with calibrated probability (2-way choice). */
60
+ export declare function scoreNoul(context: string, questionText: string, weights: OptionAttentionWeights): {
61
+ value: boolean;
62
+ prob: number;
63
+ };
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ /**
3
+ * OptionAttention — a pure-TypeScript System One decision engine.
4
+ *
5
+ * Port of the architecture popularized by vinnylarouge/jevlike (835★):
6
+ *
7
+ * Each option becomes a query vector. The query assigns attention weights
8
+ * to the context tokens; those weights produce one attended context vector
9
+ * per option. A shared dot product turns each (option, context) pair into
10
+ * one score. A softmax across options yields calibrated probabilities —
11
+ * all in a single forward pass, no autoregressive generation.
12
+ *
13
+ * Why this architecture for A3M:
14
+ * - Dynamic option sets: providers come and go; unseen options are scored
15
+ * through their text (name + strengths + tier), so the engine generalizes
16
+ * to providers it was never trained on.
17
+ * - Zero dependencies: byte-level embeddings, ~25k parameters, weights ship
18
+ * as JSON inside the npm package.
19
+ * - CPU-fast: single matmul chain, sub-millisecond for 100+ options.
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.VOCAB = void 0;
23
+ exports.tokenize = tokenize;
24
+ exports.resetQueryCache = resetQueryCache;
25
+ exports.scoreOptions = scoreOptions;
26
+ exports.scoreScalar = scoreScalar;
27
+ exports.scoreNoul = scoreNoul;
28
+ /** Number of trigram hash buckets (must match tools/train_jev.py). */
29
+ exports.VOCAB = 2048;
30
+ /**
31
+ * FNV-1a 32-bit hash of a character trigram → bucket id.
32
+ * Must match the Python trainer exactly.
33
+ */
34
+ function trigramHash(b0, b1, b2) {
35
+ let h = 0x811c9dc5;
36
+ h = Math.imul(h ^ (b0 & 0xff), 0x01000193) >>> 0;
37
+ h = Math.imul(h ^ (b1 & 0xff), 0x01000193) >>> 0;
38
+ h = Math.imul(h ^ (b2 & 0xff), 0x01000193) >>> 0;
39
+ return h % exports.VOCAB;
40
+ }
41
+ /**
42
+ * Hashed trigram tokenization — character trigrams give much sharper text
43
+ * discrimination than raw bytes ("chat" vs "code" produce disjoint buckets).
44
+ */
45
+ function tokenize(text) {
46
+ const s = " " + text + " ";
47
+ const out = [];
48
+ const cap = 384;
49
+ for (let i = 0; i + 2 < s.length && out.length < cap; i++) {
50
+ out.push(trigramHash(s.charCodeAt(i), s.charCodeAt(i + 1), s.charCodeAt(i + 2)));
51
+ }
52
+ if (out.length === 0)
53
+ out.push(trigramHash(32, 32, 32));
54
+ return out;
55
+ }
56
+ function meanPool(rows, weights) {
57
+ const D = weights.dim;
58
+ const out = new Array(D).fill(0);
59
+ if (rows.length === 0)
60
+ return out;
61
+ for (const r of rows)
62
+ for (let d = 0; d < D; d++)
63
+ out[d] += r[d];
64
+ for (let d = 0; d < D; d++)
65
+ out[d] /= rows.length;
66
+ return out;
67
+ }
68
+ function embed(tokens, weights) {
69
+ return tokens.map((t) => weights.emb[t % exports.VOCAB]);
70
+ }
71
+ /** Cache: option text → query vector. Option texts are static per provider
72
+ * profile, so q_i never changes between calls — skip the W_q matmul. */
73
+ const queryCache = new Map();
74
+ function resetQueryCache() {
75
+ queryCache.clear();
76
+ }
77
+ /** Option text → query vector q_i = W_q · meanPool(bytes) + b_q */
78
+ function optionQuery(optionText, weights) {
79
+ const hit = queryCache.get(optionText);
80
+ if (hit)
81
+ return hit;
82
+ const D = weights.dim;
83
+ const h = meanPool(embed(tokenize(optionText), weights), weights);
84
+ const q = new Array(D).fill(0);
85
+ for (let i = 0; i < D; i++) {
86
+ let s = weights.bq[i];
87
+ for (let j = 0; j < D; j++)
88
+ s += weights.wq[i][j] * h[j];
89
+ q[i] = Math.tanh(s);
90
+ }
91
+ if (queryCache.size > 512)
92
+ queryCache.clear();
93
+ queryCache.set(optionText, q);
94
+ return q;
95
+ }
96
+ /**
97
+ * Score N options against a context in one pass.
98
+ * Attention: a_ij = softmax_j( q_i · E_j / √D ), c_i = Σ_j a_ij E_j
99
+ * Score: s_i = w · (q_i ⊙ c_i) + b, probs = softmax(s / T)
100
+ */
101
+ function scoreOptions(context, options, weights) {
102
+ const D = weights.dim;
103
+ const E = embed(tokenize(context), weights);
104
+ const scale = 1 / Math.sqrt(D);
105
+ const probs = [];
106
+ for (const opt of options) {
107
+ const q = optionQuery(opt, weights);
108
+ // attention over context tokens
109
+ const attn = E.map((e) => {
110
+ let dot = 0;
111
+ for (let d = 0; d < D; d++)
112
+ dot += q[d] * e[d];
113
+ return dot * scale;
114
+ });
115
+ const maxA = Math.max(...attn, 0);
116
+ const exps = attn.map((a) => Math.exp(a - maxA));
117
+ const sumA = exps.reduce((a, b) => a + b, 0) || 1;
118
+ // attended context vector c_i
119
+ const c = new Array(D).fill(0);
120
+ for (let j = 0; j < E.length; j++) {
121
+ const a = exps[j] / sumA;
122
+ if (a < 1e-6)
123
+ continue;
124
+ for (let d = 0; d < D; d++)
125
+ c[d] += a * E[j][d];
126
+ }
127
+ // score_i = w · (q ⊙ c) + b
128
+ let s = weights.b[0];
129
+ for (let d = 0; d < D; d++)
130
+ s += weights.w[d] * q[d] * c[d];
131
+ probs.push(s / weights.temperature);
132
+ }
133
+ const maxS = Math.max(...probs);
134
+ const expP = probs.map((p) => Math.exp(p - maxS));
135
+ const sumP = expP.reduce((a, b) => a + b, 0) || 1;
136
+ const final = expP.map((e) => e / sumP);
137
+ const top = final
138
+ .map((prob, index) => ({ index, prob }))
139
+ .sort((a, b) => b.prob - a.prob)
140
+ .slice(0, 5);
141
+ return { probs: final, top };
142
+ }
143
+ /** Context → scalar in [0,1] via sigmoid(w_s · meanPool + b_s). */
144
+ function scoreScalar(context, weights) {
145
+ const D = weights.dim;
146
+ const p = meanPool(embed(tokenize(context), weights), weights);
147
+ let s = weights.bs[0];
148
+ for (let d = 0; d < D; d++)
149
+ s += weights.ws[d] * p[d];
150
+ return 1 / (1 + Math.exp(-s));
151
+ }
152
+ /** Boolean decision with calibrated probability (2-way choice). */
153
+ function scoreNoul(context, questionText, weights) {
154
+ const r = scoreOptions(context, [questionText + " — yes", questionText + " — no"], weights);
155
+ const yesProb = r.probs[0];
156
+ return { value: yesProb >= 0.5, prob: Math.max(yesProb, 1 - yesProb) };
157
+ }
158
+ //# sourceMappingURL=optionAttention.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"optionAttention.js","sourceRoot":"","sources":["../../../src/routing/jev/optionAttention.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Remote backend for Jev-compatible endpoints.
3
+ *
4
+ * Works with:
5
+ * - api.typesafe.ai (commercial Jev, "System One")
6
+ * - ekzhang/openjev-sglang (open, Jev HTTP API on SGLang; self-host on Modal)
7
+ *
8
+ * Configure via env:
9
+ * A3M_JEV_URL — endpoint base (e.g. https://your-server.modal.direct)
10
+ * A3M_JEV_API_KEY — optional bearer token
11
+ */
12
+ import type { JevRequest, JevResponse } from "./types";
13
+ export declare function remoteConfigured(): boolean;
14
+ export declare function remoteDecide(req: JevRequest, timeoutMs?: number): Promise<JevResponse | null>;
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ /**
3
+ * Remote backend for Jev-compatible endpoints.
4
+ *
5
+ * Works with:
6
+ * - api.typesafe.ai (commercial Jev, "System One")
7
+ * - ekzhang/openjev-sglang (open, Jev HTTP API on SGLang; self-host on Modal)
8
+ *
9
+ * Configure via env:
10
+ * A3M_JEV_URL — endpoint base (e.g. https://your-server.modal.direct)
11
+ * A3M_JEV_API_KEY — optional bearer token
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.remoteConfigured = remoteConfigured;
15
+ exports.remoteDecide = remoteDecide;
16
+ function remoteConfigured() {
17
+ return Boolean(process.env.A3M_JEV_URL);
18
+ }
19
+ async function remoteDecide(req, timeoutMs = 2000) {
20
+ const base = process.env.A3M_JEV_URL;
21
+ if (!base)
22
+ return null;
23
+ const key = process.env.A3M_JEV_API_KEY || "";
24
+ const controller = new AbortController();
25
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
26
+ const t0 = Date.now();
27
+ try {
28
+ const res = await fetch(`${base.replace(/\/$/, "")}/v1/decide`, {
29
+ method: "POST",
30
+ headers: {
31
+ "content-type": "application/json",
32
+ ...(key ? { authorization: `Bearer ${key}` } : {}),
33
+ },
34
+ body: JSON.stringify(req),
35
+ signal: controller.signal,
36
+ });
37
+ if (!res.ok)
38
+ return null;
39
+ const data = (await res.json());
40
+ if (!Array.isArray(data.answers))
41
+ return null;
42
+ return {
43
+ answers: data.answers,
44
+ elapsed_ms: Date.now() - t0,
45
+ backend: "remote",
46
+ };
47
+ }
48
+ catch {
49
+ return null;
50
+ }
51
+ finally {
52
+ clearTimeout(timer);
53
+ }
54
+ }
55
+ //# sourceMappingURL=remote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote.js","sourceRoot":"","sources":["../../../src/routing/jev/remote.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;AAIH,4CAEC;AAED,oCA+BC;AAnCD,SAAgB,gBAAgB;IAC9B,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;AAC1C,CAAC;AAEM,KAAK,UAAU,YAAY,CAAC,GAAe,EAAE,SAAS,GAAG,IAAI;IAClE,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;IACrC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC;IAE9C,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;IAC9D,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACtB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,EAAE;YAC9D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACnD;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;YACzB,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QACzB,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA0B,CAAC;QACzD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC;YAAE,OAAO,IAAI,CAAC;QAC9C,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,OAAiC;YAC/C,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE;YAC3B,OAAO,EAAE,QAAQ;SAClB,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC"}