@m5kdev/commons 0.31.6 → 0.31.7

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.
@@ -1 +1 @@
1
- {"version":3,"file":"ai.utils.cjs","names":["TOKEN_PRESETS","RANKED_MODELS"],"sources":["../../../../src/modules/ai/ai.utils.ts"],"sourcesContent":["import { RANKED_MODELS, TOKEN_PRESETS } from \"./ai.constants\";\r\nimport type { Category, RankedModel, SortType, TokenProfile, TokenSize } from \"./ai.types\";\r\n\r\nexport function getDefaultTokenProfile(category: Category): TokenProfile {\r\n switch (category) {\r\n case \"structured_output\":\r\n return { inputTokens: TOKEN_PRESETS.lg, outputTokens: TOKEN_PRESETS.md };\r\n case \"creative\":\r\n return { inputTokens: TOKEN_PRESETS.md, outputTokens: TOKEN_PRESETS.lg };\r\n case \"research\":\r\n return { inputTokens: TOKEN_PRESETS.xl, outputTokens: TOKEN_PRESETS.xl };\r\n case \"chat\":\r\n return { inputTokens: TOKEN_PRESETS.sm, outputTokens: TOKEN_PRESETS.md };\r\n case \"tool_use\":\r\n return { inputTokens: TOKEN_PRESETS.md, outputTokens: TOKEN_PRESETS.sm };\r\n case \"planning\":\r\n return { inputTokens: TOKEN_PRESETS.lg, outputTokens: TOKEN_PRESETS.lg };\r\n case \"classification\":\r\n return { inputTokens: TOKEN_PRESETS.sm, outputTokens: TOKEN_PRESETS.xs };\r\n default:\r\n return { inputTokens: TOKEN_PRESETS.md, outputTokens: TOKEN_PRESETS.md };\r\n }\r\n}\r\n\r\nexport function getDefaultWeights(\r\n weights?: SortType | [SortType, SortType, SortType] | [number, number, number]\r\n): [number, number, number] {\r\n if (Array.isArray(weights)) {\r\n return weights.every((weight) => typeof weight === \"number\")\r\n ? weights\r\n : weights.reduce<[number, number, number]>(\r\n (acc, weight, index) => {\r\n switch (weight) {\r\n case \"quality\":\r\n acc[0] = index === 0 ? 50 : index === 1 ? 30 : 20;\r\n break;\r\n case \"price\":\r\n acc[1] = index === 0 ? 50 : index === 1 ? 30 : 20;\r\n break;\r\n case \"speed\":\r\n acc[2] = index === 0 ? 50 : index === 1 ? 30 : 20;\r\n break;\r\n }\r\n return acc;\r\n },\r\n [20, 50, 30]\r\n );\r\n }\r\n switch (weights) {\r\n case \"quality\":\r\n return [50, 30, 20];\r\n case \"price\":\r\n return [20, 50, 30];\r\n case \"speed\":\r\n return [20, 30, 50];\r\n default:\r\n return [50, 25, 25];\r\n }\r\n}\r\n\r\nexport function weightsToPriceSensitivity(weights: [number, number, number]): number {\r\n const [qualityWeight, priceWeight, speedWeight] = weights;\r\n\r\n const total = qualityWeight + priceWeight + speedWeight;\r\n\r\n if (total <= 0) {\r\n return 1;\r\n }\r\n\r\n const normalizedPriceWeight = priceWeight / total;\r\n\r\n const min = 0.55; // very price-sensitive\r\n const max = 1.75; // price is soft / secondary\r\n\r\n // Higher price weight -> lower exponent -> stronger price penalty.\r\n const sensitivity = max - normalizedPriceWeight * (max - min);\r\n\r\n return Number(sensitivity.toFixed(3));\r\n}\r\n\r\nexport function addPriceScores(\r\n models: RankedModel[],\r\n profile: TokenProfile,\r\n priceSensitivity = 1\r\n): Array<RankedModel & { price: number; estimatedCost: number }> {\r\n const costs = models.map((model) => {\r\n return (\r\n (profile.inputTokens / 1_000_000) * model.inputCost +\r\n (profile.outputTokens / 1_000_000) * model.outputCost\r\n );\r\n });\r\n\r\n const cheapest = Math.min(...costs);\r\n const mostExpensive = Math.max(...costs);\r\n\r\n return models.map((model, index) => {\r\n const cost = costs[index];\r\n\r\n if (mostExpensive === cheapest) {\r\n return {\r\n ...model,\r\n estimatedCost: cost,\r\n price: 10,\r\n };\r\n }\r\n\r\n const safeCheapest = Math.max(cheapest, Number.EPSILON);\r\n const safeCost = Math.max(cost, Number.EPSILON);\r\n const safeMostExpensive = Math.max(mostExpensive, Number.EPSILON);\r\n\r\n const logMin = Math.log(safeCheapest);\r\n const logMax = Math.log(safeMostExpensive);\r\n const logCost = Math.log(safeCost);\r\n\r\n const normalizedRaw = (logCost - logMin) / (logMax - logMin);\r\n\r\n // < 1 makes price matter less.\r\n // > 1 makes price matter more.\r\n const normalized = normalizedRaw ** priceSensitivity;\r\n\r\n return {\r\n ...model,\r\n estimatedCost: cost,\r\n price: Math.round(10 - normalized * 9),\r\n };\r\n });\r\n}\r\n\r\nfunction clampScore(value: number): number {\r\n return Math.max(1, Math.min(10, value));\r\n}\r\n\r\nfunction shapeScoreByWeight(value: number, weight: number, maxWeight: number): number {\r\n const score = clampScore(value);\r\n const normalized = score / 10;\r\n\r\n if (maxWeight <= 0 || weight <= 0) {\r\n return 0;\r\n }\r\n\r\n const importance = (weight / maxWeight) ** 2;\r\n const expanded = normalized ** 2 * 10;\r\n const compressed = 8 + normalized * 2;\r\n return compressed + (expanded - compressed) * importance;\r\n}\r\n\r\nexport function rankModels(\r\n models: RankedModel[],\r\n profile: TokenProfile,\r\n category: Category,\r\n weights: [number, number, number]\r\n) {\r\n const scoredModels = addPriceScores(models, profile, weightsToPriceSensitivity(weights));\r\n\r\n const [qualityWeight, priceWeight, speedWeight] = weights;\r\n const maxWeight = Math.max(qualityWeight, priceWeight, speedWeight);\r\n\r\n return scoredModels\r\n .map((model) => {\r\n const qualityScore = shapeScoreByWeight(model.quality[category], qualityWeight, maxWeight);\r\n\r\n const priceScore = shapeScoreByWeight(model.price, priceWeight, maxWeight);\r\n\r\n const speedScore = shapeScoreByWeight(model.speed, speedWeight, maxWeight);\r\n\r\n return {\r\n ...model,\r\n score: qualityScore * qualityWeight + priceScore * priceWeight + speedScore * speedWeight,\r\n };\r\n })\r\n .sort((a, b) => b.score - a.score);\r\n}\r\n\r\nexport function getSortedRankedModel(\r\n models: RankedModel[],\r\n category: Category = \"chat\",\r\n weights?: SortType | [SortType, SortType, SortType] | [number, number, number],\r\n tokenProfile?: TokenProfile | number | TokenSize,\r\n filter?: (model: RankedModel) => boolean\r\n): RankedModel[] {\r\n const profile =\r\n typeof tokenProfile === \"string\"\r\n ? {\r\n inputTokens: TOKEN_PRESETS[tokenProfile as TokenSize],\r\n outputTokens: TOKEN_PRESETS[tokenProfile as TokenSize],\r\n }\r\n : typeof tokenProfile === \"number\"\r\n ? { inputTokens: tokenProfile, outputTokens: tokenProfile }\r\n : tokenProfile\r\n ? (tokenProfile as TokenProfile)\r\n : getDefaultTokenProfile(category);\r\n const rankedModels = rankModels(models, profile, category, getDefaultWeights(weights));\r\n return filter ? rankedModels.filter(filter) : rankedModels;\r\n}\r\n\r\nexport function getSortedRecommendedModels(\r\n category: Category = \"chat\",\r\n weights?: SortType | [SortType, SortType, SortType] | [number, number, number],\r\n tokenProfile?: TokenProfile | number | TokenSize,\r\n filter?: (model: RankedModel) => boolean\r\n): RankedModel[] {\r\n return getSortedRankedModel(RANKED_MODELS, category, weights, tokenProfile, filter);\r\n}\r\n\r\nexport function getSortedRecommendedModelIds(\r\n category: Category = \"chat\",\r\n weights?: SortType | [SortType, SortType, SortType] | [number, number, number],\r\n tokenProfile?: TokenProfile | number | TokenSize,\r\n filter?: (model: RankedModel) => boolean\r\n): string[] {\r\n return getSortedRankedModel(RANKED_MODELS, category, weights, tokenProfile, filter).map(\r\n (model) => model.id\r\n );\r\n}\r\n\r\nexport function arrayToPseudoXML<T extends Record<string, unknown>>(\r\n array: readonly T[],\r\n keys: readonly (keyof T)[],\r\n name = \"item\"\r\n): string {\r\n return array\r\n .map(\r\n (item) =>\r\n `<${name}>${keys\r\n .map((key) => `<${String(key)}>${String(item[key])}</${String(key)}>`)\r\n .join(\"\\n\")}</${name}>`\r\n )\r\n .join(\"\\n\");\r\n}\r\n"],"mappings":"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"}
1
+ {"version":3,"file":"ai.utils.cjs","names":["TOKEN_PRESETS","RANKED_MODELS"],"sources":["../../../../src/modules/ai/ai.utils.ts"],"sourcesContent":["import { RANKED_MODELS, TOKEN_PRESETS } from \"./ai.constants\";\r\nimport type { Category, RankedModel, SortType, TokenProfile, TokenSize } from \"./ai.types\";\r\n\r\nexport function getDefaultTokenProfile(category: Category): TokenProfile {\r\n switch (category) {\r\n case \"structured_output\":\r\n return { inputTokens: TOKEN_PRESETS.lg, outputTokens: TOKEN_PRESETS.md };\r\n case \"creative\":\r\n return { inputTokens: TOKEN_PRESETS.md, outputTokens: TOKEN_PRESETS.lg };\r\n case \"research\":\r\n return { inputTokens: TOKEN_PRESETS.xl, outputTokens: TOKEN_PRESETS.xl };\r\n case \"chat\":\r\n return { inputTokens: TOKEN_PRESETS.sm, outputTokens: TOKEN_PRESETS.md };\r\n case \"tool_use\":\r\n return { inputTokens: TOKEN_PRESETS.md, outputTokens: TOKEN_PRESETS.sm };\r\n case \"planning\":\r\n return { inputTokens: TOKEN_PRESETS.lg, outputTokens: TOKEN_PRESETS.lg };\r\n case \"classification\":\r\n return { inputTokens: TOKEN_PRESETS.sm, outputTokens: TOKEN_PRESETS.xs };\r\n default:\r\n return { inputTokens: TOKEN_PRESETS.md, outputTokens: TOKEN_PRESETS.md };\r\n }\r\n}\r\n\r\nexport function getDefaultWeights(\r\n weights?: SortType | [SortType, SortType, SortType] | [number, number, number]\r\n): [number, number, number] {\r\n if (Array.isArray(weights)) {\r\n return weights.every((weight) => typeof weight === \"number\")\r\n ? weights\r\n : weights.reduce<[number, number, number]>(\r\n (acc, weight, index) => {\r\n switch (weight) {\r\n case \"quality\":\r\n acc[0] = index === 0 ? 50 : index === 1 ? 30 : 20;\r\n break;\r\n case \"price\":\r\n acc[1] = index === 0 ? 50 : index === 1 ? 30 : 20;\r\n break;\r\n case \"speed\":\r\n acc[2] = index === 0 ? 50 : index === 1 ? 30 : 20;\r\n break;\r\n }\r\n return acc;\r\n },\r\n [20, 50, 30]\r\n );\r\n }\r\n switch (weights) {\r\n case \"quality\":\r\n return [50, 30, 20];\r\n case \"price\":\r\n return [20, 50, 30];\r\n case \"speed\":\r\n return [20, 30, 50];\r\n default:\r\n return [50, 25, 25];\r\n }\r\n}\r\n\r\nexport function weightsToPriceSensitivity(weights: [number, number, number]): number {\r\n const [qualityWeight, priceWeight, speedWeight] = weights;\r\n\r\n const total = qualityWeight + priceWeight + speedWeight;\r\n\r\n if (total <= 0) {\r\n return 1;\r\n }\r\n\r\n const normalizedPriceWeight = priceWeight / total;\r\n\r\n const min = 0.55; // very price-sensitive\r\n const max = 1.75; // price is soft / secondary\r\n\r\n // Higher price weight -> lower exponent -> stronger price penalty.\r\n const sensitivity = max - normalizedPriceWeight * (max - min);\r\n\r\n return Number(sensitivity.toFixed(3));\r\n}\r\n\r\nexport function addPriceScores(\r\n models: RankedModel[],\r\n profile: TokenProfile,\r\n priceSensitivity = 1\r\n): Array<RankedModel & { price: number; estimatedCost: number }> {\r\n const costs = models.map((model) => {\r\n return (\r\n (profile.inputTokens / 1_000_000) * model.inputCost +\r\n (profile.outputTokens / 1_000_000) * model.outputCost\r\n );\r\n });\r\n\r\n const cheapest = Math.min(...costs);\r\n const mostExpensive = Math.max(...costs);\r\n\r\n return models.map((model, index) => {\r\n const cost = costs[index];\r\n\r\n if (mostExpensive === cheapest) {\r\n return {\r\n ...model,\r\n estimatedCost: cost,\r\n price: 10,\r\n };\r\n }\r\n\r\n const safeCheapest = Math.max(cheapest, Number.EPSILON);\r\n const safeCost = Math.max(cost, Number.EPSILON);\r\n const safeMostExpensive = Math.max(mostExpensive, Number.EPSILON);\r\n\r\n const logMin = Math.log(safeCheapest);\r\n const logMax = Math.log(safeMostExpensive);\r\n const logCost = Math.log(safeCost);\r\n\r\n const normalizedRaw = (logCost - logMin) / (logMax - logMin);\r\n\r\n // < 1 makes price matter less.\r\n // > 1 makes price matter more.\r\n const normalized = normalizedRaw ** priceSensitivity;\r\n\r\n return {\r\n ...model,\r\n estimatedCost: cost,\r\n price: Math.round(10 - normalized * 9),\r\n };\r\n });\r\n}\r\n\r\nfunction clampScore(value: number): number {\r\n return Math.max(1, Math.min(10, value));\r\n}\r\n\r\nfunction getMedian(values: number[]): number | undefined {\r\n if (values.length === 0) return undefined;\r\n\r\n const sorted = [...values].sort((a, b) => a - b);\r\n const middle = Math.floor(sorted.length / 2);\r\n\r\n return sorted.length % 2 === 0\r\n ? ((sorted[middle - 1] ?? 0) + (sorted[middle] ?? 0)) / 2\r\n : sorted[middle];\r\n}\r\n\r\nexport function addSpeedScores<Model extends RankedModel>(\r\n models: Model[]\r\n): Array<Model & { speedScore: number }> {\r\n const measuredResponseTimes = models\r\n .map((model) => model.responseTimeSeconds)\r\n .filter(\r\n (responseTime): responseTime is number =>\r\n responseTime !== undefined && Number.isFinite(responseTime) && responseTime > 0\r\n );\r\n const medianResponseTime = getMedian(measuredResponseTimes);\r\n\r\n if (medianResponseTime === undefined) {\r\n return models.map((model) => ({ ...model, speedScore: 10 }));\r\n }\r\n\r\n const fastestResponseTime = Math.min(...measuredResponseTimes);\r\n\r\n return models.map((model) => {\r\n const responseTime =\r\n model.responseTimeSeconds !== undefined &&\r\n Number.isFinite(model.responseTimeSeconds) &&\r\n model.responseTimeSeconds > 0\r\n ? model.responseTimeSeconds\r\n : medianResponseTime;\r\n\r\n return {\r\n ...model,\r\n speedScore: 10 * (fastestResponseTime / responseTime),\r\n };\r\n });\r\n}\r\n\r\nfunction shapeScoreByWeight(value: number, weight: number, maxWeight: number): number {\r\n const score = clampScore(value);\r\n const normalized = score / 10;\r\n\r\n if (maxWeight <= 0 || weight <= 0) {\r\n return 0;\r\n }\r\n\r\n const importance = (weight / maxWeight) ** 2;\r\n const expanded = normalized ** 2 * 10;\r\n const compressed = 8 + normalized * 2;\r\n return compressed + (expanded - compressed) * importance;\r\n}\r\n\r\nfunction shapeSpeedScoreByWeight(value: number, weight: number, maxWeight: number): number {\r\n if (maxWeight <= 0 || weight <= 0) {\r\n return 0;\r\n }\r\n\r\n const normalized = Math.max(0, Math.min(10, value)) / 10;\r\n const importance = (weight / maxWeight) ** 2;\r\n\r\n return (1 - (1 - normalized) * importance) * 10;\r\n}\r\n\r\nexport function rankModels(\r\n models: RankedModel[],\r\n profile: TokenProfile,\r\n category: Category,\r\n weights: [number, number, number]\r\n) {\r\n const scoredModels = addSpeedScores(\r\n addPriceScores(models, profile, weightsToPriceSensitivity(weights))\r\n );\r\n\r\n const [qualityWeight, priceWeight, speedWeight] = weights;\r\n const maxWeight = Math.max(qualityWeight, priceWeight, speedWeight);\r\n\r\n return scoredModels\r\n .map((model) => {\r\n const qualityScore = shapeScoreByWeight(model.quality[category], qualityWeight, maxWeight);\r\n\r\n const priceScore = shapeScoreByWeight(model.price, priceWeight, maxWeight);\r\n\r\n const speedScore = shapeSpeedScoreByWeight(model.speedScore, speedWeight, maxWeight);\r\n\r\n return {\r\n ...model,\r\n score: qualityScore * qualityWeight + priceScore * priceWeight + speedScore * speedWeight,\r\n };\r\n })\r\n .sort((a, b) => b.score - a.score);\r\n}\r\n\r\nexport function getSortedRankedModel(\r\n models: RankedModel[],\r\n category: Category = \"chat\",\r\n weights?: SortType | [SortType, SortType, SortType] | [number, number, number],\r\n tokenProfile?: TokenProfile | number | TokenSize,\r\n filter?: (model: RankedModel) => boolean\r\n): RankedModel[] {\r\n const profile =\r\n typeof tokenProfile === \"string\"\r\n ? {\r\n inputTokens: TOKEN_PRESETS[tokenProfile as TokenSize],\r\n outputTokens: TOKEN_PRESETS[tokenProfile as TokenSize],\r\n }\r\n : typeof tokenProfile === \"number\"\r\n ? { inputTokens: tokenProfile, outputTokens: tokenProfile }\r\n : tokenProfile\r\n ? (tokenProfile as TokenProfile)\r\n : getDefaultTokenProfile(category);\r\n const rankedModels = rankModels(models, profile, category, getDefaultWeights(weights));\r\n return filter ? rankedModels.filter(filter) : rankedModels;\r\n}\r\n\r\nexport function getSortedRecommendedModels(\r\n category: Category = \"chat\",\r\n weights?: SortType | [SortType, SortType, SortType] | [number, number, number],\r\n tokenProfile?: TokenProfile | number | TokenSize,\r\n filter?: (model: RankedModel) => boolean\r\n): RankedModel[] {\r\n return getSortedRankedModel(RANKED_MODELS, category, weights, tokenProfile, filter);\r\n}\r\n\r\nexport function getSortedRecommendedModelIds(\r\n category: Category = \"chat\",\r\n weights?: SortType | [SortType, SortType, SortType] | [number, number, number],\r\n tokenProfile?: TokenProfile | number | TokenSize,\r\n filter?: (model: RankedModel) => boolean\r\n): string[] {\r\n return getSortedRankedModel(RANKED_MODELS, category, weights, tokenProfile, filter).map(\r\n (model) => model.id\r\n );\r\n}\r\n\r\nexport function arrayToPseudoXML<T extends Record<string, unknown>>(\r\n array: readonly T[],\r\n keys: readonly (keyof T)[],\r\n name = \"item\"\r\n): string {\r\n return array\r\n .map(\r\n (item) =>\r\n `<${name}>${keys\r\n .map((key) => `<${String(key)}>${String(item[key])}</${String(key)}>`)\r\n .join(\"\\n\")}</${name}>`\r\n )\r\n .join(\"\\n\");\r\n}\r\n"],"mappings":";;;;AAGA,SAAgB,uBAAuB,UAAkC;AACvE,SAAQ,UAAR;EACE,KAAK,oBACH,QAAO;GAAE,aAAaA,oCAAAA,cAAc;GAAI,cAAcA,oCAAAA,cAAc;GAAI;EAC1E,KAAK,WACH,QAAO;GAAE,aAAaA,oCAAAA,cAAc;GAAI,cAAcA,oCAAAA,cAAc;GAAI;EAC1E,KAAK,WACH,QAAO;GAAE,aAAaA,oCAAAA,cAAc;GAAI,cAAcA,oCAAAA,cAAc;GAAI;EAC1E,KAAK,OACH,QAAO;GAAE,aAAaA,oCAAAA,cAAc;GAAI,cAAcA,oCAAAA,cAAc;GAAI;EAC1E,KAAK,WACH,QAAO;GAAE,aAAaA,oCAAAA,cAAc;GAAI,cAAcA,oCAAAA,cAAc;GAAI;EAC1E,KAAK,WACH,QAAO;GAAE,aAAaA,oCAAAA,cAAc;GAAI,cAAcA,oCAAAA,cAAc;GAAI;EAC1E,KAAK,iBACH,QAAO;GAAE,aAAaA,oCAAAA,cAAc;GAAI,cAAcA,oCAAAA,cAAc;GAAI;EAC1E,QACE,QAAO;GAAE,aAAaA,oCAAAA,cAAc;GAAI,cAAcA,oCAAAA,cAAc;GAAI;;;AAI9E,SAAgB,kBACd,SAC0B;AAC1B,KAAI,MAAM,QAAQ,QAAQ,CACxB,QAAO,QAAQ,OAAO,WAAW,OAAO,WAAW,SAAS,GACxD,UACA,QAAQ,QACL,KAAK,QAAQ,UAAU;AACtB,UAAQ,QAAR;GACE,KAAK;AACH,QAAI,KAAK,UAAU,IAAI,KAAK,UAAU,IAAI,KAAK;AAC/C;GACF,KAAK;AACH,QAAI,KAAK,UAAU,IAAI,KAAK,UAAU,IAAI,KAAK;AAC/C;GACF,KAAK;AACH,QAAI,KAAK,UAAU,IAAI,KAAK,UAAU,IAAI,KAAK;AAC/C;;AAEJ,SAAO;IAET;EAAC;EAAI;EAAI;EAAG,CACb;AAEP,SAAQ,SAAR;EACE,KAAK,UACH,QAAO;GAAC;GAAI;GAAI;GAAG;EACrB,KAAK,QACH,QAAO;GAAC;GAAI;GAAI;GAAG;EACrB,KAAK,QACH,QAAO;GAAC;GAAI;GAAI;GAAG;EACrB,QACE,QAAO;GAAC;GAAI;GAAI;GAAG;;;AAIzB,SAAgB,0BAA0B,SAA2C;CACnF,MAAM,CAAC,eAAe,aAAa,eAAe;CAElD,MAAM,QAAQ,gBAAgB,cAAc;AAE5C,KAAI,SAAS,EACX,QAAO;CAGT,MAAM,wBAAwB,cAAc;CAE5C,MAAM,MAAM;CACZ,MAAM,MAAM;CAGZ,MAAM,cAAc,MAAM,yBAAyB,MAAM;AAEzD,QAAO,OAAO,YAAY,QAAQ,EAAE,CAAC;;AAGvC,SAAgB,eACd,QACA,SACA,mBAAmB,GAC4C;CAC/D,MAAM,QAAQ,OAAO,KAAK,UAAU;AAClC,SACG,QAAQ,cAAc,MAAa,MAAM,YACzC,QAAQ,eAAe,MAAa,MAAM;GAE7C;CAEF,MAAM,WAAW,KAAK,IAAI,GAAG,MAAM;CACnC,MAAM,gBAAgB,KAAK,IAAI,GAAG,MAAM;AAExC,QAAO,OAAO,KAAK,OAAO,UAAU;EAClC,MAAM,OAAO,MAAM;AAEnB,MAAI,kBAAkB,SACpB,QAAO;GACL,GAAG;GACH,eAAe;GACf,OAAO;GACR;EAGH,MAAM,eAAe,KAAK,IAAI,UAAU,OAAO,QAAQ;EACvD,MAAM,WAAW,KAAK,IAAI,MAAM,OAAO,QAAQ;EAC/C,MAAM,oBAAoB,KAAK,IAAI,eAAe,OAAO,QAAQ;EAEjE,MAAM,SAAS,KAAK,IAAI,aAAa;EACrC,MAAM,SAAS,KAAK,IAAI,kBAAkB;EAO1C,MAAM,eANU,KAAK,IAAI,SAAS,GAED,WAAW,SAAS,YAIjB;AAEpC,SAAO;GACL,GAAG;GACH,eAAe;GACf,OAAO,KAAK,MAAM,KAAK,aAAa,EAAE;GACvC;GACD;;AAGJ,SAAS,WAAW,OAAuB;AACzC,QAAO,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,MAAM,CAAC;;AAGzC,SAAS,UAAU,QAAsC;AACvD,KAAI,OAAO,WAAW,EAAG,QAAO,KAAA;CAEhC,MAAM,SAAS,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,MAAM,IAAI,EAAE;CAChD,MAAM,SAAS,KAAK,MAAM,OAAO,SAAS,EAAE;AAE5C,QAAO,OAAO,SAAS,MAAM,MACvB,OAAO,SAAS,MAAM,MAAM,OAAO,WAAW,MAAM,IACtD,OAAO;;AAGb,SAAgB,eACd,QACuC;CACvC,MAAM,wBAAwB,OAC3B,KAAK,UAAU,MAAM,oBAAoB,CACzC,QACE,iBACC,iBAAiB,KAAA,KAAa,OAAO,SAAS,aAAa,IAAI,eAAe,EACjF;CACH,MAAM,qBAAqB,UAAU,sBAAsB;AAE3D,KAAI,uBAAuB,KAAA,EACzB,QAAO,OAAO,KAAK,WAAW;EAAE,GAAG;EAAO,YAAY;EAAI,EAAE;CAG9D,MAAM,sBAAsB,KAAK,IAAI,GAAG,sBAAsB;AAE9D,QAAO,OAAO,KAAK,UAAU;EAC3B,MAAM,eACJ,MAAM,wBAAwB,KAAA,KAC9B,OAAO,SAAS,MAAM,oBAAoB,IAC1C,MAAM,sBAAsB,IACxB,MAAM,sBACN;AAEN,SAAO;GACL,GAAG;GACH,YAAY,MAAM,sBAAsB;GACzC;GACD;;AAGJ,SAAS,mBAAmB,OAAe,QAAgB,WAA2B;CAEpF,MAAM,aADQ,WAAW,MAAM,GACJ;AAE3B,KAAI,aAAa,KAAK,UAAU,EAC9B,QAAO;CAGT,MAAM,cAAc,SAAS,cAAc;CAC3C,MAAM,WAAW,cAAc,IAAI;CACnC,MAAM,aAAa,IAAI,aAAa;AACpC,QAAO,cAAc,WAAW,cAAc;;AAGhD,SAAS,wBAAwB,OAAe,QAAgB,WAA2B;AACzF,KAAI,aAAa,KAAK,UAAU,EAC9B,QAAO;CAGT,MAAM,aAAa,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,MAAM,CAAC,GAAG;CACtD,MAAM,cAAc,SAAS,cAAc;AAE3C,SAAQ,KAAK,IAAI,cAAc,cAAc;;AAG/C,SAAgB,WACd,QACA,SACA,UACA,SACA;CACA,MAAM,eAAe,eACnB,eAAe,QAAQ,SAAS,0BAA0B,QAAQ,CAAC,CACpE;CAED,MAAM,CAAC,eAAe,aAAa,eAAe;CAClD,MAAM,YAAY,KAAK,IAAI,eAAe,aAAa,YAAY;AAEnE,QAAO,aACJ,KAAK,UAAU;EACd,MAAM,eAAe,mBAAmB,MAAM,QAAQ,WAAW,eAAe,UAAU;EAE1F,MAAM,aAAa,mBAAmB,MAAM,OAAO,aAAa,UAAU;EAE1E,MAAM,aAAa,wBAAwB,MAAM,YAAY,aAAa,UAAU;AAEpF,SAAO;GACL,GAAG;GACH,OAAO,eAAe,gBAAgB,aAAa,cAAc,aAAa;GAC/E;GACD,CACD,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM;;AAGtC,SAAgB,qBACd,QACA,WAAqB,QACrB,SACA,cACA,QACe;CAYf,MAAM,eAAe,WAAW,QAV9B,OAAO,iBAAiB,WACpB;EACE,aAAaA,oCAAAA,cAAc;EAC3B,cAAcA,oCAAAA,cAAc;EAC7B,GACD,OAAO,iBAAiB,WACtB;EAAE,aAAa;EAAc,cAAc;EAAc,GACzD,eACG,eACD,uBAAuB,SAAS,EACO,UAAU,kBAAkB,QAAQ,CAAC;AACtF,QAAO,SAAS,aAAa,OAAO,OAAO,GAAG;;AAGhD,SAAgB,2BACd,WAAqB,QACrB,SACA,cACA,QACe;AACf,QAAO,qBAAqBC,2CAAAA,eAAe,UAAU,SAAS,cAAc,OAAO;;AAGrF,SAAgB,6BACd,WAAqB,QACrB,SACA,cACA,QACU;AACV,QAAO,qBAAqBA,2CAAAA,eAAe,UAAU,SAAS,cAAc,OAAO,CAAC,KACjF,UAAU,MAAM,GAClB;;AAGH,SAAgB,iBACd,OACA,MACA,OAAO,QACC;AACR,QAAO,MACJ,KACE,SACC,IAAI,KAAK,GAAG,KACT,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,GAAG,OAAO,KAAK,KAAK,CAAC,IAAI,OAAO,IAAI,CAAC,GAAG,CACrE,KAAK,KAAK,CAAC,IAAI,KAAK,GAC1B,CACA,KAAK,KAAK"}
@@ -8,20 +8,24 @@ declare function addPriceScores(models: RankedModel[], profile: TokenProfile, pr
8
8
  price: number;
9
9
  estimatedCost: number;
10
10
  }>;
