@dbx-tools/model 0.9.21 → 0.9.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -10
- package/index.ts +12 -2
- package/lib/exports.d.ts +1 -0
- package/lib/exports.js +2 -0
- package/lib/index.d.ts +12 -2
- package/lib/index.js +9 -2
- package/lib/src/_metadata-contract.d.ts +42 -0
- package/lib/src/_metadata-contract.js +11 -0
- package/lib/src/_metadata-generator.d.ts +7 -0
- package/lib/src/_metadata-generator.js +182 -0
- package/lib/src/_ranking.d.ts +20 -0
- package/lib/src/_ranking.js +226 -0
- package/lib/src/_selection.d.ts +23 -0
- package/lib/src/_selection.js +95 -0
- package/lib/src/classes.d.ts +2 -2
- package/lib/src/classes.js +10 -8
- package/lib/src/classify.d.ts +130 -0
- package/lib/src/classify.js +283 -0
- package/lib/src/fallback.d.ts +4 -4
- package/lib/src/fallback.js +7 -7
- package/lib/src/generated/model-capabilities.json +90 -0
- package/lib/src/generated/model-rate-limits.json +342 -0
- package/lib/src/generated/retired-models.json +32 -0
- package/lib/src/invoke.js +3 -3
- package/lib/src/metadata.d.ts +33 -0
- package/lib/src/metadata.js +120 -0
- package/lib/src/model-catalog.d.ts +4 -4
- package/lib/src/model-catalog.js +19 -24
- package/lib/src/model-client.d.ts +67 -0
- package/lib/src/model-client.js +181 -0
- package/lib/src/policy.d.ts +14 -8
- package/lib/src/policy.js +173 -14
- package/lib/src/python.d.ts +2 -0
- package/lib/src/python.js +3 -0
- package/lib/src/resolve.d.ts +10 -143
- package/lib/src/resolve.js +11 -196
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +15 -5
- package/src/_metadata-contract.ts +56 -0
- package/src/_metadata-generator.ts +199 -0
- package/src/_ranking.ts +260 -0
- package/src/_selection.ts +141 -0
- package/src/classes.ts +11 -7
- package/src/classify.ts +324 -0
- package/src/fallback.ts +11 -7
- package/src/generated/model-capabilities.json +90 -0
- package/src/generated/model-rate-limits.json +342 -0
- package/src/generated/retired-models.json +32 -0
- package/src/invoke.ts +2 -2
- package/src/metadata.ts +189 -0
- package/src/model-catalog.ts +26 -28
- package/src/model-client.ts +311 -0
- package/src/policy.ts +176 -19
- package/src/python.ts +2 -0
- package/src/resolve.ts +24 -270
- package/._LICENSE +0 -0
- package/._README.md +0 -0
- package/._index.ts +0 -0
- package/._package.json +0 -0
- package/lib/._index.d.ts +0 -0
- package/lib/._index.js +0 -0
- package/lib/._tsconfig.tsbuildinfo +0 -0
- package/lib/src/.__native.d.ts +0 -0
- package/lib/src/.__native.js +0 -0
- package/lib/src/._classes.d.ts +0 -0
- package/lib/src/._classes.js +0 -0
- package/lib/src/._fallback.d.ts +0 -0
- package/lib/src/._fallback.js +0 -0
- package/lib/src/._invoke.d.ts +0 -0
- package/lib/src/._invoke.js +0 -0
- package/lib/src/._model-catalog.d.ts +0 -0
- package/lib/src/._model-catalog.js +0 -0
- package/lib/src/._policy.d.ts +0 -0
- package/lib/src/._policy.js +0 -0
- package/lib/src/._resolve.d.ts +0 -0
- package/lib/src/._resolve.js +0 -0
- package/lib/src/_native.d.ts +0 -14
- package/lib/src/_native.js +0 -124
- package/src/.__native.ts +0 -0
- package/src/._classes.ts +0 -0
- package/src/._fallback.ts +0 -0
- package/src/._invoke.ts +0 -0
- package/src/._model-catalog.ts +0 -0
- package/src/._policy.ts +0 -0
- package/src/._resolve.ts +0 -0
- package/src/_native.ts +0 -174
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { ModelClass as ModelClassValues, } from "@dbx-tools/shared-model/contracts";
|
|
2
|
+
import { toModelDisplayName } from "@dbx-tools/shared-model/display";
|
|
3
|
+
import Fuse from "fuse.js";
|
|
4
|
+
import { classesAtOrBelow, CHAT_CLASS_ORDER, MODEL_CLASS_ORDER } from "./classes.js";
|
|
5
|
+
import { classifyEndpoints, endpointCapabilities, supportsToolsByFamily, versionTuple, } from "./classify.js";
|
|
6
|
+
import { modelStatusFor } from "./metadata.js";
|
|
7
|
+
import { modelFamily, modelReasoningEfforts, modelServiceNames } from "./policy.js";
|
|
8
|
+
const ModelClass = ModelClassValues;
|
|
9
|
+
const DEFAULT_FUZZY_THRESHOLD = 0.4;
|
|
10
|
+
/** Rank endpoint records through the TypeScript-owned model policy. */
|
|
11
|
+
export function rankEndpoints(endpoints, query = {}, options = {}) {
|
|
12
|
+
const originalByName = new Map(endpoints.map((endpoint) => [endpoint.name, endpoint]));
|
|
13
|
+
const normalized = endpoints.map((endpoint) => ({
|
|
14
|
+
...endpoint,
|
|
15
|
+
...(options.modelClass ? { class: options.modelClass } : {}),
|
|
16
|
+
...(options.task ? { task: options.task } : {}),
|
|
17
|
+
}));
|
|
18
|
+
const classified = options.modelClass
|
|
19
|
+
? {
|
|
20
|
+
[ModelClass.ChatThinking]: [],
|
|
21
|
+
[ModelClass.ChatBalanced]: [],
|
|
22
|
+
[ModelClass.ChatFast]: [],
|
|
23
|
+
[ModelClass.Embedding]: [],
|
|
24
|
+
[options.modelClass]: normalized,
|
|
25
|
+
}
|
|
26
|
+
: classifyEndpoints(normalized);
|
|
27
|
+
const requestedClass = options.modelClass ?? query.modelClass;
|
|
28
|
+
const eligible = requestedClass ? classesAtOrBelow(requestedClass) : CHAT_CLASS_ORDER;
|
|
29
|
+
const candidates = [];
|
|
30
|
+
for (const modelClass of eligible) {
|
|
31
|
+
for (const endpoint of classified[modelClass]) {
|
|
32
|
+
if (!options.includeDeprecated && endpoint.status?.deprecated)
|
|
33
|
+
continue;
|
|
34
|
+
if (query.requiresTools && !endpointCapabilities(endpoint).tools)
|
|
35
|
+
continue;
|
|
36
|
+
candidates.push({ endpoint, modelClass });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const search = query.search?.trim();
|
|
40
|
+
let ranked = candidates;
|
|
41
|
+
if (search) {
|
|
42
|
+
const exact = candidates.find((candidate) => candidate.endpoint.name === search);
|
|
43
|
+
if (exact) {
|
|
44
|
+
ranked = [{ ...exact, score: 0 }];
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
const threshold = query.threshold ?? DEFAULT_FUZZY_THRESHOLD;
|
|
48
|
+
const searchTokens = tokenize(search);
|
|
49
|
+
const tokenMatches = candidates
|
|
50
|
+
.filter((candidate) => {
|
|
51
|
+
const candidateTokens = new Set(searchableValues(candidate.endpoint).flatMap(tokenize));
|
|
52
|
+
return (searchTokens.length > 0 && searchTokens.every((token) => candidateTokens.has(token)));
|
|
53
|
+
})
|
|
54
|
+
.map((candidate) => ({ ...candidate, score: 0 }));
|
|
55
|
+
if (tokenMatches.length > 0) {
|
|
56
|
+
ranked = tokenMatches.sort(compareRanked);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
const fuse = new Fuse(candidates, {
|
|
60
|
+
keys: [
|
|
61
|
+
"endpoint.name",
|
|
62
|
+
"endpoint.displayName",
|
|
63
|
+
"endpoint.family",
|
|
64
|
+
"endpoint.modelServiceName",
|
|
65
|
+
"endpoint.serviceNames",
|
|
66
|
+
],
|
|
67
|
+
threshold,
|
|
68
|
+
ignoreLocation: true,
|
|
69
|
+
includeScore: true,
|
|
70
|
+
useExtendedSearch: true,
|
|
71
|
+
isCaseSensitive: false,
|
|
72
|
+
});
|
|
73
|
+
const normalizedSearch = tokenize(search).join(" ");
|
|
74
|
+
ranked = normalizedSearch
|
|
75
|
+
? fuse
|
|
76
|
+
.search(normalizedSearch)
|
|
77
|
+
.filter((result) => (result.score ?? 0) <= threshold)
|
|
78
|
+
.map((result) => ({ ...result.item, score: result.score ?? 0 }))
|
|
79
|
+
.sort(compareRanked)
|
|
80
|
+
: [];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const restored = ranked.map((result) => ({
|
|
85
|
+
...result,
|
|
86
|
+
endpoint: originalByName.get(result.endpoint.name) ?? result.endpoint,
|
|
87
|
+
}));
|
|
88
|
+
return query.limit === undefined ? restored : restored.slice(0, Math.max(0, query.limit));
|
|
89
|
+
}
|
|
90
|
+
/** Classify chat and embedding endpoints through the TypeScript-owned policy. */
|
|
91
|
+
export function classifyEndpointClasses(endpoints) {
|
|
92
|
+
const classified = classifyEndpoints(endpoints);
|
|
93
|
+
const result = new Map();
|
|
94
|
+
for (const modelClass of MODEL_CLASS_ORDER) {
|
|
95
|
+
for (const endpoint of classified[modelClass])
|
|
96
|
+
result.set(endpoint.name, modelClass);
|
|
97
|
+
}
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
/** Normalize serialized SDK endpoint records without native bindings. */
|
|
101
|
+
export function normalizeEndpoints(endpoints) {
|
|
102
|
+
const summaries = endpoints.flatMap((value) => {
|
|
103
|
+
const endpoint = record(value);
|
|
104
|
+
const name = stringValue(endpoint.name);
|
|
105
|
+
if (!name)
|
|
106
|
+
return [];
|
|
107
|
+
const entities = arrayValue(record(endpoint.config).served_entities).map(record);
|
|
108
|
+
const identities = [
|
|
109
|
+
name,
|
|
110
|
+
...entities.flatMap((entity) => [
|
|
111
|
+
stringValue(entity.entity_name),
|
|
112
|
+
stringValue(record(entity.foundation_model).name),
|
|
113
|
+
stringValue(record(entity.external_model).name),
|
|
114
|
+
].filter((identity) => Boolean(identity))),
|
|
115
|
+
];
|
|
116
|
+
const modelServiceName = entities
|
|
117
|
+
.map((entity) => stringValue(record(entity.foundation_model).name) ?? stringValue(entity.entity_name))
|
|
118
|
+
.find(Boolean);
|
|
119
|
+
const family = identities.map(modelFamily).find(Boolean);
|
|
120
|
+
const reasoningEfforts = identities.map(modelReasoningEfforts).sort((left, right) => right.length - left.length)[0] ??
|
|
121
|
+
[];
|
|
122
|
+
const profile = entities.map(modelProfile).find(Boolean);
|
|
123
|
+
const summary = {
|
|
124
|
+
name,
|
|
125
|
+
displayName: toModelDisplayName(name, providedDisplayName(endpoint, entities)),
|
|
126
|
+
...(family ? { family } : {}),
|
|
127
|
+
...(stringValue(endpoint.task) ? { task: stringValue(endpoint.task) } : {}),
|
|
128
|
+
...(stringValue(record(endpoint.state).ready)
|
|
129
|
+
? { state: stringValue(record(endpoint.state).ready) }
|
|
130
|
+
: {}),
|
|
131
|
+
...(stringValue(endpoint.description)
|
|
132
|
+
? { description: stringValue(endpoint.description) }
|
|
133
|
+
: {}),
|
|
134
|
+
supportsTools: identities.some(supportsToolsByFamily),
|
|
135
|
+
...(profile ? { profile } : {}),
|
|
136
|
+
serviceNames: Object.assign({}, ...identities.map(modelServiceNames)),
|
|
137
|
+
...(modelServiceName ? { modelServiceName } : {}),
|
|
138
|
+
...(reasoningEfforts.length ? { reasoningEfforts } : {}),
|
|
139
|
+
status: modelStatusFor(...identities),
|
|
140
|
+
};
|
|
141
|
+
return [summary];
|
|
142
|
+
});
|
|
143
|
+
const classes = classifyEndpointClasses(summaries);
|
|
144
|
+
return summaries.map((summary) => {
|
|
145
|
+
const modelClass = classes.get(summary.name);
|
|
146
|
+
return modelClass ? { ...summary, class: modelClass } : summary;
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
function compareRanked(left, right) {
|
|
150
|
+
const score = Math.round((left.score ?? 0) * 1000) - Math.round((right.score ?? 0) * 1000);
|
|
151
|
+
if (score !== 0)
|
|
152
|
+
return score;
|
|
153
|
+
const leftVersion = versionTuple(left.endpoint.name);
|
|
154
|
+
const rightVersion = versionTuple(right.endpoint.name);
|
|
155
|
+
for (let index = 0; index < 3; index += 1) {
|
|
156
|
+
const version = rightVersion[index] - leftVersion[index];
|
|
157
|
+
if (version !== 0)
|
|
158
|
+
return version;
|
|
159
|
+
}
|
|
160
|
+
const variant = modelVariantRank(left.endpoint.name) - modelVariantRank(right.endpoint.name);
|
|
161
|
+
if (variant !== 0)
|
|
162
|
+
return variant;
|
|
163
|
+
return MODEL_CLASS_ORDER.indexOf(left.modelClass) - MODEL_CLASS_ORDER.indexOf(right.modelClass);
|
|
164
|
+
}
|
|
165
|
+
function modelVariantRank(name) {
|
|
166
|
+
if (!/(?:^|[-_.])gpt(?:[-_.]|$)/i.test(name))
|
|
167
|
+
return 2;
|
|
168
|
+
if (/(?:^|[-_.])sol(?:[-_.]|$)/i.test(name))
|
|
169
|
+
return 0;
|
|
170
|
+
if (/(?:^|[-_.])luna(?:[-_.]|$)/i.test(name))
|
|
171
|
+
return 1;
|
|
172
|
+
return 2;
|
|
173
|
+
}
|
|
174
|
+
function tokenize(value) {
|
|
175
|
+
return value.toLowerCase().match(/[a-z0-9]+/g) ?? [];
|
|
176
|
+
}
|
|
177
|
+
function searchableValues(endpoint) {
|
|
178
|
+
return [
|
|
179
|
+
endpoint.name,
|
|
180
|
+
endpoint.displayName,
|
|
181
|
+
endpoint.family,
|
|
182
|
+
endpoint.modelServiceName,
|
|
183
|
+
...Object.values(endpoint.serviceNames ?? {}),
|
|
184
|
+
].filter((value) => Boolean(value));
|
|
185
|
+
}
|
|
186
|
+
function modelProfile(entity) {
|
|
187
|
+
const source = record(record(entity.foundation_model).ai_gateway_model_profile);
|
|
188
|
+
const quality = finiteNumber(source.quality);
|
|
189
|
+
const speed = finiteNumber(source.speed);
|
|
190
|
+
const cost = finiteNumber(source.cost);
|
|
191
|
+
if (quality === undefined && speed === undefined && cost === undefined)
|
|
192
|
+
return undefined;
|
|
193
|
+
return {
|
|
194
|
+
...(quality !== undefined ? { quality } : {}),
|
|
195
|
+
...(speed !== undefined ? { speed } : {}),
|
|
196
|
+
...(cost !== undefined ? { cost } : {}),
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
function providedDisplayName(endpoint, entities) {
|
|
200
|
+
for (const tag of arrayValue(endpoint.tags).map(record)) {
|
|
201
|
+
if (!["display_name", "displayName", "name"].includes(String(tag.key)))
|
|
202
|
+
continue;
|
|
203
|
+
const value = stringValue(tag.value);
|
|
204
|
+
if (value)
|
|
205
|
+
return value;
|
|
206
|
+
}
|
|
207
|
+
return entities.map((entity) => stringValue(record(entity.external_model).name)).find(Boolean);
|
|
208
|
+
}
|
|
209
|
+
function record(value) {
|
|
210
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
211
|
+
? value
|
|
212
|
+
: {};
|
|
213
|
+
}
|
|
214
|
+
function arrayValue(value) {
|
|
215
|
+
return Array.isArray(value) ? value : [];
|
|
216
|
+
}
|
|
217
|
+
function stringValue(value) {
|
|
218
|
+
if (typeof value !== "string")
|
|
219
|
+
return undefined;
|
|
220
|
+
const trimmed = value.trim();
|
|
221
|
+
return trimmed || undefined;
|
|
222
|
+
}
|
|
223
|
+
function finiteNumber(value) {
|
|
224
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiX3JhbmtpbmcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvX3JhbmtpbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLFVBQVUsSUFBSSxnQkFBZ0IsR0FLL0IsTUFBTSxtQ0FBbUMsQ0FBQztBQUMzQyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUNyRSxPQUFPLElBQUksTUFBTSxTQUFTLENBQUM7QUFFM0IsT0FBTyxFQUFFLGdCQUFnQixFQUFFLGdCQUFnQixFQUFFLGlCQUFpQixFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ3JGLE9BQU8sRUFDTCxpQkFBaUIsRUFDakIsb0JBQW9CLEVBQ3BCLHFCQUFxQixFQUNyQixZQUFZLEdBQ2IsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMvQyxPQUFPLEVBQUUsV0FBVyxFQUFFLHFCQUFxQixFQUFFLGlCQUFpQixFQUFFLE1BQU0sYUFBYSxDQUFDO0FBR3BGLE1BQU0sVUFBVSxHQUFHLGdCQUFnQixDQUFDO0FBRXBDLE1BQU0sdUJBQXVCLEdBQUcsR0FBRyxDQUFDO0FBT3BDLHVFQUF1RTtBQUN2RSxNQUFNLFVBQVUsYUFBYSxDQUMzQixTQUE0QyxFQUM1QyxRQUFvQixFQUFFLEVBQ3RCLFVBQWdDLEVBQUU7SUFFbEMsTUFBTSxjQUFjLEdBQUcsSUFBSSxHQUFHLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQUMsQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN2RixNQUFNLFVBQVUsR0FBRyxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQzlDLEdBQUcsUUFBUTtRQUNYLEdBQUcsQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssRUFBRSxPQUFPLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUM1RCxHQUFHLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7S0FDaEQsQ0FBQyxDQUFDLENBQUM7SUFDSixNQUFNLFVBQVUsR0FBRyxPQUFPLENBQUMsVUFBVTtRQUNuQyxDQUFDLENBQUM7WUFDRSxDQUFDLFVBQVUsQ0FBQyxZQUFZLENBQUMsRUFBRSxFQUFFO1lBQzdCLENBQUMsVUFBVSxDQUFDLFlBQVksQ0FBQyxFQUFFLEVBQUU7WUFDN0IsQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLEVBQUUsRUFBRTtZQUN6QixDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsRUFBRSxFQUFFO1lBQzFCLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxFQUFFLFVBQVU7U0FDakM7UUFDSCxDQUFDLENBQUMsaUJBQWlCLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDbEMsTUFBTSxjQUFjLEdBQUcsT0FBTyxDQUFDLFVBQVUsSUFBSSxLQUFLLENBQUMsVUFBVSxDQUFDO0lBQzlELE1BQU0sUUFBUSxHQUFHLGNBQWMsQ0FBQyxDQUFDLENBQUMsZ0JBQWdCLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQyxDQUFDLGdCQUFnQixDQUFDO0lBQ3RGLE1BQU0sVUFBVSxHQUFrQixFQUFFLENBQUM7SUFDckMsS0FBSyxNQUFNLFVBQVUsSUFBSSxRQUFRLEVBQUUsQ0FBQztRQUNsQyxLQUFLLE1BQU0sUUFBUSxJQUFJLFVBQVUsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1lBQzlDLElBQUksQ0FBQyxPQUFPLENBQUMsaUJBQWlCLElBQUksUUFBUSxDQUFDLE1BQU0sRUFBRSxVQUFVO2dCQUFFLFNBQVM7WUFDeEUsSUFBSSxLQUFLLENBQUMsYUFBYSxJQUFJLENBQUMsb0JBQW9CLENBQUMsUUFBUSxDQUFDLENBQUMsS0FBSztnQkFBRSxTQUFTO1lBQzNFLFVBQVUsQ0FBQyxJQUFJLENBQUMsRUFBRSxRQUFRLEVBQUUsVUFBVSxFQUFFLENBQUMsQ0FBQztRQUM1QyxDQUFDO0lBQ0gsQ0FBQztJQUVELE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxNQUFNLEVBQUUsSUFBSSxFQUFFLENBQUM7SUFDcEMsSUFBSSxNQUFNLEdBQUcsVUFBVSxDQUFDO0lBQ3hCLElBQUksTUFBTSxFQUFFLENBQUM7UUFDWCxNQUFNLEtBQUssR0FBRyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLElBQUksS0FBSyxNQUFNLENBQUMsQ0FBQztRQUNqRixJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ1YsTUFBTSxHQUFHLENBQUMsRUFBRSxHQUFHLEtBQUssRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNwQyxDQUFDO2FBQU0sQ0FBQztZQUNOLE1BQU0sU0FBUyxHQUFHLEtBQUssQ0FBQyxTQUFTLElBQUksdUJBQXVCLENBQUM7WUFDN0QsTUFBTSxZQUFZLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3RDLE1BQU0sWUFBWSxHQUFHLFVBQVU7aUJBQzVCLE1BQU0sQ0FBQyxDQUFDLFNBQVMsRUFBRSxFQUFFO2dCQUNwQixNQUFNLGVBQWUsR0FBRyxJQUFJLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUM7Z0JBQ3hGLE9BQU8sQ0FDTCxZQUFZLENBQUMsTUFBTSxHQUFHLENBQUMsSUFBSSxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQ3JGLENBQUM7WUFDSixDQUFDLENBQUM7aUJBQ0QsR0FBRyxDQUFDLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsR0FBRyxTQUFTLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUNwRCxJQUFJLFlBQVksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQzVCLE1BQU0sR0FBRyxZQUFZLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1lBQzVDLENBQUM7aUJBQU0sQ0FBQztnQkFDTixNQUFNLElBQUksR0FBRyxJQUFJLElBQUksQ0FBQyxVQUFVLEVBQUU7b0JBQ2hDLElBQUksRUFBRTt3QkFDSixlQUFlO3dCQUNmLHNCQUFzQjt3QkFDdEIsaUJBQWlCO3dCQUNqQiwyQkFBMkI7d0JBQzNCLHVCQUF1QjtxQkFDeEI7b0JBQ0QsU0FBUztvQkFDVCxjQUFjLEVBQUUsSUFBSTtvQkFDcEIsWUFBWSxFQUFFLElBQUk7b0JBQ2xCLGlCQUFpQixFQUFFLElBQUk7b0JBQ3ZCLGVBQWUsRUFBRSxLQUFLO2lCQUN2QixDQUFDLENBQUM7Z0JBQ0gsTUFBTSxnQkFBZ0IsR0FBRyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUNwRCxNQUFNLEdBQUcsZ0JBQWdCO29CQUN2QixDQUFDLENBQUMsSUFBSTt5QkFDRCxNQUFNLENBQUMsZ0JBQWdCLENBQUM7eUJBQ3hCLE1BQU0sQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxJQUFJLENBQUMsQ0FBQyxJQUFJLFNBQVMsQ0FBQzt5QkFDcEQsR0FBRyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsR0FBRyxNQUFNLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxNQUFNLENBQUMsS0FBSyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7eUJBQy9ELElBQUksQ0FBQyxhQUFhLENBQUM7b0JBQ3hCLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFDVCxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFDRCxNQUFNLFFBQVEsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ3ZDLEdBQUcsTUFBTTtRQUNULFFBQVEsRUFBRSxjQUFjLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksTUFBTSxDQUFDLFFBQVE7S0FDdEUsQ0FBQyxDQUFDLENBQUM7SUFDSixPQUFPLEtBQUssQ0FBQyxLQUFLLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO0FBQzVGLENBQUM7QUFFRCxpRkFBaUY7QUFDakYsTUFBTSxVQUFVLHVCQUF1QixDQUNyQyxTQUE0QztJQUU1QyxNQUFNLFVBQVUsR0FBRyxpQkFBaUIsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUNoRCxNQUFNLE1BQU0sR0FBRyxJQUFJLEdBQUcsRUFBc0IsQ0FBQztJQUM3QyxLQUFLLE1BQU0sVUFBVSxJQUFJLGlCQUFpQixFQUFFLENBQUM7UUFDM0MsS0FBSyxNQUFNLFFBQVEsSUFBSSxVQUFVLENBQUMsVUFBVSxDQUFDO1lBQUUsTUFBTSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLFVBQVUsQ0FBQyxDQUFDO0lBQ3ZGLENBQUM7SUFDRCxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDO0FBRUQseUVBQXlFO0FBQ3pFLE1BQU0sVUFBVSxrQkFBa0IsQ0FBQyxTQUE2QjtJQUM5RCxNQUFNLFNBQVMsR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUU7UUFDNUMsTUFBTSxRQUFRLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQy9CLE1BQU0sSUFBSSxHQUFHLFdBQVcsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDeEMsSUFBSSxDQUFDLElBQUk7WUFBRSxPQUFPLEVBQUUsQ0FBQztRQUNyQixNQUFNLFFBQVEsR0FBRyxVQUFVLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxlQUFlLENBQUMsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDakYsTUFBTSxVQUFVLEdBQUc7WUFDakIsSUFBSTtZQUNKLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQzdCO2dCQUNFLFdBQVcsQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDO2dCQUMvQixXQUFXLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLElBQUksQ0FBQztnQkFDakQsV0FBVyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLENBQUMsSUFBSSxDQUFDO2FBQ2hELENBQUMsTUFBTSxDQUFDLENBQUMsUUFBUSxFQUFzQixFQUFFLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQzlEO1NBQ0YsQ0FBQztRQUNGLE1BQU0sZ0JBQWdCLEdBQUcsUUFBUTthQUM5QixHQUFHLENBQ0YsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUNULFdBQVcsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLGdCQUFnQixDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksV0FBVyxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FDdkY7YUFDQSxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDakIsTUFBTSxNQUFNLEdBQUcsVUFBVSxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDekQsTUFBTSxnQkFBZ0IsR0FDcEIsVUFBVSxDQUFDLEdBQUcsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsRUFBRSxDQUFDLEtBQUssQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUMxRixFQUFFLENBQUM7UUFDTCxNQUFNLE9BQU8sR0FBRyxRQUFRLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN6RCxNQUFNLE9BQU8sR0FBMkI7WUFDdEMsSUFBSTtZQUNKLFdBQVcsRUFBRSxrQkFBa0IsQ0FBQyxJQUFJLEVBQUUsbUJBQW1CLENBQUMsUUFBUSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1lBQzlFLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUM3QixHQUFHLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsV0FBVyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFDM0UsR0FBRyxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLEtBQUssQ0FBQztnQkFDM0MsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLFdBQVcsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLEtBQUssQ0FBQyxFQUFFO2dCQUN0RCxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQ1AsR0FBRyxDQUFDLFdBQVcsQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDO2dCQUNuQyxDQUFDLENBQUMsRUFBRSxXQUFXLEVBQUUsV0FBVyxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsRUFBRTtnQkFDcEQsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUNQLGFBQWEsRUFBRSxVQUFVLENBQUMsSUFBSSxDQUFDLHFCQUFxQixDQUFDO1lBQ3JELEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUMvQixZQUFZLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLEVBQUUsR0FBRyxVQUFVLENBQUMsR0FBRyxDQUFDLGlCQUFpQixDQUFDLENBQUM7WUFDckUsR0FBRyxDQUFDLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxFQUFFLGdCQUFnQixFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUNqRCxHQUFHLENBQUMsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLGdCQUFnQixFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUN4RCxNQUFNLEVBQUUsY0FBYyxDQUFDLEdBQUcsVUFBVSxDQUFDO1NBQ3RDLENBQUM7UUFDRixPQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDbkIsQ0FBQyxDQUFDLENBQUM7SUFDSCxNQUFNLE9BQU8sR0FBRyx1QkFBdUIsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUNuRCxPQUFPLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRTtRQUMvQixNQUFNLFVBQVUsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUM3QyxPQUFPLFVBQVUsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLE9BQU8sRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQztJQUNsRSxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUM7QUFFRCxTQUFTLGFBQWEsQ0FBQyxJQUFpQixFQUFFLEtBQWtCO0lBQzFELE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxJQUFJLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxJQUFJLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDO0lBQzNGLElBQUksS0FBSyxLQUFLLENBQUM7UUFBRSxPQUFPLEtBQUssQ0FBQztJQUM5QixNQUFNLFdBQVcsR0FBRyxZQUFZLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNyRCxNQUFNLFlBQVksR0FBRyxZQUFZLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUN2RCxLQUFLLElBQUksS0FBSyxHQUFHLENBQUMsRUFBRSxLQUFLLEdBQUcsQ0FBQyxFQUFFLEtBQUssSUFBSSxDQUFDLEVBQUUsQ0FBQztRQUMxQyxNQUFNLE9BQU8sR0FBRyxZQUFZLENBQUMsS0FBSyxDQUFFLEdBQUcsV0FBVyxDQUFDLEtBQUssQ0FBRSxDQUFDO1FBQzNELElBQUksT0FBTyxLQUFLLENBQUM7WUFBRSxPQUFPLE9BQU8sQ0FBQztJQUNwQyxDQUFDO0lBQ0QsTUFBTSxPQUFPLEdBQUcsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsR0FBRyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzdGLElBQUksT0FBTyxLQUFLLENBQUM7UUFBRSxPQUFPLE9BQU8sQ0FBQztJQUNsQyxPQUFPLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEdBQUcsaUJBQWlCLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQztBQUNsRyxDQUFDO0FBRUQsU0FBUyxnQkFBZ0IsQ0FBQyxJQUFZO0lBQ3BDLElBQUksQ0FBQyw0QkFBNEIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO1FBQUUsT0FBTyxDQUFDLENBQUM7SUFDdkQsSUFBSSw0QkFBNEIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO1FBQUUsT0FBTyxDQUFDLENBQUM7SUFDdEQsSUFBSSw2QkFBNkIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO1FBQUUsT0FBTyxDQUFDLENBQUM7SUFDdkQsT0FBTyxDQUFDLENBQUM7QUFDWCxDQUFDO0FBRUQsU0FBUyxRQUFRLENBQUMsS0FBYTtJQUM3QixPQUFPLEtBQUssQ0FBQyxXQUFXLEVBQUUsQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxDQUFDO0FBQ3ZELENBQUM7QUFFRCxTQUFTLGdCQUFnQixDQUFDLFFBQWdDO0lBQ3hELE9BQU87UUFDTCxRQUFRLENBQUMsSUFBSTtRQUNiLFFBQVEsQ0FBQyxXQUFXO1FBQ3BCLFFBQVEsQ0FBQyxNQUFNO1FBQ2YsUUFBUSxDQUFDLGdCQUFnQjtRQUN6QixHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLFlBQVksSUFBSSxFQUFFLENBQUM7S0FDOUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxLQUFLLEVBQW1CLEVBQUUsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztBQUN2RCxDQUFDO0FBRUQsU0FBUyxZQUFZLENBQUMsTUFBK0I7SUFDbkQsTUFBTSxNQUFNLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO0lBQ2hGLE1BQU0sT0FBTyxHQUFHLFlBQVksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDN0MsTUFBTSxLQUFLLEdBQUcsWUFBWSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUN6QyxNQUFNLElBQUksR0FBRyxZQUFZLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3ZDLElBQUksT0FBTyxLQUFLLFNBQVMsSUFBSSxLQUFLLEtBQUssU0FBUyxJQUFJLElBQUksS0FBSyxTQUFTO1FBQUUsT0FBTyxTQUFTLENBQUM7SUFDekYsT0FBTztRQUNMLEdBQUcsQ0FBQyxPQUFPLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDN0MsR0FBRyxDQUFDLEtBQUssS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUN6QyxHQUFHLENBQUMsSUFBSSxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0tBQ3hDLENBQUM7QUFDSixDQUFDO0FBRUQsU0FBUyxtQkFBbUIsQ0FDMUIsUUFBaUMsRUFDakMsUUFBNEM7SUFFNUMsS0FBSyxNQUFNLEdBQUcsSUFBSSxVQUFVLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1FBQ3hELElBQUksQ0FBQyxDQUFDLGNBQWMsRUFBRSxhQUFhLEVBQUUsTUFBTSxDQUFDLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7WUFBRSxTQUFTO1FBQ2pGLE1BQU0sS0FBSyxHQUFHLFdBQVcsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDckMsSUFBSSxLQUFLO1lBQUUsT0FBTyxLQUFLLENBQUM7SUFDMUIsQ0FBQztJQUNELE9BQU8sUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7QUFDakcsQ0FBQztBQUVELFNBQVMsTUFBTSxDQUFDLEtBQWM7SUFDNUIsT0FBTyxLQUFLLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUM7UUFDaEUsQ0FBQyxDQUFFLEtBQWlDO1FBQ3BDLENBQUMsQ0FBQyxFQUFFLENBQUM7QUFDVCxDQUFDO0FBRUQsU0FBUyxVQUFVLENBQUMsS0FBYztJQUNoQyxPQUFPLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0FBQzNDLENBQUM7QUFFRCxTQUFTLFdBQVcsQ0FBQyxLQUFjO0lBQ2pDLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUTtRQUFFLE9BQU8sU0FBUyxDQUFDO0lBQ2hELE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUM3QixPQUFPLE9BQU8sSUFBSSxTQUFTLENBQUM7QUFDOUIsQ0FBQztBQUVELFNBQVMsWUFBWSxDQUFDLEtBQWM7SUFDbEMsT0FBTyxPQUFPLEtBQUssS0FBSyxRQUFRLElBQUksTUFBTSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFDakYsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIE1vZGVsQ2xhc3MgYXMgTW9kZWxDbGFzc1ZhbHVlcyxcbiAgdHlwZSBNb2RlbENsYXNzIGFzIE1vZGVsQ2xhc3NUeXBlLFxuICB0eXBlIE1vZGVsUXVlcnksXG4gIHR5cGUgUmFua2VkTW9kZWwsXG4gIHR5cGUgU2VydmluZ0VuZHBvaW50U3VtbWFyeSxcbn0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLW1vZGVsL2NvbnRyYWN0c1wiO1xuaW1wb3J0IHsgdG9Nb2RlbERpc3BsYXlOYW1lIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLW1vZGVsL2Rpc3BsYXlcIjtcbmltcG9ydCBGdXNlIGZyb20gXCJmdXNlLmpzXCI7XG5cbmltcG9ydCB7IGNsYXNzZXNBdE9yQmVsb3csIENIQVRfQ0xBU1NfT1JERVIsIE1PREVMX0NMQVNTX09SREVSIH0gZnJvbSBcIi4vY2xhc3Nlcy50c1wiO1xuaW1wb3J0IHtcbiAgY2xhc3NpZnlFbmRwb2ludHMsXG4gIGVuZHBvaW50Q2FwYWJpbGl0aWVzLFxuICBzdXBwb3J0c1Rvb2xzQnlGYW1pbHksXG4gIHZlcnNpb25UdXBsZSxcbn0gZnJvbSBcIi4vY2xhc3NpZnkudHNcIjtcbmltcG9ydCB7IG1vZGVsU3RhdHVzRm9yIH0gZnJvbSBcIi4vbWV0YWRhdGEudHNcIjtcbmltcG9ydCB7IG1vZGVsRmFtaWx5LCBtb2RlbFJlYXNvbmluZ0VmZm9ydHMsIG1vZGVsU2VydmljZU5hbWVzIH0gZnJvbSBcIi4vcG9saWN5LnRzXCI7XG5cbnR5cGUgTW9kZWxDbGFzcyA9IE1vZGVsQ2xhc3NUeXBlO1xuY29uc3QgTW9kZWxDbGFzcyA9IE1vZGVsQ2xhc3NWYWx1ZXM7XG5cbmNvbnN0IERFRkFVTFRfRlVaWllfVEhSRVNIT0xEID0gMC40O1xuaW50ZXJmYWNlIE5hdGl2ZVJhbmtpbmdPcHRpb25zIHtcbiAgcmVhZG9ubHkgaW5jbHVkZURlcHJlY2F0ZWQ/OiBib29sZWFuO1xuICByZWFkb25seSBtb2RlbENsYXNzPzogTW9kZWxDbGFzcztcbiAgcmVhZG9ubHkgdGFzaz86IHN0cmluZztcbn1cblxuLyoqIFJhbmsgZW5kcG9pbnQgcmVjb3JkcyB0aHJvdWdoIHRoZSBUeXBlU2NyaXB0LW93bmVkIG1vZGVsIHBvbGljeS4gKi9cbmV4cG9ydCBmdW5jdGlvbiByYW5rRW5kcG9pbnRzKFxuICBlbmRwb2ludHM6IHJlYWRvbmx5IFNlcnZpbmdFbmRwb2ludFN1bW1hcnlbXSxcbiAgcXVlcnk6IE1vZGVsUXVlcnkgPSB7fSxcbiAgb3B0aW9uczogTmF0aXZlUmFua2luZ09wdGlvbnMgPSB7fSxcbik6IFJhbmtlZE1vZGVsW10ge1xuICBjb25zdCBvcmlnaW5hbEJ5TmFtZSA9IG5ldyBNYXAoZW5kcG9pbnRzLm1hcCgoZW5kcG9pbnQpID0+IFtlbmRwb2ludC5uYW1lLCBlbmRwb2ludF0pKTtcbiAgY29uc3Qgbm9ybWFsaXplZCA9IGVuZHBvaW50cy5tYXAoKGVuZHBvaW50KSA9PiAoe1xuICAgIC4uLmVuZHBvaW50LFxuICAgIC4uLihvcHRpb25zLm1vZGVsQ2xhc3MgPyB7IGNsYXNzOiBvcHRpb25zLm1vZGVsQ2xhc3MgfSA6IHt9KSxcbiAgICAuLi4ob3B0aW9ucy50YXNrID8geyB0YXNrOiBvcHRpb25zLnRhc2sgfSA6IHt9KSxcbiAgfSkpO1xuICBjb25zdCBjbGFzc2lmaWVkID0gb3B0aW9ucy5tb2RlbENsYXNzXG4gICAgPyB7XG4gICAgICAgIFtNb2RlbENsYXNzLkNoYXRUaGlua2luZ106IFtdLFxuICAgICAgICBbTW9kZWxDbGFzcy5DaGF0QmFsYW5jZWRdOiBbXSxcbiAgICAgICAgW01vZGVsQ2xhc3MuQ2hhdEZhc3RdOiBbXSxcbiAgICAgICAgW01vZGVsQ2xhc3MuRW1iZWRkaW5nXTogW10sXG4gICAgICAgIFtvcHRpb25zLm1vZGVsQ2xhc3NdOiBub3JtYWxpemVkLFxuICAgICAgfVxuICAgIDogY2xhc3NpZnlFbmRwb2ludHMobm9ybWFsaXplZCk7XG4gIGNvbnN0IHJlcXVlc3RlZENsYXNzID0gb3B0aW9ucy5tb2RlbENsYXNzID8/IHF1ZXJ5Lm1vZGVsQ2xhc3M7XG4gIGNvbnN0IGVsaWdpYmxlID0gcmVxdWVzdGVkQ2xhc3MgPyBjbGFzc2VzQXRPckJlbG93KHJlcXVlc3RlZENsYXNzKSA6IENIQVRfQ0xBU1NfT1JERVI7XG4gIGNvbnN0IGNhbmRpZGF0ZXM6IFJhbmtlZE1vZGVsW10gPSBbXTtcbiAgZm9yIChjb25zdCBtb2RlbENsYXNzIG9mIGVsaWdpYmxlKSB7XG4gICAgZm9yIChjb25zdCBlbmRwb2ludCBvZiBjbGFzc2lmaWVkW21vZGVsQ2xhc3NdKSB7XG4gICAgICBpZiAoIW9wdGlvbnMuaW5jbHVkZURlcHJlY2F0ZWQgJiYgZW5kcG9pbnQuc3RhdHVzPy5kZXByZWNhdGVkKSBjb250aW51ZTtcbiAgICAgIGlmIChxdWVyeS5yZXF1aXJlc1Rvb2xzICYmICFlbmRwb2ludENhcGFiaWxpdGllcyhlbmRwb2ludCkudG9vbHMpIGNvbnRpbnVlO1xuICAgICAgY2FuZGlkYXRlcy5wdXNoKHsgZW5kcG9pbnQsIG1vZGVsQ2xhc3MgfSk7XG4gICAgfVxuICB9XG5cbiAgY29uc3Qgc2VhcmNoID0gcXVlcnkuc2VhcmNoPy50cmltKCk7XG4gIGxldCByYW5rZWQgPSBjYW5kaWRhdGVzO1xuICBpZiAoc2VhcmNoKSB7XG4gICAgY29uc3QgZXhhY3QgPSBjYW5kaWRhdGVzLmZpbmQoKGNhbmRpZGF0ZSkgPT4gY2FuZGlkYXRlLmVuZHBvaW50Lm5hbWUgPT09IHNlYXJjaCk7XG4gICAgaWYgKGV4YWN0KSB7XG4gICAgICByYW5rZWQgPSBbeyAuLi5leGFjdCwgc2NvcmU6IDAgfV07XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IHRocmVzaG9sZCA9IHF1ZXJ5LnRocmVzaG9sZCA/PyBERUZBVUxUX0ZVWlpZX1RIUkVTSE9MRDtcbiAgICAgIGNvbnN0IHNlYXJjaFRva2VucyA9IHRva2VuaXplKHNlYXJjaCk7XG4gICAgICBjb25zdCB0b2tlbk1hdGNoZXMgPSBjYW5kaWRhdGVzXG4gICAgICAgIC5maWx0ZXIoKGNhbmRpZGF0ZSkgPT4ge1xuICAgICAgICAgIGNvbnN0IGNhbmRpZGF0ZVRva2VucyA9IG5ldyBTZXQoc2VhcmNoYWJsZVZhbHVlcyhjYW5kaWRhdGUuZW5kcG9pbnQpLmZsYXRNYXAodG9rZW5pemUpKTtcbiAgICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgc2VhcmNoVG9rZW5zLmxlbmd0aCA+IDAgJiYgc2VhcmNoVG9rZW5zLmV2ZXJ5KCh0b2tlbikgPT4gY2FuZGlkYXRlVG9rZW5zLmhhcyh0b2tlbikpXG4gICAgICAgICAgKTtcbiAgICAgICAgfSlcbiAgICAgICAgLm1hcCgoY2FuZGlkYXRlKSA9PiAoeyAuLi5jYW5kaWRhdGUsIHNjb3JlOiAwIH0pKTtcbiAgICAgIGlmICh0b2tlbk1hdGNoZXMubGVuZ3RoID4gMCkge1xuICAgICAgICByYW5rZWQgPSB0b2tlbk1hdGNoZXMuc29ydChjb21wYXJlUmFua2VkKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IGZ1c2UgPSBuZXcgRnVzZShjYW5kaWRhdGVzLCB7XG4gICAgICAgICAga2V5czogW1xuICAgICAgICAgICAgXCJlbmRwb2ludC5uYW1lXCIsXG4gICAgICAgICAgICBcImVuZHBvaW50LmRpc3BsYXlOYW1lXCIsXG4gICAgICAgICAgICBcImVuZHBvaW50LmZhbWlseVwiLFxuICAgICAgICAgICAgXCJlbmRwb2ludC5tb2RlbFNlcnZpY2VOYW1lXCIsXG4gICAgICAgICAgICBcImVuZHBvaW50LnNlcnZpY2VOYW1lc1wiLFxuICAgICAgICAgIF0sXG4gICAgICAgICAgdGhyZXNob2xkLFxuICAgICAgICAgIGlnbm9yZUxvY2F0aW9uOiB0cnVlLFxuICAgICAgICAgIGluY2x1ZGVTY29yZTogdHJ1ZSxcbiAgICAgICAgICB1c2VFeHRlbmRlZFNlYXJjaDogdHJ1ZSxcbiAgICAgICAgICBpc0Nhc2VTZW5zaXRpdmU6IGZhbHNlLFxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3Qgbm9ybWFsaXplZFNlYXJjaCA9IHRva2VuaXplKHNlYXJjaCkuam9pbihcIiBcIik7XG4gICAgICAgIHJhbmtlZCA9IG5vcm1hbGl6ZWRTZWFyY2hcbiAgICAgICAgICA/IGZ1c2VcbiAgICAgICAgICAgICAgLnNlYXJjaChub3JtYWxpemVkU2VhcmNoKVxuICAgICAgICAgICAgICAuZmlsdGVyKChyZXN1bHQpID0+IChyZXN1bHQuc2NvcmUgPz8gMCkgPD0gdGhyZXNob2xkKVxuICAgICAgICAgICAgICAubWFwKChyZXN1bHQpID0+ICh7IC4uLnJlc3VsdC5pdGVtLCBzY29yZTogcmVzdWx0LnNjb3JlID8/IDAgfSkpXG4gICAgICAgICAgICAgIC5zb3J0KGNvbXBhcmVSYW5rZWQpXG4gICAgICAgICAgOiBbXTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgY29uc3QgcmVzdG9yZWQgPSByYW5rZWQubWFwKChyZXN1bHQpID0+ICh7XG4gICAgLi4ucmVzdWx0LFxuICAgIGVuZHBvaW50OiBvcmlnaW5hbEJ5TmFtZS5nZXQocmVzdWx0LmVuZHBvaW50Lm5hbWUpID8/IHJlc3VsdC5lbmRwb2ludCxcbiAgfSkpO1xuICByZXR1cm4gcXVlcnkubGltaXQgPT09IHVuZGVmaW5lZCA/IHJlc3RvcmVkIDogcmVzdG9yZWQuc2xpY2UoMCwgTWF0aC5tYXgoMCwgcXVlcnkubGltaXQpKTtcbn1cblxuLyoqIENsYXNzaWZ5IGNoYXQgYW5kIGVtYmVkZGluZyBlbmRwb2ludHMgdGhyb3VnaCB0aGUgVHlwZVNjcmlwdC1vd25lZCBwb2xpY3kuICovXG5leHBvcnQgZnVuY3Rpb24gY2xhc3NpZnlFbmRwb2ludENsYXNzZXMoXG4gIGVuZHBvaW50czogcmVhZG9ubHkgU2VydmluZ0VuZHBvaW50U3VtbWFyeVtdLFxuKTogUmVhZG9ubHlNYXA8c3RyaW5nLCBNb2RlbENsYXNzPiB7XG4gIGNvbnN0IGNsYXNzaWZpZWQgPSBjbGFzc2lmeUVuZHBvaW50cyhlbmRwb2ludHMpO1xuICBjb25zdCByZXN1bHQgPSBuZXcgTWFwPHN0cmluZywgTW9kZWxDbGFzcz4oKTtcbiAgZm9yIChjb25zdCBtb2RlbENsYXNzIG9mIE1PREVMX0NMQVNTX09SREVSKSB7XG4gICAgZm9yIChjb25zdCBlbmRwb2ludCBvZiBjbGFzc2lmaWVkW21vZGVsQ2xhc3NdKSByZXN1bHQuc2V0KGVuZHBvaW50Lm5hbWUsIG1vZGVsQ2xhc3MpO1xuICB9XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbi8qKiBOb3JtYWxpemUgc2VyaWFsaXplZCBTREsgZW5kcG9pbnQgcmVjb3JkcyB3aXRob3V0IG5hdGl2ZSBiaW5kaW5ncy4gKi9cbmV4cG9ydCBmdW5jdGlvbiBub3JtYWxpemVFbmRwb2ludHMoZW5kcG9pbnRzOiByZWFkb25seSB1bmtub3duW10pOiBTZXJ2aW5nRW5kcG9pbnRTdW1tYXJ5W10ge1xuICBjb25zdCBzdW1tYXJpZXMgPSBlbmRwb2ludHMuZmxhdE1hcCgodmFsdWUpID0+IHtcbiAgICBjb25zdCBlbmRwb2ludCA9IHJlY29yZCh2YWx1ZSk7XG4gICAgY29uc3QgbmFtZSA9IHN0cmluZ1ZhbHVlKGVuZHBvaW50Lm5hbWUpO1xuICAgIGlmICghbmFtZSkgcmV0dXJuIFtdO1xuICAgIGNvbnN0IGVudGl0aWVzID0gYXJyYXlWYWx1ZShyZWNvcmQoZW5kcG9pbnQuY29uZmlnKS5zZXJ2ZWRfZW50aXRpZXMpLm1hcChyZWNvcmQpO1xuICAgIGNvbnN0IGlkZW50aXRpZXMgPSBbXG4gICAgICBuYW1lLFxuICAgICAgLi4uZW50aXRpZXMuZmxhdE1hcCgoZW50aXR5KSA9PlxuICAgICAgICBbXG4gICAgICAgICAgc3RyaW5nVmFsdWUoZW50aXR5LmVudGl0eV9uYW1lKSxcbiAgICAgICAgICBzdHJpbmdWYWx1ZShyZWNvcmQoZW50aXR5LmZvdW5kYXRpb25fbW9kZWwpLm5hbWUpLFxuICAgICAgICAgIHN0cmluZ1ZhbHVlKHJlY29yZChlbnRpdHkuZXh0ZXJuYWxfbW9kZWwpLm5hbWUpLFxuICAgICAgICBdLmZpbHRlcigoaWRlbnRpdHkpOiBpZGVudGl0eSBpcyBzdHJpbmcgPT4gQm9vbGVhbihpZGVudGl0eSkpLFxuICAgICAgKSxcbiAgICBdO1xuICAgIGNvbnN0IG1vZGVsU2VydmljZU5hbWUgPSBlbnRpdGllc1xuICAgICAgLm1hcChcbiAgICAgICAgKGVudGl0eSkgPT5cbiAgICAgICAgICBzdHJpbmdWYWx1ZShyZWNvcmQoZW50aXR5LmZvdW5kYXRpb25fbW9kZWwpLm5hbWUpID8/IHN0cmluZ1ZhbHVlKGVudGl0eS5lbnRpdHlfbmFtZSksXG4gICAgICApXG4gICAgICAuZmluZChCb29sZWFuKTtcbiAgICBjb25zdCBmYW1pbHkgPSBpZGVudGl0aWVzLm1hcChtb2RlbEZhbWlseSkuZmluZChCb29sZWFuKTtcbiAgICBjb25zdCByZWFzb25pbmdFZmZvcnRzID1cbiAgICAgIGlkZW50aXRpZXMubWFwKG1vZGVsUmVhc29uaW5nRWZmb3J0cykuc29ydCgobGVmdCwgcmlnaHQpID0+IHJpZ2h0Lmxlbmd0aCAtIGxlZnQubGVuZ3RoKVswXSA/P1xuICAgICAgW107XG4gICAgY29uc3QgcHJvZmlsZSA9IGVudGl0aWVzLm1hcChtb2RlbFByb2ZpbGUpLmZpbmQoQm9vbGVhbik7XG4gICAgY29uc3Qgc3VtbWFyeTogU2VydmluZ0VuZHBvaW50U3VtbWFyeSA9IHtcbiAgICAgIG5hbWUsXG4gICAgICBkaXNwbGF5TmFtZTogdG9Nb2RlbERpc3BsYXlOYW1lKG5hbWUsIHByb3ZpZGVkRGlzcGxheU5hbWUoZW5kcG9pbnQsIGVudGl0aWVzKSksXG4gICAgICAuLi4oZmFtaWx5ID8geyBmYW1pbHkgfSA6IHt9KSxcbiAgICAgIC4uLihzdHJpbmdWYWx1ZShlbmRwb2ludC50YXNrKSA/IHsgdGFzazogc3RyaW5nVmFsdWUoZW5kcG9pbnQudGFzaykgfSA6IHt9KSxcbiAgICAgIC4uLihzdHJpbmdWYWx1ZShyZWNvcmQoZW5kcG9pbnQuc3RhdGUpLnJlYWR5KVxuICAgICAgICA/IHsgc3RhdGU6IHN0cmluZ1ZhbHVlKHJlY29yZChlbmRwb2ludC5zdGF0ZSkucmVhZHkpIH1cbiAgICAgICAgOiB7fSksXG4gICAgICAuLi4oc3RyaW5nVmFsdWUoZW5kcG9pbnQuZGVzY3JpcHRpb24pXG4gICAgICAgID8geyBkZXNjcmlwdGlvbjogc3RyaW5nVmFsdWUoZW5kcG9pbnQuZGVzY3JpcHRpb24pIH1cbiAgICAgICAgOiB7fSksXG4gICAgICBzdXBwb3J0c1Rvb2xzOiBpZGVudGl0aWVzLnNvbWUoc3VwcG9ydHNUb29sc0J5RmFtaWx5KSxcbiAgICAgIC4uLihwcm9maWxlID8geyBwcm9maWxlIH0gOiB7fSksXG4gICAgICBzZXJ2aWNlTmFtZXM6IE9iamVjdC5hc3NpZ24oe30sIC4uLmlkZW50aXRpZXMubWFwKG1vZGVsU2VydmljZU5hbWVzKSksXG4gICAgICAuLi4obW9kZWxTZXJ2aWNlTmFtZSA/IHsgbW9kZWxTZXJ2aWNlTmFtZSB9IDoge30pLFxuICAgICAgLi4uKHJlYXNvbmluZ0VmZm9ydHMubGVuZ3RoID8geyByZWFzb25pbmdFZmZvcnRzIH0gOiB7fSksXG4gICAgICBzdGF0dXM6IG1vZGVsU3RhdHVzRm9yKC4uLmlkZW50aXRpZXMpLFxuICAgIH07XG4gICAgcmV0dXJuIFtzdW1tYXJ5XTtcbiAgfSk7XG4gIGNvbnN0IGNsYXNzZXMgPSBjbGFzc2lmeUVuZHBvaW50Q2xhc3NlcyhzdW1tYXJpZXMpO1xuICByZXR1cm4gc3VtbWFyaWVzLm1hcCgoc3VtbWFyeSkgPT4ge1xuICAgIGNvbnN0IG1vZGVsQ2xhc3MgPSBjbGFzc2VzLmdldChzdW1tYXJ5Lm5hbWUpO1xuICAgIHJldHVybiBtb2RlbENsYXNzID8geyAuLi5zdW1tYXJ5LCBjbGFzczogbW9kZWxDbGFzcyB9IDogc3VtbWFyeTtcbiAgfSk7XG59XG5cbmZ1bmN0aW9uIGNvbXBhcmVSYW5rZWQobGVmdDogUmFua2VkTW9kZWwsIHJpZ2h0OiBSYW5rZWRNb2RlbCk6IG51bWJlciB7XG4gIGNvbnN0IHNjb3JlID0gTWF0aC5yb3VuZCgobGVmdC5zY29yZSA/PyAwKSAqIDEwMDApIC0gTWF0aC5yb3VuZCgocmlnaHQuc2NvcmUgPz8gMCkgKiAxMDAwKTtcbiAgaWYgKHNjb3JlICE9PSAwKSByZXR1cm4gc2NvcmU7XG4gIGNvbnN0IGxlZnRWZXJzaW9uID0gdmVyc2lvblR1cGxlKGxlZnQuZW5kcG9pbnQubmFtZSk7XG4gIGNvbnN0IHJpZ2h0VmVyc2lvbiA9IHZlcnNpb25UdXBsZShyaWdodC5lbmRwb2ludC5uYW1lKTtcbiAgZm9yIChsZXQgaW5kZXggPSAwOyBpbmRleCA8IDM7IGluZGV4ICs9IDEpIHtcbiAgICBjb25zdCB2ZXJzaW9uID0gcmlnaHRWZXJzaW9uW2luZGV4XSEgLSBsZWZ0VmVyc2lvbltpbmRleF0hO1xuICAgIGlmICh2ZXJzaW9uICE9PSAwKSByZXR1cm4gdmVyc2lvbjtcbiAgfVxuICBjb25zdCB2YXJpYW50ID0gbW9kZWxWYXJpYW50UmFuayhsZWZ0LmVuZHBvaW50Lm5hbWUpIC0gbW9kZWxWYXJpYW50UmFuayhyaWdodC5lbmRwb2ludC5uYW1lKTtcbiAgaWYgKHZhcmlhbnQgIT09IDApIHJldHVybiB2YXJpYW50O1xuICByZXR1cm4gTU9ERUxfQ0xBU1NfT1JERVIuaW5kZXhPZihsZWZ0Lm1vZGVsQ2xhc3MpIC0gTU9ERUxfQ0xBU1NfT1JERVIuaW5kZXhPZihyaWdodC5tb2RlbENsYXNzKTtcbn1cblxuZnVuY3Rpb24gbW9kZWxWYXJpYW50UmFuayhuYW1lOiBzdHJpbmcpOiBudW1iZXIge1xuICBpZiAoIS8oPzpefFstXy5dKWdwdCg/OlstXy5dfCQpL2kudGVzdChuYW1lKSkgcmV0dXJuIDI7XG4gIGlmICgvKD86XnxbLV8uXSlzb2woPzpbLV8uXXwkKS9pLnRlc3QobmFtZSkpIHJldHVybiAwO1xuICBpZiAoLyg/Ol58Wy1fLl0pbHVuYSg/OlstXy5dfCQpL2kudGVzdChuYW1lKSkgcmV0dXJuIDE7XG4gIHJldHVybiAyO1xufVxuXG5mdW5jdGlvbiB0b2tlbml6ZSh2YWx1ZTogc3RyaW5nKTogc3RyaW5nW10ge1xuICByZXR1cm4gdmFsdWUudG9Mb3dlckNhc2UoKS5tYXRjaCgvW2EtejAtOV0rL2cpID8/IFtdO1xufVxuXG5mdW5jdGlvbiBzZWFyY2hhYmxlVmFsdWVzKGVuZHBvaW50OiBTZXJ2aW5nRW5kcG9pbnRTdW1tYXJ5KTogc3RyaW5nW10ge1xuICByZXR1cm4gW1xuICAgIGVuZHBvaW50Lm5hbWUsXG4gICAgZW5kcG9pbnQuZGlzcGxheU5hbWUsXG4gICAgZW5kcG9pbnQuZmFtaWx5LFxuICAgIGVuZHBvaW50Lm1vZGVsU2VydmljZU5hbWUsXG4gICAgLi4uT2JqZWN0LnZhbHVlcyhlbmRwb2ludC5zZXJ2aWNlTmFtZXMgPz8ge30pLFxuICBdLmZpbHRlcigodmFsdWUpOiB2YWx1ZSBpcyBzdHJpbmcgPT4gQm9vbGVhbih2YWx1ZSkpO1xufVxuXG5mdW5jdGlvbiBtb2RlbFByb2ZpbGUoZW50aXR5OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPikge1xuICBjb25zdCBzb3VyY2UgPSByZWNvcmQocmVjb3JkKGVudGl0eS5mb3VuZGF0aW9uX21vZGVsKS5haV9nYXRld2F5X21vZGVsX3Byb2ZpbGUpO1xuICBjb25zdCBxdWFsaXR5ID0gZmluaXRlTnVtYmVyKHNvdXJjZS5xdWFsaXR5KTtcbiAgY29uc3Qgc3BlZWQgPSBmaW5pdGVOdW1iZXIoc291cmNlLnNwZWVkKTtcbiAgY29uc3QgY29zdCA9IGZpbml0ZU51bWJlcihzb3VyY2UuY29zdCk7XG4gIGlmIChxdWFsaXR5ID09PSB1bmRlZmluZWQgJiYgc3BlZWQgPT09IHVuZGVmaW5lZCAmJiBjb3N0ID09PSB1bmRlZmluZWQpIHJldHVybiB1bmRlZmluZWQ7XG4gIHJldHVybiB7XG4gICAgLi4uKHF1YWxpdHkgIT09IHVuZGVmaW5lZCA/IHsgcXVhbGl0eSB9IDoge30pLFxuICAgIC4uLihzcGVlZCAhPT0gdW5kZWZpbmVkID8geyBzcGVlZCB9IDoge30pLFxuICAgIC4uLihjb3N0ICE9PSB1bmRlZmluZWQgPyB7IGNvc3QgfSA6IHt9KSxcbiAgfTtcbn1cblxuZnVuY3Rpb24gcHJvdmlkZWREaXNwbGF5TmFtZShcbiAgZW5kcG9pbnQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICBlbnRpdGllczogcmVhZG9ubHkgUmVjb3JkPHN0cmluZywgdW5rbm93bj5bXSxcbik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGZvciAoY29uc3QgdGFnIG9mIGFycmF5VmFsdWUoZW5kcG9pbnQudGFncykubWFwKHJlY29yZCkpIHtcbiAgICBpZiAoIVtcImRpc3BsYXlfbmFtZVwiLCBcImRpc3BsYXlOYW1lXCIsIFwibmFtZVwiXS5pbmNsdWRlcyhTdHJpbmcodGFnLmtleSkpKSBjb250aW51ZTtcbiAgICBjb25zdCB2YWx1ZSA9IHN0cmluZ1ZhbHVlKHRhZy52YWx1ZSk7XG4gICAgaWYgKHZhbHVlKSByZXR1cm4gdmFsdWU7XG4gIH1cbiAgcmV0dXJuIGVudGl0aWVzLm1hcCgoZW50aXR5KSA9PiBzdHJpbmdWYWx1ZShyZWNvcmQoZW50aXR5LmV4dGVybmFsX21vZGVsKS5uYW1lKSkuZmluZChCb29sZWFuKTtcbn1cblxuZnVuY3Rpb24gcmVjb3JkKHZhbHVlOiB1bmtub3duKTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4ge1xuICByZXR1cm4gdmFsdWUgJiYgdHlwZW9mIHZhbHVlID09PSBcIm9iamVjdFwiICYmICFBcnJheS5pc0FycmF5KHZhbHVlKVxuICAgID8gKHZhbHVlIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KVxuICAgIDoge307XG59XG5cbmZ1bmN0aW9uIGFycmF5VmFsdWUodmFsdWU6IHVua25vd24pOiB1bmtub3duW10ge1xuICByZXR1cm4gQXJyYXkuaXNBcnJheSh2YWx1ZSkgPyB2YWx1ZSA6IFtdO1xufVxuXG5mdW5jdGlvbiBzdHJpbmdWYWx1ZSh2YWx1ZTogdW5rbm93bik6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGlmICh0eXBlb2YgdmFsdWUgIT09IFwic3RyaW5nXCIpIHJldHVybiB1bmRlZmluZWQ7XG4gIGNvbnN0IHRyaW1tZWQgPSB2YWx1ZS50cmltKCk7XG4gIHJldHVybiB0cmltbWVkIHx8IHVuZGVmaW5lZDtcbn1cblxuZnVuY3Rpb24gZmluaXRlTnVtYmVyKHZhbHVlOiB1bmtub3duKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gXCJudW1iZXJcIiAmJiBOdW1iZXIuaXNGaW5pdGUodmFsdWUpID8gdmFsdWUgOiB1bmRlZmluZWQ7XG59XG4iXX0=
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ModelClass, ModelQuery, RankedModel, ServingEndpointSummary } from "@dbx-tools/shared-model/contracts";
|
|
2
|
+
import type { ResolvedModel, ResolveModelOptions } from "./model-catalog.ts";
|
|
3
|
+
/** Caller intent passed to {@link resolveModel}. */
|
|
4
|
+
export interface ResolveModelInput {
|
|
5
|
+
explicit?: string;
|
|
6
|
+
fuzzy?: boolean;
|
|
7
|
+
threshold?: number;
|
|
8
|
+
requiresTools?: boolean;
|
|
9
|
+
modelClass?: ModelClass;
|
|
10
|
+
fallbacks?: readonly string[];
|
|
11
|
+
liveOnly?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/** Outcome of {@link resolveModel}: the chosen id plus how it was reached. */
|
|
14
|
+
export interface ResolvedModelSelection {
|
|
15
|
+
modelId: string;
|
|
16
|
+
source: "explicit" | "fuzzy-match" | "class" | "fallback";
|
|
17
|
+
}
|
|
18
|
+
/** Rank a catalogue against a model query, best-first. */
|
|
19
|
+
export declare function lookupModels(endpoints: readonly ServingEndpointSummary[], query?: ModelQuery): RankedModel[];
|
|
20
|
+
/** Resolve the closest model id in one catalogue snapshot. */
|
|
21
|
+
export declare function rankModelId(endpoints: readonly ServingEndpointSummary[], search: string, options?: ResolveModelOptions): ResolvedModel;
|
|
22
|
+
/** Resolve a single model id from a catalogue and caller intent. */
|
|
23
|
+
export declare function resolveModel(endpoints: readonly ServingEndpointSummary[], input?: ResolveModelInput): ResolvedModelSelection;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime-independent model ranking and selection.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import * as object from "@dbx-tools/shared-core/object";
|
|
7
|
+
import { rankEndpoints } from "./_ranking.js";
|
|
8
|
+
import { FALLBACK_MODEL_IDS, modelsForClass } from "./fallback.js";
|
|
9
|
+
import { endpointSupportsTools } from "./policy.js";
|
|
10
|
+
const DEFAULT_MODEL_FAMILY_SEARCH = "gpt";
|
|
11
|
+
/** Rank a catalogue against a model query, best-first. */
|
|
12
|
+
export function lookupModels(endpoints, query = {}) {
|
|
13
|
+
return rankEndpoints(endpoints, query);
|
|
14
|
+
}
|
|
15
|
+
/** Resolve the closest model id in one catalogue snapshot. */
|
|
16
|
+
export function rankModelId(endpoints, search, options = {}) {
|
|
17
|
+
const [top] = lookupModels(endpoints, {
|
|
18
|
+
search,
|
|
19
|
+
limit: 1,
|
|
20
|
+
...(options.threshold !== undefined ? { threshold: options.threshold } : {}),
|
|
21
|
+
...(options.requiresTools !== undefined ? { requiresTools: options.requiresTools } : {}),
|
|
22
|
+
});
|
|
23
|
+
if (!top)
|
|
24
|
+
return { modelId: search, matched: false };
|
|
25
|
+
return { modelId: top.endpoint.name, matched: true, score: top.score };
|
|
26
|
+
}
|
|
27
|
+
/** Resolve a single model id from a catalogue and caller intent. */
|
|
28
|
+
export function resolveModel(endpoints, input = {}) {
|
|
29
|
+
if (input.explicit !== undefined) {
|
|
30
|
+
if (input.fuzzy === false) {
|
|
31
|
+
if (input.requiresTools)
|
|
32
|
+
assertToolSupport(endpoints, input.explicit);
|
|
33
|
+
return { modelId: input.explicit, source: "explicit" };
|
|
34
|
+
}
|
|
35
|
+
const [top] = lookupModels(endpoints, buildQuery(input, input.explicit));
|
|
36
|
+
if (input.requiresTools && !top) {
|
|
37
|
+
throw new Error(`No tool-capable model matches "${input.explicit}"`);
|
|
38
|
+
}
|
|
39
|
+
return { modelId: top?.endpoint.name ?? input.explicit, source: "fuzzy-match" };
|
|
40
|
+
}
|
|
41
|
+
if (input.modelClass === undefined && input.fallbacks && input.fallbacks.length > 0) {
|
|
42
|
+
const present = new Set(endpoints
|
|
43
|
+
.filter((endpoint) => !input.requiresTools || endpointSupportsTools(endpoint))
|
|
44
|
+
.map((endpoint) => endpoint.name));
|
|
45
|
+
const pinned = input.fallbacks.find((id) => present.has(id));
|
|
46
|
+
if (pinned)
|
|
47
|
+
return { modelId: pinned, source: "fallback" };
|
|
48
|
+
}
|
|
49
|
+
const source = input.modelClass !== undefined ? "class" : "fallback";
|
|
50
|
+
if (input.modelClass === undefined) {
|
|
51
|
+
const [preferred] = lookupModels(endpoints, buildQuery(input, DEFAULT_MODEL_FAMILY_SEARCH));
|
|
52
|
+
if (preferred)
|
|
53
|
+
return { modelId: preferred.endpoint.name, source };
|
|
54
|
+
}
|
|
55
|
+
const [top] = lookupModels(endpoints, buildQuery(input, undefined));
|
|
56
|
+
if (top)
|
|
57
|
+
return { modelId: top.endpoint.name, source };
|
|
58
|
+
if (input.liveOnly) {
|
|
59
|
+
throw new Error("No matching live Model Serving endpoint is available");
|
|
60
|
+
}
|
|
61
|
+
const floorSource = input.modelClass !== undefined ? modelsForClass(input.modelClass) : (input.fallbacks ?? []);
|
|
62
|
+
const floor = object.sequence(floorSource).concat(FALLBACK_MODEL_IDS).distinct().toArray();
|
|
63
|
+
if (input.requiresTools) {
|
|
64
|
+
const available = new Set(endpoints.filter(endpointSupportsTools).map((endpoint) => endpoint.name));
|
|
65
|
+
const selected = floor.find((id) => available.has(id));
|
|
66
|
+
if (!selected)
|
|
67
|
+
throw new Error("No tool-capable model is available");
|
|
68
|
+
return { modelId: selected, source };
|
|
69
|
+
}
|
|
70
|
+
return { modelId: pickFirstAvailable(floor, endpoints), source };
|
|
71
|
+
}
|
|
72
|
+
function buildQuery(input, search) {
|
|
73
|
+
return {
|
|
74
|
+
...(search !== undefined ? { search } : {}),
|
|
75
|
+
...(input.modelClass !== undefined ? { modelClass: input.modelClass } : {}),
|
|
76
|
+
...(input.requiresTools !== undefined ? { requiresTools: input.requiresTools } : {}),
|
|
77
|
+
...(input.threshold !== undefined ? { threshold: input.threshold } : {}),
|
|
78
|
+
limit: 1,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function assertToolSupport(endpoints, modelId) {
|
|
82
|
+
const endpoint = endpoints.find((candidate) => candidate.name === modelId);
|
|
83
|
+
if (!endpoint || !endpointSupportsTools(endpoint)) {
|
|
84
|
+
throw new Error(`Model "${modelId}" does not support function tools`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function pickFirstAvailable(candidates, endpoints) {
|
|
88
|
+
const present = new Set(endpoints.map((endpoint) => endpoint.name));
|
|
89
|
+
for (const candidate of candidates) {
|
|
90
|
+
if (present.has(candidate))
|
|
91
|
+
return candidate;
|
|
92
|
+
}
|
|
93
|
+
return candidates[0] ?? FALLBACK_MODEL_IDS[0];
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiX3NlbGVjdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9fc2VsZWN0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7O0dBSUc7QUFDSCxPQUFPLEtBQUssTUFBTSxNQUFNLCtCQUErQixDQUFDO0FBUXhELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDOUMsT0FBTyxFQUFFLGtCQUFrQixFQUFFLGNBQWMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUVuRSxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFcEQsTUFBTSwyQkFBMkIsR0FBRyxLQUFLLENBQUM7QUFtQjFDLDBEQUEwRDtBQUMxRCxNQUFNLFVBQVUsWUFBWSxDQUMxQixTQUE0QyxFQUM1QyxRQUFvQixFQUFFO0lBRXRCLE9BQU8sYUFBYSxDQUFDLFNBQVMsRUFBRSxLQUFLLENBQUMsQ0FBQztBQUN6QyxDQUFDO0FBRUQsOERBQThEO0FBQzlELE1BQU0sVUFBVSxXQUFXLENBQ3pCLFNBQTRDLEVBQzVDLE1BQWMsRUFDZCxVQUErQixFQUFFO0lBRWpDLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxZQUFZLENBQUMsU0FBUyxFQUFFO1FBQ3BDLE1BQU07UUFDTixLQUFLLEVBQUUsQ0FBQztRQUNSLEdBQUcsQ0FBQyxPQUFPLENBQUMsU0FBUyxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsRUFBRSxTQUFTLEVBQUUsT0FBTyxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDNUUsR0FBRyxDQUFDLE9BQU8sQ0FBQyxhQUFhLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxFQUFFLGFBQWEsRUFBRSxPQUFPLENBQUMsYUFBYSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztLQUN6RixDQUFDLENBQUM7SUFDSCxJQUFJLENBQUMsR0FBRztRQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUs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Q0FBQyxDQUFDLENBQUM7SUFDcEUsS0FBSyxNQUFNLFNBQVMsSUFBSSxVQUFVLEVBQUUsQ0FBQztRQUNuQyxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDO1lBQUUsT0FBTyxTQUFTLENBQUM7SUFDL0MsQ0FBQztJQUNELE9BQU8sVUFBVSxDQUFDLENBQUMsQ0FBQyxJQUFJLGtCQUFrQixDQUFDLENBQUMsQ0FBRSxDQUFDO0FBQ2pELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFJ1bnRpbWUtaW5kZXBlbmRlbnQgbW9kZWwgcmFua2luZyBhbmQgc2VsZWN0aW9uLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuaW1wb3J0ICogYXMgb2JqZWN0IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlL29iamVjdFwiO1xuaW1wb3J0IHR5cGUge1xuICBNb2RlbENsYXNzLFxuICBNb2RlbFF1ZXJ5LFxuICBSYW5rZWRNb2RlbCxcbiAgU2VydmluZ0VuZHBvaW50U3VtbWFyeSxcbn0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLW1vZGVsL2NvbnRyYWN0c1wiO1xuXG5pbXBvcnQgeyByYW5rRW5kcG9pbnRzIH0gZnJvbSBcIi4vX3JhbmtpbmcudHNcIjtcbmltcG9ydCB7IEZBTExCQUNLX01PREVMX0lEUywgbW9kZWxzRm9yQ2xhc3MgfSBmcm9tIFwiLi9mYWxsYmFjay50c1wiO1xuaW1wb3J0IHR5cGUgeyBSZXNvbHZlZE1vZGVsLCBSZXNvbHZlTW9kZWxPcHRpb25zIH0gZnJvbSBcIi4vbW9kZWwtY2F0YWxvZy50c1wiO1xuaW1wb3J0IHsgZW5kcG9pbnRTdXBwb3J0c1Rvb2xzIH0gZnJvbSBcIi4vcG9saWN5LnRzXCI7XG5cbmNvbnN0IERFRkFVTFRfTU9ERUxfRkFNSUxZX1NFQVJDSCA9IFwiZ3B0XCI7XG5cbi8qKiBDYWxsZXIgaW50ZW50IHBhc3NlZCB0byB7QGxpbmsgcmVzb2x2ZU1vZGVsfS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVzb2x2ZU1vZGVsSW5wdXQge1xuICBleHBsaWNpdD86IHN0cmluZztcbiAgZnV6enk/OiBib29sZWFuO1xuICB0aHJlc2hvbGQ/OiBudW1iZXI7XG4gIHJlcXVpcmVzVG9vbHM/OiBib29sZWFuO1xuICBtb2RlbENsYXNzPzogTW9kZWxDbGFzcztcbiAgZmFsbGJhY2tzPzogcmVhZG9ubHkgc3RyaW5nW107XG4gIGxpdmVPbmx5PzogYm9vbGVhbjtcbn1cblxuLyoqIE91dGNvbWUgb2Yge0BsaW5rIHJlc29sdmVNb2RlbH06IHRoZSBjaG9zZW4gaWQgcGx1cyBob3cgaXQgd2FzIHJlYWNoZWQuICovXG5leHBvcnQgaW50ZXJmYWNlIFJlc29sdmVkTW9kZWxTZWxlY3Rpb24ge1xuICBtb2RlbElkOiBzdHJpbmc7XG4gIHNvdXJjZTogXCJleHBsaWNpdFwiIHwgXCJmdXp6eS1tYXRjaFwiIHwgXCJjbGFzc1wiIHwgXCJmYWxsYmFja1wiO1xufVxuXG4vKiogUmFuayBhIGNhdGFsb2d1ZSBhZ2FpbnN0IGEgbW9kZWwgcXVlcnksIGJlc3QtZmlyc3QuICovXG5leHBvcnQgZnVuY3Rpb24gbG9va3VwTW9kZWxzKFxuICBlbmRwb2ludHM6IHJlYWRvbmx5IFNlcnZpbmdFbmRwb2ludFN1bW1hcnlbXSxcbiAgcXVlcnk6IE1vZGVsUXVlcnkgPSB7fSxcbik6IFJhbmtlZE1vZGVsW10ge1xuICByZXR1cm4gcmFua0VuZHBvaW50cyhlbmRwb2ludHMsIHF1ZXJ5KTtcbn1cblxuLyoqIFJlc29sdmUgdGhlIGNsb3Nlc3QgbW9kZWwgaWQgaW4gb25lIGNhdGFsb2d1ZSBzbmFwc2hvdC4gKi9cbmV4cG9ydCBmdW5jdGlvbiByYW5rTW9kZWxJZChcbiAgZW5kcG9pbnRzOiByZWFkb25seSBTZXJ2aW5nRW5kcG9pbnRTdW1tYXJ5W10sXG4gIHNlYXJjaDogc3RyaW5nLFxuICBvcHRpb25zOiBSZXNvbHZlTW9kZWxPcHRpb25zID0ge30sXG4pOiBSZXNvbHZlZE1vZGVsIHtcbiAgY29uc3QgW3RvcF0gPSBsb29rdXBNb2RlbHMoZW5kcG9pbnRzLCB7XG4gICAgc2VhcmNoLFxuICAgIGxpbWl0OiAxLFxuICAgIC4uLihvcHRpb25zLnRocmVzaG9sZCAhPT0gdW5kZWZpbmVkID8geyB0aHJlc2hvbGQ6IG9wdGlvbnMudGhyZXNob2xkIH0gOiB7fSksXG4gICAgLi4uKG9wdGlvbnMucmVxdWlyZXNUb29scyAhPT0gdW5kZWZpbmVkID8geyByZXF1aXJlc1Rvb2xzOiBvcHRpb25zLnJlcXVpcmVzVG9vbHMgfSA6IHt9KSxcbiAgfSk7XG4gIGlmICghdG9wKSByZXR1cm4geyBtb2RlbElkOiBzZWFyY2gsIG1hdGNoZWQ6IGZhbHNlIH07XG4gIHJldHVybiB7IG1vZGVsSWQ6IHRvcC5lbmRwb2ludC5uYW1lLCBtYXRjaGVkOiB0cnVlLCBzY29yZTogdG9wLnNjb3JlIH07XG59XG5cbi8qKiBSZXNvbHZlIGEgc2luZ2xlIG1vZGVsIGlkIGZyb20gYSBjYXRhbG9ndWUgYW5kIGNhbGxlciBpbnRlbnQuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZU1vZGVsKFxuICBlbmRwb2ludHM6IHJlYWRvbmx5IFNlcnZpbmdFbmRwb2ludFN1bW1hcnlbXSxcbiAgaW5wdXQ6IFJlc29sdmVNb2RlbElucHV0ID0ge30sXG4pOiBSZXNvbHZlZE1vZGVsU2VsZWN0aW9uIHtcbiAgaWYgKGlucHV0LmV4cGxpY2l0ICE9PSB1bmRlZmluZWQpIHtcbiAgICBpZiAoaW5wdXQuZnV6enkgPT09IGZhbHNlKSB7XG4gICAgICBpZiAoaW5wdXQucmVxdWlyZXNUb29scykgYXNzZXJ0VG9vbFN1cHBvcnQoZW5kcG9pbnRzLCBpbnB1dC5leHBsaWNpdCk7XG4gICAgICByZXR1cm4geyBtb2RlbElkOiBpbnB1dC5leHBsaWNpdCwgc291cmNlOiBcImV4cGxpY2l0XCIgfTtcbiAgICB9XG4gICAgY29uc3QgW3RvcF0gPSBsb29rdXBNb2RlbHMoZW5kcG9pbnRzLCBidWlsZFF1ZXJ5KGlucHV0LCBpbnB1dC5leHBsaWNpdCkpO1xuICAgIGlmIChpbnB1dC5yZXF1aXJlc1Rvb2xzICYmICF0b3ApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgTm8gdG9vbC1jYXBhYmxlIG1vZGVsIG1hdGNoZXMgXCIke2lucHV0LmV4cGxpY2l0fVwiYCk7XG4gICAgfVxuICAgIHJldHVybiB7IG1vZGVsSWQ6IHRvcD8uZW5kcG9pbnQubmFtZSA/PyBpbnB1dC5leHBsaWNpdCwgc291cmNlOiBcImZ1enp5LW1hdGNoXCIgfTtcbiAgfVxuXG4gIGlmIChpbnB1dC5tb2RlbENsYXNzID09PSB1bmRlZmluZWQgJiYgaW5wdXQuZmFsbGJhY2tzICYmIGlucHV0LmZhbGxiYWNrcy5sZW5ndGggPiAwKSB7XG4gICAgY29uc3QgcHJlc2VudCA9IG5ldyBTZXQoXG4gICAgICBlbmRwb2ludHNcbiAgICAgICAgLmZpbHRlcigoZW5kcG9pbnQpID0+ICFpbnB1dC5yZXF1aXJlc1Rvb2xzIHx8IGVuZHBvaW50U3VwcG9ydHNUb29scyhlbmRwb2ludCkpXG4gICAgICAgIC5tYXAoKGVuZHBvaW50KSA9PiBlbmRwb2ludC5uYW1lKSxcbiAgICApO1xuICAgIGNvbnN0IHBpbm5lZCA9IGlucHV0LmZhbGxiYWNrcy5maW5kKChpZCkgPT4gcHJlc2VudC5oYXMoaWQpKTtcbiAgICBpZiAocGlubmVkKSByZXR1cm4geyBtb2RlbElkOiBwaW5uZWQsIHNvdXJjZTogXCJmYWxsYmFja1wiIH07XG4gIH1cblxuICBjb25zdCBzb3VyY2UgPSBpbnB1dC5tb2RlbENsYXNzICE9PSB1bmRlZmluZWQgPyBcImNsYXNzXCIgOiBcImZhbGxiYWNrXCI7XG4gIGlmIChpbnB1dC5tb2RlbENsYXNzID09PSB1bmRlZmluZWQpIHtcbiAgICBjb25zdCBbcHJlZmVycmVkXSA9IGxvb2t1cE1vZGVscyhlbmRwb2ludHMsIGJ1aWxkUXVlcnkoaW5wdXQsIERFRkFVTFRfTU9ERUxfRkFNSUxZX1NFQVJDSCkpO1xuICAgIGlmIChwcmVmZXJyZWQpIHJldHVybiB7IG1vZGVsSWQ6IHByZWZlcnJlZC5lbmRwb2ludC5uYW1lLCBzb3VyY2UgfTtcbiAgfVxuICBjb25zdCBbdG9wXSA9IGxvb2t1cE1vZGVscyhlbmRwb2ludHMsIGJ1aWxkUXVlcnkoaW5wdXQsIHVuZGVmaW5lZCkpO1xuICBpZiAodG9wKSByZXR1cm4geyBtb2RlbElkOiB0b3AuZW5kcG9pbnQubmFtZSwgc291cmNlIH07XG5cbiAgaWYgKGlucHV0LmxpdmVPbmx5KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFwiTm8gbWF0Y2hpbmcgbGl2ZSBNb2RlbCBTZXJ2aW5nIGVuZHBvaW50IGlzIGF2YWlsYWJsZVwiKTtcbiAgfVxuXG4gIGNvbnN0IGZsb29yU291cmNlID1cbiAgICBpbnB1dC5tb2RlbENsYXNzICE9PSB1bmRlZmluZWQgPyBtb2RlbHNGb3JDbGFzcyhpbnB1dC5tb2RlbENsYXNzKSA6IChpbnB1dC5mYWxsYmFja3MgPz8gW10pO1xuICBjb25zdCBmbG9vciA9IG9iamVjdC5zZXF1ZW5jZShmbG9vclNvdXJjZSkuY29uY2F0KEZBTExCQUNLX01PREVMX0lEUykuZGlzdGluY3QoKS50b0FycmF5KCk7XG4gIGlmIChpbnB1dC5yZXF1aXJlc1Rvb2xzKSB7XG4gICAgY29uc3QgYXZhaWxhYmxlID0gbmV3IFNldChcbiAgICAgIGVuZHBvaW50cy5maWx0ZXIoZW5kcG9pbnRTdXBwb3J0c1Rvb2xzKS5tYXAoKGVuZHBvaW50KSA9PiBlbmRwb2ludC5uYW1lKSxcbiAgICApO1xuICAgIGNvbnN0IHNlbGVjdGVkID0gZmxvb3IuZmluZCgoaWQpID0+IGF2YWlsYWJsZS5oYXMoaWQpKTtcbiAgICBpZiAoIXNlbGVjdGVkKSB0aHJvdyBuZXcgRXJyb3IoXCJObyB0b29sLWNhcGFibGUgbW9kZWwgaXMgYXZhaWxhYmxlXCIpO1xuICAgIHJldHVybiB7IG1vZGVsSWQ6IHNlbGVjdGVkLCBzb3VyY2UgfTtcbiAgfVxuICByZXR1cm4geyBtb2RlbElkOiBwaWNrRmlyc3RBdmFpbGFibGUoZmxvb3IsIGVuZHBvaW50cyksIHNvdXJjZSB9O1xufVxuXG5mdW5jdGlvbiBidWlsZFF1ZXJ5KGlucHV0OiBSZXNvbHZlTW9kZWxJbnB1dCwgc2VhcmNoOiBzdHJpbmcgfCB1bmRlZmluZWQpOiBNb2RlbFF1ZXJ5IHtcbiAgcmV0dXJuIHtcbiAgICAuLi4oc2VhcmNoICE9PSB1bmRlZmluZWQgPyB7IHNlYXJjaCB9IDoge30pLFxuICAgIC4uLihpbnB1dC5tb2RlbENsYXNzICE9PSB1bmRlZmluZWQgPyB7IG1vZGVsQ2xhc3M6IGlucHV0Lm1vZGVsQ2xhc3MgfSA6IHt9KSxcbiAgICAuLi4oaW5wdXQucmVxdWlyZXNUb29scyAhPT0gdW5kZWZpbmVkID8geyByZXF1aXJlc1Rvb2xzOiBpbnB1dC5yZXF1aXJlc1Rvb2xzIH0gOiB7fSksXG4gICAgLi4uKGlucHV0LnRocmVzaG9sZCAhPT0gdW5kZWZpbmVkID8geyB0aHJlc2hvbGQ6IGlucHV0LnRocmVzaG9sZCB9IDoge30pLFxuICAgIGxpbWl0OiAxLFxuICB9O1xufVxuXG5mdW5jdGlvbiBhc3NlcnRUb29sU3VwcG9ydChlbmRwb2ludHM6IHJlYWRvbmx5IFNlcnZpbmdFbmRwb2ludFN1bW1hcnlbXSwgbW9kZWxJZDogc3RyaW5nKTogdm9pZCB7XG4gIGNvbnN0IGVuZHBvaW50ID0gZW5kcG9pbnRzLmZpbmQoKGNhbmRpZGF0ZSkgPT4gY2FuZGlkYXRlLm5hbWUgPT09IG1vZGVsSWQpO1xuICBpZiAoIWVuZHBvaW50IHx8ICFlbmRwb2ludFN1cHBvcnRzVG9vbHMoZW5kcG9pbnQpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBNb2RlbCBcIiR7bW9kZWxJZH1cIiBkb2VzIG5vdCBzdXBwb3J0IGZ1bmN0aW9uIHRvb2xzYCk7XG4gIH1cbn1cblxuZnVuY3Rpb24gcGlja0ZpcnN0QXZhaWxhYmxlKFxuICBjYW5kaWRhdGVzOiByZWFkb25seSBzdHJpbmdbXSxcbiAgZW5kcG9pbnRzOiByZWFkb25seSBTZXJ2aW5nRW5kcG9pbnRTdW1tYXJ5W10sXG4pOiBzdHJpbmcge1xuICBjb25zdCBwcmVzZW50ID0gbmV3IFNldChlbmRwb2ludHMubWFwKChlbmRwb2ludCkgPT4gZW5kcG9pbnQubmFtZSkpO1xuICBmb3IgKGNvbnN0IGNhbmRpZGF0ZSBvZiBjYW5kaWRhdGVzKSB7XG4gICAgaWYgKHByZXNlbnQuaGFzKGNhbmRpZGF0ZSkpIHJldHVybiBjYW5kaWRhdGU7XG4gIH1cbiAgcmV0dXJuIGNhbmRpZGF0ZXNbMF0gPz8gRkFMTEJBQ0tfTU9ERUxfSURTWzBdITtcbn1cbiJdfQ==
|
package/lib/src/classes.d.ts
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @module
|
|
11
11
|
*/
|
|
12
|
-
import {
|
|
13
|
-
type ModelClass =
|
|
12
|
+
import { type ModelClass as ModelClassType } from "@dbx-tools/shared-model/contracts";
|
|
13
|
+
type ModelClass = ModelClassType;
|
|
14
14
|
declare const ModelClass: {
|
|
15
15
|
readonly ChatThinking: "chat-thinking";
|
|
16
16
|
readonly ChatBalanced: "chat-balanced";
|
package/lib/src/classes.js
CHANGED
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @module
|
|
11
11
|
*/
|
|
12
|
-
import {
|
|
13
|
-
const
|
|
12
|
+
import { ModelClass as ModelClassValues, } from "@dbx-tools/shared-model/contracts";
|
|
13
|
+
const ModelClass = ModelClassValues;
|
|
14
|
+
const MODEL_CLASSES = new Set(Object.values(ModelClassValues));
|
|
14
15
|
/**
|
|
15
16
|
* Chat capability ladder in descending order - most capable
|
|
16
17
|
* ({@link ModelClass.ChatThinking}) first, least ({@link ModelClass.ChatFast})
|
|
@@ -43,11 +44,12 @@ export function isChatClass(cls) {
|
|
|
43
44
|
* `"balanced"` / `"fast"` resolves to the corresponding `chat-*` class.
|
|
44
45
|
*/
|
|
45
46
|
export function parseModelClass(value) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
if (typeof value !== "string")
|
|
48
|
+
return null;
|
|
49
|
+
if (MODEL_CLASSES.has(value))
|
|
50
|
+
return value;
|
|
51
|
+
const prefixed = `chat-${value}`;
|
|
52
|
+
return MODEL_CLASSES.has(prefixed) ? prefixed : null;
|
|
51
53
|
}
|
|
52
54
|
/**
|
|
53
55
|
* Classes at or below `cls` in chat capability: the class itself plus every
|
|
@@ -67,4 +69,4 @@ export function classesAtOrBelow(cls) {
|
|
|
67
69
|
const index = CHAT_CLASS_ORDER.indexOf(cls);
|
|
68
70
|
return index < 0 ? [...CHAT_CLASS_ORDER] : [...CHAT_CLASS_ORDER.slice(index)];
|
|
69
71
|
}
|
|
70
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
72
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jbGFzc2VzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7O0dBVUc7QUFFSCxPQUFPLEVBQ0wsVUFBVSxJQUFJLGdCQUFnQixHQUUvQixNQUFNLG1DQUFtQyxDQUFDO0FBRzNDLE1BQU0sVUFBVSxHQUFHLGdCQUFnQixDQUFDO0FBQ3BDLE1BQU0sYUFBYSxHQUFHLElBQUksR0FBRyxDQUFhLE1BQU0sQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDO0FBRTNFOzs7Ozs7R0FNRztBQUNILE1BQU0sQ0FBQyxNQUFNLGdCQUFnQixHQUEwQjtJQUNyRCxVQUFVLENBQUMsWUFBWTtJQUN2QixVQUFVLENBQUMsWUFBWTtJQUN2QixVQUFVLENBQUMsUUFBUTtDQUNwQixDQUFDO0FBRUY7Ozs7R0FJRztBQUNILE1BQU0sQ0FBQyxNQUFNLGlCQUFpQixHQUEwQixDQUFDLEdBQUcsZ0JBQWdCLEVBQUUsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0FBRXBHLHlFQUF5RTtBQUN6RSxNQUFNLFVBQVUsV0FBVyxDQUFDLEdBQWU7SUFDekMsT0FBTyxnQkFBZ0IsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUM7QUFDeEMsQ0FBQztBQUVEOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxVQUFVLGVBQWUsQ0FBQyxLQUFjO0lBQzVDLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUTtRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQzNDLElBQUksYUFBYSxDQUFDLEdBQUcsQ0FBQyxLQUFtQixDQUFDO1FBQUUsT0FBTyxLQUFtQixDQUFDO0lBQ3ZFLE1BQU0sUUFBUSxHQUFHLFFBQVEsS0FBSyxFQUFnQixDQUFDO0lBQy9DLE9BQU8sYUFBYSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7QUFDdkQsQ0FBQztBQUVEOzs7Ozs7Ozs7OztHQVdHO0FBQ0gsTUFBTSxVQUFVLGdCQUFnQixDQUFDLEdBQWU7SUFDOUMsSUFBSSxHQUFHLEtBQUssVUFBVSxDQUFDLFNBQVM7UUFBRSxPQUFPLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ2hFLE1BQU0sS0FBSyxHQUFHLGdCQUFnQixDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUM1QyxPQUFPLEtBQUssR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7QUFDaEYsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogTW9kZWwtY2xhc3Mgb3JkZXJpbmcgZm9yIHRoZSBtb2RlbCBzZXJ2aWNlLlxuICpcbiAqIGBAZGJ4LXRvb2xzL3NoYXJlZC1tb2RlbGAgZGVjbGFyZXMgdGhlIHtAbGluayBNb2RlbENsYXNzfSB2YWx1ZXMgYW5kIHRoZWlyXG4gKiBzY2hlbWE7IHRoZSAqYmVoYXZpb3IqIG92ZXIgdGhvc2UgdmFsdWVzIC0gdGhlIGNoYXQgY2FwYWJpbGl0eSBvcmRlciwgdGhlXG4gKiBcInRoaXMgY2xhc3MgYW5kIGJlbG93XCIgY2VpbGluZywgYW5kIGNvZXJjaW5nIGxvb3NlIHJlcXVlc3QgaW5wdXQgdG8gYSBjbGFzcyAtXG4gKiBsaXZlcyBoZXJlIGluIHRoZSBzZXJ2aWNlIHNvIHRoZSBzaGFyZWQgd2lyZS1mb3JtYXQgc3VyZmFjZSBzdGF5cyBwdXJlbHlcbiAqIGRlY2xhcmF0aXZlLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQge1xuICBNb2RlbENsYXNzIGFzIE1vZGVsQ2xhc3NWYWx1ZXMsXG4gIHR5cGUgTW9kZWxDbGFzcyBhcyBNb2RlbENsYXNzVHlwZSxcbn0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLW1vZGVsL2NvbnRyYWN0c1wiO1xuXG50eXBlIE1vZGVsQ2xhc3MgPSBNb2RlbENsYXNzVHlwZTtcbmNvbnN0IE1vZGVsQ2xhc3MgPSBNb2RlbENsYXNzVmFsdWVzO1xuY29uc3QgTU9ERUxfQ0xBU1NFUyA9IG5ldyBTZXQ8TW9kZWxDbGFzcz4oT2JqZWN0LnZhbHVlcyhNb2RlbENsYXNzVmFsdWVzKSk7XG5cbi8qKlxuICogQ2hhdCBjYXBhYmlsaXR5IGxhZGRlciBpbiBkZXNjZW5kaW5nIG9yZGVyIC0gbW9zdCBjYXBhYmxlXG4gKiAoe0BsaW5rIE1vZGVsQ2xhc3MuQ2hhdFRoaW5raW5nfSkgZmlyc3QsIGxlYXN0ICh7QGxpbmsgTW9kZWxDbGFzcy5DaGF0RmFzdH0pXG4gKiBsYXN0LiB7QGxpbmsgTW9kZWxDbGFzcy5FbWJlZGRpbmd9IGlzIGEgc2VwYXJhdGUgbW9kYWxpdHkgYW5kIGlzIGRlbGliZXJhdGVseVxuICogYWJzZW50OiB0aGUgY2VpbGluZyBuZXZlciBzcGFucyBpdC4gVGhpcyBpcyB0aGUgb3JkZXIgdXNlZCB0byBmaWx0ZXIgXCJ0aGlzXG4gKiBjbGFzcyBhbmQgYmVsb3dcIiBhbmQgdG8gYnJlYWsgcmFua2luZyB0aWVzIHRvd2FyZCB0aGUgbW9yZSBjYXBhYmxlIG1vZGVsLlxuICovXG5leHBvcnQgY29uc3QgQ0hBVF9DTEFTU19PUkRFUjogcmVhZG9ubHkgTW9kZWxDbGFzc1tdID0gW1xuICBNb2RlbENsYXNzLkNoYXRUaGlua2luZyxcbiAgTW9kZWxDbGFzcy5DaGF0QmFsYW5jZWQsXG4gIE1vZGVsQ2xhc3MuQ2hhdEZhc3QsXG5dO1xuXG4vKipcbiAqIEV2ZXJ5IGNsYXNzIGluIGRpc3BsYXkgb3JkZXI6IHRoZSBjaGF0IGxhZGRlciBmb2xsb3dlZCBieVxuICoge0BsaW5rIE1vZGVsQ2xhc3MuRW1iZWRkaW5nfS4gVXNlZCB3aGVuIGZsYXR0ZW5pbmcgYSBmdWxsIGNsYXNzaWZpY2F0aW9uXG4gKiAoZS5nLiBzdGFtcGluZyB0aGUgY2xhc3Mgb250byBlYWNoIGNhY2hlZCBlbmRwb2ludCkuXG4gKi9cbmV4cG9ydCBjb25zdCBNT0RFTF9DTEFTU19PUkRFUjogcmVhZG9ubHkgTW9kZWxDbGFzc1tdID0gWy4uLkNIQVRfQ0xBU1NfT1JERVIsIE1vZGVsQ2xhc3MuRW1iZWRkaW5nXTtcblxuLyoqIFdoZXRoZXIgYGNsc2AgaXMgb25lIG9mIHRoZSBjaGF0IGNhcGFiaWxpdHkgYmFuZHMgKHZzLiBlbWJlZGRpbmcpLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzQ2hhdENsYXNzKGNsczogTW9kZWxDbGFzcyk6IGJvb2xlYW4ge1xuICByZXR1cm4gQ0hBVF9DTEFTU19PUkRFUi5pbmNsdWRlcyhjbHMpO1xufVxuXG4vKipcbiAqIENvZXJjZSBhbiBhcmJpdHJhcnkgdmFsdWUgKHF1ZXJ5IHN0cmluZywgaGVhZGVyLCBib2R5IGZpZWxkKSB0byBhXG4gKiB7QGxpbmsgTW9kZWxDbGFzc30sIHJldHVybmluZyBgbnVsbGAgd2hlbiBpdCBpc24ndCBhIGtub3duIGNsYXNzLiBMZXRzIGFcbiAqIHJvdXRlIGFjY2VwdCBhIGNsYXNzIHJlcXVlc3Qgd2l0aG91dCB0aHJvd2luZyBvbiBqdW5rIGlucHV0LlxuICpcbiAqIE1hdGNoZXMgdGhlIGZ1bGwgc2x1ZyBmaXJzdCAoYFwiY2hhdC1mYXN0XCJgLCBgXCJlbWJlZGRpbmdcImApLCB0aGVuIC0gZm9yIGEgYmFyZVxuICogY2hhdCBiYW5kIC0gcmV0cmllcyB3aXRoIGEgYGNoYXQtYCBwcmVmaXgsIHNvIHRoZSBzaG9ydGhhbmQgYFwidGhpbmtpbmdcImAgL1xuICogYFwiYmFsYW5jZWRcImAgLyBgXCJmYXN0XCJgIHJlc29sdmVzIHRvIHRoZSBjb3JyZXNwb25kaW5nIGBjaGF0LSpgIGNsYXNzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VNb2RlbENsYXNzKHZhbHVlOiB1bmtub3duKTogTW9kZWxDbGFzcyB8IG51bGwge1xuICBpZiAodHlwZW9mIHZhbHVlICE9PSBcInN0cmluZ1wiKSByZXR1cm4gbnVsbDtcbiAgaWYgKE1PREVMX0NMQVNTRVMuaGFzKHZhbHVlIGFzIE1vZGVsQ2xhc3MpKSByZXR1cm4gdmFsdWUgYXMgTW9kZWxDbGFzcztcbiAgY29uc3QgcHJlZml4ZWQgPSBgY2hhdC0ke3ZhbHVlfWAgYXMgTW9kZWxDbGFzcztcbiAgcmV0dXJuIE1PREVMX0NMQVNTRVMuaGFzKHByZWZpeGVkKSA/IHByZWZpeGVkIDogbnVsbDtcbn1cblxuLyoqXG4gKiBDbGFzc2VzIGF0IG9yIGJlbG93IGBjbHNgIGluIGNoYXQgY2FwYWJpbGl0eTogdGhlIGNsYXNzIGl0c2VsZiBwbHVzIGV2ZXJ5XG4gKiBsZXNzLWNhcGFibGUgY2hhdCBiYW5kLCBpbiB7QGxpbmsgQ0hBVF9DTEFTU19PUkRFUn0uIFRyZWF0cyBhIGNoYXQgYGNsc2AgYXMgYVxuICogY2VpbGluZyAtIHJlcXVlc3Rpbmcge0BsaW5rIE1vZGVsQ2xhc3MuQ2hhdEJhbGFuY2VkfSB5aWVsZHNcbiAqIGBbQ2hhdEJhbGFuY2VkLCBDaGF0RmFzdF1gLCBuZXZlciB7QGxpbmsgTW9kZWxDbGFzcy5DaGF0VGhpbmtpbmd9IC0gc28gYVxuICogY2xhc3MgYXNrIGNhbiBkZWdyYWRlIGRvd253YXJkIHRvIGEgc21hbGxlciBjaGF0IG1vZGVsIGJ1dCBuZXZlciBlc2NhbGF0ZSB0b1xuICogYSBsYXJnZXIgb25lLlxuICpcbiAqIHtAbGluayBNb2RlbENsYXNzLkVtYmVkZGluZ30gaXMgaXRzIG93biBtb2RhbGl0eSwgbm90IGEgcnVuZyBvbiB0aGUgY2hhdFxuICogbGFkZGVyLCBzbyBpdCB5aWVsZHMganVzdCBgW0VtYmVkZGluZ11gLiBBbiB1bnJlY29nbml6ZWQgY2xhc3MgeWllbGRzIHRoZVxuICogZnVsbCBjaGF0IGxhZGRlci5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNsYXNzZXNBdE9yQmVsb3coY2xzOiBNb2RlbENsYXNzKTogTW9kZWxDbGFzc1tdIHtcbiAgaWYgKGNscyA9PT0gTW9kZWxDbGFzcy5FbWJlZGRpbmcpIHJldHVybiBbTW9kZWxDbGFzcy5FbWJlZGRpbmddO1xuICBjb25zdCBpbmRleCA9IENIQVRfQ0xBU1NfT1JERVIuaW5kZXhPZihjbHMpO1xuICByZXR1cm4gaW5kZXggPCAwID8gWy4uLkNIQVRfQ0xBU1NfT1JERVJdIDogWy4uLkNIQVRfQ0xBU1NfT1JERVIuc2xpY2UoaW5kZXgpXTtcbn1cbiJdfQ==
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model-class classification for Databricks Model Serving endpoints.
|
|
3
|
+
*
|
|
4
|
+
* Chat capability bands are derived from the live workspace catalogue
|
|
5
|
+
* rather than a hand-maintained table. Databricks publishes
|
|
6
|
+
* per-endpoint `quality` / `speed` / `cost` scores (the AI Playground
|
|
7
|
+
* bars) on the serving list; {@link classifyEndpoints} buckets scored
|
|
8
|
+
* chat models into the chat {@link ModelClass} bands by the *relative*
|
|
9
|
+
* distribution of those scores (quantiles, not fixed cut-offs) so a
|
|
10
|
+
* brand-new model that lands outside today's score range still slots in
|
|
11
|
+
* next to its peers. Embedding endpoints (`task === "llm/v1/embeddings"`)
|
|
12
|
+
* are bucketed into {@link ModelClass.Embedding} by task, independent of
|
|
13
|
+
* any score.
|
|
14
|
+
*
|
|
15
|
+
* Unscored-but-recognizable chat endpoints are still placed by a small
|
|
16
|
+
* family heuristic ({@link classifyByFamily}) so a workspace whose
|
|
17
|
+
* models predate Foundation Model API scoring keeps working. The
|
|
18
|
+
* offline fallback floor - the hard-coded model list reached for when
|
|
19
|
+
* the live catalogue can't be read at all - is a server concern and
|
|
20
|
+
* lives in `@dbx-tools/model`, not here: a browser client never talks
|
|
21
|
+
* to Databricks directly, so it has nothing to fall back to.
|
|
22
|
+
*
|
|
23
|
+
* Pure (no Node-only imports), so a client can classify a `/models`
|
|
24
|
+
* response without server dependencies.
|
|
25
|
+
*
|
|
26
|
+
* @module
|
|
27
|
+
*/
|
|
28
|
+
import { type ModelClass as ModelClassType, type ServingEndpointSummary } from "@dbx-tools/shared-model/contracts";
|
|
29
|
+
type ModelClass = ModelClassType;
|
|
30
|
+
declare const ModelClass: {
|
|
31
|
+
readonly ChatThinking: "chat-thinking";
|
|
32
|
+
readonly ChatBalanced: "chat-balanced";
|
|
33
|
+
readonly ChatFast: "chat-fast";
|
|
34
|
+
readonly Embedding: "embedding";
|
|
35
|
+
};
|
|
36
|
+
/** What an endpoint can be asked to do, as derived by {@link endpointCapabilities}. */
|
|
37
|
+
export interface EndpointCapabilities {
|
|
38
|
+
/** OpenAI chat/completions + Responses: the surface a chat agent needs. */
|
|
39
|
+
chat: boolean;
|
|
40
|
+
/** Embedding (vector) endpoint. */
|
|
41
|
+
embedding: boolean;
|
|
42
|
+
/** Complete function-tool round-trip (call plus function_call_output replay). */
|
|
43
|
+
tools: boolean;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Provider families verified against Databricks Responses/Open Responses with
|
|
47
|
+
* both a forced function call and a stateless `function_call_output` replay.
|
|
48
|
+
*
|
|
49
|
+
* Databricks' endpoint list/OpenAPI currently exposes no tools capability bit.
|
|
50
|
+
* Keep this conservative: an unknown chat family is not agent-safe until it is
|
|
51
|
+
* verified. Gemini is excluded because it emits a call but Open Responses
|
|
52
|
+
* cannot replay the required thought signature; GPT-OSS rejects Responses
|
|
53
|
+
* passthrough entirely.
|
|
54
|
+
*/
|
|
55
|
+
export declare function supportsToolsByFamily(name: string): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Derive an endpoint's capabilities from its Databricks task hint and its
|
|
58
|
+
* classified {@link ModelClass}, so consumers filter on capability instead of
|
|
59
|
+
* re-deriving it from raw `task` / `class` strings.
|
|
60
|
+
*
|
|
61
|
+
* Either signal alone is enough: the task hint is authoritative when present,
|
|
62
|
+
* and the class covers endpoints Databricks left untasked but the classifier
|
|
63
|
+
* recognized. Embedding wins over chat when both point at it, since the two are
|
|
64
|
+
* not interchangeable.
|
|
65
|
+
*/
|
|
66
|
+
export declare function endpointCapabilities(endpoint: ServingEndpointSummary): EndpointCapabilities;
|
|
67
|
+
/** Family-heuristic classification of a single endpoint name. */
|
|
68
|
+
export interface FamilyClass {
|
|
69
|
+
/** Chat capability band the family maps to (never embedding). */
|
|
70
|
+
class: ModelClass;
|
|
71
|
+
/** Intra-family ordering hint (higher is newer / more capable). */
|
|
72
|
+
rank: number;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Numeric `[major, minor, patch]` version parsed from an endpoint
|
|
76
|
+
* name, used to order siblings within a family/tier. Starts at the
|
|
77
|
+
* first digit in the name, then reads successive separator-delimited,
|
|
78
|
+
* digit-prefixed chunks as the three components (missing ones default
|
|
79
|
+
* to `0`):
|
|
80
|
+
*
|
|
81
|
+
* - `databricks-claude-opus-4-8` -> `[4, 8, 0]`
|
|
82
|
+
* - `databricks-claude-opus-4-10` -> `[4, 10, 0]` (sorts above 4-8)
|
|
83
|
+
* - `databricks-meta-llama-3-3-70b`-> `[3, 3, 70]`
|
|
84
|
+
* - `databricks-bge-large-en` -> `[0, 0, 0]` (no digits)
|
|
85
|
+
*
|
|
86
|
+
* Component-wise comparison (not a decimal collapse) so `4.10` beats
|
|
87
|
+
* `4.8` - the bug a `major + minor/10` score would hit.
|
|
88
|
+
*/
|
|
89
|
+
export declare function versionTuple(name: string): [number, number, number];
|
|
90
|
+
/**
|
|
91
|
+
* Best-effort chat capability band for an endpoint we have no live
|
|
92
|
+
* score for, keyed off provider family and the well-known variant words
|
|
93
|
+
* in the name (`opus`/`sonnet`/`haiku`, `pro`/`mini`/`nano`,
|
|
94
|
+
* `flash`/`flash-lite`, Llama parameter sizes, etc). Returns `null` for
|
|
95
|
+
* names we don't recognize so unknown custom endpoints are never
|
|
96
|
+
* auto-selected as a default. The accompanying `rank` orders siblings
|
|
97
|
+
* within a class. Only ever returns a chat band - embedding endpoints
|
|
98
|
+
* are classified by task, not name.
|
|
99
|
+
*/
|
|
100
|
+
export declare function classifyByFamily(name: string): FamilyClass | null;
|
|
101
|
+
/**
|
|
102
|
+
* Bucket live endpoints into {@link ModelClass}es, ranked best-first
|
|
103
|
+
* within each chat band.
|
|
104
|
+
*
|
|
105
|
+
* Embedding endpoints (`task === "llm/v1/embeddings"`) go into
|
|
106
|
+
* {@link ModelClass.Embedding} by task, in listing order (they carry no
|
|
107
|
+
* capability score to rank on).
|
|
108
|
+
*
|
|
109
|
+
* Chat endpoints (`task === "llm/v1/chat"`) split into the three chat
|
|
110
|
+
* bands. Scored endpoints (those carrying a `profile.quality`) drive
|
|
111
|
+
* the banding: the observed quality distribution is split at its 1/3
|
|
112
|
+
* and 2/3 quantiles, so the top third is {@link ModelClass.ChatThinking},
|
|
113
|
+
* the bottom third {@link ModelClass.ChatFast}, and the middle
|
|
114
|
+
* {@link ModelClass.ChatBalanced}. Because the thresholds come from the
|
|
115
|
+
* data, the split adapts as Databricks adds or rescores models -
|
|
116
|
+
* nothing is pinned to a fixed score band.
|
|
117
|
+
*
|
|
118
|
+
* Unscored chat endpoints are placed by {@link classifyByFamily} and
|
|
119
|
+
* ranked after the scored ones in their band; unrecognized, unscored
|
|
120
|
+
* endpoints (e.g. custom external models) are omitted entirely so they
|
|
121
|
+
* are never picked as an automatic default.
|
|
122
|
+
*
|
|
123
|
+
* Within a chat band, scored models sort by `quality` desc, then `cost`
|
|
124
|
+
* asc, then `speed` desc, then parsed name version desc; family-only
|
|
125
|
+
* models sort by version rank then parsed version. The version
|
|
126
|
+
* tie-break ({@link versionTuple}) is what separates point releases
|
|
127
|
+
* that share a score profile (e.g. `opus-4-8` ahead of `opus-4-7`).
|
|
128
|
+
*/
|
|
129
|
+
export declare function classifyEndpoints(endpoints: readonly ServingEndpointSummary[]): Record<ModelClass, ServingEndpointSummary[]>;
|
|
130
|
+
export {};
|