Skip to content

Commit 064cb71

Browse files
committed
refactor(litellm): Remove prefix from model names
1 parent 07d0ebe commit 064cb71

5 files changed

Lines changed: 88 additions & 51 deletions

File tree

phpstan.dist.neon

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,5 @@ parameters:
55
level: 10
66
paths:
77
- src
8-
excludePaths:
9-
analyse:
10-
- src/Providers/LiteLLMModelInfoProvider.php
118
tmpDir: .phpstan-cache
129
checkBenevolentUnionTypes: true

src/Providers/LiteLLMModelInfoProvider.php

Lines changed: 62 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
namespace Cortex\ModelInfo\Providers;
66

7-
use JsonException;
87
use SensitiveParameter;
98
use Psr\SimpleCache\CacheInterface;
109
use Cortex\ModelInfo\Data\ModelInfo;
@@ -17,6 +16,10 @@
1716
use Cortex\ModelInfo\Providers\Concerns\ChecksSupport;
1817
use 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+
*/
2023
class 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;

src/Providers/OllamaModelInfoProvider.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,19 +62,20 @@ public function getModelInfo(ModelProvider $modelProvider, string $model): Model
6262

6363
return self::mapModelInfo(
6464
$this->getModelInfoResponse($model),
65+
$model,
6566
);
6667
}
6768

6869
/**
6970
* @param OllamaModelInfoResponse|OllamaModelsResponse $modelResponseBody
7071
*/
71-
protected static function mapModelInfo(array $modelResponseBody): ModelInfo
72+
protected static function mapModelInfo(array $modelResponseBody, ?string $modelName = null): ModelInfo
7273
{
7374
$modelInfo = $modelResponseBody['model_info'] ?? [];
7475
$capabilities = $modelResponseBody['capabilities'] ?? [];
7576

7677
return new ModelInfo(
77-
name: $modelResponseBody['name'],
78+
name: $modelName ?? $modelResponseBody['name'],
7879
provider: ModelProvider::Ollama,
7980
type: self::getModelType($capabilities),
8081
maxInputTokens: self::getMaxInputTokens($modelInfo),

tests/Unit/Providers/LiteLLMModelInfoProviderTest.php

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,34 @@
2626
'mode' => 'chat',
2727
],
2828
])),
29+
new Response(body: json_encode([
30+
'xai/grok-2-latest' => [
31+
'litellm_provider' => 'xai',
32+
'mode' => 'chat',
33+
],
34+
])),
2935
);
3036

3137
$provider = new LiteLLMModelInfoProvider(
3238
httpClient: $client,
3339
);
3440

35-
$models = $provider->getModels(ModelProvider::OpenAI);
41+
$openAIModels = $provider->getModels(ModelProvider::OpenAI);
42+
$xAIModels = $provider->getModels(ModelProvider::XAI);
43+
44+
expect($openAIModels)->toBeArray()
45+
->toHaveCount(2)
46+
->toContainOnlyInstancesOf(ModelInfo::class);
47+
48+
expect($openAIModels[0]->name)->toBe('gpt-4o');
49+
expect($openAIModels[1]->name)->toBe('gpt-3.5-turbo');
50+
51+
expect($xAIModels)->toBeArray()
52+
->toHaveCount(1)
53+
->toContainOnlyInstancesOf(ModelInfo::class);
3654

37-
expect($models)->toBeArray()->toContainOnlyInstancesOf(ModelInfo::class);
55+
// prefix is removed from model name
56+
expect($xAIModels[0]->name)->toBe('grok-2-latest');
3857
});
3958

4059
test('it can get the model info', function (): void {

tests/Unit/Providers/OllamaModelInfoProviderTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
new Response(body: json_encode([
5858
'name' => 'mistral-small3.1',
5959
'model_info' => [
60-
'mock.context_length' => 1024 * 8,
60+
'mock.context_length' => 1024 * 128,
6161
],
6262
'capabilities' => [
6363
'completion',
@@ -76,7 +76,7 @@
7676
expect($modelInfo->name)->toBe('mistral-small3.1');
7777
expect($modelInfo->provider)->toBe(ModelProvider::Ollama);
7878
expect($modelInfo->type)->toBe(ModelType::Chat);
79-
expect($modelInfo->maxInputTokens)->toBe(8000);
79+
expect($modelInfo->maxInputTokens)->toBe(128000);
8080
expect($modelInfo->maxOutputTokens)->toBeNull();
8181
expect($modelInfo->inputCostPerToken)->toBe(0.0);
8282
expect($modelInfo->outputCostPerToken)->toBe(0.0);

0 commit comments

Comments
 (0)