11
+ declare function addSpeedScores<Model extends RankedModel>(models: Model[]): Array<Model & {
12
+ speedScore: number;
13
+ }>;
11
14
  declare function rankModels(models: RankedModel[], profile: TokenProfile, category: Category, weights: [number, number, number]): {
12
15
  score: number;
13
16
  id: string;
14
17
  inputCost: number;
15
18
  outputCost: number;
16
19
  quality: Record<Category, number>;
17
- speed: number;
20
+ responseTimeSeconds: number;
18
21
  price: number;
19
22
  estimatedCost: number;
23
+ speedScore: number;
20
24
  }[];
21
25
  declare function getSortedRankedModel(models: RankedModel[], category?: Category, weights?: SortType | [SortType, SortType, SortType] | [number, number, number], tokenProfile?: TokenProfile | number | TokenSize, filter?: (model: RankedModel) => boolean): RankedModel[];
22
26
  declare function getSortedRecommendedModels(category?: Category, weights?: SortType | [SortType, SortType, SortType] | [number, number, number], tokenProfile?: TokenProfile | number | TokenSize, filter?: (model: RankedModel) => boolean): RankedModel[];
23
27
  declare function getSortedRecommendedModelIds(category?: Category, weights?: SortType | [SortType, SortType, SortType] | [number, number, number], tokenProfile?: TokenProfile | number | TokenSize, filter?: (model: RankedModel) => boolean): string[];
