# All files / src/models PricingRegistry.ts

79.31% Statements 23/29
78.57% Branches 11/14
100% Functions 5/5
81.48% Lines 22/27

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121

    85x
    85x

    85x

    528x
    528x
    2x

    526x
    1565x
    22x

    504x
    504x

    2x

    1x
    1x
    1x
    1x
    1x
    1x
    1x
    1x

    1x
    1x

     import { ModelRegistry } from "./ModelRegistry.js";
    import { ModelPricing } from "./types.js";

    /**
     * Registry for LLM pricing information.
     * Priority: Runtime Overrides > Library Default Patterns > ModelRegistry (models.ts)
     */
    export class PricingRegistry {
      private static pricingOverrides = new Map<string, ModelPricing>();
      private static lastUpdated: Date | null = new Date();

      // Library-level fallbacks for common model families
      private static DEFAULT_PATTERNS: Array<{
        pattern: RegExp;
        provider: string;
        pricing: ModelPricing;
      }> = [
        {
          provider: "anthropic",
          pattern: /claude-3-7/,
          pricing: {
            text_tokens: {
              standard: {
                input_per_million: 3.0,
                output_per_million: 15.0,
                reasoning_output_per_million: 37.5
              },
              batch: {
                input_per_million: 1.5,
                output_per_million: 7.5,
                reasoning_output_per_million: 18.75
              }
            }
          }
        },
        {
          provider: "anthropic",
          pattern: /claude-3/,
          pricing: {
            text_tokens: {
              standard: { input_per_million: 3.0, output_per_million: 15.0 },
              batch: { input_per_million: 1.5, output_per_million: 7.5 }
            }
          }
        },
        {
          provider: "openai",
          pattern: /gpt-3/,
          pricing: {
            text_tokens: { standard: { input_per_million: 0.5, output_per_million: 1.5 } }
          }
        }
      ];

      /**
       * Get pricing for a model.
       */
      static getPricing(modelId: string, provider: string): ModelPricing | undefined {
        // 1. Check custom overrides (Runtime/Remote)
        const key = `${provider}/${modelId}`;
        if (this.pricingOverrides.has(key)) {
          return this.pricingOverrides.get(key);
        }

        // 2. Check library default patterns (Core Overrides)
        for (const entry of this.DEFAULT_PATTERNS) {
          if (entry.provider === provider && entry.pattern.test(modelId)) {
            return entry.pricing;
          }
        }

        // 3. Fallback to registry lookup (models.ts)
        const model = ModelRegistry.find(modelId, provider);
        return model?.pricing;
      }

      /**
       * Register or override pricing at runtime.
       */
      static register(provider: string, modelId: string, pricing: ModelPricing) {
        this.pricingOverrides.set(`${provider}/${modelId}`, pricing);
      }

      /**
       * Fetch updates from a remote URL.
       */
      static async fetchUpdates(url: string) {
        try {
          const response = await fetch(url);
          Iif (!response.ok) throw new Error(response.statusText);
          const data = await response.json();
          Eif (data.models) {
            for (const [key, pricing] of Object.entries(data.models)) {
              const [provider, modelId] = key.split("/");
              Eif (provider && modelId) this.register(provider, modelId, pricing as ModelPricing);
            }
          }
          this.lastUpdated = new Date();
          return true;
        } catch (error) {
          console.error("[NodeLLM] Error fetching pricing updates:", error);
          return false;
        }
      }

      /**
       * Get the timestamp of the last update.
       */
      static getLastUpdated(): Date | null {
        return this.lastUpdated;
      }

      /**
       * Reset overrides.
       */
      static reset() {
        this.pricingOverrides.clear();
        this.lastUpdated = new Date();
      }
    }