smallm 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 +15 -0
- package/README.md +244 -0
- package/dist/benchmark.d.ts +10 -0
- package/dist/benchmark.d.ts.map +1 -0
- package/dist/benchmark.js +35 -0
- package/dist/benchmark.js.map +1 -0
- package/dist/cache-file.d.ts +40 -0
- package/dist/cache-file.d.ts.map +1 -0
- package/dist/cache-file.js +163 -0
- package/dist/cache-file.js.map +1 -0
- package/dist/cache.d.ts +23 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +58 -0
- package/dist/cache.js.map +1 -0
- package/dist/cli.d.ts +32 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +256 -0
- package/dist/cli.js.map +1 -0
- package/dist/data/benchmarks.json +61 -0
- package/dist/embeddings.d.ts +50 -0
- package/dist/embeddings.d.ts.map +1 -0
- package/dist/embeddings.js +118 -0
- package/dist/embeddings.js.map +1 -0
- package/dist/errors.d.ts +18 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +42 -0
- package/dist/errors.js.map +1 -0
- package/dist/filters.d.ts +11 -0
- package/dist/filters.d.ts.map +1 -0
- package/dist/filters.js +66 -0
- package/dist/filters.js.map +1 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +110 -0
- package/dist/index.js.map +1 -0
- package/dist/params.d.ts +21 -0
- package/dist/params.d.ts.map +1 -0
- package/dist/params.js +50 -0
- package/dist/params.js.map +1 -0
- package/dist/query.d.ts +23 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +81 -0
- package/dist/query.js.map +1 -0
- package/dist/registry/huggingface.d.ts +24 -0
- package/dist/registry/huggingface.d.ts.map +1 -0
- package/dist/registry/huggingface.js +97 -0
- package/dist/registry/huggingface.js.map +1 -0
- package/dist/registry/ollama.d.ts +3 -0
- package/dist/registry/ollama.d.ts.map +1 -0
- package/dist/registry/ollama.js +78 -0
- package/dist/registry/ollama.js.map +1 -0
- package/dist/registry/provider.d.ts +12 -0
- package/dist/registry/provider.d.ts.map +1 -0
- package/dist/registry/provider.js +3 -0
- package/dist/registry/provider.js.map +1 -0
- package/dist/scorer.d.ts +45 -0
- package/dist/scorer.d.ts.map +1 -0
- package/dist/scorer.js +161 -0
- package/dist/scorer.js.map +1 -0
- package/dist/types.d.ts +147 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/package.json +45 -0
package/dist/filters.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.applyHardFilters = applyHardFilters;
|
|
4
|
+
const huggingface_1 = require("./registry/huggingface");
|
|
5
|
+
const benchmark_1 = require("./benchmark");
|
|
6
|
+
const query_1 = require("./query");
|
|
7
|
+
/**
|
|
8
|
+
* (v0.4) Rough VRAM-per-billion-parameters estimate for fp16 inference,
|
|
9
|
+
* used only to translate paramsB into an estimated footprint for the
|
|
10
|
+
* HardwareSpec.vramGB filter below. The doc specifies "use vramGB when
|
|
11
|
+
* present" but no exact formula — this is a commonly-cited heuristic
|
|
12
|
+
* (~2GB VRAM per 1B params at fp16), not a measured or authoritative
|
|
13
|
+
* figure. Flagged here and in the README as an approximation.
|
|
14
|
+
*/
|
|
15
|
+
const ESTIMATED_GB_PER_BILLION_PARAMS = 2;
|
|
16
|
+
/**
|
|
17
|
+
* Applies hard filters before any scoring happens. A model failing ANY
|
|
18
|
+
* filter is excluded outright — it never reaches scorer.ts. Unknown values
|
|
19
|
+
* never cause exclusion (MVP Section 4.4's rule, carried forward per the
|
|
20
|
+
* v0.2/v0.3/v0.4 guides' "unknown data is never punished" cross-phase
|
|
21
|
+
* principle). Provider-agnostic throughout — never branches on
|
|
22
|
+
* model.provider (v0.4 Do's/Don'ts).
|
|
23
|
+
*/
|
|
24
|
+
function applyHardFilters(models, query) {
|
|
25
|
+
const expectedPipelineTag = (0, huggingface_1.mapTaskToPipelineTag)(query.task);
|
|
26
|
+
return models.filter((model) => {
|
|
27
|
+
// 1. maxParamsB — known + over budget => exclude. Unknown => let through.
|
|
28
|
+
if (query.maxParamsB !== undefined &&
|
|
29
|
+
model.paramsB != null &&
|
|
30
|
+
model.paramsB > query.maxParamsB) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
// 2. contextLength — known + too small => exclude. Unknown => let through.
|
|
34
|
+
if (model.contextWindow != null && model.contextWindow < query.contextLength) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
// 3. task compatibility — pipeline_tag present but doesn't map => exclude.
|
|
38
|
+
// Missing pipeline_tag entirely is treated as "can't determine", not excluded.
|
|
39
|
+
// (Ollama candidates never set pipeline_tag, so they're never excluded here —
|
|
40
|
+
// same "unknown, let through" rule, not a provider-specific carve-out.)
|
|
41
|
+
if (model.pipeline_tag && model.pipeline_tag !== expectedPipelineTag) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
// 4. (v0.2) maxLatencyMs — only enforced when benchmark data exists AND
|
|
45
|
+
// hardware is the original string-enum form (the benchmark dataset is
|
|
46
|
+
// keyed by that enum, not by arbitrary HardwareSpec objects). No
|
|
47
|
+
// benchmark entry => let through, same unknown-value rule.
|
|
48
|
+
if (query.maxLatencyMs !== undefined && (0, query_1.isHardwareEnumString)(query.hardware)) {
|
|
49
|
+
const measuredLatency = (0, benchmark_1.lookupLatencyMs)(model.id, query.hardware);
|
|
50
|
+
if (measuredLatency !== null && measuredLatency > query.maxLatencyMs) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// 5. (v0.4) HardwareSpec.vramGB — known paramsB + known vramGB budget +
|
|
55
|
+
// estimated footprint exceeds it => exclude. Unknown paramsB, or no
|
|
56
|
+
// vramGB given, => let through (unknown-value rule again).
|
|
57
|
+
if ((0, query_1.isHardwareSpec)(query.hardware) && query.hardware.vramGB !== undefined && model.paramsB != null) {
|
|
58
|
+
const estimatedVramGB = model.paramsB * ESTIMATED_GB_PER_BILLION_PARAMS;
|
|
59
|
+
if (estimatedVramGB > query.hardware.vramGB) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return true;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=filters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filters.js","sourceRoot":"","sources":["../src/filters.ts"],"names":[],"mappings":";;;AACA,wDAA8D;AAC9D,2CAA8C;AAC9C,mCAA+D;AAE/D;;;;;;;GAOG;AACH,MAAM,+BAA+B,GAAG,CAAC,CAAC;AAE1C;;;;;;;GAOG;AACH,0BAAiC,MAAiB,EAAE,KAAiB;IACnE,MAAM,mBAAmB,GAAG,IAAA,kCAAoB,EAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAE7D,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;QAC7B,0EAA0E;QAC1E,IACE,KAAK,CAAC,UAAU,KAAK,SAAS;YAC9B,KAAK,CAAC,OAAO,IAAI,IAAI;YACrB,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,UAAU,EAChC,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,2EAA2E;QAC3E,IAAI,KAAK,CAAC,aAAa,IAAI,IAAI,IAAI,KAAK,CAAC,aAAa,GAAG,KAAK,CAAC,aAAa,EAAE,CAAC;YAC7E,OAAO,KAAK,CAAC;QACf,CAAC;QAED,2EAA2E;QAC3E,kFAAkF;QAClF,iFAAiF;QACjF,2EAA2E;QAC3E,IAAI,KAAK,CAAC,YAAY,IAAI,KAAK,CAAC,YAAY,KAAK,mBAAmB,EAAE,CAAC;YACrE,OAAO,KAAK,CAAC;QACf,CAAC;QAED,wEAAwE;QACxE,yEAAyE;QACzE,oEAAoE;QACpE,8DAA8D;QAC9D,IAAI,KAAK,CAAC,YAAY,KAAK,SAAS,IAAI,IAAA,4BAAoB,EAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7E,MAAM,eAAe,GAAG,IAAA,2BAAe,EAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;YAClE,IAAI,eAAe,KAAK,IAAI,IAAI,eAAe,GAAG,KAAK,CAAC,YAAY,EAAE,CAAC;gBACrE,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QAED,wEAAwE;QACxE,uEAAuE;QACvE,8DAA8D;QAC9D,IAAI,IAAA,sBAAc,EAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,IAAI,IAAI,EAAE,CAAC;YACnG,MAAM,eAAe,GAAG,KAAK,CAAC,OAAO,GAAG,+BAA+B,CAAC;YACxE,IAAI,eAAe,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;gBAC5C,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ModelQuery, ModelMatch } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Finds and ranks models matching the given query, across one or more
|
|
4
|
+
* providers (HuggingFace by default; optionally Ollama as of v0.4).
|
|
5
|
+
*
|
|
6
|
+
* Pipeline (locked order, per MVP guide Section 5, Step 8 — unchanged since MVP):
|
|
7
|
+
* validate -> fetch -> hard-filter -> score -> tie-break -> sort -> limit -> return
|
|
8
|
+
*
|
|
9
|
+
* v0.4 changes (see post-MVP guide):
|
|
10
|
+
* - New optional `providers` field: which registries to query. Defaults
|
|
11
|
+
* to ["huggingface"] — identical behavior to v0.1-v0.3 when omitted.
|
|
12
|
+
* - The FETCH step now fans out to every requested provider in parallel
|
|
13
|
+
* and merges their RawModel[] results before hard-filtering — filters.ts
|
|
14
|
+
* and scorer.ts never see provider-specific shapes or branch on
|
|
15
|
+
* provider name (v0.4 Do's/Don'ts).
|
|
16
|
+
* - `hardware` is widened to optionally accept a structured HardwareSpec
|
|
17
|
+
* ({ type, vramGB? }) alongside the original string enum. When vramGB
|
|
18
|
+
* is given, filters.ts applies an estimated-footprint hard filter
|
|
19
|
+
* (see that file for the heuristic and its caveats).
|
|
20
|
+
* - Ollama being unreachable never fails the whole call — see
|
|
21
|
+
* registry/ollama.ts for the graceful-degradation behavior.
|
|
22
|
+
*
|
|
23
|
+
* v0.3 changes (see post-MVP guide):
|
|
24
|
+
* - New optional `scoringMode`: "rule" (default, unchanged v0.1/v0.2
|
|
25
|
+
* behavior) | "embedding" | "hybrid". Only the SCORE step changes
|
|
26
|
+
* between modes — hard filters (step 3) run identically regardless of
|
|
27
|
+
* scoringMode, per the "filters stay mode-agnostic" cross-phase
|
|
28
|
+
* principle. See scorer.ts's computeFinalScore for the per-mode logic.
|
|
29
|
+
* - "embedding" mode uses a local, dependency-free text-similarity
|
|
30
|
+
* scorer (embeddings.ts) instead of a downloaded neural model — see
|
|
31
|
+
* that file's docblock for why, and the trade-off involved.
|
|
32
|
+
*
|
|
33
|
+
* v0.2 changes (see post-MVP guide):
|
|
34
|
+
* - fetch is now backed by a file-based cache (cache-file.ts) instead of
|
|
35
|
+
* MVP's in-memory Map, so repeated queries survive process restarts.
|
|
36
|
+
* - maxLatencyMs is now a real hard filter when both it and the original
|
|
37
|
+
* string-form `hardware` are provided AND a benchmark entry exists for
|
|
38
|
+
* that (model, hardware) pair (see filters.ts, benchmark.ts). Still
|
|
39
|
+
* unenforced otherwise — unknown values are never punished.
|
|
40
|
+
* - HuggingFace fetch failures now retry transient errors (429/5xx) with
|
|
41
|
+
* backoff before throwing a typed SmallmError subclass (errors.ts).
|
|
42
|
+
*
|
|
43
|
+
* Known MVP-era limitation, still present through v0.4: candidate models
|
|
44
|
+
* from HuggingFace come only from its list endpoint, which does not return
|
|
45
|
+
* context-window data, so `contextWindow` stays null/unknown for those
|
|
46
|
+
* models and the context-fit score component stays neutral (50). Not part
|
|
47
|
+
* of any shipped phase's scope yet — tracked as a future addition.
|
|
48
|
+
*/
|
|
49
|
+
export declare function findModels(query: ModelQuery): Promise<ModelMatch[]>;
|
|
50
|
+
export type { ModelQuery, ModelMatch } from "./types";
|
|
51
|
+
export { SmallmError, HFApiError, RateLimitError, ValidationError } from "./errors";
|
|
52
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAA0B,MAAM,SAAS,CAAC;AAgBzE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAmDzE;AAKD,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAKtD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ValidationError = exports.RateLimitError = exports.HFApiError = exports.SmallmError = void 0;
|
|
4
|
+
exports.findModels = findModels;
|
|
5
|
+
const query_1 = require("./query");
|
|
6
|
+
const cache_file_1 = require("./cache-file");
|
|
7
|
+
const params_1 = require("./params");
|
|
8
|
+
const filters_1 = require("./filters");
|
|
9
|
+
const scorer_1 = require("./scorer");
|
|
10
|
+
const huggingface_1 = require("./registry/huggingface");
|
|
11
|
+
const ollama_1 = require("./registry/ollama");
|
|
12
|
+
/** (v0.4) Registry of known providers, keyed by name, for the fan-out step below. */
|
|
13
|
+
const PROVIDERS = {
|
|
14
|
+
huggingface: huggingface_1.huggingfaceProvider,
|
|
15
|
+
ollama: ollama_1.ollamaProvider,
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Finds and ranks models matching the given query, across one or more
|
|
19
|
+
* providers (HuggingFace by default; optionally Ollama as of v0.4).
|
|
20
|
+
*
|
|
21
|
+
* Pipeline (locked order, per MVP guide Section 5, Step 8 — unchanged since MVP):
|
|
22
|
+
* validate -> fetch -> hard-filter -> score -> tie-break -> sort -> limit -> return
|
|
23
|
+
*
|
|
24
|
+
* v0.4 changes (see post-MVP guide):
|
|
25
|
+
* - New optional `providers` field: which registries to query. Defaults
|
|
26
|
+
* to ["huggingface"] — identical behavior to v0.1-v0.3 when omitted.
|
|
27
|
+
* - The FETCH step now fans out to every requested provider in parallel
|
|
28
|
+
* and merges their RawModel[] results before hard-filtering — filters.ts
|
|
29
|
+
* and scorer.ts never see provider-specific shapes or branch on
|
|
30
|
+
* provider name (v0.4 Do's/Don'ts).
|
|
31
|
+
* - `hardware` is widened to optionally accept a structured HardwareSpec
|
|
32
|
+
* ({ type, vramGB? }) alongside the original string enum. When vramGB
|
|
33
|
+
* is given, filters.ts applies an estimated-footprint hard filter
|
|
34
|
+
* (see that file for the heuristic and its caveats).
|
|
35
|
+
* - Ollama being unreachable never fails the whole call — see
|
|
36
|
+
* registry/ollama.ts for the graceful-degradation behavior.
|
|
37
|
+
*
|
|
38
|
+
* v0.3 changes (see post-MVP guide):
|
|
39
|
+
* - New optional `scoringMode`: "rule" (default, unchanged v0.1/v0.2
|
|
40
|
+
* behavior) | "embedding" | "hybrid". Only the SCORE step changes
|
|
41
|
+
* between modes — hard filters (step 3) run identically regardless of
|
|
42
|
+
* scoringMode, per the "filters stay mode-agnostic" cross-phase
|
|
43
|
+
* principle. See scorer.ts's computeFinalScore for the per-mode logic.
|
|
44
|
+
* - "embedding" mode uses a local, dependency-free text-similarity
|
|
45
|
+
* scorer (embeddings.ts) instead of a downloaded neural model — see
|
|
46
|
+
* that file's docblock for why, and the trade-off involved.
|
|
47
|
+
*
|
|
48
|
+
* v0.2 changes (see post-MVP guide):
|
|
49
|
+
* - fetch is now backed by a file-based cache (cache-file.ts) instead of
|
|
50
|
+
* MVP's in-memory Map, so repeated queries survive process restarts.
|
|
51
|
+
* - maxLatencyMs is now a real hard filter when both it and the original
|
|
52
|
+
* string-form `hardware` are provided AND a benchmark entry exists for
|
|
53
|
+
* that (model, hardware) pair (see filters.ts, benchmark.ts). Still
|
|
54
|
+
* unenforced otherwise — unknown values are never punished.
|
|
55
|
+
* - HuggingFace fetch failures now retry transient errors (429/5xx) with
|
|
56
|
+
* backoff before throwing a typed SmallmError subclass (errors.ts).
|
|
57
|
+
*
|
|
58
|
+
* Known MVP-era limitation, still present through v0.4: candidate models
|
|
59
|
+
* from HuggingFace come only from its list endpoint, which does not return
|
|
60
|
+
* context-window data, so `contextWindow` stays null/unknown for those
|
|
61
|
+
* models and the context-fit score component stays neutral (50). Not part
|
|
62
|
+
* of any shipped phase's scope yet — tracked as a future addition.
|
|
63
|
+
*/
|
|
64
|
+
async function findModels(query) {
|
|
65
|
+
// 1. validate
|
|
66
|
+
const validated = (0, query_1.validateQuery)(query);
|
|
67
|
+
// (v0.2) apply per-call cache options, if provided, before the fetch step.
|
|
68
|
+
if (validated.cacheOptions) {
|
|
69
|
+
(0, cache_file_1.configureCandidateModelsCache)(validated.cacheOptions);
|
|
70
|
+
}
|
|
71
|
+
// 2. fetch — (v0.4) fan out to every requested provider, cached per
|
|
72
|
+
// (provider, task) pair, then merge before anything downstream sees them.
|
|
73
|
+
const providerLists = await Promise.all(validated.providers.map((providerName) => {
|
|
74
|
+
const provider = PROVIDERS[providerName];
|
|
75
|
+
return (0, cache_file_1.getOrFetchCached)(`${provider.name}:${validated.task}`, () => provider.listCandidates(validated));
|
|
76
|
+
}));
|
|
77
|
+
const rawCandidates = providerLists.flat();
|
|
78
|
+
const enriched = (0, params_1.enrichWithParams)(rawCandidates);
|
|
79
|
+
// 3. hard-filter — mode-agnostic and provider-agnostic, runs identically regardless of scoringMode/providers
|
|
80
|
+
const filtered = (0, filters_1.applyHardFilters)(enriched, validated);
|
|
81
|
+
// 4. score — mode-aware as of v0.3 (rule / embedding / hybrid)
|
|
82
|
+
const expectedPipelineTag = (0, huggingface_1.mapTaskToPipelineTag)(validated.task);
|
|
83
|
+
const scored = filtered.map((model) => ({
|
|
84
|
+
model,
|
|
85
|
+
result: (0, scorer_1.computeFinalScore)(model, validated, expectedPipelineTag),
|
|
86
|
+
}));
|
|
87
|
+
// 5. tie-break + 6. sort (single stable sort using the tie-break-aware comparator)
|
|
88
|
+
scored.sort((a, b) => (0, scorer_1.compareModels)({ score: a.result.finalScore, downloads: a.model.downloads ?? 0 }, { score: b.result.finalScore, downloads: b.model.downloads ?? 0 }));
|
|
89
|
+
// 7. limit
|
|
90
|
+
const top = scored.slice(0, validated.limit);
|
|
91
|
+
// 8. return — map to the public ModelMatch shape
|
|
92
|
+
return top.map(({ model, result }) => ({
|
|
93
|
+
name: model.id,
|
|
94
|
+
provider: model.provider ?? "huggingface",
|
|
95
|
+
paramsB: model.paramsB ?? null,
|
|
96
|
+
contextWindow: model.contextWindow ?? null,
|
|
97
|
+
reasonWhy: (0, scorer_1.generateReasonWhyForResult)(result),
|
|
98
|
+
score: result.finalScore,
|
|
99
|
+
scoringMode: result.scoringMode,
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
// (v0.2) Public error exports — additive. Lets consumers do
|
|
103
|
+
// `catch (e) { if (e instanceof ValidationError) ... }` without reaching
|
|
104
|
+
// into internal modules.
|
|
105
|
+
var errors_1 = require("./errors");
|
|
106
|
+
Object.defineProperty(exports, "SmallmError", { enumerable: true, get: function () { return errors_1.SmallmError; } });
|
|
107
|
+
Object.defineProperty(exports, "HFApiError", { enumerable: true, get: function () { return errors_1.HFApiError; } });
|
|
108
|
+
Object.defineProperty(exports, "RateLimitError", { enumerable: true, get: function () { return errors_1.RateLimitError; } });
|
|
109
|
+
Object.defineProperty(exports, "ValidationError", { enumerable: true, get: function () { return errors_1.ValidationError; } });
|
|
110
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/params.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { HFModel, ParamsSource } from "./types";
|
|
2
|
+
export interface ParamsExtractionResult {
|
|
3
|
+
paramsB: number | null;
|
|
4
|
+
paramsSource: ParamsSource;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Extracts a billions-of-params estimate for a model, trying id first,
|
|
8
|
+
* then tags. Config-based extraction ("config" source) would require
|
|
9
|
+
* fetching per-model detail, which the MVP pipeline does not do
|
|
10
|
+
* (see index.ts notes) — so "config" is defined in ParamsSource for
|
|
11
|
+
* forward-compat but never produced in MVP.
|
|
12
|
+
*
|
|
13
|
+
* Known limitation: sub-billion models (e.g. "opt-125m") are not detected
|
|
14
|
+
* since we only match the B suffix. They correctly fall through to
|
|
15
|
+
* "unknown" rather than being misread, which is the safe failure mode
|
|
16
|
+
* per the Unknown-Value Rule.
|
|
17
|
+
*/
|
|
18
|
+
export declare function extractParamsB(model: HFModel): ParamsExtractionResult;
|
|
19
|
+
/** Applies extraction to a full list, returning enriched copies (does not mutate input). */
|
|
20
|
+
export declare function enrichWithParams(models: HFModel[]): HFModel[];
|
|
21
|
+
//# sourceMappingURL=params.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"params.d.ts","sourceRoot":"","sources":["../src/params.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAShD,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,EAAE,YAAY,CAAC;CAC5B;AASD;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,sBAAsB,CAcrE;AAED,4FAA4F;AAC5F,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CAK7D"}
|
package/dist/params.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractParamsB = extractParamsB;
|
|
4
|
+
exports.enrichWithParams = enrichWithParams;
|
|
5
|
+
/**
|
|
6
|
+
* Matches patterns like "7B", "13b", "1.1B", "70B-Instruct".
|
|
7
|
+
* Requires a digit immediately before the B/b, and no letter/digit right after,
|
|
8
|
+
* so we don't accidentally match things like "Bert" or "B16".
|
|
9
|
+
*/
|
|
10
|
+
const PARAM_REGEX = /(\d+(?:\.\d+)?)[\-_]?[bB](?![a-zA-Z0-9])/;
|
|
11
|
+
function extractFromString(value, regex) {
|
|
12
|
+
const match = value.match(regex);
|
|
13
|
+
if (!match)
|
|
14
|
+
return null;
|
|
15
|
+
const num = parseFloat(match[1]);
|
|
16
|
+
return Number.isFinite(num) ? num : null;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Extracts a billions-of-params estimate for a model, trying id first,
|
|
20
|
+
* then tags. Config-based extraction ("config" source) would require
|
|
21
|
+
* fetching per-model detail, which the MVP pipeline does not do
|
|
22
|
+
* (see index.ts notes) — so "config" is defined in ParamsSource for
|
|
23
|
+
* forward-compat but never produced in MVP.
|
|
24
|
+
*
|
|
25
|
+
* Known limitation: sub-billion models (e.g. "opt-125m") are not detected
|
|
26
|
+
* since we only match the B suffix. They correctly fall through to
|
|
27
|
+
* "unknown" rather than being misread, which is the safe failure mode
|
|
28
|
+
* per the Unknown-Value Rule.
|
|
29
|
+
*/
|
|
30
|
+
function extractParamsB(model) {
|
|
31
|
+
const fromId = extractFromString(model.id, PARAM_REGEX);
|
|
32
|
+
if (fromId !== null) {
|
|
33
|
+
return { paramsB: fromId, paramsSource: "id" };
|
|
34
|
+
}
|
|
35
|
+
for (const tag of model.tags ?? []) {
|
|
36
|
+
const fromTag = extractFromString(tag, PARAM_REGEX);
|
|
37
|
+
if (fromTag !== null) {
|
|
38
|
+
return { paramsB: fromTag, paramsSource: "tag" };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return { paramsB: null, paramsSource: "unknown" };
|
|
42
|
+
}
|
|
43
|
+
/** Applies extraction to a full list, returning enriched copies (does not mutate input). */
|
|
44
|
+
function enrichWithParams(models) {
|
|
45
|
+
return models.map((model) => {
|
|
46
|
+
const { paramsB, paramsSource } = extractParamsB(model);
|
|
47
|
+
return { ...model, paramsB, paramsSource };
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=params.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"params.js","sourceRoot":"","sources":["../src/params.ts"],"names":[],"mappings":";;;;AAEA;;;;GAIG;AACH,MAAM,WAAW,GAAG,0CAA0C,CAAC;AAO/D,SAAS,iBAAiB,CAAC,KAAa,EAAE,KAAa;IACrD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACjC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3C,CAAC;AAED;;;;;;;;;;;GAWG;AACH,wBAA+B,KAAc;IAC3C,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;IACxD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;IACjD,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,iBAAiB,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QACpD,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;QACnD,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC;AACpD,CAAC;AAED,4FAA4F;AAC5F,0BAAiC,MAAiB;IAChD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QAC1B,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QACxD,OAAO,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/query.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { ModelQuery, ScoringMode, ProviderName, HardwareSpec } from "./types";
|
|
2
|
+
import { ValidationError } from "./errors";
|
|
3
|
+
/** True for the original v0.1-v0.3 hardware string enum. */
|
|
4
|
+
export declare function isHardwareEnumString(hardware: unknown): hardware is "cpu" | "gpu-low" | "gpu-high";
|
|
5
|
+
/** True for the v0.4 structured HardwareSpec form. */
|
|
6
|
+
export declare function isHardwareSpec(hardware: unknown): hardware is HardwareSpec;
|
|
7
|
+
/**
|
|
8
|
+
* Backward-compatible alias. As of v0.2, query validation throws the typed
|
|
9
|
+
* ValidationError (a SmallmError subclass, see errors.ts) — this name is
|
|
10
|
+
* kept so any existing `catch (e) { if (e instanceof InvalidQueryError) }`
|
|
11
|
+
* code from v0.1 keeps working unchanged (it's the same class, not a copy).
|
|
12
|
+
*/
|
|
13
|
+
export { ValidationError as InvalidQueryError };
|
|
14
|
+
/**
|
|
15
|
+
* Validates a raw ModelQuery and returns a normalized copy
|
|
16
|
+
* (limit defaulted to 5 if omitted). Throws InvalidQueryError on bad input.
|
|
17
|
+
*/
|
|
18
|
+
export declare function validateQuery(query: ModelQuery): ModelQuery & {
|
|
19
|
+
limit: number;
|
|
20
|
+
scoringMode: ScoringMode;
|
|
21
|
+
providers: ProviderName[];
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAU3C,4DAA4D;AAC5D,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,OAAO,GAChB,QAAQ,IAAI,KAAK,GAAG,SAAS,GAAG,UAAU,CAE5C;AAED,sDAAsD;AACtD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,OAAO,GAAG,QAAQ,IAAI,YAAY,CAE1E;AAED;;;;;GAKG;AACH,OAAO,EAAE,eAAe,IAAI,iBAAiB,EAAE,CAAC;AAEhD;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,UAAU,GAChB,UAAU,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE,YAAY,EAAE,CAAA;CAAE,CAgErF"}
|
package/dist/query.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InvalidQueryError = void 0;
|
|
4
|
+
exports.isHardwareEnumString = isHardwareEnumString;
|
|
5
|
+
exports.isHardwareSpec = isHardwareSpec;
|
|
6
|
+
exports.validateQuery = validateQuery;
|
|
7
|
+
const errors_1 = require("./errors");
|
|
8
|
+
Object.defineProperty(exports, "InvalidQueryError", { enumerable: true, get: function () { return errors_1.ValidationError; } });
|
|
9
|
+
const VALID_HARDWARE = new Set(["cpu", "gpu-low", "gpu-high"]);
|
|
10
|
+
const VALID_SCORING_MODES = new Set(["rule", "embedding", "hybrid"]);
|
|
11
|
+
const VALID_PROVIDERS = new Set(["huggingface", "ollama"]);
|
|
12
|
+
const VALID_HARDWARE_SPEC_TYPES = new Set(["cpu", "gpu"]);
|
|
13
|
+
const DEFAULT_LIMIT = 5;
|
|
14
|
+
const DEFAULT_SCORING_MODE = "rule";
|
|
15
|
+
const DEFAULT_PROVIDERS = ["huggingface"];
|
|
16
|
+
/** True for the original v0.1-v0.3 hardware string enum. */
|
|
17
|
+
function isHardwareEnumString(hardware) {
|
|
18
|
+
return typeof hardware === "string" && VALID_HARDWARE.has(hardware);
|
|
19
|
+
}
|
|
20
|
+
/** True for the v0.4 structured HardwareSpec form. */
|
|
21
|
+
function isHardwareSpec(hardware) {
|
|
22
|
+
return typeof hardware === "object" && hardware !== null && "type" in hardware;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Validates a raw ModelQuery and returns a normalized copy
|
|
26
|
+
* (limit defaulted to 5 if omitted). Throws InvalidQueryError on bad input.
|
|
27
|
+
*/
|
|
28
|
+
function validateQuery(query) {
|
|
29
|
+
if (!query || typeof query !== "object") {
|
|
30
|
+
throw new errors_1.ValidationError("query must be an object");
|
|
31
|
+
}
|
|
32
|
+
if (typeof query.task !== "string" || query.task.trim() === "") {
|
|
33
|
+
throw new errors_1.ValidationError("query.task is required and must be a non-empty string");
|
|
34
|
+
}
|
|
35
|
+
if (typeof query.contextLength !== "number" || !Number.isFinite(query.contextLength) || query.contextLength <= 0) {
|
|
36
|
+
throw new errors_1.ValidationError("query.contextLength is required and must be a positive number");
|
|
37
|
+
}
|
|
38
|
+
if (query.hardware !== undefined && !isHardwareEnumString(query.hardware) && !isHardwareSpec(query.hardware)) {
|
|
39
|
+
throw new errors_1.ValidationError(`query.hardware must be one of: ${[...VALID_HARDWARE].join(", ")}, or a { type, vramGB? } object`);
|
|
40
|
+
}
|
|
41
|
+
if (isHardwareSpec(query.hardware)) {
|
|
42
|
+
if (!VALID_HARDWARE_SPEC_TYPES.has(query.hardware.type)) {
|
|
43
|
+
throw new errors_1.ValidationError(`query.hardware.type must be one of: ${[...VALID_HARDWARE_SPEC_TYPES].join(", ")}`);
|
|
44
|
+
}
|
|
45
|
+
if (query.hardware.vramGB !== undefined && (typeof query.hardware.vramGB !== "number" || query.hardware.vramGB <= 0)) {
|
|
46
|
+
throw new errors_1.ValidationError("query.hardware.vramGB must be a positive number when provided");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (query.domain !== undefined && (typeof query.domain !== "string" || query.domain.trim() === "")) {
|
|
50
|
+
throw new errors_1.ValidationError("query.domain must be a non-empty string when provided");
|
|
51
|
+
}
|
|
52
|
+
if (query.maxParamsB !== undefined && (typeof query.maxParamsB !== "number" || query.maxParamsB <= 0)) {
|
|
53
|
+
throw new errors_1.ValidationError("query.maxParamsB must be a positive number when provided");
|
|
54
|
+
}
|
|
55
|
+
if (query.maxLatencyMs !== undefined && (typeof query.maxLatencyMs !== "number" || query.maxLatencyMs <= 0)) {
|
|
56
|
+
throw new errors_1.ValidationError("query.maxLatencyMs must be a positive number when provided");
|
|
57
|
+
}
|
|
58
|
+
if (query.limit !== undefined && (typeof query.limit !== "number" || !Number.isInteger(query.limit) || query.limit <= 0)) {
|
|
59
|
+
throw new errors_1.ValidationError("query.limit must be a positive integer when provided");
|
|
60
|
+
}
|
|
61
|
+
if (query.scoringMode !== undefined && !VALID_SCORING_MODES.has(query.scoringMode)) {
|
|
62
|
+
throw new errors_1.ValidationError(`query.scoringMode must be one of: ${[...VALID_SCORING_MODES].join(", ")}`);
|
|
63
|
+
}
|
|
64
|
+
if (query.providers !== undefined) {
|
|
65
|
+
if (!Array.isArray(query.providers) || query.providers.length === 0) {
|
|
66
|
+
throw new errors_1.ValidationError("query.providers must be a non-empty array when provided");
|
|
67
|
+
}
|
|
68
|
+
for (const p of query.providers) {
|
|
69
|
+
if (!VALID_PROVIDERS.has(p)) {
|
|
70
|
+
throw new errors_1.ValidationError(`query.providers entries must be one of: ${[...VALID_PROVIDERS].join(", ")}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
...query,
|
|
76
|
+
limit: query.limit ?? DEFAULT_LIMIT,
|
|
77
|
+
scoringMode: query.scoringMode ?? DEFAULT_SCORING_MODE,
|
|
78
|
+
providers: query.providers ?? DEFAULT_PROVIDERS,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { HFModel } from "../types";
|
|
2
|
+
import { HFApiError } from "../errors";
|
|
3
|
+
import { Provider } from "./provider";
|
|
4
|
+
/** Backward-compatible alias — v0.1 threw this name; v0.2 throws the same class under a new name. */
|
|
5
|
+
export { HFApiError as HuggingFaceApiError };
|
|
6
|
+
export declare function mapTaskToPipelineTag(task: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Fetches candidate models from HuggingFace for a given task.
|
|
9
|
+
* No API key required (public search endpoint, per docx 6.3).
|
|
10
|
+
*
|
|
11
|
+
* (v0.2) Retries transient failures (429 / 5xx) up to MAX_RETRIES times with
|
|
12
|
+
* exponential backoff (500ms, 1000ms, 2000ms). Non-transient failures
|
|
13
|
+
* (4xx other than 429) are thrown immediately — retrying them can't help.
|
|
14
|
+
* All thrown errors are typed SmallmError subclasses (see errors.ts).
|
|
15
|
+
*/
|
|
16
|
+
export declare function fetchCandidateModels(task: string): Promise<HFModel[]>;
|
|
17
|
+
/**
|
|
18
|
+
* (v0.4) Provider implementation wrapping fetchCandidateModels — no behavior
|
|
19
|
+
* change to the underlying fetch/retry/error logic above, this just adapts
|
|
20
|
+
* the existing function to the shared Provider interface so index.ts can
|
|
21
|
+
* treat HuggingFace the same way it treats every other provider.
|
|
22
|
+
*/
|
|
23
|
+
export declare const huggingfaceProvider: Provider;
|
|
24
|
+
//# sourceMappingURL=huggingface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"huggingface.d.ts","sourceRoot":"","sources":["../../src/registry/huggingface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,UAAU,EAAkB,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAOtC,qGAAqG;AACrG,OAAO,EAAE,UAAU,IAAI,mBAAmB,EAAE,CAAC;AA6B7C,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAsCD;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAyB3E;AAED;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,EAAE,QAGjC,CAAC"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.huggingfaceProvider = exports.HuggingFaceApiError = void 0;
|
|
4
|
+
exports.mapTaskToPipelineTag = mapTaskToPipelineTag;
|
|
5
|
+
exports.fetchCandidateModels = fetchCandidateModels;
|
|
6
|
+
const errors_1 = require("../errors");
|
|
7
|
+
Object.defineProperty(exports, "HuggingFaceApiError", { enumerable: true, get: function () { return errors_1.HFApiError; } });
|
|
8
|
+
const HF_API_BASE = "https://huggingface.co/api/models";
|
|
9
|
+
/** Number of candidates to pull per query, per docx 6.3: fixed fetch limit, no pagination in MVP. */
|
|
10
|
+
const FETCH_LIMIT = 50;
|
|
11
|
+
/** (v0.2) Retry policy: cap at 3 attempts, exponential backoff, only for transient failures. */
|
|
12
|
+
const MAX_RETRIES = 3;
|
|
13
|
+
const BACKOFF_SCHEDULE_MS = [500, 1000, 2000];
|
|
14
|
+
function sleep(ms) {
|
|
15
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
16
|
+
}
|
|
17
|
+
/** True for 429 (rate limit) and any 5xx — the only cases worth retrying. */
|
|
18
|
+
function isTransient(status) {
|
|
19
|
+
return status === 429 || (status >= 500 && status < 600);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Maps our public `task` values to HuggingFace's pipeline_tag vocabulary.
|
|
23
|
+
* Unknown/custom task strings pass through unchanged so query.task can
|
|
24
|
+
* still be a free string per the contract.
|
|
25
|
+
*/
|
|
26
|
+
const TASK_TO_PIPELINE_TAG = {
|
|
27
|
+
summarize: "summarization",
|
|
28
|
+
classify: "text-classification",
|
|
29
|
+
extract: "token-classification",
|
|
30
|
+
chat: "text-generation",
|
|
31
|
+
code: "text-generation",
|
|
32
|
+
translate: "translation",
|
|
33
|
+
};
|
|
34
|
+
function mapTaskToPipelineTag(task) {
|
|
35
|
+
return TASK_TO_PIPELINE_TAG[task] ?? task;
|
|
36
|
+
}
|
|
37
|
+
/** A single fetch attempt — no retry logic here, that lives in fetchCandidateModels. */
|
|
38
|
+
async function fetchOnce(url) {
|
|
39
|
+
const response = await fetch(url);
|
|
40
|
+
if (!response.ok) {
|
|
41
|
+
if (response.status === 429) {
|
|
42
|
+
throw new errors_1.RateLimitError(`HuggingFace API rate-limited the request (429)`);
|
|
43
|
+
}
|
|
44
|
+
throw new errors_1.HFApiError(`HuggingFace API request failed with status ${response.status}`, response.status);
|
|
45
|
+
}
|
|
46
|
+
const data = (await response.json());
|
|
47
|
+
return data.map((item) => ({
|
|
48
|
+
id: item.id,
|
|
49
|
+
provider: "huggingface",
|
|
50
|
+
pipeline_tag: item.pipeline_tag,
|
|
51
|
+
tags: item.tags ?? [],
|
|
52
|
+
downloads: item.downloads ?? 0,
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Fetches candidate models from HuggingFace for a given task.
|
|
57
|
+
* No API key required (public search endpoint, per docx 6.3).
|
|
58
|
+
*
|
|
59
|
+
* (v0.2) Retries transient failures (429 / 5xx) up to MAX_RETRIES times with
|
|
60
|
+
* exponential backoff (500ms, 1000ms, 2000ms). Non-transient failures
|
|
61
|
+
* (4xx other than 429) are thrown immediately — retrying them can't help.
|
|
62
|
+
* All thrown errors are typed SmallmError subclasses (see errors.ts).
|
|
63
|
+
*/
|
|
64
|
+
async function fetchCandidateModels(task) {
|
|
65
|
+
const pipelineTag = mapTaskToPipelineTag(task);
|
|
66
|
+
const url = `${HF_API_BASE}?pipeline_tag=${encodeURIComponent(pipelineTag)}&limit=${FETCH_LIMIT}&sort=downloads&direction=-1`;
|
|
67
|
+
let lastError;
|
|
68
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
69
|
+
try {
|
|
70
|
+
return await fetchOnce(url);
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
if (!(err instanceof errors_1.HFApiError))
|
|
74
|
+
throw err; // unexpected error shape — don't swallow it
|
|
75
|
+
const status = err.status ?? 0;
|
|
76
|
+
const canRetry = isTransient(status) && attempt < MAX_RETRIES;
|
|
77
|
+
lastError = err;
|
|
78
|
+
if (!canRetry)
|
|
79
|
+
throw err;
|
|
80
|
+
await sleep(BACKOFF_SCHEDULE_MS[attempt]);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Unreachable in practice (the loop always returns or throws), but keeps TS happy
|
|
84
|
+
// and gives a sane fallback if MAX_RETRIES were ever set to a negative number.
|
|
85
|
+
throw lastError ?? new errors_1.HFApiError("HuggingFace API request failed with no response");
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* (v0.4) Provider implementation wrapping fetchCandidateModels — no behavior
|
|
89
|
+
* change to the underlying fetch/retry/error logic above, this just adapts
|
|
90
|
+
* the existing function to the shared Provider interface so index.ts can
|
|
91
|
+
* treat HuggingFace the same way it treats every other provider.
|
|
92
|
+
*/
|
|
93
|
+
exports.huggingfaceProvider = {
|
|
94
|
+
name: "huggingface",
|
|
95
|
+
listCandidates: (query) => fetchCandidateModels(query.task),
|
|
96
|
+
};
|
|
97
|
+
//# sourceMappingURL=huggingface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"huggingface.js","sourceRoot":"","sources":["../../src/registry/huggingface.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ollama.d.ts","sourceRoot":"","sources":["../../src/registry/ollama.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAiGtC,eAAO,MAAM,cAAc,EAAE,QAG5B,CAAC"}
|