@aiping.cn/model_router 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +169 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +149 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/cloud.d.ts +23 -0
- package/dist/providers/cloud.d.ts.map +1 -0
- package/dist/providers/cloud.js +128 -0
- package/dist/providers/cloud.js.map +1 -0
- package/dist/providers/local.d.ts +25 -0
- package/dist/providers/local.d.ts.map +1 -0
- package/dist/providers/local.js +167 -0
- package/dist/providers/local.js.map +1 -0
- package/dist/router/router.d.ts +10 -0
- package/dist/router/router.d.ts.map +1 -0
- package/dist/router/router.js +48 -0
- package/dist/router/router.js.map +1 -0
- package/dist/router/rules.d.ts +61 -0
- package/dist/router/rules.d.ts.map +1 -0
- package/dist/router/rules.js +178 -0
- package/dist/router/rules.js.map +1 -0
- package/dist/router/scorer.d.ts +7 -0
- package/dist/router/scorer.d.ts.map +1 -0
- package/dist/router/scorer.js +34 -0
- package/dist/router/scorer.js.map +1 -0
- package/dist/setup/detector.d.ts +28 -0
- package/dist/setup/detector.d.ts.map +1 -0
- package/dist/setup/detector.js +169 -0
- package/dist/setup/detector.js.map +1 -0
- package/dist/setup/wizard.d.ts +6 -0
- package/dist/setup/wizard.d.ts.map +1 -0
- package/dist/setup/wizard.js +527 -0
- package/dist/setup/wizard.js.map +1 -0
- package/dist/types.d.ts +66 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -0
- package/openclaw.plugin.json +70 -0
- package/package.json +52 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LocalAdapterError = exports.LocalAdapter = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* LocalAdapter forwards requests to an Ollama-compatible local server
|
|
6
|
+
* using the OpenAI-compatible /v1/chat/completions endpoint.
|
|
7
|
+
*/
|
|
8
|
+
class LocalAdapter {
|
|
9
|
+
config;
|
|
10
|
+
constructor(config) {
|
|
11
|
+
this.config = config;
|
|
12
|
+
}
|
|
13
|
+
get baseUrl() {
|
|
14
|
+
return this.config.localProxyUrl.replace(/\/$/, '');
|
|
15
|
+
}
|
|
16
|
+
buildHeaders() {
|
|
17
|
+
const headers = {
|
|
18
|
+
'Content-Type': 'application/json',
|
|
19
|
+
};
|
|
20
|
+
if (this.config.localProxyKey) {
|
|
21
|
+
headers['Authorization'] = `Bearer ${this.config.localProxyKey}`;
|
|
22
|
+
}
|
|
23
|
+
return headers;
|
|
24
|
+
}
|
|
25
|
+
async chat(request) {
|
|
26
|
+
const body = JSON.stringify({
|
|
27
|
+
...request,
|
|
28
|
+
model: this.config.localModel,
|
|
29
|
+
stream: false,
|
|
30
|
+
});
|
|
31
|
+
const controller = new AbortController();
|
|
32
|
+
const timeoutId = setTimeout(() => controller.abort(), this.config.localTimeoutMs);
|
|
33
|
+
try {
|
|
34
|
+
const res = await fetch(`${this.baseUrl}/v1/chat/completions`, {
|
|
35
|
+
method: 'POST',
|
|
36
|
+
headers: this.buildHeaders(),
|
|
37
|
+
body,
|
|
38
|
+
signal: controller.signal,
|
|
39
|
+
});
|
|
40
|
+
if (!res.ok) {
|
|
41
|
+
const text = await res.text().catch(() => '');
|
|
42
|
+
throw new LocalAdapterError(`Local model returned ${res.status}: ${text}`, res.status);
|
|
43
|
+
}
|
|
44
|
+
const data = (await res.json());
|
|
45
|
+
// Normalise the model field so the caller always sees the virtual model name
|
|
46
|
+
return { ...data, model: request.model };
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
if (err.name === 'AbortError') {
|
|
50
|
+
throw new LocalAdapterError(`Local model timed out after ${this.config.localTimeoutMs}ms`, 408);
|
|
51
|
+
}
|
|
52
|
+
throw err;
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
clearTimeout(timeoutId);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async *chatStream(request) {
|
|
59
|
+
const body = JSON.stringify({
|
|
60
|
+
...request,
|
|
61
|
+
model: this.config.localModel,
|
|
62
|
+
stream: true,
|
|
63
|
+
});
|
|
64
|
+
const controller = new AbortController();
|
|
65
|
+
const timeoutId = setTimeout(() => controller.abort(), this.config.localTimeoutMs);
|
|
66
|
+
try {
|
|
67
|
+
const res = await fetch(`${this.baseUrl}/v1/chat/completions`, {
|
|
68
|
+
method: 'POST',
|
|
69
|
+
headers: this.buildHeaders(),
|
|
70
|
+
body,
|
|
71
|
+
signal: controller.signal,
|
|
72
|
+
});
|
|
73
|
+
if (!res.ok) {
|
|
74
|
+
const text = await res.text().catch(() => '');
|
|
75
|
+
throw new LocalAdapterError(`Local model returned ${res.status}: ${text}`, res.status);
|
|
76
|
+
}
|
|
77
|
+
if (!res.body)
|
|
78
|
+
throw new LocalAdapterError('Empty response body', 500);
|
|
79
|
+
const reader = res.body.getReader();
|
|
80
|
+
const decoder = new TextDecoder();
|
|
81
|
+
while (true) {
|
|
82
|
+
const { done, value } = await reader.read();
|
|
83
|
+
if (done)
|
|
84
|
+
break;
|
|
85
|
+
yield decoder.decode(value, { stream: true });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
if (err.name === 'AbortError') {
|
|
90
|
+
throw new LocalAdapterError(`Local model stream timed out after ${this.config.localTimeoutMs}ms`, 408);
|
|
91
|
+
}
|
|
92
|
+
throw err;
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
clearTimeout(timeoutId);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
async ping() {
|
|
99
|
+
const start = Date.now();
|
|
100
|
+
try {
|
|
101
|
+
const res = await fetch(`${this.baseUrl}/api/tags`, {
|
|
102
|
+
method: 'GET',
|
|
103
|
+
headers: this.buildHeaders(),
|
|
104
|
+
signal: AbortSignal.timeout(5000),
|
|
105
|
+
});
|
|
106
|
+
const latencyMs = Date.now() - start;
|
|
107
|
+
if (!res.ok) {
|
|
108
|
+
// Fallback: also try OpenAI-compatible /v1/models
|
|
109
|
+
const res2 = await fetch(`${this.baseUrl}/v1/models`, {
|
|
110
|
+
method: 'GET',
|
|
111
|
+
headers: this.buildHeaders(),
|
|
112
|
+
signal: AbortSignal.timeout(5000),
|
|
113
|
+
});
|
|
114
|
+
if (!res2.ok) {
|
|
115
|
+
return { ok: false, latencyMs, error: `HTTP ${res.status}` };
|
|
116
|
+
}
|
|
117
|
+
return { ok: true, latencyMs: Date.now() - start };
|
|
118
|
+
}
|
|
119
|
+
return { ok: true, latencyMs };
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
return {
|
|
123
|
+
ok: false,
|
|
124
|
+
latencyMs: Date.now() - start,
|
|
125
|
+
error: err.message,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/** Returns list of model names available on the local server. */
|
|
130
|
+
async listModels() {
|
|
131
|
+
try {
|
|
132
|
+
// Try Ollama native endpoint first
|
|
133
|
+
const res = await fetch(`${this.baseUrl}/api/tags`, {
|
|
134
|
+
headers: this.buildHeaders(),
|
|
135
|
+
signal: AbortSignal.timeout(5000),
|
|
136
|
+
});
|
|
137
|
+
if (res.ok) {
|
|
138
|
+
const data = (await res.json());
|
|
139
|
+
return (data.models ?? []).map((m) => m.name);
|
|
140
|
+
}
|
|
141
|
+
// Fallback: OpenAI-compatible /v1/models
|
|
142
|
+
const res2 = await fetch(`${this.baseUrl}/v1/models`, {
|
|
143
|
+
headers: this.buildHeaders(),
|
|
144
|
+
signal: AbortSignal.timeout(5000),
|
|
145
|
+
});
|
|
146
|
+
if (res2.ok) {
|
|
147
|
+
const data2 = (await res2.json());
|
|
148
|
+
return (data2.data ?? []).map((m) => m.id);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
// ignored
|
|
153
|
+
}
|
|
154
|
+
return [];
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
exports.LocalAdapter = LocalAdapter;
|
|
158
|
+
class LocalAdapterError extends Error {
|
|
159
|
+
statusCode;
|
|
160
|
+
constructor(message, statusCode) {
|
|
161
|
+
super(message);
|
|
162
|
+
this.statusCode = statusCode;
|
|
163
|
+
this.name = 'LocalAdapterError';
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
exports.LocalAdapterError = LocalAdapterError;
|
|
167
|
+
//# sourceMappingURL=local.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local.js","sourceRoot":"","sources":["../../src/providers/local.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ChatRequest, RoutingDecision, PluginConfig } from '../types.js';
|
|
2
|
+
import { Scorer } from './scorer.js';
|
|
3
|
+
export declare class Router {
|
|
4
|
+
private readonly scorer;
|
|
5
|
+
private readonly config;
|
|
6
|
+
constructor(config: PluginConfig, scorer?: Scorer);
|
|
7
|
+
decide(request: ChatRequest): RoutingDecision;
|
|
8
|
+
private log;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/router/router.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,eAAe,EACf,YAAY,EACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,qBAAa,MAAM;IACjB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;gBAE1B,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,MAAM;IAKjD,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,eAAe;IA+B7C,OAAO,CAAC,GAAG;CAQZ"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Router = void 0;
|
|
4
|
+
const scorer_js_1 = require("./scorer.js");
|
|
5
|
+
class Router {
|
|
6
|
+
scorer;
|
|
7
|
+
config;
|
|
8
|
+
constructor(config, scorer) {
|
|
9
|
+
this.config = config;
|
|
10
|
+
this.scorer = scorer ?? new scorer_js_1.Scorer();
|
|
11
|
+
}
|
|
12
|
+
decide(request) {
|
|
13
|
+
const { totalScore, dimensionScores, forced } = this.scorer.score(request);
|
|
14
|
+
if (forced) {
|
|
15
|
+
const decision = {
|
|
16
|
+
target: forced,
|
|
17
|
+
score: totalScore,
|
|
18
|
+
forced: true,
|
|
19
|
+
reasons: dimensionScores.map((d) => `[${d.name}] ${d.reason}`),
|
|
20
|
+
};
|
|
21
|
+
this.log(decision);
|
|
22
|
+
return decision;
|
|
23
|
+
}
|
|
24
|
+
const target = totalScore >= this.config.routingThreshold ? 'cloud' : 'local';
|
|
25
|
+
const decision = {
|
|
26
|
+
target,
|
|
27
|
+
score: totalScore,
|
|
28
|
+
forced: false,
|
|
29
|
+
reasons: [
|
|
30
|
+
`Score ${totalScore} vs threshold ${this.config.routingThreshold} → ${target}`,
|
|
31
|
+
...dimensionScores
|
|
32
|
+
.filter((d) => d.score > 0)
|
|
33
|
+
.map((d) => `[${d.name}] ${d.reason} (+${d.score})`),
|
|
34
|
+
],
|
|
35
|
+
};
|
|
36
|
+
this.log(decision);
|
|
37
|
+
return decision;
|
|
38
|
+
}
|
|
39
|
+
log(decision) {
|
|
40
|
+
if (!this.config.debugRouting)
|
|
41
|
+
return;
|
|
42
|
+
console.log(`[aiping:router] → ${decision.target.toUpperCase()} ` +
|
|
43
|
+
`(score=${decision.score}, forced=${decision.forced})\n` +
|
|
44
|
+
decision.reasons.map((r) => ` • ${r}`).join('\n'));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.Router = Router;
|
|
48
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/router/router.ts"],"names":[],"mappings":";;;AAKA,2CAAqC;AAErC,MAAa,MAAM;IACA,MAAM,CAAS;IACf,MAAM,CAAe;IAEtC,YAAY,MAAoB,EAAE,MAAe;QAC/C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,IAAI,kBAAM,EAAE,CAAC;IACvC,CAAC;IAED,MAAM,CAAC,OAAoB;QACzB,MAAM,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAE3E,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,QAAQ,GAAoB;gBAChC,MAAM,EAAE,MAAM;gBACd,KAAK,EAAE,UAAU;gBACjB,MAAM,EAAE,IAAI;gBACZ,OAAO,EAAE,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC;aAC/D,CAAC;YACF,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACnB,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,MAAM,MAAM,GAAG,UAAU,IAAI,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;QAC9E,MAAM,QAAQ,GAAoB;YAChC,MAAM;YACN,KAAK,EAAE,UAAU;YACjB,MAAM,EAAE,KAAK;YACb,OAAO,EAAE;gBACP,SAAS,UAAU,iBAAiB,IAAI,CAAC,MAAM,CAAC,gBAAgB,MAAM,MAAM,EAAE;gBAC9E,GAAG,eAAe;qBACf,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;qBAC1B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,KAAK,GAAG,CAAC;aACvD;SACF,CAAC;QAEF,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACnB,OAAO,QAAQ,CAAC;IAClB,CAAC;IAEO,GAAG,CAAC,QAAyB;QACnC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY;YAAE,OAAO;QACtC,OAAO,CAAC,GAAG,CACT,qBAAqB,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,GAAG;YACnD,UAAU,QAAQ,CAAC,KAAK,YAAY,QAAQ,CAAC,MAAM,KAAK;YACxD,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CACrD,CAAC;IACJ,CAAC;CACF;AAhDD,wBAgDC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { ChatRequest, DimensionScore, RuleScorer } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Token Count Scorer
|
|
4
|
+
* Long inputs are harder for small local models (limited context window).
|
|
5
|
+
* > 4000 estimated tokens → full 30 points (relaxed to keep ~90% local)
|
|
6
|
+
* Scales linearly from 0 at 1500 tokens to 30 at 4000 tokens.
|
|
7
|
+
*/
|
|
8
|
+
export declare class TokenCountScorer implements RuleScorer {
|
|
9
|
+
readonly name = "token_count";
|
|
10
|
+
readonly maxScore = 30;
|
|
11
|
+
private readonly LOW_THRESHOLD;
|
|
12
|
+
private readonly HIGH_THRESHOLD;
|
|
13
|
+
score(request: ChatRequest): DimensionScore;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Code Complexity Scorer
|
|
17
|
+
* Large code blocks require strong reasoning capabilities.
|
|
18
|
+
* Code fences with > 80 lines → full 20 points (relaxed to keep ~90% local).
|
|
19
|
+
*/
|
|
20
|
+
export declare class CodeComplexityScorer implements RuleScorer {
|
|
21
|
+
readonly name = "code_complexity";
|
|
22
|
+
readonly maxScore = 20;
|
|
23
|
+
private readonly LINE_THRESHOLD;
|
|
24
|
+
score(request: ChatRequest): DimensionScore;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Reasoning Depth Scorer
|
|
28
|
+
* Only triggers for clearly heavy analytical tasks (≥2 strong keywords).
|
|
29
|
+
* Single keyword matches no longer score to reduce cloud routing rate.
|
|
30
|
+
*/
|
|
31
|
+
export declare class ReasoningDepthScorer implements RuleScorer {
|
|
32
|
+
readonly name = "reasoning_depth";
|
|
33
|
+
readonly maxScore = 15;
|
|
34
|
+
private readonly STRONG_KEYWORDS;
|
|
35
|
+
score(request: ChatRequest): DimensionScore;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Multi-turn Context Scorer
|
|
39
|
+
* Long conversation histories require the model to synthesize and track many facts.
|
|
40
|
+
* > 16 messages → full 20 points (relaxed to keep ~90% local).
|
|
41
|
+
*/
|
|
42
|
+
export declare class MultiTurnContextScorer implements RuleScorer {
|
|
43
|
+
readonly name = "multi_turn_context";
|
|
44
|
+
readonly maxScore = 20;
|
|
45
|
+
private readonly TURN_THRESHOLD;
|
|
46
|
+
score(request: ChatRequest): DimensionScore;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Override Scorer
|
|
50
|
+
* Detects explicit @local or @cloud directives in the last user message.
|
|
51
|
+
* These force routing and override all other scores.
|
|
52
|
+
*/
|
|
53
|
+
export declare class OverrideScorer implements RuleScorer {
|
|
54
|
+
readonly name = "override_directive";
|
|
55
|
+
readonly maxScore = 0;
|
|
56
|
+
score(request: ChatRequest): DimensionScore & {
|
|
57
|
+
forced?: 'local' | 'cloud';
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export declare const DEFAULT_SCORERS: RuleScorer[];
|
|
61
|
+
//# sourceMappingURL=rules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../src/router/rules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAa3E;;;;;GAKG;AACH,qBAAa,gBAAiB,YAAW,UAAU;IACjD,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,QAAQ,CAAC,QAAQ,MAAM;IAEvB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAQ;IACtC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAQ;IAEvC,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc;CAoB5C;AAED;;;;GAIG;AACH,qBAAa,oBAAqB,YAAW,UAAU;IACrD,QAAQ,CAAC,IAAI,qBAAqB;IAClC,QAAQ,CAAC,QAAQ,MAAM;IAEvB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAM;IAErC,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc;CAuB5C;AAED;;;;GAIG;AACH,qBAAa,oBAAqB,YAAW,UAAU;IACrD,QAAQ,CAAC,IAAI,qBAAqB;IAClC,QAAQ,CAAC,QAAQ,MAAM;IAGvB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAQ9B;IAEF,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc;CAe5C;AAED;;;;GAIG;AACH,qBAAa,sBAAuB,YAAW,UAAU;IACvD,QAAQ,CAAC,IAAI,wBAAwB;IACrC,QAAQ,CAAC,QAAQ,MAAM;IAEvB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAM;IAErC,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc;CAc5C;AAED;;;;GAIG;AACH,qBAAa,cAAe,YAAW,UAAU;IAC/C,QAAQ,CAAC,IAAI,wBAAwB;IACrC,QAAQ,CAAC,QAAQ,KAAK;IAEtB,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,GAAG;QAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAA;KAAE;CAoC7E;AAGD,eAAO,MAAM,eAAe,EAAE,UAAU,EAMvC,CAAC"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_SCORERS = exports.OverrideScorer = exports.MultiTurnContextScorer = exports.ReasoningDepthScorer = exports.CodeComplexityScorer = exports.TokenCountScorer = void 0;
|
|
4
|
+
// Estimates token count from a string using a simple heuristic (~4 chars per token)
|
|
5
|
+
function estimateTokens(text) {
|
|
6
|
+
return Math.ceil(text.length / 4);
|
|
7
|
+
}
|
|
8
|
+
function extractAllText(request) {
|
|
9
|
+
return request.messages
|
|
10
|
+
.map((m) => (typeof m.content === 'string' ? m.content : ''))
|
|
11
|
+
.join('\n');
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Token Count Scorer
|
|
15
|
+
* Long inputs are harder for small local models (limited context window).
|
|
16
|
+
* > 4000 estimated tokens → full 30 points (relaxed to keep ~90% local)
|
|
17
|
+
* Scales linearly from 0 at 1500 tokens to 30 at 4000 tokens.
|
|
18
|
+
*/
|
|
19
|
+
class TokenCountScorer {
|
|
20
|
+
name = 'token_count';
|
|
21
|
+
maxScore = 30;
|
|
22
|
+
LOW_THRESHOLD = 1500;
|
|
23
|
+
HIGH_THRESHOLD = 4000;
|
|
24
|
+
score(request) {
|
|
25
|
+
const text = extractAllText(request);
|
|
26
|
+
const tokens = estimateTokens(text);
|
|
27
|
+
let points = 0;
|
|
28
|
+
let reason = `~${tokens} estimated tokens`;
|
|
29
|
+
if (tokens >= this.HIGH_THRESHOLD) {
|
|
30
|
+
points = this.maxScore;
|
|
31
|
+
reason += ` (≥${this.HIGH_THRESHOLD} → cloud favored)`;
|
|
32
|
+
}
|
|
33
|
+
else if (tokens > this.LOW_THRESHOLD) {
|
|
34
|
+
points = Math.round(((tokens - this.LOW_THRESHOLD) / (this.HIGH_THRESHOLD - this.LOW_THRESHOLD)) *
|
|
35
|
+
this.maxScore);
|
|
36
|
+
reason += ` (scaling ${this.LOW_THRESHOLD}-${this.HIGH_THRESHOLD})`;
|
|
37
|
+
}
|
|
38
|
+
return { name: this.name, score: points, maxScore: this.maxScore, reason };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
exports.TokenCountScorer = TokenCountScorer;
|
|
42
|
+
/**
|
|
43
|
+
* Code Complexity Scorer
|
|
44
|
+
* Large code blocks require strong reasoning capabilities.
|
|
45
|
+
* Code fences with > 80 lines → full 20 points (relaxed to keep ~90% local).
|
|
46
|
+
*/
|
|
47
|
+
class CodeComplexityScorer {
|
|
48
|
+
name = 'code_complexity';
|
|
49
|
+
maxScore = 20;
|
|
50
|
+
LINE_THRESHOLD = 80;
|
|
51
|
+
score(request) {
|
|
52
|
+
const text = extractAllText(request);
|
|
53
|
+
const codeBlockRegex = /```[\s\S]*?```/g;
|
|
54
|
+
const blocks = text.match(codeBlockRegex) ?? [];
|
|
55
|
+
let maxBlockLines = 0;
|
|
56
|
+
for (const block of blocks) {
|
|
57
|
+
const lines = block.split('\n').length;
|
|
58
|
+
if (lines > maxBlockLines)
|
|
59
|
+
maxBlockLines = lines;
|
|
60
|
+
}
|
|
61
|
+
let points = 0;
|
|
62
|
+
let reason = `${blocks.length} code block(s), max ${maxBlockLines} lines`;
|
|
63
|
+
if (maxBlockLines >= this.LINE_THRESHOLD) {
|
|
64
|
+
points = this.maxScore;
|
|
65
|
+
reason += ` (≥${this.LINE_THRESHOLD} lines → cloud favored)`;
|
|
66
|
+
}
|
|
67
|
+
else if (blocks.length > 0) {
|
|
68
|
+
points = Math.round((maxBlockLines / this.LINE_THRESHOLD) * this.maxScore);
|
|
69
|
+
}
|
|
70
|
+
return { name: this.name, score: points, maxScore: this.maxScore, reason };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
exports.CodeComplexityScorer = CodeComplexityScorer;
|
|
74
|
+
/**
|
|
75
|
+
* Reasoning Depth Scorer
|
|
76
|
+
* Only triggers for clearly heavy analytical tasks (≥2 strong keywords).
|
|
77
|
+
* Single keyword matches no longer score to reduce cloud routing rate.
|
|
78
|
+
*/
|
|
79
|
+
class ReasoningDepthScorer {
|
|
80
|
+
name = 'reasoning_depth';
|
|
81
|
+
maxScore = 15;
|
|
82
|
+
// Only "strong" multi-word or unambiguously complex phrases trigger scoring
|
|
83
|
+
STRONG_KEYWORDS = [
|
|
84
|
+
// English – multi-word / unambiguous
|
|
85
|
+
'explain in detail', 'step by step', 'step-by-step',
|
|
86
|
+
'reason through', 'pros and cons', 'trade-offs', 'trade offs',
|
|
87
|
+
'critically evaluate', 'comprehensive analysis',
|
|
88
|
+
// Chinese – unambiguously heavy
|
|
89
|
+
'详细分析', '逐步分析', '全面对比', '深度分析', '系统性分析',
|
|
90
|
+
'优缺点对比', '深入推理',
|
|
91
|
+
];
|
|
92
|
+
score(request) {
|
|
93
|
+
const text = extractAllText(request).toLowerCase();
|
|
94
|
+
const matched = this.STRONG_KEYWORDS.filter((kw) => text.includes(kw.toLowerCase()));
|
|
95
|
+
// Require ≥1 strong multi-word phrase to score
|
|
96
|
+
const points = matched.length >= 1 ? this.maxScore : 0;
|
|
97
|
+
const reason = matched.length >= 1
|
|
98
|
+
? `强推理关键词: ${matched.slice(0, 3).join(', ')}`
|
|
99
|
+
: '无强推理关键词';
|
|
100
|
+
return { name: this.name, score: points, maxScore: this.maxScore, reason };
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
exports.ReasoningDepthScorer = ReasoningDepthScorer;
|
|
104
|
+
/**
|
|
105
|
+
* Multi-turn Context Scorer
|
|
106
|
+
* Long conversation histories require the model to synthesize and track many facts.
|
|
107
|
+
* > 16 messages → full 20 points (relaxed to keep ~90% local).
|
|
108
|
+
*/
|
|
109
|
+
class MultiTurnContextScorer {
|
|
110
|
+
name = 'multi_turn_context';
|
|
111
|
+
maxScore = 20;
|
|
112
|
+
TURN_THRESHOLD = 16;
|
|
113
|
+
score(request) {
|
|
114
|
+
const turns = request.messages.length;
|
|
115
|
+
let points = 0;
|
|
116
|
+
let reason = `${turns} message(s) in context`;
|
|
117
|
+
if (turns >= this.TURN_THRESHOLD) {
|
|
118
|
+
points = this.maxScore;
|
|
119
|
+
reason += ` (≥${this.TURN_THRESHOLD} turns → cloud favored)`;
|
|
120
|
+
}
|
|
121
|
+
else if (turns > 1) {
|
|
122
|
+
points = Math.round((turns / this.TURN_THRESHOLD) * this.maxScore);
|
|
123
|
+
}
|
|
124
|
+
return { name: this.name, score: points, maxScore: this.maxScore, reason };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
exports.MultiTurnContextScorer = MultiTurnContextScorer;
|
|
128
|
+
/**
|
|
129
|
+
* Override Scorer
|
|
130
|
+
* Detects explicit @local or @cloud directives in the last user message.
|
|
131
|
+
* These force routing and override all other scores.
|
|
132
|
+
*/
|
|
133
|
+
class OverrideScorer {
|
|
134
|
+
name = 'override_directive';
|
|
135
|
+
maxScore = 0; // Does not contribute to score; uses forced field
|
|
136
|
+
score(request) {
|
|
137
|
+
const lastUserMessage = [...request.messages]
|
|
138
|
+
.reverse()
|
|
139
|
+
.find((m) => m.role === 'user');
|
|
140
|
+
const content = typeof lastUserMessage?.content === 'string'
|
|
141
|
+
? lastUserMessage.content
|
|
142
|
+
: '';
|
|
143
|
+
if (/@local\b/i.test(content)) {
|
|
144
|
+
return {
|
|
145
|
+
name: this.name,
|
|
146
|
+
score: 0,
|
|
147
|
+
maxScore: this.maxScore,
|
|
148
|
+
reason: '@local directive detected — forcing local routing',
|
|
149
|
+
forced: 'local',
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
if (/@cloud\b/i.test(content)) {
|
|
153
|
+
return {
|
|
154
|
+
name: this.name,
|
|
155
|
+
score: 0,
|
|
156
|
+
maxScore: this.maxScore,
|
|
157
|
+
reason: '@cloud directive detected — forcing cloud routing',
|
|
158
|
+
forced: 'cloud',
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
name: this.name,
|
|
163
|
+
score: 0,
|
|
164
|
+
maxScore: this.maxScore,
|
|
165
|
+
reason: 'No override directive',
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
exports.OverrideScorer = OverrideScorer;
|
|
170
|
+
// Default set of rule scorers (ordered by processing speed, cheapest first)
|
|
171
|
+
exports.DEFAULT_SCORERS = [
|
|
172
|
+
new OverrideScorer(),
|
|
173
|
+
new MultiTurnContextScorer(),
|
|
174
|
+
new TokenCountScorer(),
|
|
175
|
+
new CodeComplexityScorer(),
|
|
176
|
+
new ReasoningDepthScorer(),
|
|
177
|
+
];
|
|
178
|
+
//# sourceMappingURL=rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/router/rules.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scorer.d.ts","sourceRoot":"","sources":["../../src/router/scorer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG1E,qBAAa,MAAM;IACjB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;gBAE3B,OAAO,GAAE,UAAU,EAAoB;IAInD,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,aAAa;CA2B3C"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Scorer = void 0;
|
|
4
|
+
const rules_js_1 = require("./rules.js");
|
|
5
|
+
class Scorer {
|
|
6
|
+
scorers;
|
|
7
|
+
constructor(scorers = rules_js_1.DEFAULT_SCORERS) {
|
|
8
|
+
this.scorers = scorers;
|
|
9
|
+
}
|
|
10
|
+
score(request) {
|
|
11
|
+
let totalScore = 0;
|
|
12
|
+
const dimensionScores = [];
|
|
13
|
+
let forced;
|
|
14
|
+
for (const scorer of this.scorers) {
|
|
15
|
+
// OverrideScorer may return a `forced` field via duck-typing
|
|
16
|
+
const result = scorer.score(request);
|
|
17
|
+
dimensionScores.push({
|
|
18
|
+
name: result.name,
|
|
19
|
+
score: result.score,
|
|
20
|
+
maxScore: result.maxScore,
|
|
21
|
+
reason: result.reason,
|
|
22
|
+
});
|
|
23
|
+
totalScore += result.score;
|
|
24
|
+
if (result.forced) {
|
|
25
|
+
forced = result.forced;
|
|
26
|
+
// Short-circuit: override directives take immediate effect
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return { totalScore, dimensionScores, forced };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.Scorer = Scorer;
|
|
34
|
+
//# sourceMappingURL=scorer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scorer.js","sourceRoot":"","sources":["../../src/router/scorer.ts"],"names":[],"mappings":";;;AACA,yCAA6D;AAE7D,MAAa,MAAM;IACA,OAAO,CAAe;IAEvC,YAAY,UAAwB,0BAAe;QACjD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,OAAoB;QACxB,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,MAAM,eAAe,GAAG,EAAE,CAAC;QAC3B,IAAI,MAAqC,CAAC;QAE1C,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClC,6DAA6D;YAC7D,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAwC,CAAC;YAE5E,eAAe,CAAC,IAAI,CAAC;gBACnB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,MAAM,EAAE,MAAM,CAAC,MAAM;aACtB,CAAC,CAAC;YAEH,UAAU,IAAI,MAAM,CAAC,KAAK,CAAC;YAE3B,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;gBAClB,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;gBACvB,2DAA2D;gBAC3D,MAAM;YACR,CAAC;QACH,CAAC;QAED,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,EAAE,CAAC;IACjD,CAAC;CACF;AAlCD,wBAkCC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface OllamaModel {
|
|
2
|
+
name: string;
|
|
3
|
+
size?: string;
|
|
4
|
+
modifiedAt?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface OllamaStatus {
|
|
7
|
+
binaryFound: boolean;
|
|
8
|
+
serviceRunning: boolean;
|
|
9
|
+
models: OllamaModel[];
|
|
10
|
+
latencyMs?: number;
|
|
11
|
+
error?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface AipingStatus {
|
|
14
|
+
reachable: boolean;
|
|
15
|
+
keyValid: boolean;
|
|
16
|
+
model: string;
|
|
17
|
+
latencyMs?: number;
|
|
18
|
+
error?: string;
|
|
19
|
+
errorCode?: number;
|
|
20
|
+
}
|
|
21
|
+
export declare function detectOllama(baseUrl?: string): Promise<OllamaStatus>;
|
|
22
|
+
export declare function detectAiping(apiKey: string, model?: string): Promise<AipingStatus>;
|
|
23
|
+
export declare const RECOMMENDED_MODELS: Array<{
|
|
24
|
+
name: string;
|
|
25
|
+
size: string;
|
|
26
|
+
desc: string;
|
|
27
|
+
}>;
|
|
28
|
+
//# sourceMappingURL=detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../../src/setup/detector.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,OAAO,CAAC;IACxB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD,wBAAsB,YAAY,CAAC,OAAO,SAA2B,GAAG,OAAO,CAAC,YAAY,CAAC,CA4C5F;AA2CD,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,SAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CA2E5F;AAMD,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAMlF,CAAC"}
|