Skip to content

Commit

Permalink
calculate cache usage
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisB-TL committed Dec 16, 2024
1 parent 9c99853 commit bff43cb
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 11 deletions.
6 changes: 4 additions & 2 deletions src/Providers/Anthropic/Handlers/Structured.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ public function handle(Request $request): ProviderResponse
text: $this->extractText($data),
toolCalls: $this->extractToolCalls($data),
usage: new Usage(
data_get($data, 'usage.input_tokens'),
data_get($data, 'usage.output_tokens'),
promptTokens: data_get($data, 'usage.input_tokens'),
completionTokens: data_get($data, 'usage.output_tokens'),
cacheWriteInputTokens: data_get($data, 'usage.cache_creation_input_tokens', null),
cacheReadInputTokens: data_get($data, 'usage.cache_read_input_tokens', null)
),
finishReason: FinishReasonMap::map(data_get($data, 'stop_reason', '')),
response: [
Expand Down
6 changes: 4 additions & 2 deletions src/Providers/Anthropic/Handlers/Text.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ public function handle(Request $request): ProviderResponse
text: $this->extractText($data),
toolCalls: $this->extractToolCalls($data),
usage: new Usage(
data_get($data, 'usage.input_tokens'),
data_get($data, 'usage.output_tokens'),
promptTokens: data_get($data, 'usage.input_tokens'),
completionTokens: data_get($data, 'usage.output_tokens'),
cacheWriteInputTokens: data_get($data, 'usage.cache_creation_input_tokens'),
cacheReadInputTokens: data_get($data, 'usage.cache_read_input_tokens')
),
finishReason: FinishReasonMap::map(data_get($data, 'stop_reason', '')),
response: [
Expand Down
12 changes: 9 additions & 3 deletions src/Structured/ResponseBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,18 @@ protected function decodeObject(string $responseText): ?array
protected function calculateTotalUsage(): Usage
{
return new Usage(
$this
promptTokens: $this
->steps
->sum(fn (Step $result): int => $result->usage->promptTokens),
$this
completionTokens: $this
->steps
->sum(fn (Step $result): int => $result->usage->completionTokens)
->sum(fn (Step $result): int => $result->usage->completionTokens),
cacheWriteInputTokens: $this->steps->contains(fn (Step $result): bool => $result->usage->cacheWriteInputTokens !== null)
? $this->steps->sum(fn (Step $result): int => $result->usage->cacheWriteInputTokens ?? 0)
: null,
cacheReadInputTokens: $this->steps->contains(fn (Step $result): bool => $result->usage->cacheReadInputTokens !== null)
? $this->steps->sum(fn (Step $result): int => $result->usage->cacheReadInputTokens ?? 0)
: null,
);
}
}
12 changes: 9 additions & 3 deletions src/Text/ResponseBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,18 @@ public function toResponse(): Response
protected function calculateTotalUsage(): Usage
{
return new Usage(
$this
promptTokens: $this
->steps
->sum(fn (Step $result): int => $result->usage->promptTokens),
$this
completionTokens: $this
->steps
->sum(fn (Step $result): int => $result->usage->completionTokens)
->sum(fn (Step $result): int => $result->usage->completionTokens),
cacheWriteInputTokens: $this->steps->contains(fn (Step $result): bool => $result->usage->cacheWriteInputTokens !== null)
? $this->steps->sum(fn (Step $result): int => $result->usage->cacheWriteInputTokens ?? 0)
: null,
cacheReadInputTokens: $this->steps->contains(fn (Step $result): bool => $result->usage->cacheReadInputTokens !== null)
? $this->steps->sum(fn (Step $result): int => $result->usage->cacheReadInputTokens ?? 0)
: null,
);
}
}
4 changes: 3 additions & 1 deletion src/ValueObjects/Usage.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ class Usage
{
public function __construct(
public readonly int $promptTokens,
public readonly int $completionTokens
public readonly int $completionTokens,
public readonly ?int $cacheWriteInputTokens = null,
public readonly ?int $cacheReadInputTokens = null
) {}
}
1 change: 1 addition & 0 deletions tests/Fixtures/anthropic/calculate-cache-usage-1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"id":"msg_01X2Qk7LtNEh4HB9xpYU57XU","type":"message","role":"assistant","model":"claude-3-5-sonnet-20240620","content":[{"type":"text","text":"I am an AI assistant created by Anthropic to be helpful, harmless, and honest. I don't have a physical form or avatar - I'm a language model trained to engage in conversation and help with tasks. How can I assist you today?"}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":11,"output_tokens":55, "cache_creation_input_tokens" : 200, "cache_read_input_tokens": 100}}
20 changes: 20 additions & 0 deletions tests/Providers/Anthropic/AnthropicTextTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use EchoLabs\Prism\Facades\Tool;
use EchoLabs\Prism\Prism;
use EchoLabs\Prism\ValueObjects\Messages\Support\Image;
use EchoLabs\Prism\ValueObjects\Messages\SystemMessage;
use EchoLabs\Prism\ValueObjects\Messages\UserMessage;
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Http;
Expand All @@ -27,6 +28,8 @@

expect($response->usage->promptTokens)->toBe(11);
expect($response->usage->completionTokens)->toBe(55);
expect($response->usage->cacheWriteInputTokens)->toBeNull();
expect($response->usage->cacheReadInputTokens)->toBeNull();
expect($response->response['id'])->toBe('msg_01X2Qk7LtNEh4HB9xpYU57XU');
expect($response->response['model'])->toBe('claude-3-5-sonnet-20240620');
expect($response->text)->toBe(
Expand Down Expand Up @@ -159,3 +162,20 @@

expect($response->toolCalls[0]->name)->toBe('weather');
});

it('can calculate cache usage correctly', function (): void {
config()->set('prism.providers.anthropic.beta_features', 'prompt-caching-2024-07-31');

FixtureResponse::fakeResponseSequence('v1/messages', 'anthropic/calculate-cache-usage');

$response = Prism::text()
->using('anthropic', 'claude-3-5-sonnet-20240620')
->withMessages([
(new SystemMessage('Old context'))->withProviderMeta(Provider::Anthropic, ['cacheType' => 'ephemeral']),
(new UserMessage('New context'))->withProviderMeta(Provider::Anthropic, ['cacheType' => 'ephemeral'])
])
->generate();

expect($response->usage->cacheWriteInputTokens)->toBe(200);
expect($response->usage->cacheReadInputTokens)->ToBe(100);
});

0 comments on commit bff43cb

Please sign in to comment.