@dbx-tools/model 0.9.32 → 0.9.37

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.
Files changed (52) hide show
  1. package/README.md +3 -3
  2. package/exports.ts +1 -0
  3. package/index.ts +12 -8
  4. package/lib/index.d.ts +12 -8
  5. package/lib/index.js +8 -5
  6. package/lib/scripts/generate-metadata.d.ts +1 -0
  7. package/lib/scripts/generate-metadata.js +65 -0
  8. package/lib/src/_metadata-contract.d.ts +12 -6
  9. package/lib/src/_metadata-contract.js +3 -1
  10. package/lib/src/_metadata-generator.d.ts +3 -1
  11. package/lib/src/_metadata-generator.js +148 -1
  12. package/lib/src/_ranking.js +39 -12
  13. package/lib/src/_selection.d.ts +1 -17
  14. package/lib/src/_selection.js +1 -1
  15. package/lib/src/classify.d.ts +1 -17
  16. package/lib/src/classify.js +1 -1
  17. package/lib/src/generated/model-reasoning.json +147 -0
  18. package/lib/src/invoke.d.ts +8 -0
  19. package/lib/src/invoke.js +13 -1
  20. package/lib/src/metadata-cache.d.ts +84 -0
  21. package/lib/src/metadata-cache.js +234 -0
  22. package/lib/src/metadata.d.ts +52 -17
  23. package/lib/src/metadata.js +251 -18
  24. package/lib/src/model-catalog.d.ts +1 -19
  25. package/lib/src/model-catalog.js +9 -2
  26. package/lib/src/model-client.d.ts +11 -19
  27. package/lib/src/model-client.js +42 -24
  28. package/lib/src/reasoning-translation.d.ts +105 -0
  29. package/lib/src/reasoning-translation.js +444 -0
  30. package/lib/src/resolve.d.ts +2 -4
  31. package/lib/src/resolve.js +2 -2
  32. package/lib/src/serving-wire.d.ts +37 -0
  33. package/lib/src/serving-wire.js +211 -0
  34. package/lib/tsconfig.tsbuildinfo +1 -1
  35. package/package.json +110 -17
  36. package/src/_metadata-contract.ts +17 -7
  37. package/src/_metadata-generator.ts +160 -0
  38. package/src/_ranking.ts +40 -11
  39. package/src/_selection.ts +4 -19
  40. package/src/classify.ts +2 -18
  41. package/src/generated/model-reasoning.json +147 -0
  42. package/src/invoke.ts +16 -0
  43. package/src/metadata-cache.ts +322 -0
  44. package/src/metadata.ts +334 -43
  45. package/src/model-catalog.ts +8 -25
  46. package/src/model-client.ts +67 -44
  47. package/src/reasoning-translation.ts +495 -0
  48. package/src/resolve.ts +10 -11
  49. package/src/serving-wire.ts +231 -0
  50. package/lib/src/python.d.ts +0 -2
  51. package/lib/src/python.js +0 -3
  52. package/src/python.ts +0 -2
package/src/metadata.ts CHANGED
@@ -1,66 +1,80 @@
1
1
  /**
2
- * Build-generated Databricks model retirement, capability, and rate-limit metadata.
2
+ * Build-generated Databricks model retirement, capability, rate-limit, and
3
+ * reasoning-effort metadata, plus a daily write-through cache for refreshed
4
+ * docs and error-learned reasoning ladders.
3
5
  *
4
- * The committed snapshots are refreshed by `bun run model:metadata`. Runtime
5
- * lookups build their normalized sets and maps once per process and perform no
6
- * documentation network requests.
6
+ * Committed snapshots seed every process. {@link refreshModelMetadata} pulls
7
+ * documentation through {@link createMetadataCache} (cacache memoize + disk) and
8
+ * rebuilds the in-memory index. Error-learned efforts use the same store via
9
+ * {@link rememberReasoningLevels}. Disk writes are skipped in Databricks Apps.
7
10
  *
8
11
  * @module
9
12
  */