24
28
  declare function arrayToPseudoXML<T extends Record<string, unknown>>(array: readonly T[], keys: readonly (keyof T)[], name?: string): string;
25
29
  //#endregion
26
- export { addPriceScores, arrayToPseudoXML, getDefaultTokenProfile, getDefaultWeights, getSortedRankedModel, getSortedRecommendedModelIds, getSortedRecommendedModels, rankModels, weightsToPriceSensitivity };
30
+ export { addPriceScores, addSpeedScores, arrayToPseudoXML, getDefaultTokenProfile, getDefaultWeights, getSortedRankedModel, getSortedRecommendedModelIds, getSortedRecommendedModels, rankModels, weightsToPriceSensitivity };
27
31
  //# sourceMappingURL=ai.utils.d.cts.map
@@ -8,20 +8,24 @@ declare function addPriceScores(models: RankedModel[], profile: TokenProfile, pr
8
8
  price: number;
9
9
  estimatedCost: number;
10
10
  }>;
11
+ declare function addSpeedScores<Model extends RankedModel>(models: Model[]): Array<Model & {
12
+ speedScore: number;
13
+ }>;
11
14
  declare function rankModels(models: RankedModel[], profile: TokenProfile, category: Category, weights: [number, number, number]): {
12
15
  score: number;
13
16
  id: string;
14
17
  inputCost: number;
15
18
  outputCost: number;
16
19
  quality: Record<Category, number>;
17
- speed: number;
20
+ responseTimeSeconds: number;
18
21
  price: number;
19
22
  estimatedCost: number;
23
+ speedScore: number;
20
24
  }[];
