@shop-os/modelkit 0.2.12 → 0.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/catalog.cjs CHANGED
@@ -23,6 +23,7 @@ __export(catalog_entry_exports, {
23
23
  ADAPTER_IDS: () => ADAPTER_IDS,
24
24
  Catalog: () => Catalog,
25
25
  CatalogModelSchema: () => CatalogModelSchema,
26
+ CatalogModelSchemaBase: () => CatalogModelSchemaBase,
26
27
  CatalogSchema: () => CatalogSchema,
27
28
  ExposureSchema: () => ExposureSchema,
28
29
  IMAGE_MODELS: () => IMAGE_MODELS,
@@ -179,7 +180,9 @@ function normalizeExposure(value) {
179
180
  if (value === "catalog") return ["cowork", "space_builder"];
180
181
  if (value === "internal") return [];
181
182
  if (Array.isArray(value)) {
182
- if (value.every((entry) => SURFACES.includes(entry))) {
183
+ if (value.every(
184
+ (entry) => SURFACES.includes(entry)
185
+ )) {
183
186
  const present = new Set(value);
184
187
  return SURFACES.filter((surface) => present.has(surface));
185
188
  }
@@ -1877,7 +1880,215 @@ var MODELS = [
1877
1880
  ];
1878
1881
 
1879
1882
  // src/catalog/schema.ts
1883
+ var import_zod2 = require("zod");
1884
+
1885
+ // src/catalog/collisions.ts
1886
+ function collisionIssues(rows) {
1887
+ const issues = [];
1888
+ const seenIds = /* @__PURE__ */ new Map();
1889
+ const seenAliases = /* @__PURE__ */ new Map();
1890
+ rows.forEach((row, index) => {
1891
+ if (seenIds.has(row.id)) {
1892
+ issues.push({
1893
+ index,
1894
+ path: ["id"],
1895
+ message: `Duplicate model id "${row.id}"`
1896
+ });
1897
+ } else {
1898
+ const aliasOwner = seenAliases.get(row.id);
1899
+ if (aliasOwner !== void 0) {
1900
+ issues.push({
1901
+ index: aliasOwner.index,
1902
+ path: ["aliases", aliasOwner.aliasIndex],
1903
+ message: `Alias "${row.id}" collides with a model id`
1904
+ });
1905
+ }
1906
+ seenIds.set(row.id, index);
1907
+ }
1908
+ const local = /* @__PURE__ */ new Set();
1909
+ for (const [aliasIndex, alias] of row.aliases.entries()) {
1910
+ if (alias === row.id || seenIds.has(alias)) {
1911
+ issues.push({
1912
+ index,
1913
+ path: ["aliases", aliasIndex],
1914
+ message: `Alias "${alias}" collides with a model id`
1915
+ });
1916
+ } else if (local.has(alias) || seenAliases.has(alias)) {
1917
+ issues.push({
1918
+ index,
1919
+ path: ["aliases", aliasIndex],
1920
+ message: `Duplicate alias "${alias}"`
1921
+ });
1922
+ }
1923
+ local.add(alias);
1924
+ if (!seenAliases.has(alias)) seenAliases.set(alias, { index, aliasIndex });
1925
+ }
1926
+ });
1927
+ return issues;
1928
+ }
1929
+
1930
+ // src/catalog/input-spec.ts
1880
1931
  var import_zod = require("zod");
1932
+ var VIDEO_INPUT_SPEC_KEYS = [
1933
+ "prompt",
1934
+ "durationSeconds",
1935
+ "aspectRatio",
1936
+ "resolution",
1937
+ "firstFrame",
1938
+ "lastFrame",
1939
+ "seed",
1940
+ "negativePrompt",
1941
+ "generateAudio",
1942
+ "cfgScale",
1943
+ "promptExpansion",
1944
+ "referenceImages"
1945
+ ];
1946
+ var AUDIO_INPUT_SPEC_KEYS = [
1947
+ "prompt",
1948
+ "durationSeconds",
1949
+ "seed",
1950
+ "negativePrompt",
1951
+ "references",
1952
+ "sourceVideo",
1953
+ "instrumental"
1954
+ ];
1955
+ var INPUT_SPEC_SUPPORTS_KEYS = [
1956
+ "lastFrame",
1957
+ "seed",
1958
+ "negativePrompt",
1959
+ "generateAudio",
1960
+ "cfgScale",
1961
+ "promptExpansion",
1962
+ "instrumental"
1963
+ ];
1964
+ var VIDEO_KEY_SET = new Set(VIDEO_INPUT_SPEC_KEYS);
1965
+ var AUDIO_KEY_SET = new Set(AUDIO_INPUT_SPEC_KEYS);
1966
+ var ALL_KEY_SET = /* @__PURE__ */ new Set([
1967
+ ...VIDEO_INPUT_SPEC_KEYS,
1968
+ ...AUDIO_INPUT_SPEC_KEYS
1969
+ ]);
1970
+ var ProviderScalarSchema = import_zod.z.union([import_zod.z.string(), import_zod.z.number(), import_zod.z.boolean()]);
1971
+ var FieldsSchema = import_zod.z.record(import_zod.z.string(), import_zod.z.string().min(1)).superRefine((fields, ctx) => {
1972
+ const keys = Object.keys(fields);
1973
+ if (keys.length === 0) {
1974
+ ctx.addIssue({
1975
+ code: "custom",
1976
+ message: "inputSpec.fields must name at least one field"
1977
+ });
1978
+ return;
1979
+ }
1980
+ for (const key of keys) {
1981
+ if (!ALL_KEY_SET.has(key)) {
1982
+ ctx.addIssue({
1983
+ code: "custom",
1984
+ message: `inputSpec.fields has unknown canonical key "${key}"`
1985
+ });
1986
+ }
1987
+ }
1988
+ });
1989
+ var ValuesSchema = import_zod.z.record(import_zod.z.string(), import_zod.z.record(import_zod.z.string(), ProviderScalarSchema)).superRefine((values, ctx) => {
1990
+ for (const key of Object.keys(values)) {
1991
+ if (!ALL_KEY_SET.has(key)) {
1992
+ ctx.addIssue({
1993
+ code: "custom",
1994
+ message: `inputSpec.values has unknown canonical key "${key}"`
1995
+ });
1996
+ }
1997
+ }
1998
+ });
1999
+ var StaticSchema = import_zod.z.record(import_zod.z.string(), ProviderScalarSchema);
2000
+ var InputSpecSchema = import_zod.z.strictObject({
2001
+ fields: FieldsSchema,
2002
+ values: ValuesSchema.optional(),
2003
+ static: StaticSchema.optional()
2004
+ }).superRefine((spec, ctx) => {
2005
+ const mappedNames = new Set(Object.values(spec.fields));
2006
+ for (const key of Object.keys(spec.static ?? {})) {
2007
+ if (mappedNames.has(key)) {
2008
+ ctx.addIssue({
2009
+ code: "custom",
2010
+ path: ["static", key],
2011
+ message: `inputSpec.static "${key}" collides with a mapped field name`
2012
+ });
2013
+ }
2014
+ }
2015
+ });
2016
+ function validateInputSpec(raw, row) {
2017
+ const parsed = InputSpecSchema.safeParse(raw);
2018
+ if (!parsed.success) {
2019
+ return {
2020
+ ok: false,
2021
+ issues: parsed.error.issues.map((issue) => ({
2022
+ path: issue.path,
2023
+ message: issue.message
2024
+ }))
2025
+ };
2026
+ }
2027
+ const spec = parsed.data;
2028
+ if (row.adapter !== "replicate") {
2029
+ return {
2030
+ ok: false,
2031
+ issues: [{ path: [], message: "inputSpec is only supported on replicate rows" }]
2032
+ };
2033
+ }
2034
+ const issues = [];
2035
+ if (row.type !== "video" && row.type !== "audio") {
2036
+ issues.push({
2037
+ path: [],
2038
+ message: `inputSpec is not supported for "${row.type}" rows`
2039
+ });
2040
+ } else {
2041
+ const allowed = row.type === "video" ? VIDEO_KEY_SET : AUDIO_KEY_SET;
2042
+ for (const key of Object.keys(spec.fields)) {
2043
+ if (!allowed.has(key)) {
2044
+ issues.push({
2045
+ path: ["fields", key],
2046
+ message: `inputSpec.fields "${key}" is not supported for ${row.type} rows`
2047
+ });
2048
+ }
2049
+ }
2050
+ for (const key of Object.keys(spec.values ?? {})) {
2051
+ if (!allowed.has(key)) {
2052
+ issues.push({
2053
+ path: ["values", key],
2054
+ message: `inputSpec.values "${key}" is not supported for ${row.type} rows`
2055
+ });
2056
+ }
2057
+ }
2058
+ }
2059
+ const seenNames = /* @__PURE__ */ new Map();
2060
+ for (const [key, name] of Object.entries(spec.fields)) {
2061
+ const first = seenNames.get(name);
2062
+ if (first === void 0) seenNames.set(name, key);
2063
+ else {
2064
+ issues.push({
2065
+ path: ["fields", key],
2066
+ message: `inputSpec.fields "${first}" and "${key}" both map to "${name}"`
2067
+ });
2068
+ }
2069
+ }
2070
+ for (const key of Object.keys(spec.values ?? {})) {
2071
+ if (!(key in spec.fields)) {
2072
+ issues.push({
2073
+ path: ["values", key],
2074
+ message: `inputSpec.values "${key}" has no matching fields entry`
2075
+ });
2076
+ }
2077
+ }
2078
+ const supports = row.constraints.supports ?? [];
2079
+ for (const key of INPUT_SPEC_SUPPORTS_KEYS) {
2080
+ if (key in spec.fields && !supports.includes(key)) {
2081
+ issues.push({
2082
+ path: ["fields", key],
2083
+ message: `inputSpec.fields "${key}" needs "${key}" in constraints.supports`
2084
+ });
2085
+ }
2086
+ }
2087
+ if (issues.length > 0) return { ok: false, issues };
2088
+ return { ok: true, spec };
2089
+ }
2090
+
2091
+ // src/catalog/schema.ts
1881
2092
  var ADAPTER_IDS = [
1882
2093
  "ai-sdk-text",
1883
2094
  "google-image",
@@ -1890,16 +2101,16 @@ var ADAPTER_IDS = [
1890
2101
  "higgsfield",
1891
2102
  "xai-video"
1892
2103
  ];
1893
- var ModelTypeSchema = import_zod.z.enum(["text", "image", "video", "audio", "upscale", "bg-remove"]);
1894
- var LifecycleSchema = import_zod.z.enum(["active", "deprecated", "retired"]);
1895
- var SurfaceSchema = import_zod.z.enum(["cowork", "space_builder"]);
2104
+ var ModelTypeSchema = import_zod2.z.enum(["text", "image", "video", "audio", "upscale", "bg-remove"]);
2105
+ var LifecycleSchema = import_zod2.z.enum(["active", "deprecated", "retired"]);
2106
+ var SurfaceSchema = import_zod2.z.enum(["cowork", "space_builder"]);
1896
2107
  var SURFACES2 = SurfaceSchema.options;
1897
- var ExposureSchema = import_zod.z.preprocess(
2108
+ var ExposureSchema = import_zod2.z.preprocess(
1898
2109
  normalizeExposure,
1899
- import_zod.z.array(SurfaceSchema)
2110
+ import_zod2.z.array(SurfaceSchema)
1900
2111
  );
1901
- var AdapterSchema = import_zod.z.enum(ADAPTER_IDS);
1902
- var AspectRatioSchema = import_zod.z.enum([
2112
+ var AdapterSchema = import_zod2.z.enum(ADAPTER_IDS);
2113
+ var AspectRatioSchema = import_zod2.z.enum([
1903
2114
  "1:1",
1904
2115
  "16:9",
1905
2116
  "9:16",
@@ -1914,12 +2125,12 @@ var AspectRatioSchema = import_zod.z.enum([
1914
2125
  "97:30",
1915
2126
  "adaptive"
1916
2127
  ]);
1917
- var ImageSizeSchema = import_zod.z.enum(["512", "1K", "2K", "4K"]);
1918
- var VideoResolutionSchema = import_zod.z.enum(["360p", "480p", "720p", "768p", "1080p", "2k", "4k"]);
1919
- var ImageQualitySchema = import_zod.z.enum(["auto", "low", "medium", "high", "xhigh", "max"]);
1920
- var OutputFormatSchema = import_zod.z.enum(["png", "jpeg", "webp"]);
1921
- var RequiredInputSchema = import_zod.z.enum(["firstFrame", "sourceVideo", "references"]);
1922
- var SupportedOptionSchema = import_zod.z.enum([
2128
+ var ImageSizeSchema = import_zod2.z.enum(["512", "1K", "2K", "4K"]);
2129
+ var VideoResolutionSchema = import_zod2.z.enum(["360p", "480p", "720p", "768p", "1080p", "2k", "4k"]);
2130
+ var ImageQualitySchema = import_zod2.z.enum(["auto", "low", "medium", "high", "xhigh", "max"]);
2131
+ var OutputFormatSchema = import_zod2.z.enum(["png", "jpeg", "webp"]);
2132
+ var RequiredInputSchema = import_zod2.z.enum(["firstFrame", "sourceVideo", "references"]);
2133
+ var SupportedOptionSchema = import_zod2.z.enum([
1923
2134
  "seed",
1924
2135
  "quality",
1925
2136
  "negativePrompt",
@@ -1938,128 +2149,128 @@ var SupportedOptionSchema = import_zod.z.enum([
1938
2149
  "taskType",
1939
2150
  "instrumental"
1940
2151
  ]);
1941
- var UsageUnitSchema = import_zod.z.enum([
2152
+ var UsageUnitSchema = import_zod2.z.enum([
1942
2153
  "tokens",
1943
2154
  "images",
1944
2155
  "seconds",
1945
2156
  "reported_cost_usd",
1946
2157
  "compute_seconds"
1947
2158
  ]);
1948
- var PricingKindSchema = import_zod.z.enum(["token", "image_size", "video_per_second", "flat"]);
1949
- var ProviderOptionValueSchema = import_zod.z.lazy(
1950
- () => import_zod.z.union([
1951
- import_zod.z.string(),
1952
- import_zod.z.number(),
1953
- import_zod.z.boolean(),
1954
- import_zod.z.array(ProviderOptionValueSchema),
1955
- import_zod.z.record(import_zod.z.string(), ProviderOptionValueSchema)
2159
+ var PricingKindSchema = import_zod2.z.enum(["token", "image_size", "video_per_second", "flat"]);
2160
+ var ProviderOptionValueSchema = import_zod2.z.lazy(
2161
+ () => import_zod2.z.union([
2162
+ import_zod2.z.string(),
2163
+ import_zod2.z.number(),
2164
+ import_zod2.z.boolean(),
2165
+ import_zod2.z.array(ProviderOptionValueSchema),
2166
+ import_zod2.z.record(import_zod2.z.string(), ProviderOptionValueSchema)
1956
2167
  ])
1957
2168
  );
1958
- var ProviderOptionsSchema = import_zod.z.record(import_zod.z.string(), import_zod.z.record(import_zod.z.string(), ProviderOptionValueSchema));
1959
- var ReferenceLimitsSchema = import_zod.z.looseObject({
1960
- images: import_zod.z.number().optional(),
1961
- imagesWithVideo: import_zod.z.number().optional(),
1962
- videos: import_zod.z.number().optional(),
1963
- audios: import_zod.z.number().optional(),
1964
- total: import_zod.z.number().optional(),
1965
- audioOnly: import_zod.z.boolean().optional()
2169
+ var ProviderOptionsSchema = import_zod2.z.record(import_zod2.z.string(), import_zod2.z.record(import_zod2.z.string(), ProviderOptionValueSchema));
2170
+ var ReferenceLimitsSchema = import_zod2.z.looseObject({
2171
+ images: import_zod2.z.number().optional(),
2172
+ imagesWithVideo: import_zod2.z.number().optional(),
2173
+ videos: import_zod2.z.number().optional(),
2174
+ audios: import_zod2.z.number().optional(),
2175
+ total: import_zod2.z.number().optional(),
2176
+ audioOnly: import_zod2.z.boolean().optional()
1966
2177
  });
1967
- var ModelConstraintsSchema = import_zod.z.looseObject({
1968
- aspectRatios: import_zod.z.array(AspectRatioSchema).optional(),
1969
- sizes: import_zod.z.array(ImageSizeSchema).optional(),
1970
- resolutions: import_zod.z.array(VideoResolutionSchema).optional(),
1971
- durations: import_zod.z.union([import_zod.z.looseObject({ min: import_zod.z.number(), max: import_zod.z.number() }), import_zod.z.array(import_zod.z.number())]).optional(),
1972
- durationPresets: import_zod.z.array(import_zod.z.number()).optional(),
1973
- qualityOptions: import_zod.z.array(import_zod.z.string()).optional(),
1974
- exactSizes: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
2178
+ var ModelConstraintsSchema = import_zod2.z.looseObject({
2179
+ aspectRatios: import_zod2.z.array(AspectRatioSchema).optional(),
2180
+ sizes: import_zod2.z.array(ImageSizeSchema).optional(),
2181
+ resolutions: import_zod2.z.array(VideoResolutionSchema).optional(),
2182
+ durations: import_zod2.z.union([import_zod2.z.looseObject({ min: import_zod2.z.number(), max: import_zod2.z.number() }), import_zod2.z.array(import_zod2.z.number())]).optional(),
2183
+ durationPresets: import_zod2.z.array(import_zod2.z.number()).optional(),
2184
+ qualityOptions: import_zod2.z.array(import_zod2.z.string()).optional(),
2185
+ exactSizes: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.string()).optional(),
1975
2186
  references: ReferenceLimitsSchema.optional(),
1976
- requires: import_zod.z.array(RequiredInputSchema).optional(),
1977
- supports: import_zod.z.array(SupportedOptionSchema).optional(),
1978
- ratioIgnoredWith: import_zod.z.array(import_zod.z.enum(["firstFrame", "sourceVideo"])).optional()
2187
+ requires: import_zod2.z.array(RequiredInputSchema).optional(),
2188
+ supports: import_zod2.z.array(SupportedOptionSchema).optional(),
2189
+ ratioIgnoredWith: import_zod2.z.array(import_zod2.z.enum(["firstFrame", "sourceVideo"])).optional()
1979
2190
  });
1980
- var MediaRefSchema = import_zod.z.union([
1981
- import_zod.z.looseObject({ url: import_zod.z.string(), label: import_zod.z.string().optional() }),
1982
- import_zod.z.looseObject({
1983
- bytes: import_zod.z.instanceof(Uint8Array),
1984
- mime: import_zod.z.string(),
1985
- label: import_zod.z.string().optional()
2191
+ var MediaRefSchema = import_zod2.z.union([
2192
+ import_zod2.z.looseObject({ url: import_zod2.z.string(), label: import_zod2.z.string().optional() }),
2193
+ import_zod2.z.looseObject({
2194
+ bytes: import_zod2.z.instanceof(Uint8Array),
2195
+ mime: import_zod2.z.string(),
2196
+ label: import_zod2.z.string().optional()
1986
2197
  })
1987
2198
  ]);
1988
- var ImageSafetySettingSchema = import_zod.z.looseObject({ category: import_zod.z.string(), threshold: import_zod.z.string() });
1989
- var UpscaleOptionsSchema = import_zod.z.looseObject({
1990
- enhanceModel: import_zod.z.string().optional(),
1991
- subjectDetection: import_zod.z.string().optional(),
1992
- faceEnhancement: import_zod.z.boolean().optional(),
1993
- faceEnhancementCreativity: import_zod.z.number().optional(),
1994
- faceEnhancementStrength: import_zod.z.number().optional()
2199
+ var ImageSafetySettingSchema = import_zod2.z.looseObject({ category: import_zod2.z.string(), threshold: import_zod2.z.string() });
2200
+ var UpscaleOptionsSchema = import_zod2.z.looseObject({
2201
+ enhanceModel: import_zod2.z.string().optional(),
2202
+ subjectDetection: import_zod2.z.string().optional(),
2203
+ faceEnhancement: import_zod2.z.boolean().optional(),
2204
+ faceEnhancementCreativity: import_zod2.z.number().optional(),
2205
+ faceEnhancementStrength: import_zod2.z.number().optional()
1995
2206
  });
1996
- var DefaultsSchema = import_zod.z.looseObject({
1997
- references: import_zod.z.array(MediaRefSchema).optional(),
2207
+ var DefaultsSchema = import_zod2.z.looseObject({
2208
+ references: import_zod2.z.array(MediaRefSchema).optional(),
1998
2209
  aspectRatio: AspectRatioSchema.optional(),
1999
2210
  size: ImageSizeSchema.optional(),
2000
- exactSize: import_zod.z.string().optional(),
2211
+ exactSize: import_zod2.z.string().optional(),
2001
2212
  quality: ImageQualitySchema.optional(),
2002
- seed: import_zod.z.number().optional(),
2003
- count: import_zod.z.number().optional(),
2213
+ seed: import_zod2.z.number().optional(),
2214
+ count: import_zod2.z.number().optional(),
2004
2215
  outputFormat: OutputFormatSchema.optional(),
2005
- scaleFactor: import_zod.z.number().optional(),
2006
- safetySettings: import_zod.z.array(ImageSafetySettingSchema).optional(),
2007
- temperature: import_zod.z.number().optional(),
2216
+ scaleFactor: import_zod2.z.number().optional(),
2217
+ safetySettings: import_zod2.z.array(ImageSafetySettingSchema).optional(),
2218
+ temperature: import_zod2.z.number().optional(),
2008
2219
  upscale: UpscaleOptionsSchema.optional(),
2009
2220
  firstFrame: MediaRefSchema.optional(),
2010
2221
  lastFrame: MediaRefSchema.optional(),
2011
2222
  sourceVideo: MediaRefSchema.optional(),
2012
- referenceImages: import_zod.z.array(MediaRefSchema).optional(),
2013
- referenceVideos: import_zod.z.array(MediaRefSchema).optional(),
2014
- referenceAudios: import_zod.z.array(MediaRefSchema).optional(),
2223
+ referenceImages: import_zod2.z.array(MediaRefSchema).optional(),
2224
+ referenceVideos: import_zod2.z.array(MediaRefSchema).optional(),
2225
+ referenceAudios: import_zod2.z.array(MediaRefSchema).optional(),
2015
2226
  resolution: VideoResolutionSchema.optional(),
2016
- durationSeconds: import_zod.z.number().optional(),
2017
- generateAudio: import_zod.z.boolean().optional(),
2018
- negativePrompt: import_zod.z.string().optional(),
2019
- cfgScale: import_zod.z.number().optional(),
2020
- promptExpansion: import_zod.z.enum(["fast", "balanced", "quality"]).optional(),
2021
- watermark: import_zod.z.boolean().optional(),
2022
- safetyChecker: import_zod.z.boolean().optional(),
2023
- taskType: import_zod.z.enum(["reference", "edit", "extend"]).optional(),
2024
- mode: import_zod.z.enum(["standard", "pro"]).optional(),
2025
- instrumental: import_zod.z.boolean().optional()
2227
+ durationSeconds: import_zod2.z.number().optional(),
2228
+ generateAudio: import_zod2.z.boolean().optional(),
2229
+ negativePrompt: import_zod2.z.string().optional(),
2230
+ cfgScale: import_zod2.z.number().optional(),
2231
+ promptExpansion: import_zod2.z.enum(["fast", "balanced", "quality"]).optional(),
2232
+ watermark: import_zod2.z.boolean().optional(),
2233
+ safetyChecker: import_zod2.z.boolean().optional(),
2234
+ taskType: import_zod2.z.enum(["reference", "edit", "extend"]).optional(),
2235
+ mode: import_zod2.z.enum(["standard", "pro"]).optional(),
2236
+ instrumental: import_zod2.z.boolean().optional()
2026
2237
  });
2027
- var CatalogDisplaySchema = import_zod.z.looseObject({
2028
- provider: import_zod.z.string(),
2029
- description: import_zod.z.string(),
2030
- logo: import_zod.z.string().optional(),
2031
- costTier: import_zod.z.union([import_zod.z.literal(1), import_zod.z.literal(2), import_zod.z.literal(3)]).optional(),
2032
- recommended: import_zod.z.boolean().optional(),
2033
- sortOrder: import_zod.z.number().optional(),
2034
- chat: import_zod.z.looseObject({
2238
+ var CatalogDisplaySchema = import_zod2.z.looseObject({
2239
+ provider: import_zod2.z.string(),
2240
+ description: import_zod2.z.string(),
2241
+ logo: import_zod2.z.string().optional(),
2242
+ costTier: import_zod2.z.union([import_zod2.z.literal(1), import_zod2.z.literal(2), import_zod2.z.literal(3)]).optional(),
2243
+ recommended: import_zod2.z.boolean().optional(),
2244
+ sortOrder: import_zod2.z.number().optional(),
2245
+ chat: import_zod2.z.looseObject({
2035
2246
  providerOptions: ProviderOptionsSchema.optional(),
2036
- temperature: import_zod.z.number().optional()
2247
+ temperature: import_zod2.z.number().optional()
2037
2248
  }).optional()
2038
2249
  });
2039
- var CatalogCapabilitiesSchema = import_zod.z.looseObject({
2040
- acceptsSourceVideo: import_zod.z.boolean().optional(),
2041
- framesExcludeReferences: import_zod.z.boolean().optional(),
2042
- reasoning: import_zod.z.boolean().optional(),
2043
- vision: import_zod.z.boolean().optional(),
2044
- contextWindow: import_zod.z.number().optional()
2250
+ var CatalogCapabilitiesSchema = import_zod2.z.looseObject({
2251
+ acceptsSourceVideo: import_zod2.z.boolean().optional(),
2252
+ framesExcludeReferences: import_zod2.z.boolean().optional(),
2253
+ reasoning: import_zod2.z.boolean().optional(),
2254
+ vision: import_zod2.z.boolean().optional(),
2255
+ contextWindow: import_zod2.z.number().optional()
2045
2256
  });
2046
- var CatalogModelSchemaBase = import_zod.z.looseObject({
2047
- id: import_zod.z.string().min(1),
2048
- aliases: import_zod.z.array(import_zod.z.string()).default([]),
2049
- label: import_zod.z.string().min(1),
2257
+ var CatalogModelSchemaBase = import_zod2.z.looseObject({
2258
+ id: import_zod2.z.string().min(1),
2259
+ aliases: import_zod2.z.array(import_zod2.z.string()).default([]),
2260
+ label: import_zod2.z.string().min(1),
2050
2261
  type: ModelTypeSchema,
2051
2262
  adapter: AdapterSchema,
2052
- providerModelId: import_zod.z.string().min(1),
2263
+ providerModelId: import_zod2.z.string().min(1),
2053
2264
  lifecycle: LifecycleSchema,
2054
- replacedBy: import_zod.z.string().optional(),
2265
+ replacedBy: import_zod2.z.string().optional(),
2055
2266
  exposure: ExposureSchema,
2056
2267
  constraints: ModelConstraintsSchema,
2057
2268
  defaults: DefaultsSchema,
2058
2269
  providerOptions: ProviderOptionsSchema.optional(),
2059
- usage: import_zod.z.looseObject({
2270
+ usage: import_zod2.z.looseObject({
2060
2271
  unit: UsageUnitSchema,
2061
- slug: import_zod.z.string().optional(),
2062
- providerLabel: import_zod.z.string().optional()
2272
+ slug: import_zod2.z.string().optional(),
2273
+ providerLabel: import_zod2.z.string().optional()
2063
2274
  }),
2064
2275
  pricingKind: PricingKindSchema,
2065
2276
  display: CatalogDisplaySchema.optional(),
@@ -2097,44 +2308,29 @@ var CatalogModelSchema = CatalogModelSchemaBase.superRefine(
2097
2308
  message: 'transport must be "direct" or "bedrock"'
2098
2309
  });
2099
2310
  }
2311
+ const inputSpecRaw = row.providerOptions?.["modelkit"]?.["inputSpec"];
2312
+ if (inputSpecRaw !== void 0) {
2313
+ const result = validateInputSpec(inputSpecRaw, row);
2314
+ if (!result.ok) {
2315
+ for (const issue of result.issues) {
2316
+ ctx.addIssue({
2317
+ code: "custom",
2318
+ path: ["providerOptions", "modelkit", "inputSpec", ...issue.path],
2319
+ message: issue.message
2320
+ });
2321
+ }
2322
+ }
2323
+ }
2100
2324
  }
2101
2325
  );
2102
- var CatalogSchema = import_zod.z.array(CatalogModelSchemaBase).superRefine((rows, ctx) => {
2103
- const seenIds = /* @__PURE__ */ new Map();
2104
- rows.forEach((row, index) => {
2105
- if (seenIds.has(row.id)) {
2106
- ctx.addIssue({
2107
- code: "custom",
2108
- path: [index, "id"],
2109
- message: `Duplicate model id "${row.id}"`
2110
- });
2111
- } else {
2112
- seenIds.set(row.id, index);
2113
- }
2114
- });
2115
- const seenAliases = /* @__PURE__ */ new Map();
2116
- rows.forEach((row, index) => {
2117
- row.aliases.forEach((alias, aliasIndex) => {
2118
- const path = [index, "aliases", aliasIndex];
2119
- if (alias === row.id || seenIds.has(alias)) {
2120
- ctx.addIssue({
2121
- code: "custom",
2122
- path,
2123
- message: `Alias "${alias}" collides with a model id`
2124
- });
2125
- return;
2126
- }
2127
- if (seenAliases.has(alias)) {
2128
- ctx.addIssue({
2129
- code: "custom",
2130
- path,
2131
- message: `Duplicate alias "${alias}"`
2132
- });
2133
- } else {
2134
- seenAliases.set(alias, index);
2135
- }
2326
+ var CatalogSchema = import_zod2.z.array(CatalogModelSchemaBase).superRefine((rows, ctx) => {
2327
+ for (const issue of collisionIssues(rows)) {
2328
+ ctx.addIssue({
2329
+ code: "custom",
2330
+ path: [issue.index, ...issue.path],
2331
+ message: issue.message
2136
2332
  });
2137
- });
2333
+ }
2138
2334
  });
2139
2335
 
2140
2336
  // src/catalog/live.ts
@@ -2149,26 +2345,102 @@ var liveState = store[KEY] ??= {
2149
2345
  };
2150
2346
  var liveCatalog = liveState.catalog;
2151
2347
 
2348
+ // src/json.ts
2349
+ var import_zod3 = require("zod");
2350
+ var JsonValueSchema = import_zod3.z.lazy(
2351
+ () => import_zod3.z.union([
2352
+ import_zod3.z.string(),
2353
+ import_zod3.z.number(),
2354
+ import_zod3.z.boolean(),
2355
+ import_zod3.z.null(),
2356
+ import_zod3.z.array(JsonValueSchema),
2357
+ import_zod3.z.record(import_zod3.z.string(), JsonValueSchema)
2358
+ ])
2359
+ );
2360
+ var JsonObjectSchema = import_zod3.z.record(import_zod3.z.string(), JsonValueSchema);
2361
+ var thrownErrorSchema = import_zod3.z.object({
2362
+ message: import_zod3.z.string().optional(),
2363
+ status: import_zod3.z.number().optional(),
2364
+ statusCode: import_zod3.z.number().optional(),
2365
+ responseBody: import_zod3.z.string().optional()
2366
+ });
2367
+
2152
2368
  // src/catalog/load.ts
2153
- var import_zod2 = require("zod");
2369
+ var import_zod4 = require("zod");
2154
2370
  function rowCount() {
2155
2371
  return liveCatalog.list({ lifecycle: ["active", "deprecated", "retired"] }).length;
2156
2372
  }
2157
2373
  function authHeaders(auth) {
2158
2374
  return "bearer" in auth ? { Authorization: `Bearer ${auth.bearer}` } : { "x-api-key": auth.apiKey };
2159
2375
  }
2160
- var EnvelopeSchema = import_zod2.z.object({
2161
- rows: CatalogSchema,
2162
- revision: import_zod2.z.string().optional()
2376
+ var EnvelopeSchema = import_zod4.z.object({
2377
+ rows: import_zod4.z.array(JsonValueSchema),
2378
+ revision: import_zod4.z.string().optional()
2163
2379
  });
2164
- function toEnvelope(data) {
2165
- if (data.rows.length === 0) throw new Error("invalid catalog response: no rows");
2166
- const envelope = { rows: data.rows };
2380
+ function dropReason(path, message) {
2381
+ return path.length === 0 ? message : `${path.map((part) => String(part)).join(".")} ${message}`;
2382
+ }
2383
+ function rowId(raw) {
2384
+ const parsed = import_zod4.z.object({ id: import_zod4.z.string().min(1) }).loose().safeParse(raw);
2385
+ if (!parsed.success) return "?";
2386
+ return parsed.data.id;
2387
+ }
2388
+ function quarantine(rawRows, logger) {
2389
+ const valid = [];
2390
+ let dropped = 0;
2391
+ for (const raw of rawRows) {
2392
+ const parsed = CatalogModelSchemaBase.safeParse(raw);
2393
+ if (!parsed.success) {
2394
+ const first = parsed.error.issues[0];
2395
+ const reason = first ? dropReason(first.path, first.message) : "invalid row";
2396
+ logger.warn(`[modelkit] catalog row dropped id=${rowId(raw)} reason=${reason}`);
2397
+ dropped += 1;
2398
+ continue;
2399
+ }
2400
+ const row = parsed.data;
2401
+ const inputSpecRaw = row.providerOptions?.["modelkit"]?.["inputSpec"];
2402
+ if (inputSpecRaw !== void 0) {
2403
+ const result = validateInputSpec(inputSpecRaw, row);
2404
+ if (!result.ok) {
2405
+ const first = result.issues[0];
2406
+ const detail = first ? dropReason(first.path, first.message) : "invalid inputSpec";
2407
+ logger.warn(
2408
+ `[modelkit] catalog row ${row.id} has an invalid providerOptions.modelkit.inputSpec: ${detail}; calls fail until it is fixed`
2409
+ );
2410
+ }
2411
+ }
2412
+ valid.push(row);
2413
+ }
2414
+ let kept = valid;
2415
+ for (; ; ) {
2416
+ const issues = collisionIssues(kept);
2417
+ if (issues.length === 0) break;
2418
+ const firstByIndex = /* @__PURE__ */ new Map();
2419
+ for (const issue of issues) {
2420
+ if (!firstByIndex.has(issue.index)) firstByIndex.set(issue.index, issue);
2421
+ }
2422
+ for (const [index, issue] of [...firstByIndex.entries()].sort((a, b) => a[0] - b[0])) {
2423
+ const row = kept[index];
2424
+ if (!row) continue;
2425
+ logger.warn(
2426
+ `[modelkit] catalog row dropped id=${row.id} reason=${String(issue.path[0] ?? "")} ${issue.message}`
2427
+ );
2428
+ }
2429
+ const dropSet = new Set(firstByIndex.keys());
2430
+ kept = kept.filter((_, index) => !dropSet.has(index));
2431
+ dropped += dropSet.size;
2432
+ }
2433
+ return { rows: kept, dropped };
2434
+ }
2435
+ function toEnvelope(data, logger) {
2436
+ const { rows, dropped } = quarantine(data.rows, logger);
2437
+ if (rows.length === 0) throw new Error("invalid catalog response: no rows");
2438
+ const envelope = { rows, dropped };
2167
2439
  if (data.revision !== void 0) envelope.revision = data.revision;
2168
2440
  return envelope;
2169
2441
  }
2170
- function describeError(err) {
2171
- return err instanceof Error ? err.message : String(err);
2442
+ function describeError(cause) {
2443
+ return cause instanceof Error ? cause.message : String(cause);
2172
2444
  }
2173
2445
  function logPrimed(logger, result) {
2174
2446
  const revision = result.revision === void 0 ? "" : ` revision=${result.revision}`;
@@ -2189,9 +2461,9 @@ async function fetchRemote(source, logger) {
2189
2461
  const json = await res.json();
2190
2462
  const parsed = EnvelopeSchema.safeParse(json);
2191
2463
  if (!parsed.success) throw new Error("invalid catalog response: missing rows");
2192
- const { rows, revision: rev } = toEnvelope(parsed.data);
2193
- if (rev === void 0) return { rows, fromCache: false };
2194
- return { rows, revision: rev, fromCache: false };
2464
+ const { rows, revision: rev, dropped } = toEnvelope(parsed.data, logger);
2465
+ if (rev === void 0) return { rows, fromCache: false, dropped };
2466
+ return { rows, revision: rev, fromCache: false, dropped };
2195
2467
  }
2196
2468
  async function writeCache(source, logger, rows, rev) {
2197
2469
  if (!source.cache) return;
@@ -2216,6 +2488,7 @@ async function prime(source, logger) {
2216
2488
  await writeCache(source, logger, fetched.rows, fetched.revision);
2217
2489
  const result = { origin: liveState.origin, rowCount: rowCount() };
2218
2490
  if (fetched.revision !== void 0) result.revision = fetched.revision;
2491
+ if (fetched.dropped > 0) result.droppedRows = fetched.dropped;
2219
2492
  logPrimed(logger, result);
2220
2493
  return result;
2221
2494
  } catch (err) {
@@ -2226,7 +2499,7 @@ async function prime(source, logger) {
2226
2499
  if (!cached) throw new Error("no cached catalog");
2227
2500
  const cachedParsed = EnvelopeSchema.safeParse(JSON.parse(cached));
2228
2501
  if (!cachedParsed.success) throw new Error("invalid catalog response: missing rows");
2229
- const { rows, revision: rev } = toEnvelope(cachedParsed.data);
2502
+ const { rows, revision: rev, dropped } = toEnvelope(cachedParsed.data, logger);
2230
2503
  liveCatalog.replace(rows);
2231
2504
  liveState.origin = "last-good";
2232
2505
  liveState.revision = rev;
@@ -2236,6 +2509,7 @@ async function prime(source, logger) {
2236
2509
  error
2237
2510
  };
2238
2511
  if (rev !== void 0) result.revision = rev;
2512
+ if (dropped > 0) result.droppedRows = dropped;
2239
2513
  logPrimed(logger, result);
2240
2514
  return result;
2241
2515
  } catch (cacheErr) {