Skip to content

Commit 04c08f2

Browse files
authored
Merge pull request #494 from IsraelOrtuno/main
fix: add missing properties (specially `cached_usage`) to chat `CreateResponseUsage`
2 parents 2b4522b + a49b26f commit 04c08f2

8 files changed

+154
-5
lines changed

src/Responses/Chat/CreateResponse.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ private function __construct(
4141
/**
4242
* Acts as static factory, and returns a new Response instance.
4343
*
44-
* @param array{id: string, object: string, created: int, model: string, system_fingerprint?: string, choices: array<int, array{index: int, message: array{role: string, content: ?string, function_call: ?array{name: string, arguments: string}, tool_calls: ?array<int, array{id: string, type: string, function: array{name: string, arguments: string}}>}, finish_reason: string|null}>, usage: array{prompt_tokens: int, completion_tokens: int|null, total_tokens: int}} $attributes
44+
* @param array{id: string, object: string, created: int, model: string, system_fingerprint?: string, choices: array<int, array{index: int, message: array{role: string, content: ?string, function_call: ?array{name: string, arguments: string}, tool_calls: ?array<int, array{id: string, type: string, function: array{name: string, arguments: string}}>}, finish_reason: string|null}>, usage: array{prompt_tokens: int, completion_tokens: int|null, total_tokens: int, prompt_tokens_details?:array{cached_tokens:int}, completion_tokens_details?:array{audio_tokens?:int, reasoning_tokens:int, accepted_prediction_tokens:int, rejected_prediction_tokens:int}}} $attributes
4545
*/
4646
public static function from(array $attributes, MetaInformation $meta): self
4747
{

src/Responses/Chat/CreateResponseUsage.php

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,43 @@ private function __construct(
1010
public readonly int $promptTokens,
1111
public readonly ?int $completionTokens,
1212
public readonly int $totalTokens,
13+
public readonly ?CreateResponseUsagePromptTokensDetails $promptTokensDetails,
14+
public readonly ?CreateResponseUsageCompletionTokensDetails $completionTokensDetails
1315
) {}
1416

1517
/**
16-
* @param array{prompt_tokens: int, completion_tokens: int|null, total_tokens: int} $attributes
18+
* @param array{prompt_tokens: int, completion_tokens: int|null, total_tokens: int, prompt_tokens_details?:array{cached_tokens:int}, completion_tokens_details?:array{audio_tokens?:int, reasoning_tokens:int, accepted_prediction_tokens:int, rejected_prediction_tokens:int}} $attributes
1719
*/
1820
public static function from(array $attributes): self
1921
{
2022
return new self(
2123
$attributes['prompt_tokens'],
2224
$attributes['completion_tokens'] ?? null,
2325
$attributes['total_tokens'],
26+
isset($attributes['prompt_tokens_details']) ? CreateResponseUsagePromptTokensDetails::from($attributes['prompt_tokens_details']) : null,
27+
isset($attributes['completion_tokens_details']) ? CreateResponseUsageCompletionTokensDetails::from($attributes['completion_tokens_details']) : null
2428
);
2529
}
2630

2731
/**
28-
* @return array{prompt_tokens: int, completion_tokens: int|null, total_tokens: int}
32+
* @return array{prompt_tokens: int, completion_tokens: int|null, total_tokens: int, prompt_tokens_details?:array{cached_tokens:int}}
2933
*/
3034
public function toArray(): array
3135
{
32-
return [
36+
$result = [
3337
'prompt_tokens' => $this->promptTokens,
3438
'completion_tokens' => $this->completionTokens,
3539
'total_tokens' => $this->totalTokens,
3640
];
41+
42+
if ($this->promptTokensDetails) {
43+
$result['prompt_tokens_details'] = $this->promptTokensDetails->toArray();
44+
}
45+
46+
if ($this->completionTokensDetails) {
47+
$result['completion_tokens_details'] = $this->completionTokensDetails->toArray();
48+
}
49+
50+
return $result;
3751
}
3852
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenAI\Responses\Chat;
6+
7+
final class CreateResponseUsageCompletionTokensDetails
8+
{
9+
private function __construct(
10+
public readonly ?int $audioTokens,
11+
public readonly int $reasoningTokens,
12+
public readonly int $acceptedPredictionTokens,
13+
public readonly int $rejectedPredictionTokens
14+
) {}
15+
16+
/**
17+
* @param array{audio_tokens?:int, reasoning_tokens:int, accepted_prediction_tokens:int, rejected_prediction_tokens:int} $attributes
18+
*/
19+
public static function from(array $attributes): self
20+
{
21+
return new self(
22+
$attributes['audio_tokens'] ?? null,
23+
$attributes['reasoning_tokens'],
24+
$attributes['accepted_prediction_tokens'],
25+
$attributes['rejected_prediction_tokens'],
26+
);
27+
}
28+
29+
/**
30+
* @return array{audio_tokens?:int, reasoning_tokens:int, accepted_prediction_tokens:int, rejected_prediction_tokens:int}
31+
*/
32+
public function toArray(): array
33+
{
34+
$result = [
35+
'reasoning_tokens' => $this->reasoningTokens,
36+
'accepted_prediction_tokens' => $this->acceptedPredictionTokens,
37+
'rejected_prediction_tokens' => $this->rejectedPredictionTokens,
38+
];
39+
40+
if (! is_null($this->audioTokens)) {
41+
$result['audio_tokens'] = $this->audioTokens;
42+
}
43+
44+
return $result;
45+
}
46+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenAI\Responses\Chat;
6+
7+
final class CreateResponseUsagePromptTokensDetails
8+
{
9+
private function __construct(
10+
public readonly ?int $audioTokens,
11+
public readonly int $cachedTokens
12+
) {}
13+
14+
/**
15+
* @param array{audio_tokens?:int, cached_tokens?: int} $attributes
16+
*/
17+
public static function from(array $attributes): self
18+
{
19+
return new self(
20+
$attributes['audio_tokens'] ?? null,
21+
$attributes['cached_tokens'] ?? 0,
22+
);
23+
}
24+
25+
/**
26+
* @return array{cached_tokens: int, audio_tokens?:int}
27+
*/
28+
public function toArray(): array
29+
{
30+
$result = [
31+
'cached_tokens' => $this->cachedTokens,
32+
];
33+
34+
if (! is_null($this->audioTokens)) {
35+
$result['audio_tokens'] = $this->audioTokens;
36+
}
37+
38+
return $result;
39+
}
40+
}

tests/Fixtures/Chat.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ function chatCompletion(): array
2424
'prompt_tokens' => 9,
2525
'completion_tokens' => 12,
2626
'total_tokens' => 21,
27+
'prompt_tokens_details' => [
28+
'cached_tokens' => 5,
29+
],
30+
'completion_tokens_details' => [
31+
'reasoning_tokens' => 0,
32+
'accepted_prediction_tokens' => 0,
33+
'rejected_prediction_tokens' => 0,
34+
],
2735
],
2836
];
2937
}

tests/Responses/Chat/CreateResponseUsage.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
<?php
22

33
use OpenAI\Responses\Chat\CreateResponseUsage;
4+
use OpenAI\Responses\Chat\CreateResponseUsageCompletionTokensDetails;
5+
use OpenAI\Responses\Chat\CreateResponseUsagePromptTokensDetails;
46

57
test('from', function () {
68
$result = CreateResponseUsage::from(chatCompletion()['usage']);
79

810
expect($result)
911
->promptTokens->toBe(9)
1012
->completionTokens->toBe(12)
11-
->totalTokens->toBe(21);
13+
->totalTokens->toBe(21)
14+
->promptTokensDetails->toBeInstanceOf(CreateResponseUsagePromptTokensDetails::class)
15+
->completionTokensDetails->toBeInstanceOf(CreateResponseUsageCompletionTokensDetails::class);
1216
});
1317

1418
test('to array', function () {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
use OpenAI\Responses\Chat\CreateResponseUsageCompletionTokensDetails;
4+
5+
test('from', function () {
6+
$result = CreateResponseUsageCompletionTokensDetails::from(chatCompletion()['usage']['completion_tokens_details']);
7+
8+
expect($result)
9+
->audioTokens->toBeNull()
10+
->reasoningTokens->toBe(0)
11+
->acceptedPredictionTokens->toBe(0)
12+
->rejectedPredictionTokens->toBe(0);
13+
});
14+
15+
test('to array', function () {
16+
$result = CreateResponseUsageCompletionTokensDetails::from(chatCompletion()['usage']['completion_tokens_details']);
17+
18+
expect($result->toArray())
19+
->toBe(chatCompletion()['usage']['completion_tokens_details']);
20+
});
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
use OpenAI\Responses\Chat\CreateResponseUsagePromptTokensDetails;
4+
5+
test('from', function () {
6+
$result = CreateResponseUsagePromptTokensDetails::from(chatCompletion()['usage']['prompt_tokens_details']);
7+
8+
expect($result)
9+
->cachedTokens->toBe(5);
10+
});
11+
12+
test('to array', function () {
13+
$result = CreateResponseUsagePromptTokensDetails::from(chatCompletion()['usage']['prompt_tokens_details']);
14+
15+
expect($result->toArray())
16+
->toBe(chatCompletion()['usage']['prompt_tokens_details']);
17+
});

0 commit comments

Comments
 (0)