'default', 'anthropic' => 'standard', 'gemini' => 'standard']; /** @return array{0:?Amount, 1:?string} the exact cost, or null and the reason */ public static function price(Rate $rate, int $inputTokens, int $outputTokens, ?int $cachedInputTokens, ?int $otherTokens, ?string $processingTier): array { if ($inputTokens < 0 || $outputTokens < 0 || ($otherTokens !== null && $otherTokens < 0)) { return [null, self::DETAILS_INVALID]; } // The list prices standard processing only: priority, flex, batch or any other tier is billed differently, and an unreported tier // cannot be assumed to be the standard one. if ($processingTier === null || $processingTier === '') { return [null, self::TIER_UNKNOWN]; } if ($processingTier !== (self::STANDARD_TIER[$rate->provider] ?? '')) { return [null, self::TIER_NOT_PRICED]; } if ($otherTokens !== null && $otherTokens > 0) { return [null, self::OTHER_CATEGORIES]; } $out = Amount::ofTokens($outputTokens, $rate->outputMicro); if ($rate->provider === 'anthropic') { return $otherTokens === null ? [null, self::DETAILS_MISSING] : [Amount::ofTokens($inputTokens, $rate->inputMicro)->plus($out), null]; } if ($cachedInputTokens === null) { return [null, self::DETAILS_MISSING]; } if ($cachedInputTokens < 0 || $cachedInputTokens > $inputTokens) { return [null, self::DETAILS_INVALID]; } if ($cachedInputTokens > 0 && $rate->cachedInputMicro === null) { return [null, self::NO_CACHED_RATE]; } $in = Amount::ofTokens($inputTokens - $cachedInputTokens, $rate->inputMicro)->plus(Amount::ofTokens($cachedInputTokens, (int) $rate->cachedInputMicro)); return [$in->plus($out), null]; } }