engine.ts 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import type { DiscoveredModel, ExternalSignalMap } from '../types';
  2. import { extractFeatureVector } from './features';
  3. import type {
  4. FeatureVector,
  5. FeatureWeights,
  6. ScoredCandidate,
  7. ScoringAgentName,
  8. } from './types';
  9. import { getFeatureWeights } from './weights';
  10. function weightedFeatures(
  11. features: FeatureVector,
  12. weights: FeatureWeights,
  13. ): FeatureVector {
  14. return {
  15. status: features.status * weights.status,
  16. context: features.context * weights.context,
  17. output: features.output * weights.output,
  18. versionBonus: features.versionBonus * weights.versionBonus,
  19. reasoning: features.reasoning * weights.reasoning,
  20. toolcall: features.toolcall * weights.toolcall,
  21. attachment: features.attachment * weights.attachment,
  22. quality: features.quality * weights.quality,
  23. coding: features.coding * weights.coding,
  24. latencyPenalty: features.latencyPenalty * weights.latencyPenalty,
  25. pricePenalty: features.pricePenalty * weights.pricePenalty,
  26. };
  27. }
  28. function sumFeatures(features: FeatureVector): number {
  29. return (
  30. features.status +
  31. features.context +
  32. features.output +
  33. features.versionBonus +
  34. features.reasoning +
  35. features.toolcall +
  36. features.attachment +
  37. features.quality +
  38. features.coding +
  39. features.latencyPenalty +
  40. features.pricePenalty
  41. );
  42. }
  43. function withStableTieBreak(
  44. left: ScoredCandidate,
  45. right: ScoredCandidate,
  46. ): number {
  47. if (left.totalScore !== right.totalScore) {
  48. return right.totalScore - left.totalScore;
  49. }
  50. const providerDelta = left.model.providerID.localeCompare(
  51. right.model.providerID,
  52. );
  53. if (providerDelta !== 0) {
  54. return providerDelta;
  55. }
  56. return left.model.model.localeCompare(right.model.model);
  57. }
  58. export function scoreCandidateV2(
  59. model: DiscoveredModel,
  60. agent: ScoringAgentName,
  61. externalSignals?: ExternalSignalMap,
  62. ): ScoredCandidate {
  63. const features = extractFeatureVector(model, agent, externalSignals);
  64. const weights = getFeatureWeights(agent);
  65. const weighted = weightedFeatures(features, weights);
  66. return {
  67. model,
  68. totalScore: Math.round(sumFeatures(weighted) * 1000) / 1000,
  69. scoreBreakdown: {
  70. features,
  71. weighted,
  72. },
  73. };
  74. }
  75. export function rankModelsV2(
  76. models: DiscoveredModel[],
  77. agent: ScoringAgentName,
  78. externalSignals?: ExternalSignalMap,
  79. ): ScoredCandidate[] {
  80. return models
  81. .map((model) => scoreCandidateV2(model, agent, externalSignals))
  82. .sort(withStableTieBreak);
  83. }