10
13
  import * as functionUtils from "@dbx-tools/shared-core/function-utils";
11
- import type { ModelStatus, ServingEndpointSummary } from "@dbx-tools/shared-model/contracts";
14
+ import * as log from "@dbx-tools/shared-core/log";
15
+ import type {
16
+ ModelCapabilities,
17
+ ModelMetadata,
18
+ ModelRateLimits,
19
+ ModelStatus,
20
+ ServingEndpointSummary,
21
+ } from "@dbx-tools/shared-model/contracts";
12
22
 
13
- import capabilitiesSnapshotJson from "./generated/model-capabilities.json" with { type: "json" };
14
- import rateLimitsSnapshotJson from "./generated/model-rate-limits.json" with { type: "json" };
15
- import retiredModelsSnapshotJson from "./generated/retired-models.json" with { type: "json" };
16
23
  import {
17
24
  MODEL_METADATA_TTL_MS,
18
25
  MODEL_RATE_LIMITS_URL,
19
26
  OPENAI_RESPONSES_MODELS_URL,
27
+ QUERY_REASON_MODELS_URL,
20
28
  RETIRED_MODELS_URL,
21
29
  WEB_SEARCH_MODELS_URL,
22
30
  type ModelCapabilitiesSnapshot,
23
31
  type ModelCapabilityCatalogue,
24
- type ModelRateLimits,
25
32
  type ModelRateLimitsSnapshot,
33
+ type ReasoningModelsSnapshot,
26
34
  type RetiredModelsSnapshot,
27
35
  } from "./_metadata-contract.ts";
36
+ import {
37
+ parseModelCapabilities,
38
+ parseModelRateLimits,
39
+ parseReasoningModels,
40
+ parseRetiredModels,
41
+ } from "./_metadata-generator.ts";
42
+ import {
43
+ createMetadataCache,
44
+ mergePreferFreshList,
45
+ mergePreferFreshRecord,
46
+ type MetadataCache,
47
+ } from "./metadata-cache.ts";
48
+ import capabilitiesSnapshotJson from "./generated/model-capabilities.json" with { type: "json" };
49
+ import rateLimitsSnapshotJson from "./generated/model-rate-limits.json" with { type: "json" };
50
+ import reasoningSnapshotJson from "./generated/model-reasoning.json" with { type: "json" };
51
+ import retiredModelsSnapshotJson from "./generated/retired-models.json" with { type: "json" };
28
52
  import { modelSearchQuery } from "./policy.ts";
53
+ import {
54
+ defaultReasoningLevels,
55
+ documentedReasoningLevels,
56
+ parseReasoning,
57
+ parseReasoningLevels,
58
+ type ReasoningLevel,
59
+ type ReasoningModelCatalogue,
60
+ uniqueReasoningLevels,
61
+ } from "./reasoning-translation.ts";
29
62
 
30
63
  export {
31
64
  MODEL_METADATA_TTL_MS,
32
65
  MODEL_RATE_LIMITS_URL,
33
66
  OPENAI_RESPONSES_MODELS_URL,
67
+ QUERY_REASON_MODELS_URL,
34
68
  RETIRED_MODELS_URL,
35
69
  WEB_SEARCH_MODELS_URL,
36
70
  };
37
- export type {
38
- ModelCapabilitiesSnapshot,
39
- ModelCapabilityCatalogue,
40
- ModelRateLimitCatalogue,
41
- ModelRateLimits,
42
- ModelRateLimitsSnapshot,
43
- RetiredModelsSnapshot,
44
- } from "./_metadata-contract.ts";
71
+
72
+ const logger = log.logger("model/metadata");
45
73
 
46
74
  const retiredModelsSnapshot = retiredModelsSnapshotJson as RetiredModelsSnapshot;
47
75
  const capabilitiesSnapshot = capabilitiesSnapshotJson as ModelCapabilitiesSnapshot;