21
25
  declare function getSortedRankedModel(models: RankedModel[], category?: Category, weights?: SortType | [SortType, SortType, SortType] | [number, number, number], tokenProfile?: TokenProfile | number | TokenSize, filter?: (model: RankedModel) => boolean): RankedModel[];
22
26
  declare function getSortedRecommendedModels(category?: Category, weights?: SortType | [SortType, SortType, SortType] | [number, number, number], tokenProfile?: TokenProfile | number | TokenSize, filter?: (model: RankedModel) => boolean): RankedModel[];
23
27
  declare function getSortedRecommendedModelIds(category?: Category, weights?: SortType | [SortType, SortType, SortType] | [number, number, number], tokenProfile?: TokenProfile | number | TokenSize, filter?: (model: RankedModel) => boolean): string[];
24
28
  declare function arrayToPseudoXML<T extends Record<string, unknown>>(array: readonly T[], keys: readonly (keyof T)[], name?: string): string;
25
29
  //#endregion
26
- export { addPriceScores, arrayToPseudoXML, getDefaultTokenProfile, getDefaultWeights, getSortedRankedModel, getSortedRecommendedModelIds, getSortedRecommendedModels, rankModels, weightsToPriceSensitivity };
30
+ export { addPriceScores, addSpeedScores, arrayToPseudoXML, getDefaultTokenProfile, getDefaultWeights, getSortedRankedModel, getSortedRecommendedModelIds, getSortedRecommendedModels, rankModels, weightsToPriceSensitivity };
27
31
  //# sourceMappingURL=ai.utils.d.mts.map
