* } */ class OpenRouterModelMetadataDirectory extends AbstractApiBasedModelMetadataDirectory { /** * {@inheritDoc} * * @since 1.0.0 */ protected function sendListModelsRequest(): array { $httpTransporter = $this->getHttpTransporter(); $request = new Request( HttpMethodEnum::GET(), OpenRouterProvider::url($this->getModelsApiPath()), [], null ); $request = $this->getRequestAuthentication()->authenticateRequest($request); $response = $httpTransporter->send($request); $modelsMetadata = $this->parseResponseToModelMetadataList($response); $modelMetadataMap = []; foreach ($modelsMetadata as $modelMetadata) { $modelMetadataMap[$modelMetadata->getId()] = $modelMetadata; } return $modelMetadataMap; } /** * Parses the OpenRouter API response to a list of model metadata. * * @since 1.0.0 * * @param Response $response HTTP response from OpenRouter. * @return ModelMetadata[] List of model metadata. * @throws ResponseException If response is invalid. */ protected function parseResponseToModelMetadataList(Response $response): array { /** @var OpenRouterModelsResponseData $responseData */ $responseData = $response->getData(); if (!isset($responseData['data']) || !is_array($responseData['data'])) { throw ResponseException::fromMissingData('OpenRouter', 'data'); } $modelsMetadata = []; foreach ($responseData['data'] as $model) { $modelMetadata = $this->parseModelToMetadata($model); if (null !== $modelMetadata) { $modelsMetadata[] = $modelMetadata; } } return $modelsMetadata; } /** * Parses a single model from the OpenRouter API response to ModelMetadata. * * @since 1.0.0 * * @param array $model Model data from OpenRouter API. * @return ModelMetadata|null Model metadata or null if model should be skipped. */ protected function parseModelToMetadata(array $model): ?ModelMetadata { if (!isset($model['id']) || empty($model['id'])) { return null; } $modelId = $model['id']; $modelName = $model['name'] ?? $modelId; $capabilities = $this->determineCapabilities($model); $options = $this->determineSupportedOptions($model); return new ModelMetadata( $modelId, $modelName, $capabilities, $options ); } /** * Determines model capabilities based on OpenRouter model data. * * @since 1.0.0 * * @param array $model Model data from OpenRouter API. * @return CapabilityEnum[] List of capabilities. */ protected function determineCapabilities(array $model): array { $capabilities = [ CapabilityEnum::textGeneration(), CapabilityEnum::chatHistory(), ]; $modality = $model['architecture']['modality'] ?? 'text->text'; if (str_contains($modality, 'image')) { $capabilities[] = CapabilityEnum::imageGeneration(); } return $capabilities; } /** * Determines supported options based on OpenRouter model data. * * @since 1.0.0 * * @param array $model Model data from OpenRouter API. * @return SupportedOption[] List of supported options. */ protected function determineSupportedOptions(array $model): array { $options = [ new SupportedOption(OptionEnum::systemInstruction()), new SupportedOption(OptionEnum::maxTokens()), new SupportedOption(OptionEnum::temperature()), new SupportedOption(OptionEnum::topP()), new SupportedOption(OptionEnum::stopSequences()), new SupportedOption(OptionEnum::customOptions()), ]; $modality = $model['architecture']['modality'] ?? 'text->text'; $inputModalities = [ModalityEnum::text()]; $outputModalities = [ModalityEnum::text()]; if (str_contains($modality, '+image->') || str_contains($modality, 'image+')) { $inputModalities[] = ModalityEnum::image(); } if (str_contains($modality, '->text+image') || str_contains($modality, '->image')) { $outputModalities[] = ModalityEnum::image(); } $options[] = new SupportedOption(OptionEnum::inputModalities(), [$inputModalities]); $options[] = new SupportedOption(OptionEnum::outputModalities(), [$outputModalities]); return $options; } /** * Gets the API path for listing models. * * @since 1.0.0 * * @return string API path. */ protected function getModelsApiPath(): string { return '/models'; } }