48
76
  const rateLimitsSnapshot = rateLimitsSnapshotJson as ModelRateLimitsSnapshot;
49
-
50
- /** Documented capabilities resolved for one model identity. */
51
- export interface ModelCapabilities {
52
- readonly responses: boolean;
53
- readonly imageInput: boolean;
54
- readonly applyPatch: boolean;
55
- readonly webSearch: boolean;
56
- }
57
-
58
- /** Combined build-generated metadata resolved for one model identity. */
59
- export interface ModelMetadata {
60
- readonly status: ModelStatus;
61
- readonly capabilities: ModelCapabilities;
62
- readonly rateLimits?: ModelRateLimits;
63
- }
77
+ const reasoningSnapshot = reasoningSnapshotJson as ReasoningModelsSnapshot;
64
78
 
65
79
  interface MetadataIndex {
66
80
  readonly retiredNames: readonly string[];
@@ -69,25 +83,261 @@ interface MetadataIndex {
69
83
  readonly [Key in keyof ModelCapabilityCatalogue]: ReadonlySet<string>;
70
84
  };
71
85
  readonly rateLimits: ReadonlyMap<string, ModelRateLimits>;
86
+ readonly reasoning: ReasoningModelCatalogue;
87
+ readonly learnedReasoning: ReasoningModelCatalogue;
72
88
  }
73
89
 