@@ -118,6 +118,28 @@ function addPriceScores(models, profile, priceSensitivity = 1) {
118
118
  function clampScore(value) {
119
119
  return Math.max(1, Math.min(10, value));
120
120
  }
121
+ function getMedian(values) {
122
+ if (values.length === 0) return void 0;
123
+ const sorted = [...values].sort((a, b) => a - b);
124
+ const middle = Math.floor(sorted.length / 2);
125
+ return sorted.length % 2 === 0 ? ((sorted[middle - 1] ?? 0) + (sorted[middle] ?? 0)) / 2 : sorted[middle];
126
+ }
127
+ function addSpeedScores(models) {
128
+ const measuredResponseTimes = models.map((model) => model.responseTimeSeconds).filter((responseTime) => responseTime !== void 0 && Number.isFinite(responseTime) && responseTime > 0);
129
+ const medianResponseTime = getMedian(measuredResponseTimes);
130
+ if (medianResponseTime === void 0) return models.map((model) => ({
131
+ ...model,
132
+ speedScore: 10
133
+ }));
134
+ const fastestResponseTime = Math.min(...measuredResponseTimes);
135
+ return models.map((model) => {
136
+ const responseTime = model.responseTimeSeconds !== void 0 && Number.isFinite(model.responseTimeSeconds) && model.responseTimeSeconds > 0 ? model.responseTimeSeconds : medianResponseTime;
137
+ return {
138
+ ...model,
139
+ speedScore: 10 * (fastestResponseTime / responseTime)
140
+ };
141
+ });
142
+ }
121
143
  function shapeScoreByWeight(value, weight, maxWeight) {
122
144
  const normalized = clampScore(value) / 10;
123
145
  if (maxWeight <= 0 || weight <= 0) return 0;
@@ -126,14 +148,20 @@ function shapeScoreByWeight(value, weight, maxWeight) {
126
148
  const compressed = 8 + normalized * 2;
127
149
  return compressed + (expanded - compressed) * importance;
128
150
  }
151
+ function shapeSpeedScoreByWeight(value, weight, maxWeight) {
152
+ if (maxWeight <= 0 || weight <= 0) return 0;
153
+ const normalized = Math.max(0, Math.min(10, value)) / 10;
154
+ const importance = (weight / maxWeight) ** 2;
155
+ return (1 - (1 - normalized) * importance) * 10;
156
+ }
129
157
  function rankModels(models, profile, category, weights) {
130
- const scoredModels = addPriceScores(models, profile, weightsToPriceSensitivity(weights));
158
+ const scoredModels = addSpeedScores(addPriceScores(models, profile, weightsToPriceSensitivity(weights)));
131
159
  const [qualityWeight, priceWeight, speedWeight] = weights;
132
160
  const maxWeight = Math.max(qualityWeight, priceWeight, speedWeight);
133
161
  return scoredModels.map((model) => {
134
162
  const qualityScore = shapeScoreByWeight(model.quality[category], qualityWeight, maxWeight);
135
163
  const priceScore = shapeScoreByWeight(model.price, priceWeight, maxWeight);
136
- const speedScore = shapeScoreByWeight(model.speed, speedWeight, maxWeight);
164
+ const speedScore = shapeSpeedScoreByWeight(model.speedScore, speedWeight, maxWeight);
137
165
  return {
138
166
  ...model,
139
167
  score: qualityScore * qualityWeight + priceScore * priceWeight + speedScore * speedWeight
@@ -160,6 +188,6 @@ function arrayToPseudoXML(array, keys, name = "item") {
160
188
  return array.map((item) => `<${name}>${keys.map((key) => `<${String(key)}>${String(item[key])}</${String(key)}>`).join("\n")}</${name}>`).join("\n");
161
189
  }
162
190
  //#endregion
163
- export { addPriceScores, arrayToPseudoXML, getDefaultTokenProfile, getDefaultWeights, getSortedRankedModel, getSortedRecommendedModelIds, getSortedRecommendedModels, rankModels, weightsToPriceSensitivity };
191
+ export { addPriceScores, addSpeedScores, arrayToPseudoXML, getDefaultTokenProfile, getDefaultWeights, getSortedRankedModel, getSortedRecommendedModelIds, getSortedRecommendedModels, rankModels, weightsToPriceSensitivity };
164
192
 
165
193
  //# sourceMappingURL=ai.utils.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ai.utils.mjs","names":[],"sources":["../../../../src/modules/ai/ai.utils.ts"],"sourcesContent":["import { RANKED_MODELS, TOKEN_PRESETS } from \"./ai.constants\";\r\nimport type { Category, RankedModel, SortType, TokenProfile, TokenSize } from \"./ai.types\";\r\n\r\nexport function getDefaultTokenProfile(category: Category): TokenProfile {\r\n switch (category) {\r\n case \"structured_output\":\r\n return { inputTokens: TOKEN_PRESETS.lg, outputTokens: TOKEN_PRESETS.md };\r\n case \"creative\":\r\n return { inputTokens: TOKEN_PRESETS.md, outputTokens: TOKEN_PRESETS.lg };\r\n case \"research\":\r\n return { inputTokens: TOKEN_PRESETS.xl, outputTokens: TOKEN_PRESETS.xl };\r\n case \"chat\":\r\n return { inputTokens: TOKEN_PRESETS.sm, outputTokens: TOKEN_PRESETS.md };\r\n case \"tool_use\":\r\n return { inputTokens: TOKEN_PRESETS.md, outputTokens: TOKEN_PRESETS.sm };\r\n case \"planning\":\r\n return { inputTokens: TOKEN_PRESETS.lg, outputTokens: TOKEN_PRESETS.lg };\r\n case \"classification\":\r\n return { inputTokens: TOKEN_PRESETS.sm, outputTokens: TOKEN_PRESETS.xs };\r\n default:\r\n return { inputTokens: TOKEN_PRESETS.md, outputTokens: TOKEN_PRESETS.md };\r\n }\r\n}\r\n\r\nexport function getDefaultWeights(\r\n weights?: SortType | [SortType, SortType, SortType] | [number, number, number]\r\n): [number, number, number] {\r\n if (Array.isArray(weights)) {\r\n return weights.every((weight) => typeof weight === \"number\")\r\n ? weights\r\n : weights.reduce<[number, number, number]>(\r\n (acc, weight, index) => {\r\n switch (weight) {\r\n case \"quality\":\r\n acc[0] = index === 0 ? 50 : index === 1 ? 30 : 20;\r\n break;\r\n case \"price\":\r\n acc[1] = index === 0 ? 50 : index === 1 ? 30 : 20;\r\n break;\r\n case \"speed\":\r\n acc[2] = index === 0 ? 50 : index === 1 ? 30 : 20;\r\n break;\r\n }\r\n return acc;\r\n },\r\n [20, 50, 30]\r\n );\r\n }\r\n switch (weights) {\r\n case \"quality\":\r\n return [50, 30, 20];\r\n case \"price\":\r\n return [20, 50, 30];\r\n case \"speed\":\r\n return [20, 30, 50];\r\n default:\r\n return [50, 25, 25];\r\n }\r\n}\r\n\r\nexport function weightsToPriceSensitivity(weights: [number, number, number]): number {\r\n const [qualityWeight, priceWeight, speedWeight] = weights;\r\n\r\n const total = qualityWeight + priceWeight + speedWeight;\r\n\r\n if (total <= 0) {\r\n return 1;\r\n }\r\n\r\n const normalizedPriceWeight = priceWeight / total;\r\n\r\n const min = 0.55; // very price-sensitive\r\n const max = 1.75; // price is soft / secondary\r\n\r\n // Higher price weight -> lower exponent -> stronger price penalty.\r\n const sensitivity = max - normalizedPriceWeight * (max - min);\r\n\r\n return Number(sensitivity.toFixed(3));\r\n}\r\n\r\nexport function addPriceScores(\r\n models: RankedModel[],\r\n profile: TokenProfile,\r\n priceSensitivity = 1\r\n): Array<RankedModel & { price: number; estimatedCost: number }> {\r\n const costs = models.map((model) => {\r\n return (\r\n (profile.inputTokens / 1_000_000) * model.inputCost +\r\n (profile.outputTokens / 1_000_000) * model.outputCost\r\n );\r\n });\r\n\r\n const cheapest = Math.min(...costs);\r\n const mostExpensive = Math.max(...costs);\r\n\r\n return models.map((model, index) => {\r\n const cost = costs[index];\r\n\r\n if (mostExpensive === cheapest) {\r\n return {\r\n ...model,\r\n estimatedCost: cost,\r\n price: 10,\r\n };\r\n }\r\n\r\n const safeCheapest = Math.max(cheapest, Number.EPSILON);\r\n const safeCost = Math.max(cost, Number.EPSILON);\r\n const safeMostExpensive = Math.max(mostExpensive, Number.EPSILON);\r\n\r\n const logMin = Math.log(safeCheapest);\r\n const logMax = Math.log(safeMostExpensive);\r\n const logCost = Math.log(safeCost);\r\n\r\n const normalizedRaw = (logCost - logMin) / (logMax - logMin);\r\n\r\n // < 1 makes price matter less.\r\n // > 1 makes price matter more.\r\n const normalized = normalizedRaw ** priceSensitivity;\r\n\r\n return {\r\n ...model,\r\n estimatedCost: cost,\r\n price: Math.round(10 - normalized * 9),\r\n };\r\n });\r\n}\r\n\r\nfunction clampScore(value: number): number {\r\n return Math.max(1, Math.min(10, value));\r\n}\r\n\r\nfunction shapeScoreByWeight(value: number, weight: number, maxWeight: number): number {\r\n const score = clampScore(value);\r\n const normalized = score / 10;\r\n\r\n if (maxWeight <= 0 || weight <= 0) {\r\n return 0;\r\n }\r\n\r\n const importance = (weight / maxWeight) ** 2;\r\n const expanded = normalized ** 2 * 10;\r\n const compressed = 8 + normalized * 2;\r\n return compressed + (expanded - compressed) * importance;\r\n}\r\n\r\nexport function rankModels(\r\n models: RankedModel[],\r\n profile: TokenProfile,\r\n category: Category,\r\n weights: [number, number, number]\r\n) {\r\n const scoredModels = addPriceScores(models, profile, weightsToPriceSensitivity(weights));\r\n\r\n const [qualityWeight, priceWeight, speedWeight] = weights;\r\n const maxWeight = Math.max(qualityWeight, priceWeight, speedWeight);\r\n\r\n return scoredModels\r\n .map((model) => {\r\n const qualityScore = shapeScoreByWeight(model.quality[category], qualityWeight, maxWeight);\r\n\r\n const priceScore = shapeScoreByWeight(model.price, priceWeight, maxWeight);\r\n\r\n const speedScore = shapeScoreByWeight(model.speed, speedWeight, maxWeight);\r\n\r\n return {\r\n ...model,\r\n score: qualityScore * qualityWeight + priceScore * priceWeight + speedScore * speedWeight,\r\n };\r\n })\r\n .sort((a, b) => b.score - a.score);\r\n}\r\n\r\nexport function getSortedRankedModel(\r\n models: RankedModel[],\r\n category: Category = \"chat\",\r\n weights?: SortType | [SortType, SortType, SortType] | [number, number, number],\r\n tokenProfile?: TokenProfile | number | TokenSize,\r\n filter?: (model: RankedModel) => boolean\r\n): RankedModel[] {\r\n const profile =\r\n typeof tokenProfile === \"string\"\r\n ? {\r\n inputTokens: TOKEN_PRESETS[tokenProfile as TokenSize],\r\n outputTokens: TOKEN_PRESETS[tokenProfile as TokenSize],\r\n }\r\n : typeof tokenProfile === \"number\"\r\n ? { inputTokens: tokenProfile, outputTokens: tokenProfile }\r\n : tokenProfile\r\n ? (tokenProfile as TokenProfile)\r\n : getDefaultTokenProfile(category);\r\n const rankedModels = rankModels(models, profile, category, getDefaultWeights(weights));\r\n return filter ? rankedModels.filter(filter) : rankedModels;\r\n}\r\n\r\nexport function getSortedRecommendedModels(\r\n category: Category = \"chat\",\r\n weights?: SortType | [SortType, SortType, SortType] | [number, number, number],\r\n tokenProfile?: TokenProfile | number | TokenSize,\r\n filter?: (model: RankedModel) => boolean\r\n): RankedModel[] {\r\n return getSortedRankedModel(RANKED_MODELS, category, weights, tokenProfile, filter);\r\n}\r\n\r\nexport function getSortedRecommendedModelIds(\r\n category: Category = \"chat\",\r\n weights?: SortType | [SortType, SortType, SortType] | [number, number, number],\r\n tokenProfile?: TokenProfile | number | TokenSize,\r\n filter?: (model: RankedModel) => boolean\r\n): string[] {\r\n return getSortedRankedModel(RANKED_MODELS, category, weights, tokenProfile, filter).map(\r\n (model) => model.id\r\n );\r\n}\r\n\r\nexport function arrayToPseudoXML<T extends Record<string, unknown>>(\r\n array: readonly T[],\r\n keys: readonly (keyof T)[],\r\n name = \"item\"\r\n): string {\r\n return array\r\n .map(\r\n (item) =>\r\n `<${name}>${keys\r\n .map((key) => `<${String(key)}>${String(item[key])}</${String(key)}>`)\r\n .join(\"\\n\")}</${name}>`\r\n )\r\n .join(\"\\n\");\r\n}\r\n"],"mappings":";;;AAGA,SAAgB,uBAAuB,UAAkC;AACvE,SAAQ,UAAR;EACE,KAAK,oBACH,QAAO;GAAE,aAAa,cAAc;GAAI,cAAc,cAAc;GAAI;EAC1E,KAAK,WACH,QAAO;GAAE,aAAa,cAAc;GAAI,cAAc,cAAc;GAAI;EAC1E,KAAK,WACH,QAAO;GAAE,aAAa,cAAc;GAAI,cAAc,cAAc;GAAI;EAC1E,KAAK,OACH,QAAO;GAAE,aAAa,cAAc;GAAI,cAAc,cAAc;GAAI;EAC1E,KAAK,WACH,QAAO;GAAE,aAAa,cAAc;GAAI,cAAc,cAAc;GAAI;EAC1E,KAAK,WACH,QAAO;GAAE,aAAa,cAAc;GAAI,cAAc,cAAc;GAAI;EAC1E,KAAK,iBACH,QAAO;GAAE,aAAa,cAAc;GAAI,cAAc,cAAc;GAAI;EAC1E,QACE,QAAO;GAAE,aAAa,cAAc;GAAI,cAAc,cAAc;GAAI;;;AAI9E,SAAgB,kBACd,SAC0B;AAC1B,KAAI,MAAM,QAAQ,QAAQ,CACxB,QAAO,QAAQ,OAAO,WAAW,OAAO,WAAW,SAAS,GACxD,UACA,QAAQ,QACL,KAAK,QAAQ,UAAU;AACtB,UAAQ,QAAR;GACE,KAAK;AACH,QAAI,KAAK,UAAU,IAAI,KAAK,UAAU,IAAI,KAAK;AAC/C;GACF,KAAK;AACH,QAAI,KAAK,UAAU,IAAI,KAAK,UAAU,IAAI,KAAK;AAC/C;GACF,KAAK;AACH,QAAI,KAAK,UAAU,IAAI,KAAK,UAAU,IAAI,KAAK;AAC/C;;AAEJ,SAAO;IAET;EAAC;EAAI;EAAI;EAAG,CACb;AAEP,SAAQ,SAAR;EACE,KAAK,UACH,QAAO;GAAC;GAAI;GAAI;GAAG;EACrB,KAAK,QACH,QAAO;GAAC;GAAI;GAAI;GAAG;EACrB,KAAK,QACH,QAAO;GAAC;GAAI;GAAI;GAAG;EACrB,QACE,QAAO;GAAC;GAAI;GAAI;GAAG;;;AAIzB,SAAgB,0BAA0B,SAA2C;CACnF,MAAM,CAAC,eAAe,aAAa,eAAe;CAElD,MAAM,QAAQ,gBAAgB,cAAc;AAE5C,KAAI,SAAS,EACX,QAAO;CAGT,MAAM,wBAAwB,cAAc;CAE5C,MAAM,MAAM;CACZ,MAAM,MAAM;CAGZ,MAAM,cAAc,MAAM,yBAAyB,MAAM;AAEzD,QAAO,OAAO,YAAY,QAAQ,EAAE,CAAC;;AAGvC,SAAgB,eACd,QACA,SACA,mBAAmB,GAC4C;CAC/D,MAAM,QAAQ,OAAO,KAAK,UAAU;AAClC,SACG,QAAQ,cAAc,MAAa,MAAM,YACzC,QAAQ,eAAe,MAAa,MAAM;GAE7C;CAEF,MAAM,WAAW,KAAK,IAAI,GAAG,MAAM;CACnC,MAAM,gBAAgB,KAAK,IAAI,GAAG,MAAM;AAExC,QAAO,OAAO,KAAK,OAAO,UAAU;EAClC,MAAM,OAAO,MAAM;AAEnB,MAAI,kBAAkB,SACpB,QAAO;GACL,GAAG;GACH,eAAe;GACf,OAAO;GACR;EAGH,MAAM,eAAe,KAAK,IAAI,UAAU,OAAO,QAAQ;EACvD,MAAM,WAAW,KAAK,IAAI,MAAM,OAAO,QAAQ;EAC/C,MAAM,oBAAoB,KAAK,IAAI,eAAe,OAAO,QAAQ;EAEjE,MAAM,SAAS,KAAK,IAAI,aAAa;EACrC,MAAM,SAAS,KAAK,IAAI,kBAAkB;EAO1C,MAAM,eANU,KAAK,IAAI,SAAS,GAED,WAAW,SAAS,YAIjB;AAEpC,SAAO;GACL,GAAG;GACH,eAAe;GACf,OAAO,KAAK,MAAM,KAAK,aAAa,EAAE;GACvC;GACD;;AAGJ,SAAS,WAAW,OAAuB;AACzC,QAAO,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,MAAM,CAAC;;AAGzC,SAAS,mBAAmB,OAAe,QAAgB,WAA2B;CAEpF,MAAM,aADQ,WAAW,MAAM,GACJ;AAE3B,KAAI,aAAa,KAAK,UAAU,EAC9B,QAAO;CAGT,MAAM,cAAc,SAAS,cAAc;CAC3C,MAAM,WAAW,cAAc,IAAI;CACnC,MAAM,aAAa,IAAI,aAAa;AACpC,QAAO,cAAc,WAAW,cAAc;;AAGhD,SAAgB,WACd,QACA,SACA,UACA,SACA;CACA,MAAM,eAAe,eAAe,QAAQ,SAAS,0BAA0B,QAAQ,CAAC;CAExF,MAAM,CAAC,eAAe,aAAa,eAAe;CAClD,MAAM,YAAY,KAAK,IAAI,eAAe,aAAa,YAAY;AAEnE,QAAO,aACJ,KAAK,UAAU;EACd,MAAM,eAAe,mBAAmB,MAAM,QAAQ,WAAW,eAAe,UAAU;EAE1F,MAAM,aAAa,mBAAmB,MAAM,OAAO,aAAa,UAAU;EAE1E,MAAM,aAAa,mBAAmB,MAAM,OAAO,aAAa,UAAU;AAE1E,SAAO;GACL,GAAG;GACH,OAAO,eAAe,gBAAgB,aAAa,cAAc,aAAa;GAC/E;GACD,CACD,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM;;AAGtC,SAAgB,qBACd,QACA,WAAqB,QACrB,SACA,cACA,QACe;CAYf,MAAM,eAAe,WAAW,QAV9B,OAAO,iBAAiB,WACpB;EACE,aAAa,cAAc;EAC3B,cAAc,cAAc;EAC7B,GACD,OAAO,iBAAiB,WACtB;EAAE,aAAa;EAAc,cAAc;EAAc,GACzD,eACG,eACD,uBAAuB,SAAS,EACO,UAAU,kBAAkB,QAAQ,CAAC;AACtF,QAAO,SAAS,aAAa,OAAO,OAAO,GAAG;;AAGhD,SAAgB,2BACd,WAAqB,QACrB,SACA,cACA,QACe;AACf,QAAO,qBAAqB,eAAe,UAAU,SAAS,cAAc,OAAO;;AAGrF,SAAgB,6BACd,WAAqB,QACrB,SACA,cACA,QACU;AACV,QAAO,qBAAqB,eAAe,UAAU,SAAS,cAAc,OAAO,CAAC,KACjF,UAAU,MAAM,GAClB;;AAGH,SAAgB,iBACd,OACA,MACA,OAAO,QACC;AACR,QAAO,MACJ,KACE,SACC,IAAI,KAAK,GAAG,KACT,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,GAAG,OAAO,KAAK,KAAK,CAAC,IAAI,OAAO,IAAI,CAAC,GAAG,CACrE,KAAK,KAAK,CAAC,IAAI,KAAK,GAC1B,CACA,KAAK,KAAK"}
1
+ {"version":3,"file":"ai.utils.mjs","names":[],"sources":["../../../../src/modules/ai/ai.utils.ts"],"sourcesContent":["import { RANKED_MODELS, TOKEN_PRESETS } from \"./ai.constants\";\r\nimport type { Category, RankedModel, SortType, TokenProfile, TokenSize } from \"./ai.types\";\r\n\r\nexport function getDefaultTokenProfile(category: Category): TokenProfile {\r\n switch (category) {\r\n case \"structured_output\":\r\n return { inputTokens: TOKEN_PRESETS.lg, outputTokens: TOKEN_PRESETS.md };\r\n case \"creative\":\r\n return { inputTokens: TOKEN_PRESETS.md, outputTokens: TOKEN_PRESETS.lg };\r\n case \"research\":\r\n return { inputTokens: TOKEN_PRESETS.xl, outputTokens: TOKEN_PRESETS.xl };\r\n case \"chat\":\r\n return { inputTokens: TOKEN_PRESETS.sm, outputTokens: TOKEN_PRESETS.md };\r\n case \"tool_use\":\r\n return { inputTokens: TOKEN_PRESETS.md, outputTokens: TOKEN_PRESETS.sm };\r\n case \"planning\":\r\n return { inputTokens: TOKEN_PRESETS.lg, outputTokens: TOKEN_PRESETS.lg };\r\n case \"classification\":\r\n return { inputTokens: TOKEN_PRESETS.sm, outputTokens: TOKEN_PRESETS.xs };\r\n default:\r\n return { inputTokens: TOKEN_PRESETS.md, outputTokens: TOKEN_PRESETS.md };\r\n }\r\n}\r\n\r\nexport function getDefaultWeights(\r\n weights?: SortType | [SortType, SortType, SortType] | [number, number, number]\r\n): [number, number, number] {\r\n if (Array.isArray(weights)) {\r\n return weights.every((weight) => typeof weight === \"number\")\r\n ? weights\r\n : weights.reduce<[number, number, number]>(\r\n (acc, weight, index) => {\r\n switch (weight) {\r\n case \"quality\":\r\n acc[0] = index === 0 ? 50 : index === 1 ? 30 : 20;\r\n break;\r\n case \"price\":\r\n acc[1] = index === 0 ? 50 : index === 1 ? 30 : 20;\r\n break;\r\n case \"speed\":\r\n acc[2] = index === 0 ? 50 : index === 1 ? 30 : 20;\r\n break;\r\n }\r\n return acc;\r\n },\r\n [20, 50, 30]\r\n );\r\n }\r\n switch (weights) {\r\n case \"quality\":\r\n return [50, 30, 20];\r\n case \"price\":\r\n return [20, 50, 30];\r\n case \"speed\":\r\n return [20, 30, 50];\r\n default:\r\n return [50, 25, 25];\r\n }\r\n}\r\n\r\nexport function weightsToPriceSensitivity(weights: [number, number, number]): number {\r\n const [qualityWeight, priceWeight, speedWeight] = weights;\r\n\r\n const total = qualityWeight + priceWeight + speedWeight;\r\n\r\n if (total <= 0) {\r\n return 1;\r\n }\r\n\r\n const normalizedPriceWeight = priceWeight / total;\r\n\r\n const min = 0.55; // very price-sensitive\r\n const max = 1.75; // price is soft / secondary\r\n\r\n // Higher price weight -> lower exponent -> stronger price penalty.\r\n const sensitivity = max - normalizedPriceWeight * (max - min);\r\n\r\n return Number(sensitivity.toFixed(3));\r\n}\r\n\r\nexport function addPriceScores(\r\n models: RankedModel[],\r\n profile: TokenProfile,\r\n priceSensitivity = 1\r\n): Array<RankedModel & { price: number; estimatedCost: number }> {\r\n const costs = models.map((model) => {\r\n return (\r\n (profile.inputTokens / 1_000_000) * model.inputCost +\r\n (profile.outputTokens / 1_000_000) * model.outputCost\r\n );\r\n });\r\n\r\n const cheapest = Math.min(...costs);\r\n const mostExpensive = Math.max(...costs);\r\n\r\n return models.map((model, index) => {\r\n const cost = costs[index];\r\n\r\n if (mostExpensive === cheapest) {\r\n return {\r\n ...model,\r\n estimatedCost: cost,\r\n price: 10,\r\n };\r\n }\r\n\r\n const safeCheapest = Math.max(cheapest, Number.EPSILON);\r\n const safeCost = Math.max(cost, Number.EPSILON);\r\n const safeMostExpensive = Math.max(mostExpensive, Number.EPSILON);\r\n\r\n const logMin = Math.log(safeCheapest);\r\n const logMax = Math.log(safeMostExpensive);\r\n const logCost = Math.log(safeCost);\r\n\r\n const normalizedRaw = (logCost - logMin) / (logMax - logMin);\r\n\r\n // < 1 makes price matter less.\r\n // > 1 makes price matter more.\r\n const normalized = normalizedRaw ** priceSensitivity;\r\n\r\n return {\r\n ...model,\r\n estimatedCost: cost,\r\n price: Math.round(10 - normalized * 9),\r\n };\r\n });\r\n}\r\n\r\nfunction clampScore(value: number): number {\r\n return Math.max(1, Math.min(10, value));\r\n}\r\n\r\nfunction getMedian(values: number[]): number | undefined {\r\n if (values.length === 0) return undefined;\r\n\r\n const sorted = [...values].sort((a, b) => a - b);\r\n const middle = Math.floor(sorted.length / 2);\r\n\r\n return sorted.length % 2 === 0\r\n ? ((sorted[middle - 1] ?? 0) + (sorted[middle] ?? 0)) / 2\r\n : sorted[middle];\r\n}\r\n\r\nexport function addSpeedScores<Model extends RankedModel>(\r\n models: Model[]\r\n): Array<Model & { speedScore: number }> {\r\n const measuredResponseTimes = models\r\n .map((model) => model.responseTimeSeconds)\r\n .filter(\r\n (responseTime): responseTime is number =>\r\n responseTime !== undefined && Number.isFinite(responseTime) && responseTime > 0\r\n );\r\n const medianResponseTime = getMedian(measuredResponseTimes);\r\n\r\n if (medianResponseTime === undefined) {\r\n return models.map((model) => ({ ...model, speedScore: 10 }));\r\n }\r\n\r\n const fastestResponseTime = Math.min(...measuredResponseTimes);\r\n\r\n return models.map((model) => {\r\n const responseTime =\r\n model.responseTimeSeconds !== undefined &&\r\n Number.isFinite(model.responseTimeSeconds) &&\r\n model.responseTimeSeconds > 0\r\n ? model.responseTimeSeconds\r\n : medianResponseTime;\r\n\r\n return {\r\n ...model,\r\n speedScore: 10 * (fastestResponseTime / responseTime),\r\n };\r\n });\r\n}\r\n\r\nfunction shapeScoreByWeight(value: number, weight: number, maxWeight: number): number {\r\n const score = clampScore(value);\r\n const normalized = score / 10;\r\n\r\n if (maxWeight <= 0 || weight <= 0) {\r\n return 0;\r\n }\r\n\r\n const importance = (weight / maxWeight) ** 2;\r\n const expanded = normalized ** 2 * 10;\r\n const compressed = 8 + normalized * 2;\r\n return compressed + (expanded - compressed) * importance;\r\n}\r\n\r\nfunction shapeSpeedScoreByWeight(value: number, weight: number, maxWeight: number): number {\r\n if (maxWeight <= 0 || weight <= 0) {\r\n return 0;\r\n }\r\n\r\n const normalized = Math.max(0, Math.min(10, value)) / 10;\r\n const importance = (weight / maxWeight) ** 2;\r\n\r\n return (1 - (1 - normalized) * importance) * 10;\r\n}\r\n\r\nexport function rankModels(\r\n models: RankedModel[],\r\n profile: TokenProfile,\r\n category: Category,\r\n weights: [number, number, number]\r\n) {\r\n const scoredModels = addSpeedScores(\r\n addPriceScores(models, profile, weightsToPriceSensitivity(weights))\r\n );\r\n\r\n const [qualityWeight, priceWeight, speedWeight] = weights;\r\n const maxWeight = Math.max(qualityWeight, priceWeight, speedWeight);\r\n\r\n return scoredModels\r\n .map((model) => {\r\n const qualityScore = shapeScoreByWeight(model.quality[category], qualityWeight, maxWeight);\r\n\r\n const priceScore = shapeScoreByWeight(model.price, priceWeight, maxWeight);\r\n\r\n const speedScore = shapeSpeedScoreByWeight(model.speedScore, speedWeight, maxWeight);\r\n\r\n return {\r\n ...model,\r\n score: qualityScore * qualityWeight + priceScore * priceWeight + speedScore * speedWeight,\r\n };\r\n })\r\n .sort((a, b) => b.score - a.score);\r\n}\r\n\r\nexport function getSortedRankedModel(\r\n models: RankedModel[],\r\n category: Category = \"chat\",\r\n weights?: SortType | [SortType, SortType, SortType] | [number, number, number],\r\n tokenProfile?: TokenProfile | number | TokenSize,\r\n filter?: (model: RankedModel) => boolean\r\n): RankedModel[] {\r\n const profile =\r\n typeof tokenProfile === \"string\"\r\n ? {\r\n inputTokens: TOKEN_PRESETS[tokenProfile as TokenSize],\r\n outputTokens: TOKEN_PRESETS[tokenProfile as TokenSize],\r\n }\r\n : typeof tokenProfile === \"number\"\r\n ? { inputTokens: tokenProfile, outputTokens: tokenProfile }\r\n : tokenProfile\r\n ? (tokenProfile as TokenProfile)\r\n : getDefaultTokenProfile(category);\r\n const rankedModels = rankModels(models, profile, category, getDefaultWeights(weights));\r\n return filter ? rankedModels.filter(filter) : rankedModels;\r\n}\r\n\r\nexport function getSortedRecommendedModels(\r\n category: Category = \"chat\",\r\n weights?: SortType | [SortType, SortType, SortType] | [number, number, number],\r\n tokenProfile?: TokenProfile | number | TokenSize,\r\n filter?: (model: RankedModel) => boolean\r\n): RankedModel[] {\r\n return getSortedRankedModel(RANKED_MODELS, category, weights, tokenProfile, filter);\r\n}\r\n\r\nexport function getSortedRecommendedModelIds(\r\n category: Category = \"chat\",\r\n weights?: SortType | [SortType, SortType, SortType] | [number, number, number],\r\n tokenProfile?: TokenProfile | number | TokenSize,\r\n filter?: (model: RankedModel) => boolean\r\n): string[] {\r\n return getSortedRankedModel(RANKED_MODELS, category, weights, tokenProfile, filter).map(\r\n (model) => model.id\r\n );\r\n}\r\n\r\nexport function arrayToPseudoXML<T extends Record<string, unknown>>(\r\n array: readonly T[],\r\n keys: readonly (keyof T)[],\r\n name = \"item\"\r\n): string {\r\n return array\r\n .map(\r\n (item) =>\r\n `<${name}>${keys\r\n .map((key) => `<${String(key)}>${String(item[key])}</${String(key)}>`)\r\n .join(\"\\n\")}</${name}>`\r\n )\r\n .join(\"\\n\");\r\n}\r\n"],"mappings":"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"}
@@ -12,9 +12,9 @@ declare const notificationProviderSchema: z.ZodEnum<{
12
12
  fcm: "fcm";
13
13
  }>;
14
14
  declare const notificationSendStatusSchema: z.ZodEnum<{
15
+ failed: "failed";
15
16
  pending: "pending";
16
17
  sent: "sent";
17
- failed: "failed";
18
18
  }>;
19
19
  /** Web Push `PushSubscriptionJSON` subset we persist and accept from clients. */
20
20
  declare const pushSubscriptionJsonSchema: z.ZodObject<{
@@ -100,9 +100,9 @@ declare const notificationSendLogSelectSchema: z.ZodObject<{
100
100
  body: z.ZodString;
101
101
  data: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
102
102
  status: z.ZodEnum<{
103
+ failed: "failed";
103
104
  pending: "pending";
104
105
  sent: "sent";
105
- failed: "failed";
106
106
  }>;
107
107
  error: z.ZodNullable<z.ZodString>;
108
108
  jobId: z.ZodNullable<z.ZodString>;
@@ -127,9 +127,9 @@ declare const notificationListSendLogsOutputSchema: z.ZodArray<z.ZodObject<{
127
127
  body: z.ZodString;
128
128
  data: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
129
129
  status: z.ZodEnum<{
130
+ failed: "failed";
130
131
  pending: "pending";
131
132
  sent: "sent";
132
- failed: "failed";
133
133
  }>;
134
134
  error: z.ZodNullable<z.ZodString>;
135
135
  jobId: z.ZodNullable<z.ZodString>;
@@ -12,9 +12,9 @@ declare const notificationProviderSchema: z.ZodEnum<{
12
12
  fcm: "fcm";
13
13
  }>;
14
14
  declare const notificationSendStatusSchema: z.ZodEnum<{
15
+ failed: "failed";
15
16
  pending: "pending";
16
17
  sent: "sent";
17
- failed: "failed";
18
18
  }>;
19
19
  /** Web Push `PushSubscriptionJSON` subset we persist and accept from clients. */
20
20
  declare const pushSubscriptionJsonSchema: z.ZodObject<{
@@ -100,9 +100,9 @@ declare const notificationSendLogSelectSchema: z.ZodObject<{
100
100
  body: z.ZodString;
101
101
  data: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
102
102
  status: z.ZodEnum<{
103
+ failed: "failed";
103
104
  pending: "pending";
104
105
  sent: "sent";
105
- failed: "failed";
106
106
  }>;
107
107
  error: z.ZodNullable<z.ZodString>;
108
108
  jobId: z.ZodNullable<z.ZodString>;
@@ -127,9 +127,9 @@ declare const notificationListSendLogsOutputSchema: z.ZodArray<z.ZodObject<{
127
127
  body: z.ZodString;
128
128
  data: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
129
129
  status: z.ZodEnum<{
130
+ failed: "failed";
130
131
  pending: "pending";
131
132
  sent: "sent";
132
- failed: "failed";
133
133
  }>;
134
134
  error: z.ZodNullable<z.ZodString>;
135
135
  jobId: z.ZodNullable<z.ZodString>;
@@ -7,8 +7,8 @@ declare const filterSchema: z.ZodObject<{
7
7
  string: "string";
8
8
  number: "number";
9
9
  boolean: "boolean";
10
- enum: "enum";
11
10
  date: "date";
11
+ enum: "enum";
12
12
  jsonArray: "jsonArray";
13
13
  }>;
14
14
  method: z.ZodEnum<{
@@ -39,8 +39,8 @@ declare const filtersSchema: z.ZodArray<z.ZodObject<{
39
39
  string: "string";
40
40
  number: "number";
41
41
  boolean: "boolean";
42
- enum: "enum";
43
42
  date: "date";
43
+ enum: "enum";
44
44
  jsonArray: "jsonArray";
45
45
  }>;
46
46
  method: z.ZodEnum<{
@@ -79,8 +79,8 @@ declare const querySchema: z.ZodObject<{
79
79
  string: "string";
80
80
  number: "number";
81
81
  boolean: "boolean";
82
- enum: "enum";
83
82
  date: "date";
83
+ enum: "enum";
84
84
  jsonArray: "jsonArray";
85
85
  }>;
86
86
  method: z.ZodEnum<{
@@ -7,8 +7,8 @@ declare const filterSchema: z.ZodObject<{
7
7
  string: "string";
8
8
  number: "number";
9
9
  boolean: "boolean";
10
- enum: "enum";
11
10
  date: "date";
11
+ enum: "enum";
12
12
  jsonArray: "jsonArray";
13
13
  }>;
14
14
  method: z.ZodEnum<{
@@ -39,8 +39,8 @@ declare const filtersSchema: z.ZodArray<z.ZodObject<{
39
39
  string: "string";
40
40
  number: "number";
41
41
  boolean: "boolean";
42
- enum: "enum";
43
42
  date: "date";
43
+ enum: "enum";
44
44
  jsonArray: "jsonArray";
45
45
  }>;
46
46
  method: z.ZodEnum<{
@@ -79,8 +79,8 @@ declare const querySchema: z.ZodObject<{
79
79
  string: "string";
80
80
  number: "number";
81
81
  boolean: "boolean";
82
- enum: "enum";
83
82
  date: "date";
83
+ enum: "enum";
84
84
  jsonArray: "jsonArray";
85
85
  }>;
86
86
  method: z.ZodEnum<{
@@ -37,8 +37,8 @@ declare const tagListInputSchema: z.ZodObject<{
37
37
  string: "string";
38
38
  number: "number";
39
39
  boolean: "boolean";
40
- enum: "enum";
41
40
  date: "date";
41
+ enum: "enum";
42
42
  jsonArray: "jsonArray";
43
43
  }>;
44
44
  method: z.ZodEnum<{
@@ -37,8 +37,8 @@ declare const tagListInputSchema: z.ZodObject<{
37
37
  string: "string";
38
38
  number: "number";
39
39
  boolean: "boolean";
40
- enum: "enum";
41
40
  date: "date";
41
+ enum: "enum";
42
42
  jsonArray: "jsonArray";
43
43
  }>;
44
44
  method: z.ZodEnum<{
@@ -11,10 +11,10 @@ declare const workflowSelectSchema: z.ZodObject<{
11
11
  input: z.ZodUnknown;
12
12
  output: z.ZodUnknown;
13
13
  status: z.ZodEnum<{
14
- failed: "failed";
15
14
  queued: "queued";
16
15
  running: "running";
17
16
  completed: "completed";
17
+ failed: "failed";
18
18
  }>;
19
19
  error: z.ZodNullable<z.ZodString>;
20
20
  retries: z.ZodNumber;
@@ -28,10 +28,10 @@ declare const workflowReadInputSchema: z.ZodObject<{
28
28
  }, z.core.$strip>;
29
29
  declare const workflowListInputSchema: z.ZodObject<{
30
30
  status: z.ZodOptional<z.ZodArray<z.ZodEnum<{
31
- failed: "failed";
32
31
  queued: "queued";
33
32
  running: "running";
34
33
  completed: "completed";
34
+ failed: "failed";
35
35
  }>>>;
36
36
  jobName: z.ZodOptional<z.ZodString>;
37
37
  }, z.core.$strip>;
@@ -51,10 +51,10 @@ declare const workflowReadOutputSchema: z.ZodObject<{
51
51
  input: z.ZodUnknown;
52
52
  output: z.ZodUnknown;
53
53
  status: z.ZodEnum<{
54
- failed: "failed";
55
54
  queued: "queued";
56
55
  running: "running";
57
56
  completed: "completed";
57
+ failed: "failed";
58
58
  }>;
59
59
  error: z.ZodNullable<z.ZodString>;
60
60
  retries: z.ZodNumber;
@@ -73,10 +73,10 @@ declare const workflowListOutputSchema: z.ZodArray<z.ZodObject<{
73
73
  input: z.ZodUnknown;
74
74
  output: z.ZodUnknown;
75
75
  status: z.ZodEnum<{
76
- failed: "failed";
77
76
  queued: "queued";
78
77
  running: "running";
79
78
  completed: "completed";
79
+ failed: "failed";
80
80
  }>;
81
81
  error: z.ZodNullable<z.ZodString>;
82
82
  retries: z.ZodNumber;
@@ -11,10 +11,10 @@ declare const workflowSelectSchema: z.ZodObject<{
11
11
  input: z.ZodUnknown;
12
12
  output: z.ZodUnknown;
13
13
  status: z.ZodEnum<{
14
- failed: "failed";
15
14
  queued: "queued";
16
15
  running: "running";
17
16
  completed: "completed";
17
+ failed: "failed";
18
18
  }>;
19
19
  error: z.ZodNullable<z.ZodString>;
20
20
  retries: z.ZodNumber;
@@ -28,10 +28,10 @@ declare const workflowReadInputSchema: z.ZodObject<{
28
28
  }, z.core.$strip>;
29
29
  declare const workflowListInputSchema: z.ZodObject<{
30
30
  status: z.ZodOptional<z.ZodArray<z.ZodEnum<{
31
- failed: "failed";
32
31
  queued: "queued";
33
32
  running: "running";
34
33
  completed: "completed";
34
+ failed: "failed";
35
35
  }>>>;
36
36
  jobName: z.ZodOptional<z.ZodString>;
37
37
  }, z.core.$strip>;
@@ -51,10 +51,10 @@ declare const workflowReadOutputSchema: z.ZodObject<{
51
51
  input: z.ZodUnknown;
52
52
  output: z.ZodUnknown;
53
53
  status: z.ZodEnum<{
54
- failed: "failed";
55
54
  queued: "queued";
56
55
  running: "running";
57
56
  completed: "completed";
57
+ failed: "failed";
58
58
  }>;
59
59
  error: z.ZodNullable<z.ZodString>;
60
60
  retries: z.ZodNumber;
@@ -73,10 +73,10 @@ declare const workflowListOutputSchema: z.ZodArray<z.ZodObject<{
73
73
  input: z.ZodUnknown;
74
74
  output: z.ZodUnknown;
75
75
  status: z.ZodEnum<{
76
- failed: "failed";
77
76
  queued: "queued";
78
77
  running: "running";
79
78
  completed: "completed";
79
+ failed: "failed";
80
80
  }>;
81
81
  error: z.ZodNullable<z.ZodString>;
82
82
  retries: z.ZodNumber;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m5kdev/commons",
3
- "version": "0.31.6",
3
+ "version": "0.31.7",
4
4
  "license": "GPL-3.0-only",
5
5
  "repository": {
6
6
  "type": "git",
@@ -18,7 +18,7 @@
18
18
  "devDependencies": {
19
19
  "tsdown": "0.21.7",
20
20
  "typescript": "6.0.3",
21
- "@m5kdev/config": "0.31.6"
21
+ "@m5kdev/config": "0.31.7"
22
22
  },
23
23
  "exports": {
24
24
  "./utils/*": {