@sriinnu/kosha-discovery 0.5.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/LICENSE +21 -0
- package/README.md +286 -0
- package/dist/aliases.d.ts +51 -0
- package/dist/aliases.d.ts.map +1 -0
- package/dist/aliases.js +115 -0
- package/dist/aliases.js.map +1 -0
- package/dist/cache.d.ts +57 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +123 -0
- package/dist/cache.js.map +1 -0
- package/dist/cli-commands.d.ts +142 -0
- package/dist/cli-commands.d.ts.map +1 -0
- package/dist/cli-commands.js +746 -0
- package/dist/cli-commands.js.map +1 -0
- package/dist/cli-format.d.ts +119 -0
- package/dist/cli-format.d.ts.map +1 -0
- package/dist/cli-format.js +171 -0
- package/dist/cli-format.js.map +1 -0
- package/dist/cli.d.ts +15 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +143 -0
- package/dist/cli.js.map +1 -0
- package/dist/credentials/index.d.ts +2 -0
- package/dist/credentials/index.d.ts.map +1 -0
- package/dist/credentials/index.js +2 -0
- package/dist/credentials/index.js.map +1 -0
- package/dist/credentials/resolver.d.ts +170 -0
- package/dist/credentials/resolver.d.ts.map +1 -0
- package/dist/credentials/resolver.js +597 -0
- package/dist/credentials/resolver.js.map +1 -0
- package/dist/discovery/anthropic.d.ts +49 -0
- package/dist/discovery/anthropic.d.ts.map +1 -0
- package/dist/discovery/anthropic.js +101 -0
- package/dist/discovery/anthropic.js.map +1 -0
- package/dist/discovery/base.d.ts +59 -0
- package/dist/discovery/base.d.ts.map +1 -0
- package/dist/discovery/base.js +123 -0
- package/dist/discovery/base.js.map +1 -0
- package/dist/discovery/bedrock.d.ts +122 -0
- package/dist/discovery/bedrock.d.ts.map +1 -0
- package/dist/discovery/bedrock.js +356 -0
- package/dist/discovery/bedrock.js.map +1 -0
- package/dist/discovery/cerebras.d.ts +43 -0
- package/dist/discovery/cerebras.d.ts.map +1 -0
- package/dist/discovery/cerebras.js +65 -0
- package/dist/discovery/cerebras.js.map +1 -0
- package/dist/discovery/cohere.d.ts +57 -0
- package/dist/discovery/cohere.d.ts.map +1 -0
- package/dist/discovery/cohere.js +82 -0
- package/dist/discovery/cohere.js.map +1 -0
- package/dist/discovery/deepinfra.d.ts +41 -0
- package/dist/discovery/deepinfra.d.ts.map +1 -0
- package/dist/discovery/deepinfra.js +86 -0
- package/dist/discovery/deepinfra.js.map +1 -0
- package/dist/discovery/deepseek.d.ts +17 -0
- package/dist/discovery/deepseek.d.ts.map +1 -0
- package/dist/discovery/deepseek.js +45 -0
- package/dist/discovery/deepseek.js.map +1 -0
- package/dist/discovery/fireworks.d.ts +48 -0
- package/dist/discovery/fireworks.d.ts.map +1 -0
- package/dist/discovery/fireworks.js +101 -0
- package/dist/discovery/fireworks.js.map +1 -0
- package/dist/discovery/glm.d.ts +17 -0
- package/dist/discovery/glm.d.ts.map +1 -0
- package/dist/discovery/glm.js +52 -0
- package/dist/discovery/glm.js.map +1 -0
- package/dist/discovery/google.d.ts +53 -0
- package/dist/discovery/google.d.ts.map +1 -0
- package/dist/discovery/google.js +122 -0
- package/dist/discovery/google.js.map +1 -0
- package/dist/discovery/groq.d.ts +44 -0
- package/dist/discovery/groq.d.ts.map +1 -0
- package/dist/discovery/groq.js +89 -0
- package/dist/discovery/groq.js.map +1 -0
- package/dist/discovery/index.d.ts +48 -0
- package/dist/discovery/index.d.ts.map +1 -0
- package/dist/discovery/index.js +116 -0
- package/dist/discovery/index.js.map +1 -0
- package/dist/discovery/llama-cpp.d.ts +45 -0
- package/dist/discovery/llama-cpp.d.ts.map +1 -0
- package/dist/discovery/llama-cpp.js +137 -0
- package/dist/discovery/llama-cpp.js.map +1 -0
- package/dist/discovery/minimax.d.ts +16 -0
- package/dist/discovery/minimax.d.ts.map +1 -0
- package/dist/discovery/minimax.js +56 -0
- package/dist/discovery/minimax.js.map +1 -0
- package/dist/discovery/mistral.d.ts +45 -0
- package/dist/discovery/mistral.d.ts.map +1 -0
- package/dist/discovery/mistral.js +82 -0
- package/dist/discovery/mistral.js.map +1 -0
- package/dist/discovery/moonshot.d.ts +16 -0
- package/dist/discovery/moonshot.d.ts.map +1 -0
- package/dist/discovery/moonshot.js +46 -0
- package/dist/discovery/moonshot.js.map +1 -0
- package/dist/discovery/nvidia.d.ts +60 -0
- package/dist/discovery/nvidia.d.ts.map +1 -0
- package/dist/discovery/nvidia.js +145 -0
- package/dist/discovery/nvidia.js.map +1 -0
- package/dist/discovery/ollama.d.ts +57 -0
- package/dist/discovery/ollama.d.ts.map +1 -0
- package/dist/discovery/ollama.js +151 -0
- package/dist/discovery/ollama.js.map +1 -0
- package/dist/discovery/openai-compatible.d.ts +126 -0
- package/dist/discovery/openai-compatible.d.ts.map +1 -0
- package/dist/discovery/openai-compatible.js +161 -0
- package/dist/discovery/openai-compatible.js.map +1 -0
- package/dist/discovery/openai.d.ts +62 -0
- package/dist/discovery/openai.d.ts.map +1 -0
- package/dist/discovery/openai.js +157 -0
- package/dist/discovery/openai.js.map +1 -0
- package/dist/discovery/openrouter.d.ts +78 -0
- package/dist/discovery/openrouter.d.ts.map +1 -0
- package/dist/discovery/openrouter.js +184 -0
- package/dist/discovery/openrouter.js.map +1 -0
- package/dist/discovery/perplexity.d.ts +66 -0
- package/dist/discovery/perplexity.d.ts.map +1 -0
- package/dist/discovery/perplexity.js +86 -0
- package/dist/discovery/perplexity.js.map +1 -0
- package/dist/discovery/together.d.ts +41 -0
- package/dist/discovery/together.d.ts.map +1 -0
- package/dist/discovery/together.js +88 -0
- package/dist/discovery/together.js.map +1 -0
- package/dist/discovery/vertex.d.ts +146 -0
- package/dist/discovery/vertex.d.ts.map +1 -0
- package/dist/discovery/vertex.js +371 -0
- package/dist/discovery/vertex.js.map +1 -0
- package/dist/discovery/zai.d.ts +17 -0
- package/dist/discovery/zai.d.ts.map +1 -0
- package/dist/discovery/zai.js +51 -0
- package/dist/discovery/zai.js.map +1 -0
- package/dist/discovery-contract.d.ts +186 -0
- package/dist/discovery-contract.d.ts.map +1 -0
- package/dist/discovery-contract.js +115 -0
- package/dist/discovery-contract.js.map +1 -0
- package/dist/discovery-routes.d.ts +14 -0
- package/dist/discovery-routes.d.ts.map +1 -0
- package/dist/discovery-routes.js +98 -0
- package/dist/discovery-routes.js.map +1 -0
- package/dist/enrichment/index.d.ts +2 -0
- package/dist/enrichment/index.d.ts.map +1 -0
- package/dist/enrichment/index.js +2 -0
- package/dist/enrichment/index.js.map +1 -0
- package/dist/enrichment/litellm.d.ts +52 -0
- package/dist/enrichment/litellm.d.ts.map +1 -0
- package/dist/enrichment/litellm.js +205 -0
- package/dist/enrichment/litellm.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/normalize.d.ts +64 -0
- package/dist/normalize.d.ts.map +1 -0
- package/dist/normalize.js +166 -0
- package/dist/normalize.js.map +1 -0
- package/dist/provider-catalog.d.ts +62 -0
- package/dist/provider-catalog.d.ts.map +1 -0
- package/dist/provider-catalog.js +331 -0
- package/dist/provider-catalog.js.map +1 -0
- package/dist/registry-delta.d.ts +17 -0
- package/dist/registry-delta.d.ts.map +1 -0
- package/dist/registry-delta.js +74 -0
- package/dist/registry-delta.js.map +1 -0
- package/dist/registry-discovery.d.ts +66 -0
- package/dist/registry-discovery.d.ts.map +1 -0
- package/dist/registry-discovery.js +339 -0
- package/dist/registry-discovery.js.map +1 -0
- package/dist/registry-query.d.ts +74 -0
- package/dist/registry-query.d.ts.map +1 -0
- package/dist/registry-query.js +310 -0
- package/dist/registry-query.js.map +1 -0
- package/dist/registry-runtime.d.ts +48 -0
- package/dist/registry-runtime.d.ts.map +1 -0
- package/dist/registry-runtime.js +255 -0
- package/dist/registry-runtime.js.map +1 -0
- package/dist/registry-selection.d.ts +31 -0
- package/dist/registry-selection.d.ts.map +1 -0
- package/dist/registry-selection.js +167 -0
- package/dist/registry-selection.js.map +1 -0
- package/dist/registry-state.d.ts +92 -0
- package/dist/registry-state.d.ts.map +1 -0
- package/dist/registry-state.js +35 -0
- package/dist/registry-state.js.map +1 -0
- package/dist/registry.d.ts +127 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +248 -0
- package/dist/registry.js.map +1 -0
- package/dist/resilience.d.ts +212 -0
- package/dist/resilience.d.ts.map +1 -0
- package/dist/resilience.js +292 -0
- package/dist/resilience.js.map +1 -0
- package/dist/security.d.ts +44 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +184 -0
- package/dist/security.js.map +1 -0
- package/dist/server.d.ts +41 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +320 -0
- package/dist/server.js.map +1 -0
- package/dist/shell-safe.d.ts +15 -0
- package/dist/shell-safe.d.ts.map +1 -0
- package/dist/shell-safe.js +20 -0
- package/dist/shell-safe.js.map +1 -0
- package/dist/types.d.ts +365 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/logo.svg +81 -0
- package/package.json +85 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kosha-discovery — OpenAI-compatible provider base class.
|
|
3
|
+
*
|
|
4
|
+
* Many providers (NVIDIA, Together AI, Fireworks AI, Groq, Mistral AI,
|
|
5
|
+
* DeepInfra, Cerebras, Perplexity, etc.) expose an OpenAI-compatible
|
|
6
|
+
* `/v1/models` endpoint with Bearer auth. This base class extracts the
|
|
7
|
+
* shared discover/filter/map pipeline so concrete providers only need to
|
|
8
|
+
* define identity fields and override the three hooks:
|
|
9
|
+
*
|
|
10
|
+
* - {@link isRelevantModel} — filter out irrelevant models
|
|
11
|
+
* - {@link classifyModel} — determine origin, mode, and capabilities
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
import type { CredentialResult, ModelCard, ModelMode } from "../types.js";
|
|
16
|
+
import { BaseDiscoverer } from "./base.js";
|
|
17
|
+
/** Shape of a single model from any OpenAI-compatible `/v1/models` response. */
|
|
18
|
+
export interface OpenAICompatibleModel {
|
|
19
|
+
id: string;
|
|
20
|
+
object: string;
|
|
21
|
+
created: number;
|
|
22
|
+
owned_by: string;
|
|
23
|
+
/** Some providers (Together AI) include a type field. */
|
|
24
|
+
type?: string;
|
|
25
|
+
/** Some providers (Groq) include a context_window field. */
|
|
26
|
+
context_window?: number;
|
|
27
|
+
/** Some providers expose explicit max output tokens. */
|
|
28
|
+
max_output_tokens?: number;
|
|
29
|
+
/** Some providers expose explicit max input tokens. */
|
|
30
|
+
max_input_tokens?: number;
|
|
31
|
+
/** Some embedding providers expose vector dimensionality. */
|
|
32
|
+
output_vector_size?: number;
|
|
33
|
+
}
|
|
34
|
+
/** Standard response shape from `GET /v1/models`. */
|
|
35
|
+
export interface OpenAICompatibleListResponse {
|
|
36
|
+
data: OpenAICompatibleModel[];
|
|
37
|
+
object: string;
|
|
38
|
+
}
|
|
39
|
+
/** Classification result returned by the per-provider hook. */
|
|
40
|
+
export interface ModelClassification {
|
|
41
|
+
originProvider: string;
|
|
42
|
+
mode: ModelMode;
|
|
43
|
+
capabilities: string[];
|
|
44
|
+
contextWindow?: number;
|
|
45
|
+
maxOutputTokens?: number;
|
|
46
|
+
maxInputTokens?: number;
|
|
47
|
+
dimensions?: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Base class for providers that expose an OpenAI-compatible `/v1/models` endpoint.
|
|
51
|
+
*
|
|
52
|
+
* Concrete subclasses set `providerId`, `providerName`, `baseUrl` and override:
|
|
53
|
+
*
|
|
54
|
+
* - {@link isRelevantModel} — Return false to filter a model out.
|
|
55
|
+
* - {@link classifyModel} — Return origin, mode, and capabilities.
|
|
56
|
+
*
|
|
57
|
+
* The `discover()` pipeline handles auth, fetch, filter, and card construction.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* export class MyProviderDiscoverer extends OpenAICompatibleDiscoverer {
|
|
61
|
+
* readonly providerId = "myprovider";
|
|
62
|
+
* readonly providerName = "My Provider";
|
|
63
|
+
* readonly baseUrl = "https://api.myprovider.com";
|
|
64
|
+
*
|
|
65
|
+
* protected isRelevantModel(model: OpenAICompatibleModel): boolean { ... }
|
|
66
|
+
* protected classifyModel(model: OpenAICompatibleModel): ModelClassification { ... }
|
|
67
|
+
* }
|
|
68
|
+
*/
|
|
69
|
+
export declare abstract class OpenAICompatibleDiscoverer extends BaseDiscoverer {
|
|
70
|
+
/**
|
|
71
|
+
* Fetch the model list, filter, classify, and return normalized cards.
|
|
72
|
+
*
|
|
73
|
+
* @param credential - Must contain `apiKey` or `accessToken`.
|
|
74
|
+
* @param options - Optional timeout override (default 10 s).
|
|
75
|
+
*/
|
|
76
|
+
discover(credential: CredentialResult, options?: {
|
|
77
|
+
timeout?: number;
|
|
78
|
+
}): Promise<ModelCard[]>;
|
|
79
|
+
/**
|
|
80
|
+
* Ordered model-list endpoints to try.
|
|
81
|
+
*
|
|
82
|
+
* Most providers use `/v1/models`. Some OpenAI-compatible APIs expose
|
|
83
|
+
* `/models` at versioned base URLs; subclasses can override this.
|
|
84
|
+
*/
|
|
85
|
+
protected modelListEndpoints(): string[];
|
|
86
|
+
/**
|
|
87
|
+
* Return false to exclude a model from discovery results.
|
|
88
|
+
*
|
|
89
|
+
* Default implementation keeps all models. Override to filter
|
|
90
|
+
* reward models, fine-tune snapshots, deprecated entries, etc.
|
|
91
|
+
*/
|
|
92
|
+
protected isRelevantModel(_model: OpenAICompatibleModel): boolean;
|
|
93
|
+
/**
|
|
94
|
+
* Classify a model: determine origin provider, mode, and capabilities.
|
|
95
|
+
*
|
|
96
|
+
* Must be implemented by each concrete subclass since classification
|
|
97
|
+
* rules are provider-specific.
|
|
98
|
+
*/
|
|
99
|
+
protected abstract classifyModel(model: OpenAICompatibleModel): ModelClassification;
|
|
100
|
+
/**
|
|
101
|
+
* Extract origin provider from a `vendor/model-name` namespaced ID.
|
|
102
|
+
* Returns `fallback` if no `/` is present.
|
|
103
|
+
*/
|
|
104
|
+
protected extractPrefixOrigin(id: string, fallback: string, aliases?: Record<string, string>): string;
|
|
105
|
+
/**
|
|
106
|
+
* Infer origin from flat model ID keywords (for providers like Groq
|
|
107
|
+
* that don't use namespaced IDs).
|
|
108
|
+
*
|
|
109
|
+
* Checks keywords in order — put more-specific matches first
|
|
110
|
+
* (e.g. "deepseek" before "llama" for `deepseek-r1-distill-llama-70b`).
|
|
111
|
+
*/
|
|
112
|
+
protected inferOriginFromKeywords(lower: string, rules: [string, string][], fallback: string): string;
|
|
113
|
+
/** Check if a lowercase model ID looks like an embedding model. */
|
|
114
|
+
protected looksLikeEmbedding(lower: string): boolean;
|
|
115
|
+
/** Check if a lowercase model ID looks like a vision model. */
|
|
116
|
+
protected looksLikeVision(lower: string): boolean;
|
|
117
|
+
/** Check if a lowercase model ID looks like a code model. */
|
|
118
|
+
protected looksLikeCode(lower: string): boolean;
|
|
119
|
+
/** Check if a lowercase model ID looks like an audio/speech model. */
|
|
120
|
+
protected looksLikeAudio(lower: string): boolean;
|
|
121
|
+
/** Check if ID contains common "reward model" patterns to filter. */
|
|
122
|
+
protected looksLikeReward(lower: string): boolean;
|
|
123
|
+
/** Build a ModelCard from a raw API model + classification. */
|
|
124
|
+
private toCard;
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=openai-compatible.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-compatible.d.ts","sourceRoot":"","sources":["../../src/discovery/openai-compatible.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,gFAAgF;AAChF,MAAM,WAAW,qBAAqB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wDAAwD;IACxD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,uDAAuD;IACvD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6DAA6D;IAC7D,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,qDAAqD;AACrD,MAAM,WAAW,4BAA4B;IAC5C,IAAI,EAAE,qBAAqB,EAAE,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;CACf;AAED,+DAA+D;AAC/D,MAAM,WAAW,mBAAmB;IACnC,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,SAAS,CAAC;IAChB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,8BAAsB,0BAA2B,SAAQ,cAAc;IACtE;;;;;OAKG;IACG,QAAQ,CAAC,UAAU,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAkClG;;;;;OAKG;IACH,SAAS,CAAC,kBAAkB,IAAI,MAAM,EAAE;IAIxC;;;;;OAKG;IACH,SAAS,CAAC,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO;IAIjE;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,EAAE,qBAAqB,GAAG,mBAAmB;IAMnF;;;OAGG;IACH,SAAS,CAAC,mBAAmB,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM;IASrG;;;;;;OAMG;IACH,SAAS,CAAC,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAOrG,mEAAmE;IACnE,SAAS,CAAC,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAIpD,+DAA+D;IAC/D,SAAS,CAAC,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAMjD,6DAA6D;IAC7D,SAAS,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAK/C,sEAAsE;IACtE,SAAS,CAAC,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAIhD,qEAAqE;IACrE,SAAS,CAAC,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAQjD,+DAA+D;IAC/D,OAAO,CAAC,MAAM;CAed"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kosha-discovery — OpenAI-compatible provider base class.
|
|
3
|
+
*
|
|
4
|
+
* Many providers (NVIDIA, Together AI, Fireworks AI, Groq, Mistral AI,
|
|
5
|
+
* DeepInfra, Cerebras, Perplexity, etc.) expose an OpenAI-compatible
|
|
6
|
+
* `/v1/models` endpoint with Bearer auth. This base class extracts the
|
|
7
|
+
* shared discover/filter/map pipeline so concrete providers only need to
|
|
8
|
+
* define identity fields and override the three hooks:
|
|
9
|
+
*
|
|
10
|
+
* - {@link isRelevantModel} — filter out irrelevant models
|
|
11
|
+
* - {@link classifyModel} — determine origin, mode, and capabilities
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
import { BaseDiscoverer } from "./base.js";
|
|
16
|
+
/**
|
|
17
|
+
* Base class for providers that expose an OpenAI-compatible `/v1/models` endpoint.
|
|
18
|
+
*
|
|
19
|
+
* Concrete subclasses set `providerId`, `providerName`, `baseUrl` and override:
|
|
20
|
+
*
|
|
21
|
+
* - {@link isRelevantModel} — Return false to filter a model out.
|
|
22
|
+
* - {@link classifyModel} — Return origin, mode, and capabilities.
|
|
23
|
+
*
|
|
24
|
+
* The `discover()` pipeline handles auth, fetch, filter, and card construction.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* export class MyProviderDiscoverer extends OpenAICompatibleDiscoverer {
|
|
28
|
+
* readonly providerId = "myprovider";
|
|
29
|
+
* readonly providerName = "My Provider";
|
|
30
|
+
* readonly baseUrl = "https://api.myprovider.com";
|
|
31
|
+
*
|
|
32
|
+
* protected isRelevantModel(model: OpenAICompatibleModel): boolean { ... }
|
|
33
|
+
* protected classifyModel(model: OpenAICompatibleModel): ModelClassification { ... }
|
|
34
|
+
* }
|
|
35
|
+
*/
|
|
36
|
+
export class OpenAICompatibleDiscoverer extends BaseDiscoverer {
|
|
37
|
+
/**
|
|
38
|
+
* Fetch the model list, filter, classify, and return normalized cards.
|
|
39
|
+
*
|
|
40
|
+
* @param credential - Must contain `apiKey` or `accessToken`.
|
|
41
|
+
* @param options - Optional timeout override (default 10 s).
|
|
42
|
+
*/
|
|
43
|
+
async discover(credential, options) {
|
|
44
|
+
const apiKey = credential.apiKey ?? credential.accessToken;
|
|
45
|
+
if (!apiKey) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
const timeoutMs = this.validateTimeout(options?.timeout);
|
|
49
|
+
const headers = {
|
|
50
|
+
Authorization: `Bearer ${apiKey}`,
|
|
51
|
+
};
|
|
52
|
+
let response = null;
|
|
53
|
+
let lastError;
|
|
54
|
+
for (const endpoint of this.modelListEndpoints()) {
|
|
55
|
+
try {
|
|
56
|
+
response = await this.fetchJSON(endpoint, headers, timeoutMs);
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
lastError = error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (!response) {
|
|
64
|
+
throw lastError instanceof Error ? lastError : new Error(`${this.providerName} API request failed`);
|
|
65
|
+
}
|
|
66
|
+
return response.data
|
|
67
|
+
.filter((model) => this.isRelevantModel(model))
|
|
68
|
+
.map((model) => this.toCard(model));
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Ordered model-list endpoints to try.
|
|
72
|
+
*
|
|
73
|
+
* Most providers use `/v1/models`. Some OpenAI-compatible APIs expose
|
|
74
|
+
* `/models` at versioned base URLs; subclasses can override this.
|
|
75
|
+
*/
|
|
76
|
+
modelListEndpoints() {
|
|
77
|
+
return [`${this.baseUrl}/v1/models`];
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Return false to exclude a model from discovery results.
|
|
81
|
+
*
|
|
82
|
+
* Default implementation keeps all models. Override to filter
|
|
83
|
+
* reward models, fine-tune snapshots, deprecated entries, etc.
|
|
84
|
+
*/
|
|
85
|
+
isRelevantModel(_model) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
// Shared classification helpers — subclasses can call these for common logic
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
/**
|
|
92
|
+
* Extract origin provider from a `vendor/model-name` namespaced ID.
|
|
93
|
+
* Returns `fallback` if no `/` is present.
|
|
94
|
+
*/
|
|
95
|
+
extractPrefixOrigin(id, fallback, aliases) {
|
|
96
|
+
const slashIdx = id.indexOf("/");
|
|
97
|
+
if (slashIdx === -1)
|
|
98
|
+
return fallback;
|
|
99
|
+
const prefix = id.slice(0, slashIdx).toLowerCase();
|
|
100
|
+
if (aliases && prefix in aliases)
|
|
101
|
+
return aliases[prefix];
|
|
102
|
+
return prefix;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Infer origin from flat model ID keywords (for providers like Groq
|
|
106
|
+
* that don't use namespaced IDs).
|
|
107
|
+
*
|
|
108
|
+
* Checks keywords in order — put more-specific matches first
|
|
109
|
+
* (e.g. "deepseek" before "llama" for `deepseek-r1-distill-llama-70b`).
|
|
110
|
+
*/
|
|
111
|
+
inferOriginFromKeywords(lower, rules, fallback) {
|
|
112
|
+
for (const [keyword, origin] of rules) {
|
|
113
|
+
if (lower.includes(keyword))
|
|
114
|
+
return origin;
|
|
115
|
+
}
|
|
116
|
+
return fallback;
|
|
117
|
+
}
|
|
118
|
+
/** Check if a lowercase model ID looks like an embedding model. */
|
|
119
|
+
looksLikeEmbedding(lower) {
|
|
120
|
+
return lower.includes("embed") || lower.includes("rerank");
|
|
121
|
+
}
|
|
122
|
+
/** Check if a lowercase model ID looks like a vision model. */
|
|
123
|
+
looksLikeVision(lower) {
|
|
124
|
+
return lower.includes("vision") || lower.includes("vlm") || lower.includes("llava") ||
|
|
125
|
+
lower.includes("pixtral") || lower.includes("neva") || lower.includes("fuyu") ||
|
|
126
|
+
lower.includes("cogvlm") || lower.includes("vila");
|
|
127
|
+
}
|
|
128
|
+
/** Check if a lowercase model ID looks like a code model. */
|
|
129
|
+
looksLikeCode(lower) {
|
|
130
|
+
return lower.includes("code") || lower.includes("codestral") ||
|
|
131
|
+
lower.includes("starcoder") || lower.includes("codellama") || lower.includes("coder");
|
|
132
|
+
}
|
|
133
|
+
/** Check if a lowercase model ID looks like an audio/speech model. */
|
|
134
|
+
looksLikeAudio(lower) {
|
|
135
|
+
return lower.includes("whisper") || lower.includes("tts");
|
|
136
|
+
}
|
|
137
|
+
/** Check if ID contains common "reward model" patterns to filter. */
|
|
138
|
+
looksLikeReward(lower) {
|
|
139
|
+
return lower.includes("reward");
|
|
140
|
+
}
|
|
141
|
+
// ---------------------------------------------------------------------------
|
|
142
|
+
// Private
|
|
143
|
+
// ---------------------------------------------------------------------------
|
|
144
|
+
/** Build a ModelCard from a raw API model + classification. */
|
|
145
|
+
toCard(model) {
|
|
146
|
+
const classification = this.classifyModel(model);
|
|
147
|
+
return this.makeCard({
|
|
148
|
+
id: model.id,
|
|
149
|
+
name: model.id,
|
|
150
|
+
provider: this.providerId,
|
|
151
|
+
originProvider: classification.originProvider,
|
|
152
|
+
mode: classification.mode,
|
|
153
|
+
capabilities: classification.capabilities,
|
|
154
|
+
contextWindow: classification.contextWindow ?? model.context_window ?? 0,
|
|
155
|
+
maxOutputTokens: classification.maxOutputTokens ?? model.max_output_tokens ?? 0,
|
|
156
|
+
maxInputTokens: classification.maxInputTokens ?? model.max_input_tokens,
|
|
157
|
+
dimensions: classification.dimensions ?? model.output_vector_size,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=openai-compatible.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-compatible.js","sourceRoot":"","sources":["../../src/discovery/openai-compatible.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kosha-discovery — OpenAI provider discoverer.
|
|
3
|
+
*
|
|
4
|
+
* Queries the OpenAI `/v1/models` endpoint, filters out irrelevant
|
|
5
|
+
* legacy/fine-tuned models, and maps the rest into {@link ModelCard} objects.
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import type { CredentialResult, ModelCard } from "../types.js";
|
|
9
|
+
import { BaseDiscoverer } from "./base.js";
|
|
10
|
+
/**
|
|
11
|
+
* Discovers models available through the OpenAI API.
|
|
12
|
+
*
|
|
13
|
+
* The OpenAI list endpoint returns *every* model the key has access to,
|
|
14
|
+
* including deprecated completions models (babbage, davinci, curie, ada)
|
|
15
|
+
* and fine-tune snapshots. This discoverer filters those out and keeps
|
|
16
|
+
* only chat, embedding, image, and audio models.
|
|
17
|
+
*/
|
|
18
|
+
export declare class OpenAIDiscoverer extends BaseDiscoverer {
|
|
19
|
+
readonly providerId = "openai";
|
|
20
|
+
readonly providerName = "OpenAI";
|
|
21
|
+
readonly baseUrl = "https://api.openai.com";
|
|
22
|
+
/**
|
|
23
|
+
* Fetch the full model list from OpenAI, filter, and normalize.
|
|
24
|
+
* @param credential - Must contain an `apiKey` or `accessToken`.
|
|
25
|
+
* @param options - Optional timeout override (default 10 s).
|
|
26
|
+
*/
|
|
27
|
+
discover(credential: CredentialResult, options?: {
|
|
28
|
+
timeout?: number;
|
|
29
|
+
}): Promise<ModelCard[]>;
|
|
30
|
+
/**
|
|
31
|
+
* Determine whether a model ID represents a model we want to track.
|
|
32
|
+
*
|
|
33
|
+
* We exclude:
|
|
34
|
+
* - Fine-tune snapshots (contain "ft:" or ":ft-")
|
|
35
|
+
* - Legacy completions-only models (babbage, davinci, curie, ada) which
|
|
36
|
+
* lack chat support and clutter results
|
|
37
|
+
*/
|
|
38
|
+
private isRelevantModel;
|
|
39
|
+
/** Check if the model ID belongs to the chat model family. */
|
|
40
|
+
private isChatModel;
|
|
41
|
+
/** Check if the model ID belongs to the embedding family. */
|
|
42
|
+
private isEmbeddingModel;
|
|
43
|
+
/** Check if the model ID belongs to the image generation family (DALL-E). */
|
|
44
|
+
private isImageModel;
|
|
45
|
+
/** Check if the model ID belongs to the audio family (Whisper / TTS). */
|
|
46
|
+
private isAudioModel;
|
|
47
|
+
/** Convert an OpenAI model object into a normalized {@link ModelCard}. */
|
|
48
|
+
private toModelCard;
|
|
49
|
+
/** Map a model ID to its primary {@link ModelMode}. */
|
|
50
|
+
private inferMode;
|
|
51
|
+
/**
|
|
52
|
+
* Infer capability flags from the model ID.
|
|
53
|
+
*
|
|
54
|
+
* Key design decisions:
|
|
55
|
+
* - o-series reasoning models (o1, o3, o4) do NOT get "function_calling"
|
|
56
|
+
* because their reasoning loop does not support tool use in the same way.
|
|
57
|
+
* - GPT-4o / GPT-4 Turbo get "vision" since they accept image inputs.
|
|
58
|
+
* - GPT-4o-mini lacks vision but retains function_calling.
|
|
59
|
+
*/
|
|
60
|
+
private inferCapabilities;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=openai.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/discovery/openai.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAa,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAgB3C;;;;;;;GAOG;AACH,qBAAa,gBAAiB,SAAQ,cAAc;IACnD,QAAQ,CAAC,UAAU,YAAY;IAC/B,QAAQ,CAAC,YAAY,YAAY;IACjC,QAAQ,CAAC,OAAO,4BAA4B;IAE5C;;;;OAIG;IACG,QAAQ,CAAC,UAAU,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAkBlG;;;;;;;OAOG;IACH,OAAO,CAAC,eAAe;IAsBvB,8DAA8D;IAC9D,OAAO,CAAC,WAAW;IAUnB,6DAA6D;IAC7D,OAAO,CAAC,gBAAgB;IAIxB,6EAA6E;IAC7E,OAAO,CAAC,YAAY;IAIpB,yEAAyE;IACzE,OAAO,CAAC,YAAY;IAIpB,0EAA0E;IAC1E,OAAO,CAAC,WAAW;IAcnB,uDAAuD;IACvD,OAAO,CAAC,SAAS;IAOjB;;;;;;;;OAQG;IACH,OAAO,CAAC,iBAAiB;CA8CzB"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kosha-discovery — OpenAI provider discoverer.
|
|
3
|
+
*
|
|
4
|
+
* Queries the OpenAI `/v1/models` endpoint, filters out irrelevant
|
|
5
|
+
* legacy/fine-tuned models, and maps the rest into {@link ModelCard} objects.
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import { BaseDiscoverer } from "./base.js";
|
|
9
|
+
/**
|
|
10
|
+
* Discovers models available through the OpenAI API.
|
|
11
|
+
*
|
|
12
|
+
* The OpenAI list endpoint returns *every* model the key has access to,
|
|
13
|
+
* including deprecated completions models (babbage, davinci, curie, ada)
|
|
14
|
+
* and fine-tune snapshots. This discoverer filters those out and keeps
|
|
15
|
+
* only chat, embedding, image, and audio models.
|
|
16
|
+
*/
|
|
17
|
+
export class OpenAIDiscoverer extends BaseDiscoverer {
|
|
18
|
+
providerId = "openai";
|
|
19
|
+
providerName = "OpenAI";
|
|
20
|
+
baseUrl = "https://api.openai.com";
|
|
21
|
+
/**
|
|
22
|
+
* Fetch the full model list from OpenAI, filter, and normalize.
|
|
23
|
+
* @param credential - Must contain an `apiKey` or `accessToken`.
|
|
24
|
+
* @param options - Optional timeout override (default 10 s).
|
|
25
|
+
*/
|
|
26
|
+
async discover(credential, options) {
|
|
27
|
+
const apiKey = credential.apiKey ?? credential.accessToken;
|
|
28
|
+
if (!apiKey) {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
const timeoutMs = this.validateTimeout(options?.timeout);
|
|
32
|
+
const headers = {
|
|
33
|
+
Authorization: `Bearer ${apiKey}`,
|
|
34
|
+
};
|
|
35
|
+
const response = await this.fetchJSON(`${this.baseUrl}/v1/models`, headers, timeoutMs);
|
|
36
|
+
return response.data
|
|
37
|
+
.filter((model) => this.isRelevantModel(model.id))
|
|
38
|
+
.map((model) => this.toModelCard(model));
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Determine whether a model ID represents a model we want to track.
|
|
42
|
+
*
|
|
43
|
+
* We exclude:
|
|
44
|
+
* - Fine-tune snapshots (contain "ft:" or ":ft-")
|
|
45
|
+
* - Legacy completions-only models (babbage, davinci, curie, ada) which
|
|
46
|
+
* lack chat support and clutter results
|
|
47
|
+
*/
|
|
48
|
+
isRelevantModel(id) {
|
|
49
|
+
const lower = id.toLowerCase();
|
|
50
|
+
// Skip fine-tune snapshots — they are user-specific variants
|
|
51
|
+
if (lower.includes("ft:") || lower.includes(":ft-")) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
// Skip legacy completions-era models that predate the chat API
|
|
55
|
+
if (lower.startsWith("babbage") || lower.startsWith("davinci") || lower.startsWith("curie") || lower.startsWith("ada")) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
// Keep chat, embedding, image, and audio models
|
|
59
|
+
return (this.isChatModel(lower) ||
|
|
60
|
+
this.isEmbeddingModel(lower) ||
|
|
61
|
+
this.isImageModel(lower) ||
|
|
62
|
+
this.isAudioModel(lower));
|
|
63
|
+
}
|
|
64
|
+
/** Check if the model ID belongs to the chat model family. */
|
|
65
|
+
isChatModel(id) {
|
|
66
|
+
return (id.startsWith("gpt-") ||
|
|
67
|
+
id.startsWith("o1") ||
|
|
68
|
+
id.startsWith("o3") ||
|
|
69
|
+
id.startsWith("o4") ||
|
|
70
|
+
id.startsWith("chatgpt-"));
|
|
71
|
+
}
|
|
72
|
+
/** Check if the model ID belongs to the embedding family. */
|
|
73
|
+
isEmbeddingModel(id) {
|
|
74
|
+
return id.includes("embedding");
|
|
75
|
+
}
|
|
76
|
+
/** Check if the model ID belongs to the image generation family (DALL-E). */
|
|
77
|
+
isImageModel(id) {
|
|
78
|
+
return id.includes("dall-e");
|
|
79
|
+
}
|
|
80
|
+
/** Check if the model ID belongs to the audio family (Whisper / TTS). */
|
|
81
|
+
isAudioModel(id) {
|
|
82
|
+
return id.includes("whisper") || id.includes("tts");
|
|
83
|
+
}
|
|
84
|
+
/** Convert an OpenAI model object into a normalized {@link ModelCard}. */
|
|
85
|
+
toModelCard(model) {
|
|
86
|
+
const id = model.id.toLowerCase();
|
|
87
|
+
const mode = this.inferMode(id);
|
|
88
|
+
const capabilities = this.inferCapabilities(id);
|
|
89
|
+
return this.makeCard({
|
|
90
|
+
id: model.id,
|
|
91
|
+
name: model.id,
|
|
92
|
+
provider: this.providerId,
|
|
93
|
+
mode,
|
|
94
|
+
capabilities,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
/** Map a model ID to its primary {@link ModelMode}. */
|
|
98
|
+
inferMode(id) {
|
|
99
|
+
if (this.isEmbeddingModel(id))
|
|
100
|
+
return "embedding";
|
|
101
|
+
if (this.isImageModel(id))
|
|
102
|
+
return "image";
|
|
103
|
+
if (this.isAudioModel(id))
|
|
104
|
+
return "audio";
|
|
105
|
+
return "chat";
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Infer capability flags from the model ID.
|
|
109
|
+
*
|
|
110
|
+
* Key design decisions:
|
|
111
|
+
* - o-series reasoning models (o1, o3, o4) do NOT get "function_calling"
|
|
112
|
+
* because their reasoning loop does not support tool use in the same way.
|
|
113
|
+
* - GPT-4o / GPT-4 Turbo get "vision" since they accept image inputs.
|
|
114
|
+
* - GPT-4o-mini lacks vision but retains function_calling.
|
|
115
|
+
*/
|
|
116
|
+
inferCapabilities(id) {
|
|
117
|
+
// Embedding models — single capability
|
|
118
|
+
if (this.isEmbeddingModel(id)) {
|
|
119
|
+
return ["embedding"];
|
|
120
|
+
}
|
|
121
|
+
// Image generation models (DALL-E)
|
|
122
|
+
if (this.isImageModel(id)) {
|
|
123
|
+
return ["image_generation"];
|
|
124
|
+
}
|
|
125
|
+
// Audio models — Whisper for STT, TTS for speech synthesis
|
|
126
|
+
if (this.isAudioModel(id)) {
|
|
127
|
+
if (id.includes("whisper"))
|
|
128
|
+
return ["speech_to_text"];
|
|
129
|
+
if (id.includes("tts"))
|
|
130
|
+
return ["text_to_speech"];
|
|
131
|
+
return ["audio"];
|
|
132
|
+
}
|
|
133
|
+
// Reasoning models (o1, o3, o4 series) — no function_calling
|
|
134
|
+
// because their chain-of-thought architecture handles tool use differently
|
|
135
|
+
if (id.startsWith("o1") || id.startsWith("o3") || id.startsWith("o4")) {
|
|
136
|
+
return ["chat", "code", "nlu"];
|
|
137
|
+
}
|
|
138
|
+
// GPT-4o-mini — capable but lacks vision (must be checked before gpt-4o)
|
|
139
|
+
if (id.includes("gpt-4o-mini")) {
|
|
140
|
+
return ["chat", "function_calling", "code", "nlu"];
|
|
141
|
+
}
|
|
142
|
+
// GPT-4o and GPT-4 Turbo — full capabilities including vision
|
|
143
|
+
if (id.includes("gpt-4o") || id.includes("gpt-4-turbo")) {
|
|
144
|
+
return ["chat", "vision", "function_calling", "code", "nlu"];
|
|
145
|
+
}
|
|
146
|
+
// GPT-4 (non-turbo, non-4o)
|
|
147
|
+
if (id.startsWith("gpt-4")) {
|
|
148
|
+
return ["chat", "function_calling", "code", "nlu"];
|
|
149
|
+
}
|
|
150
|
+
// GPT-3.5 and other chat models — basic chat with function calling
|
|
151
|
+
if (id.startsWith("gpt-") || id.startsWith("chatgpt-")) {
|
|
152
|
+
return ["chat", "function_calling", "code"];
|
|
153
|
+
}
|
|
154
|
+
return ["chat"];
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=openai.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/discovery/openai.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kosha-discovery — OpenRouter aggregator discoverer.
|
|
3
|
+
*
|
|
4
|
+
* OpenRouter is a unified gateway that proxies requests to many upstream
|
|
5
|
+
* providers (OpenAI, Anthropic, Google, Meta, Mistral, etc.). Its model
|
|
6
|
+
* list endpoint returns rich metadata including pricing, context lengths,
|
|
7
|
+
* and architecture info — making it one of the most informative sources.
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import type { CredentialResult, ModelCard } from "../types.js";
|
|
11
|
+
import { BaseDiscoverer } from "./base.js";
|
|
12
|
+
/**
|
|
13
|
+
* Discovers models available through the OpenRouter aggregator.
|
|
14
|
+
*
|
|
15
|
+
* OpenRouter acts as a single gateway to dozens of providers. Its model
|
|
16
|
+
* list is publicly accessible (no API key required), though an
|
|
17
|
+
* authenticated request gets higher rate limits.
|
|
18
|
+
*/
|
|
19
|
+
export declare class OpenRouterDiscoverer extends BaseDiscoverer {
|
|
20
|
+
readonly providerId = "openrouter";
|
|
21
|
+
readonly providerName = "OpenRouter";
|
|
22
|
+
readonly baseUrl = "https://openrouter.ai";
|
|
23
|
+
/**
|
|
24
|
+
* Fetch the full model catalogue from OpenRouter.
|
|
25
|
+
*
|
|
26
|
+
* @param credential - API key is **optional** for this provider.
|
|
27
|
+
* The endpoint works without auth, just with stricter rate limits.
|
|
28
|
+
* @param options - Optional timeout override (default 15 s — larger because the
|
|
29
|
+
* response contains hundreds of models).
|
|
30
|
+
*/
|
|
31
|
+
discover(credential: CredentialResult, options?: {
|
|
32
|
+
timeout?: number;
|
|
33
|
+
}): Promise<ModelCard[]>;
|
|
34
|
+
/**
|
|
35
|
+
* Filter out unavailable models. OpenRouter marks delisted models
|
|
36
|
+
* with `pricing.prompt === "-1"`.
|
|
37
|
+
*/
|
|
38
|
+
private isAvailable;
|
|
39
|
+
/** Convert an OpenRouter model object into a normalized {@link ModelCard}. */
|
|
40
|
+
private toModelCard;
|
|
41
|
+
/**
|
|
42
|
+
* Extract the canonical origin-provider slug from an OpenRouter compound
|
|
43
|
+
* model ID of the form `{vendor}/{model-name}`.
|
|
44
|
+
*
|
|
45
|
+
* OpenRouter uses vendor-namespaced IDs (e.g. `anthropic/claude-opus-4-6`,
|
|
46
|
+
* `meta-llama/llama-3-70b`). We take the prefix before the first `/` and
|
|
47
|
+
* normalise it to our canonical slug so that downstream consumers can group
|
|
48
|
+
* models by original creator regardless of which gateway serves them.
|
|
49
|
+
*
|
|
50
|
+
* @param modelId - Raw OpenRouter model ID.
|
|
51
|
+
* @returns Canonical provider slug (e.g. `"anthropic"`, `"meta"`, `"openai"`).
|
|
52
|
+
*/
|
|
53
|
+
private extractOriginProvider;
|
|
54
|
+
/** Infer the primary {@link ModelMode} from modality and naming patterns. */
|
|
55
|
+
private inferMode;
|
|
56
|
+
/**
|
|
57
|
+
* Infer capability flags from architecture modality and model ID.
|
|
58
|
+
*/
|
|
59
|
+
private inferCapabilities;
|
|
60
|
+
/**
|
|
61
|
+
* Heuristic to identify "modern chat models" that support structured
|
|
62
|
+
* tool use (function calling), code generation, and NLU.
|
|
63
|
+
*
|
|
64
|
+
* We match on known provider/model family prefixes. This is intentionally
|
|
65
|
+
* broad — false positives are benign (extra capability flags), while false
|
|
66
|
+
* negatives would hide useful features.
|
|
67
|
+
*/
|
|
68
|
+
private isModernChatModel;
|
|
69
|
+
/**
|
|
70
|
+
* Parse OpenRouter's per-token pricing into our per-million format.
|
|
71
|
+
*
|
|
72
|
+
* OpenRouter returns pricing as **cost per single token** (stringified
|
|
73
|
+
* floats). We multiply by 1,000,000 to convert to our standard
|
|
74
|
+
* per-million-token pricing representation.
|
|
75
|
+
*/
|
|
76
|
+
private parsePricing;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=openrouter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openrouter.d.ts","sourceRoot":"","sources":["../../src/discovery/openrouter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAA2B,MAAM,aAAa,CAAC;AACxF,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAwC3C;;;;;;GAMG;AACH,qBAAa,oBAAqB,SAAQ,cAAc;IACvD,QAAQ,CAAC,UAAU,gBAAgB;IACnC,QAAQ,CAAC,YAAY,gBAAgB;IACrC,QAAQ,CAAC,OAAO,2BAA2B;IAE3C;;;;;;;OAOG;IACG,QAAQ,CAAC,UAAU,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IAsBlG;;;OAGG;IACH,OAAO,CAAC,WAAW;IAInB,8EAA8E;IAC9E,OAAO,CAAC,WAAW;IAmBnB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,qBAAqB;IAyB7B,6EAA6E;IAC7E,OAAO,CAAC,SAAS;IAkBjB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA6BzB;;;;;;;OAOG;IACH,OAAO,CAAC,iBAAiB;IAczB;;;;;;OAMG;IACH,OAAO,CAAC,YAAY;CAgBpB"}
|