@routerxjs/core 0.0.0-dev-20260318021459
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/dist/chunk-VPPWHNGZ.js +91 -0
- package/dist/chunk-VPPWHNGZ.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/router/index.d.ts +101 -0
- package/dist/router/index.js +7 -0
- package/dist/router/index.js.map +1 -0
- package/package.json +29 -0
- package/src/index.ts +10 -0
- package/src/router/Router.ts +121 -0
- package/src/router/index.ts +8 -0
- package/src/router/types.ts +77 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// src/router/Router.ts
|
|
2
|
+
function modelName(entry) {
|
|
3
|
+
return typeof entry === "string" ? entry : entry.name;
|
|
4
|
+
}
|
|
5
|
+
function upstreamModelName(entry) {
|
|
6
|
+
return typeof entry === "string" ? entry : entry.upstreamModel;
|
|
7
|
+
}
|
|
8
|
+
var Router = class {
|
|
9
|
+
providers;
|
|
10
|
+
defaultProviderId;
|
|
11
|
+
constructor(config) {
|
|
12
|
+
this.providers = config.providers;
|
|
13
|
+
this.defaultProviderId = config.defaultProviderId;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Find the best provider for a given model
|
|
17
|
+
*/
|
|
18
|
+
route(model) {
|
|
19
|
+
const candidates = [];
|
|
20
|
+
for (const provider of this.providers) {
|
|
21
|
+
if (provider.enabled === false) continue;
|
|
22
|
+
const entry = provider.models.find((m) => modelName(m) === model);
|
|
23
|
+
if (entry) {
|
|
24
|
+
candidates.push({ provider, entry });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
candidates.sort((a, b) => (a.provider.priority ?? 100) - (b.provider.priority ?? 100));
|
|
28
|
+
if (candidates.length > 0) {
|
|
29
|
+
const { provider, entry } = candidates[0];
|
|
30
|
+
return {
|
|
31
|
+
provider,
|
|
32
|
+
model,
|
|
33
|
+
upstreamModel: upstreamModelName(entry)
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
if (this.defaultProviderId) {
|
|
37
|
+
const defaultProvider = this.providers.find(
|
|
38
|
+
(p) => p.id === this.defaultProviderId && p.enabled !== false
|
|
39
|
+
);
|
|
40
|
+
if (defaultProvider) {
|
|
41
|
+
return { provider: defaultProvider, model, upstreamModel: model };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* List all available models across all providers
|
|
48
|
+
*/
|
|
49
|
+
listModels() {
|
|
50
|
+
const models = [];
|
|
51
|
+
for (const provider of this.providers) {
|
|
52
|
+
if (provider.enabled === false) continue;
|
|
53
|
+
for (const entry of provider.models) {
|
|
54
|
+
models.push({
|
|
55
|
+
model: modelName(entry),
|
|
56
|
+
upstreamModel: upstreamModelName(entry),
|
|
57
|
+
providerId: provider.id,
|
|
58
|
+
protocol: provider.protocol
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return models;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Add a provider at runtime
|
|
66
|
+
*/
|
|
67
|
+
addProvider(provider) {
|
|
68
|
+
const existing = this.providers.findIndex((p) => p.id === provider.id);
|
|
69
|
+
if (existing >= 0) {
|
|
70
|
+
this.providers[existing] = provider;
|
|
71
|
+
} else {
|
|
72
|
+
this.providers.push(provider);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Remove a provider
|
|
77
|
+
*/
|
|
78
|
+
removeProvider(id) {
|
|
79
|
+
const idx = this.providers.findIndex((p) => p.id === id);
|
|
80
|
+
if (idx >= 0) {
|
|
81
|
+
this.providers.splice(idx, 1);
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export {
|
|
89
|
+
Router
|
|
90
|
+
};
|
|
91
|
+
//# sourceMappingURL=chunk-VPPWHNGZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/router/Router.ts"],"sourcesContent":["/**\n * Router — model matching and provider selection\n *\n * Given a model name, find the best provider to serve it.\n * Supports model name mapping (client name → upstream provider name).\n */\n\nimport type { ModelEntry, RegisteredProvider, RouteResult, RouterConfig } from \"./types\";\n\n/** Resolve a ModelEntry to its client-facing name */\nfunction modelName(entry: ModelEntry): string {\n return typeof entry === \"string\" ? entry : entry.name;\n}\n\n/** Resolve a ModelEntry to its upstream name */\nfunction upstreamModelName(entry: ModelEntry): string {\n return typeof entry === \"string\" ? entry : entry.upstreamModel;\n}\n\nexport class Router {\n private providers: RegisteredProvider[];\n private defaultProviderId?: string;\n\n constructor(config: RouterConfig) {\n this.providers = config.providers;\n this.defaultProviderId = config.defaultProviderId;\n }\n\n /**\n * Find the best provider for a given model\n */\n route(model: string): RouteResult | null {\n // Find providers that have this model (by client-facing name)\n const candidates: Array<{ provider: RegisteredProvider; entry: ModelEntry }> = [];\n\n for (const provider of this.providers) {\n if (provider.enabled === false) continue;\n const entry = provider.models.find((m) => modelName(m) === model);\n if (entry) {\n candidates.push({ provider, entry });\n }\n }\n\n // Sort by priority\n candidates.sort((a, b) => (a.provider.priority ?? 100) - (b.provider.priority ?? 100));\n\n if (candidates.length > 0) {\n const { provider, entry } = candidates[0];\n return {\n provider,\n model,\n upstreamModel: upstreamModelName(entry),\n };\n }\n\n // Fallback to default provider\n if (this.defaultProviderId) {\n const defaultProvider = this.providers.find(\n (p) => p.id === this.defaultProviderId && p.enabled !== false\n );\n if (defaultProvider) {\n return { provider: defaultProvider, model, upstreamModel: model };\n }\n }\n\n return null;\n }\n\n /**\n * List all available models across all providers\n */\n listModels(): Array<{\n model: string;\n upstreamModel: string;\n providerId: string;\n protocol: string;\n }> {\n const models: Array<{\n model: string;\n upstreamModel: string;\n providerId: string;\n protocol: string;\n }> = [];\n for (const provider of this.providers) {\n if (provider.enabled === false) continue;\n for (const entry of provider.models) {\n models.push({\n model: modelName(entry),\n upstreamModel: upstreamModelName(entry),\n providerId: provider.id,\n protocol: provider.protocol,\n });\n }\n }\n return models;\n }\n\n /**\n * Add a provider at runtime\n */\n addProvider(provider: RegisteredProvider): void {\n const existing = this.providers.findIndex((p) => p.id === provider.id);\n if (existing >= 0) {\n this.providers[existing] = provider;\n } else {\n this.providers.push(provider);\n }\n }\n\n /**\n * Remove a provider\n */\n removeProvider(id: string): boolean {\n const idx = this.providers.findIndex((p) => p.id === id);\n if (idx >= 0) {\n this.providers.splice(idx, 1);\n return true;\n }\n return false;\n }\n}\n"],"mappings":";AAUA,SAAS,UAAU,OAA2B;AAC5C,SAAO,OAAO,UAAU,WAAW,QAAQ,MAAM;AACnD;AAGA,SAAS,kBAAkB,OAA2B;AACpD,SAAO,OAAO,UAAU,WAAW,QAAQ,MAAM;AACnD;AAEO,IAAM,SAAN,MAAa;AAAA,EACV;AAAA,EACA;AAAA,EAER,YAAY,QAAsB;AAChC,SAAK,YAAY,OAAO;AACxB,SAAK,oBAAoB,OAAO;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAmC;AAEvC,UAAM,aAAyE,CAAC;AAEhF,eAAW,YAAY,KAAK,WAAW;AACrC,UAAI,SAAS,YAAY,MAAO;AAChC,YAAM,QAAQ,SAAS,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC,MAAM,KAAK;AAChE,UAAI,OAAO;AACT,mBAAW,KAAK,EAAE,UAAU,MAAM,CAAC;AAAA,MACrC;AAAA,IACF;AAGA,eAAW,KAAK,CAAC,GAAG,OAAO,EAAE,SAAS,YAAY,QAAQ,EAAE,SAAS,YAAY,IAAI;AAErF,QAAI,WAAW,SAAS,GAAG;AACzB,YAAM,EAAE,UAAU,MAAM,IAAI,WAAW,CAAC;AACxC,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,eAAe,kBAAkB,KAAK;AAAA,MACxC;AAAA,IACF;AAGA,QAAI,KAAK,mBAAmB;AAC1B,YAAM,kBAAkB,KAAK,UAAU;AAAA,QACrC,CAAC,MAAM,EAAE,OAAO,KAAK,qBAAqB,EAAE,YAAY;AAAA,MAC1D;AACA,UAAI,iBAAiB;AACnB,eAAO,EAAE,UAAU,iBAAiB,OAAO,eAAe,MAAM;AAAA,MAClE;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,aAKG;AACD,UAAM,SAKD,CAAC;AACN,eAAW,YAAY,KAAK,WAAW;AACrC,UAAI,SAAS,YAAY,MAAO;AAChC,iBAAW,SAAS,SAAS,QAAQ;AACnC,eAAO,KAAK;AAAA,UACV,OAAO,UAAU,KAAK;AAAA,UACtB,eAAe,kBAAkB,KAAK;AAAA,UACtC,YAAY,SAAS;AAAA,UACrB,UAAU,SAAS;AAAA,QACrB,CAAC;AAAA,MACH;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,UAAoC;AAC9C,UAAM,WAAW,KAAK,UAAU,UAAU,CAAC,MAAM,EAAE,OAAO,SAAS,EAAE;AACrE,QAAI,YAAY,GAAG;AACjB,WAAK,UAAU,QAAQ,IAAI;AAAA,IAC7B,OAAO;AACL,WAAK,UAAU,KAAK,QAAQ;AAAA,IAC9B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,IAAqB;AAClC,UAAM,MAAM,KAAK,UAAU,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE;AACvD,QAAI,OAAO,GAAG;AACZ,WAAK,UAAU,OAAO,KAAK,CAAC;AAC5B,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AACF;","names":[]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ModelEntry, ProviderProtocol, RegisteredProvider, RouteResult, Router, RouterConfig } from './router/index.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Router Types — routing configuration and model matching
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Supported upstream provider protocols
|
|
6
|
+
*/
|
|
7
|
+
type ProviderProtocol = "openai-compatible" | "anthropic";
|
|
8
|
+
/**
|
|
9
|
+
* Model entry — either a plain string or an object with upstream mapping
|
|
10
|
+
*
|
|
11
|
+
* Plain string: model name is the same on both sides
|
|
12
|
+
* Object: name is what clients request, upstreamModel is what the provider expects
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* // Simple — same name both sides
|
|
16
|
+
* "gpt-4o"
|
|
17
|
+
*
|
|
18
|
+
* // Mapped — "deepseek-v3" externally, "ep-xxx" at the provider
|
|
19
|
+
* { name: "deepseek-v3", upstreamModel: "ep-20250101-xxx" }
|
|
20
|
+
*/
|
|
21
|
+
type ModelEntry = string | {
|
|
22
|
+
name: string;
|
|
23
|
+
upstreamModel: string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* A registered upstream provider with its capabilities
|
|
27
|
+
*/
|
|
28
|
+
interface RegisteredProvider {
|
|
29
|
+
/** Unique provider ID */
|
|
30
|
+
id: string;
|
|
31
|
+
/** Display name */
|
|
32
|
+
name: string;
|
|
33
|
+
/** Protocol this provider speaks */
|
|
34
|
+
protocol: ProviderProtocol;
|
|
35
|
+
/** API key */
|
|
36
|
+
apiKey: string;
|
|
37
|
+
/** Custom base URL */
|
|
38
|
+
baseUrl?: string;
|
|
39
|
+
/** Models this provider can serve */
|
|
40
|
+
models: ModelEntry[];
|
|
41
|
+
/** Priority for model matching (lower = higher priority) */
|
|
42
|
+
priority?: number;
|
|
43
|
+
/** Whether this provider is enabled */
|
|
44
|
+
enabled?: boolean;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The result of routing a request to a provider
|
|
48
|
+
*/
|
|
49
|
+
interface RouteResult {
|
|
50
|
+
/** The matched provider */
|
|
51
|
+
provider: RegisteredProvider;
|
|
52
|
+
/** The model name as requested by the client */
|
|
53
|
+
model: string;
|
|
54
|
+
/** The model name to send to the upstream provider (may differ from model) */
|
|
55
|
+
upstreamModel: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Router configuration
|
|
59
|
+
*/
|
|
60
|
+
interface RouterConfig {
|
|
61
|
+
/** Registered providers */
|
|
62
|
+
providers: RegisteredProvider[];
|
|
63
|
+
/** Default provider ID (fallback when no model match) */
|
|
64
|
+
defaultProviderId?: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Router — model matching and provider selection
|
|
69
|
+
*
|
|
70
|
+
* Given a model name, find the best provider to serve it.
|
|
71
|
+
* Supports model name mapping (client name → upstream provider name).
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
declare class Router {
|
|
75
|
+
private providers;
|
|
76
|
+
private defaultProviderId?;
|
|
77
|
+
constructor(config: RouterConfig);
|
|
78
|
+
/**
|
|
79
|
+
* Find the best provider for a given model
|
|
80
|
+
*/
|
|
81
|
+
route(model: string): RouteResult | null;
|
|
82
|
+
/**
|
|
83
|
+
* List all available models across all providers
|
|
84
|
+
*/
|
|
85
|
+
listModels(): Array<{
|
|
86
|
+
model: string;
|
|
87
|
+
upstreamModel: string;
|
|
88
|
+
providerId: string;
|
|
89
|
+
protocol: string;
|
|
90
|
+
}>;
|
|
91
|
+
/**
|
|
92
|
+
* Add a provider at runtime
|
|
93
|
+
*/
|
|
94
|
+
addProvider(provider: RegisteredProvider): void;
|
|
95
|
+
/**
|
|
96
|
+
* Remove a provider
|
|
97
|
+
*/
|
|
98
|
+
removeProvider(id: string): boolean;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export { type ModelEntry, type ProviderProtocol, type RegisteredProvider, type RouteResult, Router, type RouterConfig };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@routerxjs/core",
|
|
3
|
+
"version": "0.0.0-dev-20260318021459",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./router": {
|
|
13
|
+
"types": "./dist/router/index.d.ts",
|
|
14
|
+
"import": "./dist/router/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"src"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsup",
|
|
23
|
+
"typecheck": "tsc --noEmit",
|
|
24
|
+
"test": "bun test"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"typescript": "^5.9.3"
|
|
28
|
+
}
|
|
29
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Router — model matching and provider selection
|
|
3
|
+
*
|
|
4
|
+
* Given a model name, find the best provider to serve it.
|
|
5
|
+
* Supports model name mapping (client name → upstream provider name).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { ModelEntry, RegisteredProvider, RouteResult, RouterConfig } from "./types";
|
|
9
|
+
|
|
10
|
+
/** Resolve a ModelEntry to its client-facing name */
|
|
11
|
+
function modelName(entry: ModelEntry): string {
|
|
12
|
+
return typeof entry === "string" ? entry : entry.name;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Resolve a ModelEntry to its upstream name */
|
|
16
|
+
function upstreamModelName(entry: ModelEntry): string {
|
|
17
|
+
return typeof entry === "string" ? entry : entry.upstreamModel;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export class Router {
|
|
21
|
+
private providers: RegisteredProvider[];
|
|
22
|
+
private defaultProviderId?: string;
|
|
23
|
+
|
|
24
|
+
constructor(config: RouterConfig) {
|
|
25
|
+
this.providers = config.providers;
|
|
26
|
+
this.defaultProviderId = config.defaultProviderId;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Find the best provider for a given model
|
|
31
|
+
*/
|
|
32
|
+
route(model: string): RouteResult | null {
|
|
33
|
+
// Find providers that have this model (by client-facing name)
|
|
34
|
+
const candidates: Array<{ provider: RegisteredProvider; entry: ModelEntry }> = [];
|
|
35
|
+
|
|
36
|
+
for (const provider of this.providers) {
|
|
37
|
+
if (provider.enabled === false) continue;
|
|
38
|
+
const entry = provider.models.find((m) => modelName(m) === model);
|
|
39
|
+
if (entry) {
|
|
40
|
+
candidates.push({ provider, entry });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Sort by priority
|
|
45
|
+
candidates.sort((a, b) => (a.provider.priority ?? 100) - (b.provider.priority ?? 100));
|
|
46
|
+
|
|
47
|
+
if (candidates.length > 0) {
|
|
48
|
+
const { provider, entry } = candidates[0];
|
|
49
|
+
return {
|
|
50
|
+
provider,
|
|
51
|
+
model,
|
|
52
|
+
upstreamModel: upstreamModelName(entry),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Fallback to default provider
|
|
57
|
+
if (this.defaultProviderId) {
|
|
58
|
+
const defaultProvider = this.providers.find(
|
|
59
|
+
(p) => p.id === this.defaultProviderId && p.enabled !== false
|
|
60
|
+
);
|
|
61
|
+
if (defaultProvider) {
|
|
62
|
+
return { provider: defaultProvider, model, upstreamModel: model };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* List all available models across all providers
|
|
71
|
+
*/
|
|
72
|
+
listModels(): Array<{
|
|
73
|
+
model: string;
|
|
74
|
+
upstreamModel: string;
|
|
75
|
+
providerId: string;
|
|
76
|
+
protocol: string;
|
|
77
|
+
}> {
|
|
78
|
+
const models: Array<{
|
|
79
|
+
model: string;
|
|
80
|
+
upstreamModel: string;
|
|
81
|
+
providerId: string;
|
|
82
|
+
protocol: string;
|
|
83
|
+
}> = [];
|
|
84
|
+
for (const provider of this.providers) {
|
|
85
|
+
if (provider.enabled === false) continue;
|
|
86
|
+
for (const entry of provider.models) {
|
|
87
|
+
models.push({
|
|
88
|
+
model: modelName(entry),
|
|
89
|
+
upstreamModel: upstreamModelName(entry),
|
|
90
|
+
providerId: provider.id,
|
|
91
|
+
protocol: provider.protocol,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return models;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Add a provider at runtime
|
|
100
|
+
*/
|
|
101
|
+
addProvider(provider: RegisteredProvider): void {
|
|
102
|
+
const existing = this.providers.findIndex((p) => p.id === provider.id);
|
|
103
|
+
if (existing >= 0) {
|
|
104
|
+
this.providers[existing] = provider;
|
|
105
|
+
} else {
|
|
106
|
+
this.providers.push(provider);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Remove a provider
|
|
112
|
+
*/
|
|
113
|
+
removeProvider(id: string): boolean {
|
|
114
|
+
const idx = this.providers.findIndex((p) => p.id === id);
|
|
115
|
+
if (idx >= 0) {
|
|
116
|
+
this.providers.splice(idx, 1);
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Router Types — routing configuration and model matching
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Supported upstream provider protocols
|
|
7
|
+
*/
|
|
8
|
+
export type ProviderProtocol = "openai-compatible" | "anthropic";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Model entry — either a plain string or an object with upstream mapping
|
|
12
|
+
*
|
|
13
|
+
* Plain string: model name is the same on both sides
|
|
14
|
+
* Object: name is what clients request, upstreamModel is what the provider expects
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* // Simple — same name both sides
|
|
18
|
+
* "gpt-4o"
|
|
19
|
+
*
|
|
20
|
+
* // Mapped — "deepseek-v3" externally, "ep-xxx" at the provider
|
|
21
|
+
* { name: "deepseek-v3", upstreamModel: "ep-20250101-xxx" }
|
|
22
|
+
*/
|
|
23
|
+
export type ModelEntry = string | { name: string; upstreamModel: string };
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* A registered upstream provider with its capabilities
|
|
27
|
+
*/
|
|
28
|
+
export interface RegisteredProvider {
|
|
29
|
+
/** Unique provider ID */
|
|
30
|
+
id: string;
|
|
31
|
+
|
|
32
|
+
/** Display name */
|
|
33
|
+
name: string;
|
|
34
|
+
|
|
35
|
+
/** Protocol this provider speaks */
|
|
36
|
+
protocol: ProviderProtocol;
|
|
37
|
+
|
|
38
|
+
/** API key */
|
|
39
|
+
apiKey: string;
|
|
40
|
+
|
|
41
|
+
/** Custom base URL */
|
|
42
|
+
baseUrl?: string;
|
|
43
|
+
|
|
44
|
+
/** Models this provider can serve */
|
|
45
|
+
models: ModelEntry[];
|
|
46
|
+
|
|
47
|
+
/** Priority for model matching (lower = higher priority) */
|
|
48
|
+
priority?: number;
|
|
49
|
+
|
|
50
|
+
/** Whether this provider is enabled */
|
|
51
|
+
enabled?: boolean;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The result of routing a request to a provider
|
|
56
|
+
*/
|
|
57
|
+
export interface RouteResult {
|
|
58
|
+
/** The matched provider */
|
|
59
|
+
provider: RegisteredProvider;
|
|
60
|
+
|
|
61
|
+
/** The model name as requested by the client */
|
|
62
|
+
model: string;
|
|
63
|
+
|
|
64
|
+
/** The model name to send to the upstream provider (may differ from model) */
|
|
65
|
+
upstreamModel: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Router configuration
|
|
70
|
+
*/
|
|
71
|
+
export interface RouterConfig {
|
|
72
|
+
/** Registered providers */
|
|
73
|
+
providers: RegisteredProvider[];
|
|
74
|
+
|
|
75
|
+
/** Default provider ID (fallback when no model match) */
|
|
76
|
+
defaultProviderId?: string;
|
|
77
|
+
}
|