74
- const metadataIndex = functionUtils.memoize<MetadataIndex>(() => ({
75
- retiredNames: Object.freeze([...retiredModelsSnapshot.models]),
76
- retiredKeys: new Set(retiredModelsSnapshot.models.map(retiredModelKey).filter(Boolean)),
77
- capabilities: {
78
- responses: new Set(capabilitiesSnapshot.capabilities.responses),
79
- imageInput: new Set(capabilitiesSnapshot.capabilities.imageInput),
80
- applyPatch: new Set(capabilitiesSnapshot.capabilities.applyPatch),
81
- webSearch: new Set(capabilitiesSnapshot.capabilities.webSearch),
90
+ type CapabilitySets = ModelCapabilityCatalogue;
91
+
92
+ const USER_AGENT = "dbx-tools-model-metadata/1";
93
+
94
+ const retiredCache = createMetadataCache<readonly string[]>({
95
+ key: "retired-models",
96
+ fallback: retiredModelsSnapshot.models,
97
+ load: async () => parseRetiredModels(await loadPage(RETIRED_MODELS_URL), nowSeconds()).models,
98
+ merge: mergePreferFreshList,
99
+ });
100
+
101
+ const capabilitiesCache = createMetadataCache<CapabilitySets>({
102
+ key: "model-capabilities",
103
+ fallback: capabilitiesSnapshot.capabilities,
104
+ load: async () => {
105
+ const [responsesHtml, webSearchHtml] = await Promise.all([
106
+ loadPage(OPENAI_RESPONSES_MODELS_URL),
107
+ loadPage(WEB_SEARCH_MODELS_URL),
108
+ ]);
109
+ return parseModelCapabilities(responsesHtml, webSearchHtml, nowSeconds()).capabilities;
82
110
  },
83
- rateLimits: new Map(Object.entries(rateLimitsSnapshot.catalogue.models)),
84
- }));
111
+ merge: (input) => ({
112
+ responses: mergePreferFreshList({
113
+ fresh: input.fresh?.responses,
114
+ previous: input.previous?.responses,
115
+ fallback: input.fallback.responses,
116
+ }),
117
+ imageInput: mergePreferFreshList({
118
+ fresh: input.fresh?.imageInput,
119
+ previous: input.previous?.imageInput,
120
+ fallback: input.fallback.imageInput,
121
+ }),
122
+ applyPatch: mergePreferFreshList({
123
+ fresh: input.fresh?.applyPatch,
124
+ previous: input.previous?.applyPatch,
125
+ fallback: input.fallback.applyPatch,
126
+ }),
127
+ webSearch: mergePreferFreshList({
128
+ fresh: input.fresh?.webSearch,
129
+ previous: input.previous?.webSearch,
130
+ fallback: input.fallback.webSearch,
131
+ }),
132
+ }),
133
+ });
134
+
135
+ const rateLimitsCache = createMetadataCache<Readonly<Record<string, ModelRateLimits>>>({
136
+ key: "model-rate-limits",
137
+ fallback: rateLimitsSnapshot.catalogue.models,
138
+ load: async () =>
139
+ parseModelRateLimits(await loadPage(MODEL_RATE_LIMITS_URL), nowSeconds()).catalogue.models,
140
+ merge: mergePreferFreshRecord,
141
+ });
142
+
143
+ const reasoningDocsCache = createMetadataCache<Readonly<Record<string, readonly string[]>>>({
144
+ key: "model-reasoning",
145
+ fallback: reasoningSnapshot.catalogue.models,
146
+ load: async () =>
147
+ parseReasoningModels(await loadPage(QUERY_REASON_MODELS_URL), nowSeconds()).catalogue.models,
148
+ merge: mergePreferFreshRecord,
149
+ });
150
+
151
+ const learnedReasoningCache = createMetadataCache<Readonly<Record<string, readonly ReasoningLevel[]>>>({
152
+ key: "learned-reasoning",
153
+ fallback: {},
154
+ merge: mergePreferFreshRecord,
155
+ });
156
+
157
+ let liveIndex: MetadataIndex | undefined;
158
+
159
+ const metadataIndex = functionUtils.memoize<MetadataIndex>(() => liveIndex ?? buildIndexFromCommitted());
160
+
161
+ function buildIndexFromCommitted(): MetadataIndex {
162
+ return buildIndex({
163
+ retiredNames: retiredModelsSnapshot.models,
164
+ capabilities: capabilitiesSnapshot.capabilities,
165
+ rateLimits: rateLimitsSnapshot.catalogue.models,
166
+ reasoning: reasoningSnapshot.catalogue.models,
167
+ learnedReasoning: {},
168
+ });
169
+ }
170
+
171
+ function buildIndex(input: {
172
+ readonly retiredNames: readonly string[];
173
+ readonly capabilities: CapabilitySets;
174
+ readonly rateLimits: Readonly<Record<string, ModelRateLimits>>;
175
+ readonly reasoning: Readonly<Record<string, readonly string[]>>;
176
+ readonly learnedReasoning: Readonly<Record<string, readonly ReasoningLevel[]>>;
177
+ }): MetadataIndex {
178
+ return {
179
+ retiredNames: Object.freeze([...input.retiredNames]),
180
+ retiredKeys: new Set(input.retiredNames.map(retiredModelKey).filter(Boolean)),
181
+ capabilities: {
182
+ responses: new Set(input.capabilities.responses),
183
+ imageInput: new Set(input.capabilities.imageInput),
184
+ applyPatch: new Set(input.capabilities.applyPatch),
185
+ webSearch: new Set(input.capabilities.webSearch),
186
+ },
187
+ rateLimits: new Map(Object.entries(input.rateLimits)),
188
+ reasoning: freezeReasoningCatalogue(input.reasoning),
189
+ learnedReasoning: freezeLearnedCatalogue(input.learnedReasoning),
190
+ };
191
+ }
192
+
193
+ function freezeReasoningCatalogue(
194
+ models: Readonly<Record<string, readonly string[]>>,
195
+ ): ReasoningModelCatalogue {
196
+ return Object.freeze(
197
+ Object.fromEntries(
198
+ Object.entries(models).map(([key, levels]) => [
199
+ key,
200
+ Object.freeze(
201
+ uniqueReasoningLevels(levels.flatMap((level) => parseReasoning(level) ?? [])),
202
+ ),
203
+ ]),
204
+ ),
205
+ );
206
+ }
207
+
208
+ function freezeLearnedCatalogue(
209
+ models: Readonly<Record<string, readonly ReasoningLevel[]>>,
210
+ ): ReasoningModelCatalogue {
211
+ return Object.freeze(
212
+ Object.fromEntries(
213
+ Object.entries(models).map(([key, levels]) => [
214
+ key,
215
+ Object.freeze(uniqueReasoningLevels(levels)),
216
+ ]),
217
+ ),
218
+ );
219
+ }
220
+
221
+ let refreshInflight: Promise<MetadataIndex> | undefined;
222
+
223
+ /**
224
+ * Hydrate or refresh documentation + learned caches into the process index.
225
+ *
226
+ * Safe to call on gateway startup. Concurrent callers share one refresh.
227
+ */
228
+ export async function refreshModelMetadata(): Promise<MetadataIndex> {
229
+ if (refreshInflight) return refreshInflight;
230
+ refreshInflight = (async () => {
231
+ const [retiredNames, capabilities, rateLimits, reasoning, learnedReasoning] = await Promise.all([
232
+ retiredCache.get(),
233
+ capabilitiesCache.get(),
234
+ rateLimitsCache.get(),
235
+ reasoningDocsCache.get(),
236
+ learnedReasoningCache.get(),
237
+ ]);
238
+ liveIndex = buildIndex({
239
+ retiredNames,
240
+ capabilities,
241
+ rateLimits,
242
+ reasoning,
243
+ learnedReasoning,
244
+ });
245
+ return liveIndex;
246
+ })().finally(() => {
247
+ refreshInflight = undefined;
248
+ });
249
+ return refreshInflight;
250
+ }
251
+
252
+ void hydrateModelMetadata().catch((error) => {
253
+ logger.warn("metadata cache hydrate failed; using committed snapshots", { error });
254
+ });
255
+
256
+ /** Load cacache / memory entries without forcing a network refresh. */
257
+ export async function hydrateModelMetadata(): Promise<MetadataIndex> {
258
+ const [retiredNames, capabilities, rateLimits, reasoning, learnedReasoning] = await Promise.all([
259
+ peekOrFallback(retiredCache, retiredModelsSnapshot.models),
260
+ peekOrFallback(capabilitiesCache, capabilitiesSnapshot.capabilities),
261
+ peekOrFallback(rateLimitsCache, rateLimitsSnapshot.catalogue.models),
262
+ peekOrFallback(reasoningDocsCache, reasoningSnapshot.catalogue.models),
263
+ peekOrFallback(learnedReasoningCache, {}),
264
+ ]);
265
+ liveIndex = buildIndex({
266
+ retiredNames,
267
+ capabilities,
268
+ rateLimits,
269
+ reasoning,
270
+ learnedReasoning,
271
+ });
272
+ return liveIndex;
273
+ }
274
+
275
+ async function peekOrFallback<T>(cache: MetadataCache<T>, fallback: T): Promise<T> {
276
+ const peeked = await cache.peek();
277
+ if (peeked !== undefined) return peeked;
278
+ return cache.get().catch(() => fallback);
279
+ }
280
+
281
+ /** Absolute cacache root used by the documentation / learned caches. */
282
+ export function modelMetadataCachePath(): string {
283
+ return retiredCache.path;
284
+ }
85
285
 
86
286
  /** Return the committed retired-model names. The array is cached and immutable. */
87
287
  export function retiredModelNames(): readonly string[] {
88
288
  return metadataIndex().retiredNames;
89
289
  }
90
290
 
291
+ /** Return the committed reasoning-effort catalogue. Cached per process. */
292
+ export function reasoningModelCatalogue(): ReasoningModelCatalogue {
293
+ return metadataIndex().reasoning;
294
+ }
295
+
296
+ /** Return error-learned reasoning ladders persisted in the metadata cache. */
297
+ export function learnedReasoningCatalogue(): ReasoningModelCatalogue {
298
+ return metadataIndex().learnedReasoning;
299
+ }
300
+
301
+ /**
302
+ * Store levels learned from an upstream error and persist them write-through.
303
+ *
304
+ * Empty lists are ignored so a failed parse cannot wipe defaults. Error bodies
305
+ * themselves are never stored - only the parsed ladder.
306
+ */
307
+ export async function rememberReasoningLevels(
308
+ model: string,
309
+ levels: readonly ReasoningLevel[],
310
+ ): Promise<ReasoningLevel[]> {
311
+ const unique = uniqueReasoningLevels(levels);
312
+ if (unique.length === 0) return modelReasoningLevelsFor(model);
313
+ const key = modelKey(model);
314
+ if (!key) return modelReasoningLevelsFor(model);
315
+ const catalogue = await learnedReasoningCache.update((current) => ({
316
+ ...current,
317
+ [key]: unique,
318
+ }));
319
+ const current = metadataIndex();
320
+ liveIndex = {
321
+ ...current,
322
+ learnedReasoning: freezeLearnedCatalogue(catalogue),
323
+ };
324
+ return [...unique];
325
+ }
326
+
327
+ /**
328
+ * Parse an upstream error body and persist the supported ladder for `model`.
329
+ *
330
+ * Accepts the same nested Databricks envelopes as {@link parseReasoningLevels}.
331
+ * Returns the levels that were stored (or the current lookup when parse yields
332
+ * nothing). The raw error body is never written to disk.
333
+ */
334
+ export async function learnReasoningLevelsFromError(
335
+ model: string,
336
+ body: unknown,
337
+ ): Promise<ReasoningLevel[]> {
338
+ return rememberReasoningLevels(model, parseReasoningLevels(body));
339
+ }
340
+
91
341
  /** Resolve whether any supplied identity is listed in the retirement snapshot. */
92
342
  export function modelStatusFor(
93
343
  ...models: readonly (string | ServingEndpointSummary)[]
@@ -131,6 +381,30 @@ export function modelRateLimitsFor(
131
381
  return undefined;
132
382
  }
133
383
 
384
+ /**
385
+ * Resolve reasoning levels: learned from errors, then documentation, then
386
+ * family defaults.
387
+ *
388
+ * Does not parse error bodies; callers should use {@link parseReasoningLevels}
389
+ * and then {@link rememberReasoningLevels}.
390
+ */
391
+ export function modelReasoningLevelsFor(
392
+ model: string | ServingEndpointSummary,
393
+ ): ReasoningLevel[] {
394
+ const index = metadataIndex();
395
+ for (const identity of modelIdentities(model)) {
396
+ const learned = documentedReasoningLevels(identity, index.learnedReasoning);
397
+ if (learned?.length) return learned;
398
+ }
399
+ for (const identity of modelIdentities(model)) {
400
+ const documented = documentedReasoningLevels(identity, index.reasoning);
401
+ if (documented?.length) return documented;
402
+ }
403
+ const primary =
404
+ typeof model === "string" ? model : (model.modelServiceName ?? model.name);
405
+ return defaultReasoningLevels(primary);
406
+ }
407
+
134
408
  /** Resolve retirement, capability, and rate-limit metadata together. */
135
409
  export function modelMetadataFor(model: string | ServingEndpointSummary): ModelMetadata {
136
410
  const rateLimits = modelRateLimitsFor(model);
@@ -141,16 +415,18 @@ export function modelMetadataFor(model: string | ServingEndpointSummary): ModelM
141
415
  };
142
416
  }
143
417
 
144
- /** Return generation timestamps for the three committed metadata snapshots. */
418
+ /** Return generation timestamps for the committed metadata snapshots. */
145
419
  export function modelMetadataGeneratedAt(): Readonly<{
146
420
  retiredModels: number;
147
421
  capabilities: number;
148
422
  rateLimits: number;
423
+ reasoning: number;
149
424
  }> {
150
425
  return {
151
426
  retiredModels: retiredModelsSnapshot.generatedAt,
152
427
  capabilities: capabilitiesSnapshot.generatedAt,
153
428
  rateLimits: rateLimitsSnapshot.generatedAt,
429
+ reasoning: reasoningSnapshot.generatedAt,
154
430
  };
155
431
  }
156
432
 
@@ -187,3 +463,18 @@ function retiredModelKey(value: string): string {
187
463
  while (tokens[0] && RETIRED_MODEL_PREFIXES.has(tokens[0])) tokens.shift();
188
464
  return tokens.join("-");
189
465
  }
466
+
467
+ async function loadPage(url: string): Promise<string> {
468
+ const response = await fetch(url, {
469
+ headers: { "user-agent": USER_AGENT },
470
+ signal: AbortSignal.timeout(15_000),
471
+ });
472
+ if (!response.ok) {
473
+ throw new Error(`Databricks documentation returned HTTP ${response.status}: ${url}`);
474
+ }
475
+ return response.text();
476
+ }
477
+
478
+ function nowSeconds(): number {
479
+ return Math.floor(Date.now() / 1000);
480
+ }
@@ -25,7 +25,13 @@ import { createHash } from "node:crypto";
25
25
  import { CacheManager } from "@databricks/appkit";
26
26
  import { appkit } from "@dbx-tools/appkit";
27
27
  import { errorUtils, log } from "@dbx-tools/shared-core";
28
- import { model, type ServingEndpointSummary } from "@dbx-tools/shared-model";
28
+ import {
29
+ model,
30
+ type ResolvedModel,
31
+ type ResolveModelOptions,
32
+ type ScoredEndpoint,
33
+ type ServingEndpointSummary,
34
+ } from "@dbx-tools/shared-model";
29
35
 
30
36
  import { classifyEndpointClasses, normalizeEndpoints, rankEndpoints } from "./_ranking.ts";
31
37
 
@@ -140,9 +146,7 @@ async function fetchEndpoints(client: WorkspaceClientLike): Promise<ServingEndpo
140
146
  * classification of the whole set. Endpoints the classifier doesn't recognize
141
147
  * (custom, unscored, non-LLM) are left without a class.
142
148
  */
143
- function stampModelClasses(
144
- summaries: readonly ServingEndpointSummary[],
145
- ): ServingEndpointSummary[] {
149
+ function stampModelClasses(summaries: readonly ServingEndpointSummary[]): ServingEndpointSummary[] {
146
150
  const classOf = classifyEndpointClasses(summaries);
147
151
  return summaries.map((summary) => {
148
152
  const cls = classOf.get(summary.name);
@@ -218,27 +222,6 @@ export async function clearServingEndpointsCache(
218
222
  * callers can fall back to the original input (Databricks will then return a
219
223
  * clean 404).
220
224
  */
221
- export interface ResolvedModel {
222
- modelId: string;
223
- matched: boolean;
224
- score?: number;
225
- }
226
-
227
- /** Options accepted by {@link resolveModelId} / {@link searchServingEndpoints}. */
228
- export interface ResolveModelOptions {
229
- /** Fuzzy distance threshold (0 = exact, 1 = anything). Default `0.4`. */
230
- threshold?: number;
231
- /** Require a model verified for a complete function-tool round-trip. */
232
- requiresTools?: boolean;
233
- }
234
-
235
- /** A serving endpoint paired with its fuzzy-match distance for a query. */
236
- export interface ScoredEndpoint {
237
- endpoint: ServingEndpointSummary;
238
- /** Fuzzy distance: `0` is exact, `1` is no match. */
239
- score: number;
240
- }
241
-
242
225
  /**
243
226
  * Fuzzy-rank endpoints by how closely their `name` matches `input`, best
244
227
  * (lowest score) first, keeping only those within `threshold`: