44
55namespace Cortex \ModelInfo \Providers ;
66
7- use JsonException ;
87use SensitiveParameter ;
98use Psr \SimpleCache \CacheInterface ;
109use Cortex \ModelInfo \Data \ModelInfo ;
1716use Cortex \ModelInfo \Providers \Concerns \ChecksSupport ;
1817use Cortex \ModelInfo \Providers \Concerns \MakesRequests ;
1918
19+ /**
20+ * @phpstan-type LiteLLMModelInfoResponse array{litellm_provider: string, mode: string, max_input_tokens: ?int, max_output_tokens: ?int, input_cost_per_token: ?float, output_cost_per_token: ?float, supports_response_schema: ?bool, supports_function_calling: ?bool, supports_vision: ?bool, supports_tool_choice: ?bool, supports_reasoning: ?bool, supports_web_search: ?bool, supports_prompt_caching: ?bool, supports_audio_input: ?bool, supports_audio_output: ?bool, deprecation_date?: ?string}
21+ * @phpstan-type LiteLLMModelInfoResponseWithName array{name: string, litellm_provider: string, mode: string, max_input_tokens: ?int, max_output_tokens: ?int, input_cost_per_token: ?float, output_cost_per_token: ?float, supports_response_schema: ?bool, supports_function_calling: ?bool, supports_vision: ?bool, supports_tool_choice: ?bool, supports_reasoning: ?bool, supports_web_search: ?bool, supports_prompt_caching: ?bool, supports_audio_input: ?bool, supports_audio_output: ?bool, deprecation_date?: ?string}
22+ */
2023class LiteLLMModelInfoProvider implements ModelInfoProvider
2124{
2225 use ChecksSupport;
@@ -52,18 +55,17 @@ public function getModels(ModelProvider $modelProvider): array
5255 {
5356 $ this ->checkSupportOrFail ($ modelProvider );
5457
55- $ body = $ this ->getStaticResponse ();
58+ $ body = $ this ->getResponse ();
5659
57- $ models = array_filter (
60+ $ models = self :: removePrefixFromModelName ( array_filter (
5861 $ body ,
5962 fn (array $ model ): bool => $ model ['litellm_provider ' ] === $ modelProvider ->value ,
60- );
63+ )) ;
6164
62- return array_values ( array_map (
63- fn (array $ modelInfo, string $ model ): ModelInfo => self ::mapModelInfo ($ modelProvider, $ model , $ modelInfo ),
65+ return array_map (
66+ fn (array $ modelInfo ): ModelInfo => self ::mapModelInfo ($ modelProvider , $ modelInfo ),
6467 $ models ,
65- array_keys ($ models ),
66- ));
68+ );
6769 }
6870
6971 /**
@@ -73,50 +75,59 @@ public function getModelInfo(ModelProvider $modelProvider, string $model): Model
7375 {
7476 $ this ->checkSupportOrFail ($ modelProvider );
7577
76- $ body = $ this ->getStaticResponse ();
78+ $ body = $ this ->getResponse ();
7779
78- $ models = array_filter (
80+ $ models = self :: removePrefixFromModelName ( array_filter (
7981 $ body ,
8082 fn (array $ model ): bool => $ model ['litellm_provider ' ] === $ modelProvider ->value ,
81- );
83+ )) ;
8284
8385 $ modelInfo = array_values (
84- array_filter (
85- $ models ,
86- fn (string $ key ): bool => $ key === $ model ,
87- ARRAY_FILTER_USE_KEY ,
88- ),
86+ array_filter ($ models , fn (array $ modelInfo ): bool => $ modelInfo ['name ' ] === $ model ),
8987 )[0 ] ?? null ;
9088
9189 if ($ modelInfo === null ) {
9290 throw new ModelInfoException ('Model not found ' );
9391 }
9492
95- return self ::mapModelInfo ($ modelProvider , $ model , $ modelInfo );
93+ return self ::mapModelInfo ($ modelProvider , $ modelInfo );
9694 }
9795
98- protected static function mapModelInfo (
99- ModelProvider $ modelProvider ,
100- string $ model ,
101- array $ modelInfo ,
102- ): ModelInfo {
96+ /**
97+ * @param array<array-key, LiteLLMModelInfoResponse> $models
98+ *
99+ * @return array<array-key, LiteLLMModelInfoResponseWithName>
100+ */
101+ protected static function removePrefixFromModelName (array $ models ): array
102+ {
103+ return array_map (fn (array $ modelInfo , string $ modelName ): array => [
104+ 'name ' => str_replace ($ modelInfo ['litellm_provider ' ] . '/ ' , '' , $ modelName ),
105+ ...$ modelInfo ,
106+ ], $ models , array_keys ($ models ));
107+ }
108+
109+ /**
110+ * @param LiteLLMModelInfoResponseWithName $modelInfo
111+ */
112+ protected static function mapModelInfo (ModelProvider $ modelProvider , array $ modelInfo ): ModelInfo
113+ {
103114 return new ModelInfo (
104- name: $ model ,
115+ name: $ modelInfo [ ' name ' ] ,
105116 provider: $ modelProvider ,
106- type: self ::mapModelType ($ modelInfo ['mode ' ] ?? '' ),
117+ type: self ::mapModelType ($ modelInfo ['mode ' ]),
107118 maxInputTokens: $ modelInfo ['max_input_tokens ' ] ?? null ,
108119 maxOutputTokens: $ modelInfo ['max_output_tokens ' ] ?? null ,
109120 inputCostPerToken: $ modelInfo ['input_cost_per_token ' ] ?? 0.0 ,
110121 outputCostPerToken: $ modelInfo ['output_cost_per_token ' ] ?? 0.0 ,
111122 features: self ::getFeatures ($ modelInfo ),
112- isDeprecated: isset ($ modelInfo ['deprecation_date ' ]) && $ modelInfo [ ' deprecation_date ' ] !== null ,
123+ isDeprecated: isset ($ modelInfo ['deprecation_date ' ]),
113124 );
114125 }
115126
116127 /**
117- * @param array<string, mixed> $info
128+ * @param LiteLLMModelInfoResponse $info
118129 *
119- * @return array<int , \Cortex\Enums\ModelFeature>
130+ * @return array<array-key , \Cortex\ModelInfo \Enums\ModelFeature>
120131 */
121132 protected static function getFeatures (array $ info ): array
122133 {
@@ -177,39 +188,48 @@ protected static function mapModelType(string $type): ModelType
177188 }
178189
179190 /**
180- * @throws \Cortex\Exceptions\ModelInfoException
191+ * @throws \Cortex\ModelInfo\ Exceptions\ModelInfoException
181192 *
182- * @return array<string, mixed >
193+ * @return array<array-key, LiteLLMModelInfoResponse >
183194 */
184195 protected function getStaticResponse (): array
185196 {
186- $ request = self ::discoverHttpRequestFactory ()->createRequest ('GET ' , self ::LITELLM_STATIC_URL );
187- $ response = $ this ->httpClient ->sendRequest ($ request );
188-
189- if ($ response ->getStatusCode () !== 200 ) {
190- throw new ModelInfoException ('Failed to get model info ' );
191- }
197+ $ request = self ::discoverHttpRequestFactoryOrFail ()
198+ ->createRequest ('GET ' , self ::LITELLM_STATIC_URL );
192199
193- try {
194- return json_decode ($ response ->getBody ()->getContents (), true , flags: JSON_THROW_ON_ERROR );
195- } catch (JsonException $ jsonException ) {
196- throw new ModelInfoException ('Failed to decode model info ' , previous: $ jsonException );
197- }
200+ // @phpstan-ignore return.type
201+ return $ this ->getJsonResponse ($ request );
198202 }
199203
200204 /**
201205 * @throws \Cortex\ModelInfo\Exceptions\ModelInfoException
202206 *
203- * @return array<string, mixed >
207+ * @return array<array-key, LiteLLMModelInfoResponse >
204208 */
205209 protected function getApiModelsResponse (): array
206210 {
207- $ request = self ::discoverHttpRequestFactory ()
211+ $ request = self ::discoverHttpRequestFactoryOrFail ()
208212 ->createRequest ('GET ' , $ this ->host . '/v1/models ' );
209213
214+ // @phpstan-ignore return.type
210215 return $ this ->getJsonResponse ($ request );
211216 }
212217
218+ /**
219+ * @throws \Cortex\ModelInfo\Exceptions\ModelInfoException
220+ *
221+ * @return array<array-key, LiteLLMModelInfoResponse>
222+ */
223+ protected function getResponse (): array
224+ {
225+ return $ this ->shouldUseStaticResponse ()
226+ ? $ this ->getStaticResponse ()
227+ : $ this ->getApiModelsResponse ();
228+ }
229+
230+ /**
231+ * Determine if the static response should be used.
232+ */
213233 protected function shouldUseStaticResponse (): bool
214234 {
215235 return $ this ->host === null || $ this ->apiKey === null ;
0 commit comments