From 9c998533c47e559f8dddcf043af6d10cbc13a87c Mon Sep 17 00:00:00 2001 From: Chris Bridges Date: Fri, 13 Dec 2024 11:26:09 +0000 Subject: [PATCH 1/3] draft anthropic caching --- config/prism.php | 2 + src/Concerns/HasProviderMeta.php | 29 +++++++++++ src/PrismManager.php | 1 + src/Providers/Anthropic/Anthropic.php | 6 ++- .../Anthropic/Enums/AnthropicCacheType.php | 8 +++ src/Providers/Anthropic/Maps/MessageMap.php | 49 +++++++++++-------- src/Providers/Anthropic/Maps/ToolMap.php | 25 ++++++---- src/Tool.php | 25 ++-------- .../Messages/AssistantMessage.php | 3 ++ src/ValueObjects/Messages/SystemMessage.php | 5 +- src/ValueObjects/Messages/UserMessage.php | 3 ++ .../Anthropic/AnthropicBetaHeaderTest.php | 34 +++++++++++++ tests/Providers/Anthropic/MessageMapTest.php | 47 +++++++++++++++++- tests/Providers/Anthropic/ToolMapTest.php | 30 ++++++++++++ 14 files changed, 212 insertions(+), 55 deletions(-) create mode 100644 src/Concerns/HasProviderMeta.php create mode 100644 src/Providers/Anthropic/Enums/AnthropicCacheType.php create mode 100644 tests/Providers/Anthropic/AnthropicBetaHeaderTest.php diff --git a/config/prism.php b/config/prism.php index 83f6546..a0f2d50 100644 --- a/config/prism.php +++ b/config/prism.php @@ -15,6 +15,8 @@ 'anthropic' => [ 'api_key' => env('ANTHROPIC_API_KEY', ''), 'version' => env('ANTHROPIC_API_VERSION', '2023-06-01'), + // Seperate each feature with a comma with no spaces. + 'beta_features' => ENV('ANTHROPIC_BETA_FEATURES', null), ], 'ollama' => [ 'url' => env('OLLAMA_URL', 'http://localhost:11434/v1'), diff --git a/src/Concerns/HasProviderMeta.php b/src/Concerns/HasProviderMeta.php new file mode 100644 index 0000000..6e2bb56 --- /dev/null +++ b/src/Concerns/HasProviderMeta.php @@ -0,0 +1,29 @@ +> */ + protected $providerMeta = []; + + /** + * @param array $meta + */ + public function withProviderMeta(Provider $provider, array $meta): self + { + $this->providerMeta[$provider->value] = $meta; + + return $this; + } + + /** + * @return array> $meta + */ + public function providerMeta(Provider $provider): array + { + return data_get($this->providerMeta, $provider->value, []); + } +} diff --git a/src/PrismManager.php b/src/PrismManager.php index f4701c2..96d8110 100644 --- a/src/PrismManager.php +++ b/src/PrismManager.php @@ -117,6 +117,7 @@ protected function createAnthropicProvider(array $config): Anthropic return new Anthropic( $config['api_key'], $config['version'], + $config['beta_features'] ); } diff --git a/src/Providers/Anthropic/Anthropic.php b/src/Providers/Anthropic/Anthropic.php index 76857c9..3a70e83 100644 --- a/src/Providers/Anthropic/Anthropic.php +++ b/src/Providers/Anthropic/Anthropic.php @@ -20,6 +20,7 @@ class Anthropic implements Provider public function __construct( public readonly string $apiKey, public readonly string $apiVersion, + public readonly ?string $betaFeatures = null ) {} #[\Override] @@ -56,10 +57,11 @@ public function embeddings(EmbeddingRequest $request): EmbeddingResponse */ protected function client(array $options = [], array $retry = []): PendingRequest { - return Http::withHeaders([ + return Http::withHeaders(array_filter([ 'x-api-key' => $this->apiKey, 'anthropic-version' => $this->apiVersion, - ]) + 'anthropic-beta' => $this->betaFeatures, + ])) ->withOptions($options) ->retry(...$retry) ->baseUrl('https://api.anthropic.com/v1'); diff --git a/src/Providers/Anthropic/Enums/AnthropicCacheType.php b/src/Providers/Anthropic/Enums/AnthropicCacheType.php new file mode 100644 index 0000000..e21331a --- /dev/null +++ b/src/Providers/Anthropic/Enums/AnthropicCacheType.php @@ -0,0 +1,8 @@ +providerMeta(Provider::Anthropic), 'cacheType', null); + + return array_filter([ 'role' => 'user', 'content' => $systemMessage->content, - ]; + 'cache_control' => $cacheType ? ['type' => $cacheType instanceof UnitEnum ? $cacheType->name : $cacheType] : null, + ]); } /** @@ -86,10 +91,16 @@ protected static function mapUserMessage(UserMessage $message): array ]; }, $message->images()); + $cacheType = data_get($message->providerMeta(Provider::Anthropic), 'cacheType', null); + return [ 'role' => 'user', 'content' => [ - ['type' => 'text', 'text' => $message->text()], + array_filter([ + 'type' => 'text', + 'text' => $message->text(), + 'cache_control' => $cacheType ? ['type' => $cacheType instanceof UnitEnum ? $cacheType->name : $cacheType] : null, + ]), ...$imageParts, ], @@ -101,32 +112,30 @@ protected static function mapUserMessage(UserMessage $message): array */ protected static function mapAssistantMessage(AssistantMessage $message): array { - if ($message->toolCalls) { - $content = []; + $content = []; - if ($message->content !== '' && $message->content !== '0') { - $content[] = [ - 'type' => 'text', - 'text' => $message->content, - ]; - } + if ($message->content !== '' && $message->content !== '0') { + $cacheType = data_get($message->providerMeta(Provider::Anthropic), 'cacheType', null); - $toolCalls = array_map(fn (ToolCall $toolCall): array => [ + $content[] = array_filter([ + 'type' => 'text', + 'text' => $message->content, + 'cache_control' => $cacheType ? ['type' => $cacheType instanceof UnitEnum ? $cacheType->name : $cacheType] : null, + ]); + } + + $toolCalls = $message->toolCalls + ? array_map(fn (ToolCall $toolCall): array => [ 'type' => 'tool_use', 'id' => $toolCall->id, 'name' => $toolCall->name, 'input' => $toolCall->arguments(), - ], $message->toolCalls); - - return [ - 'role' => 'assistant', - 'content' => array_merge($content, $toolCalls), - ]; - } + ], $message->toolCalls) + : []; return [ 'role' => 'assistant', - 'content' => $message->content, + 'content' => array_merge($content, $toolCalls), ]; } } diff --git a/src/Providers/Anthropic/Maps/ToolMap.php b/src/Providers/Anthropic/Maps/ToolMap.php index 75ade55..292e194 100644 --- a/src/Providers/Anthropic/Maps/ToolMap.php +++ b/src/Providers/Anthropic/Maps/ToolMap.php @@ -4,7 +4,9 @@ namespace EchoLabs\Prism\Providers\Anthropic\Maps; +use EchoLabs\Prism\Enums\Provider; use EchoLabs\Prism\Tool as PrismTool; +use UnitEnum; class ToolMap { @@ -14,14 +16,19 @@ class ToolMap */ public static function map(array $tools): array { - return array_map(fn (PrismTool $tool): array => [ - 'name' => $tool->name(), - 'description' => $tool->description(), - 'input_schema' => [ - 'type' => 'object', - 'properties' => $tool->parameters(), - 'required' => $tool->requiredParameters(), - ], - ], $tools); + return array_map(function (PrismTool $tool): array { + $cacheType = data_get($tool->providerMeta(Provider::Anthropic), 'cacheType', null); + + return array_filter([ + 'name' => $tool->name(), + 'description' => $tool->description(), + 'input_schema' => [ + 'type' => 'object', + 'properties' => $tool->parameters(), + 'required' => $tool->requiredParameters(), + ], + 'cache_control' => $cacheType ? ['type' => $cacheType instanceof UnitEnum ? $cacheType->name : $cacheType] : null, + ]); + }, $tools); } } diff --git a/src/Tool.php b/src/Tool.php index bbb1494..c1993f1 100644 --- a/src/Tool.php +++ b/src/Tool.php @@ -6,8 +6,8 @@ use ArgumentCountError; use Closure; +use EchoLabs\Prism\Concerns\HasProviderMeta; use EchoLabs\Prism\Contracts\Schema; -use EchoLabs\Prism\Enums\Provider; use EchoLabs\Prism\Exceptions\PrismException; use EchoLabs\Prism\Schema\ArraySchema; use EchoLabs\Prism\Schema\BooleanSchema; @@ -21,6 +21,8 @@ class Tool { + use HasProviderMeta; + protected string $name = ''; protected string $description; @@ -34,9 +36,6 @@ class Tool /** @var Closure():string|callable():string */ protected $fn; - /** @var array> */ - protected $providerMeta = []; - public function as(string $name): self { $this->name = $name; @@ -139,24 +138,6 @@ public function withEnumParameter( return $this; } - /** - * @param array $meta - */ - public function withProviderMeta(Provider $provider, array $meta): self - { - $this->providerMeta[$provider->value] = $meta; - - return $this; - } - - /** - * @return array> $meta - */ - public function providerMeta(Provider $provider): array - { - return data_get($this->providerMeta, $provider->value, []); - } - /** @return array */ public function requiredParameters(): array { diff --git a/src/ValueObjects/Messages/AssistantMessage.php b/src/ValueObjects/Messages/AssistantMessage.php index 2793d50..3f78bee 100644 --- a/src/ValueObjects/Messages/AssistantMessage.php +++ b/src/ValueObjects/Messages/AssistantMessage.php @@ -4,11 +4,14 @@ namespace EchoLabs\Prism\ValueObjects\Messages; +use EchoLabs\Prism\Concerns\HasProviderMeta; use EchoLabs\Prism\Contracts\Message; use EchoLabs\Prism\ValueObjects\ToolCall; class AssistantMessage implements Message { + use HasProviderMeta; + /** * @param ToolCall[] $toolCalls */ diff --git a/src/ValueObjects/Messages/SystemMessage.php b/src/ValueObjects/Messages/SystemMessage.php index 95e88be..e9edd40 100644 --- a/src/ValueObjects/Messages/SystemMessage.php +++ b/src/ValueObjects/Messages/SystemMessage.php @@ -4,11 +4,14 @@ namespace EchoLabs\Prism\ValueObjects\Messages; +use EchoLabs\Prism\Concerns\HasProviderMeta; use EchoLabs\Prism\Contracts\Message; class SystemMessage implements Message { + use HasProviderMeta; + public function __construct( - public readonly string $content, + public readonly string $content ) {} } diff --git a/src/ValueObjects/Messages/UserMessage.php b/src/ValueObjects/Messages/UserMessage.php index 13da895..58790d0 100644 --- a/src/ValueObjects/Messages/UserMessage.php +++ b/src/ValueObjects/Messages/UserMessage.php @@ -4,12 +4,15 @@ namespace EchoLabs\Prism\ValueObjects\Messages; +use EchoLabs\Prism\Concerns\HasProviderMeta; use EchoLabs\Prism\Contracts\Message; use EchoLabs\Prism\ValueObjects\Messages\Support\Image; use EchoLabs\Prism\ValueObjects\Messages\Support\Text; class UserMessage implements Message { + use HasProviderMeta; + /** * @param array $additionalContent */ diff --git a/tests/Providers/Anthropic/AnthropicBetaHeaderTest.php b/tests/Providers/Anthropic/AnthropicBetaHeaderTest.php new file mode 100644 index 0000000..74815ab --- /dev/null +++ b/tests/Providers/Anthropic/AnthropicBetaHeaderTest.php @@ -0,0 +1,34 @@ +set('prism.providers.anthropic.api_key', env('ANTHROPIC_API_KEY', 'sk-1234')); +}); + +it('does not set the anthropic-beta header if no beta feature is enabled in config', function (): void { + FixtureResponse::fakeResponseSequence('v1/messages', 'anthropic/generate-text-with-a-prompt'); + + Prism::text() + ->using('anthropic', 'claude-3-5-sonnet-20240620') + ->withPrompt('Who are you?') + ->generate(); + + Http::assertSent(fn (Request $request) => $request->hasHeader('anthropic-beta') === false); +}); + +it('sends the anthropic-beta header if a beta feature is enabled in config', function (): void { + config()->set('prism.providers.anthropic.beta_features', 'prompt-caching-2024-07-31'); + + FixtureResponse::fakeResponseSequence('v1/messages', 'anthropic/generate-text-with-a-prompt'); + + Prism::text() + ->using('anthropic', 'claude-3-5-sonnet-20240620') + ->withPrompt('Who are you?') + ->generate(); + + Http::assertSent(fn (Request $request) => $request->hasHeader('anthropic-beta', 'prompt-caching-2024-07-31')); +}); diff --git a/tests/Providers/Anthropic/MessageMapTest.php b/tests/Providers/Anthropic/MessageMapTest.php index e61d405..7b17821 100644 --- a/tests/Providers/Anthropic/MessageMapTest.php +++ b/tests/Providers/Anthropic/MessageMapTest.php @@ -4,6 +4,8 @@ namespace Tests\Providers\Anthropic; +use EchoLabs\Prism\Enums\Provider; +use EchoLabs\Prism\Providers\Anthropic\Enums\AnthropicCacheType; use EchoLabs\Prism\Providers\Anthropic\Maps\MessageMap; use EchoLabs\Prism\ValueObjects\Messages\AssistantMessage; use EchoLabs\Prism\ValueObjects\Messages\Support\Image; @@ -73,7 +75,12 @@ new AssistantMessage('I am Nyx'), ]))->toContain([ 'role' => 'assistant', - 'content' => 'I am Nyx', + 'content' => [ + [ + 'type' => 'text', + 'text' => 'I am Nyx', + ], + ], ]); }); @@ -143,3 +150,41 @@ 'content' => 'Who are you?', ]]); }); + +it('sets the cache type on a UserMessage if cacheType providerMeta is set on message', function (mixed $cacheType): void { + expect(MessageMap::map([ + (new UserMessage(content: 'Who are you?'))->withProviderMeta(Provider::Anthropic, ['cacheType' => $cacheType]), + ]))->toBe([[ + 'role' => 'user', + 'content' => [ + [ + 'type' => 'text', + 'text' => 'Who are you?', + 'cache_control' => ['type' => 'ethemeral'], + ], + ], + ]]); +})->with([ + 'ethemeral', + AnthropicCacheType::ethemeral, +]); + +it('sets the cache type on an AssistantMessage if cacheType providerMeta is set on message using an enum', function (mixed $cacheType): void { + expect(MessageMap::map([ + (new AssistantMessage(content: 'Who are you?'))->withProviderMeta(Provider::Anthropic, ['cacheType' => $cacheType]), + ]))->toBe([[ + 'role' => 'assistant', + 'content' => [ + [ + 'type' => 'text', + 'text' => 'Who are you?', + 'cache_control' => ['type' => AnthropicCacheType::ethemeral->name], + ], + ], + ]]); +})->with([ + 'ethemeral', + AnthropicCacheType::ethemeral, +]); + +it('sets the cache type on a SystemMessage if cacheType providerMeta is set on message using an enum', function (): void {})->todo('This test will need adding when the multiple system prompts PR gets merged.'); diff --git a/tests/Providers/Anthropic/ToolMapTest.php b/tests/Providers/Anthropic/ToolMapTest.php index b61de83..70fe9a1 100644 --- a/tests/Providers/Anthropic/ToolMapTest.php +++ b/tests/Providers/Anthropic/ToolMapTest.php @@ -4,6 +4,8 @@ namespace Tests\Providers\Anthropic; +use EchoLabs\Prism\Enums\Provider; +use EchoLabs\Prism\Providers\Anthropic\Enums\AnthropicCacheType; use EchoLabs\Prism\Providers\Anthropic\Maps\ToolMap; use EchoLabs\Prism\Tool; @@ -29,3 +31,31 @@ ], ]]); }); + +it('sets the cache typeif cacheType providerMeta is set on tool', function (mixed $cacheType): void { + $tool = (new Tool) + ->as('search') + ->for('Searching the web') + ->withStringParameter('query', 'the detailed search query') + ->using(fn (): string => '[Search results]') + ->withProviderMeta(Provider::Anthropic, ['cacheType' => $cacheType]); + + expect(ToolMap::map([$tool]))->toBe([[ + 'name' => 'search', + 'description' => 'Searching the web', + 'input_schema' => [ + 'type' => 'object', + 'properties' => [ + 'query' => [ + 'description' => 'the detailed search query', + 'type' => 'string', + ], + ], + 'required' => ['query'], + ], + 'cache_control' => ['type' => 'ethemeral'], + ]]); +})->with([ + 'ethemeral', + AnthropicCacheType::ethemeral, +]); From bff43cb79523ca3e2fd1450f3371c70700e922ad Mon Sep 17 00:00:00 2001 From: Chris Bridges Date: Mon, 16 Dec 2024 20:02:45 +0000 Subject: [PATCH 2/3] calculate cache usage --- .../Anthropic/Handlers/Structured.php | 6 ++++-- src/Providers/Anthropic/Handlers/Text.php | 6 ++++-- src/Structured/ResponseBuilder.php | 12 ++++++++--- src/Text/ResponseBuilder.php | 12 ++++++++--- src/ValueObjects/Usage.php | 4 +++- .../anthropic/calculate-cache-usage-1.json | 1 + .../Providers/Anthropic/AnthropicTextTest.php | 20 +++++++++++++++++++ 7 files changed, 50 insertions(+), 11 deletions(-) create mode 100644 tests/Fixtures/anthropic/calculate-cache-usage-1.json diff --git a/src/Providers/Anthropic/Handlers/Structured.php b/src/Providers/Anthropic/Handlers/Structured.php index dfc2b0a..11792e1 100644 --- a/src/Providers/Anthropic/Handlers/Structured.php +++ b/src/Providers/Anthropic/Handlers/Structured.php @@ -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: [ diff --git a/src/Providers/Anthropic/Handlers/Text.php b/src/Providers/Anthropic/Handlers/Text.php index 7f49492..7658952 100644 --- a/src/Providers/Anthropic/Handlers/Text.php +++ b/src/Providers/Anthropic/Handlers/Text.php @@ -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: [ diff --git a/src/Structured/ResponseBuilder.php b/src/Structured/ResponseBuilder.php index 1de33ae..6e43e9a 100644 --- a/src/Structured/ResponseBuilder.php +++ b/src/Structured/ResponseBuilder.php @@ -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, ); } } diff --git a/src/Text/ResponseBuilder.php b/src/Text/ResponseBuilder.php index e144adb..3b43077 100644 --- a/src/Text/ResponseBuilder.php +++ b/src/Text/ResponseBuilder.php @@ -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, ); } } diff --git a/src/ValueObjects/Usage.php b/src/ValueObjects/Usage.php index e7a2b03..533a575 100644 --- a/src/ValueObjects/Usage.php +++ b/src/ValueObjects/Usage.php @@ -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 ) {} } diff --git a/tests/Fixtures/anthropic/calculate-cache-usage-1.json b/tests/Fixtures/anthropic/calculate-cache-usage-1.json new file mode 100644 index 0000000..dd2f1da --- /dev/null +++ b/tests/Fixtures/anthropic/calculate-cache-usage-1.json @@ -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}} \ No newline at end of file diff --git a/tests/Providers/Anthropic/AnthropicTextTest.php b/tests/Providers/Anthropic/AnthropicTextTest.php index 2d404ca..008dfbc 100644 --- a/tests/Providers/Anthropic/AnthropicTextTest.php +++ b/tests/Providers/Anthropic/AnthropicTextTest.php @@ -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; @@ -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( @@ -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); +}); \ No newline at end of file From a7b32b38a7cfb709064210fe179213d454099ca4 Mon Sep 17 00:00:00 2001 From: Chris Bridges Date: Mon, 16 Dec 2024 20:04:20 +0000 Subject: [PATCH 3/3] correct spelling of ephemeral --- src/Providers/Anthropic/Enums/AnthropicCacheType.php | 2 +- tests/Providers/Anthropic/AnthropicTextTest.php | 4 ++-- tests/Providers/Anthropic/MessageMapTest.php | 12 ++++++------ tests/Providers/Anthropic/ToolMapTest.php | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Providers/Anthropic/Enums/AnthropicCacheType.php b/src/Providers/Anthropic/Enums/AnthropicCacheType.php index e21331a..e3581e9 100644 --- a/src/Providers/Anthropic/Enums/AnthropicCacheType.php +++ b/src/Providers/Anthropic/Enums/AnthropicCacheType.php @@ -4,5 +4,5 @@ enum AnthropicCacheType { - case ethemeral; + case ephemeral; } diff --git a/tests/Providers/Anthropic/AnthropicTextTest.php b/tests/Providers/Anthropic/AnthropicTextTest.php index 008dfbc..d8eb1f8 100644 --- a/tests/Providers/Anthropic/AnthropicTextTest.php +++ b/tests/Providers/Anthropic/AnthropicTextTest.php @@ -172,10 +172,10 @@ ->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']) + (new UserMessage('New context'))->withProviderMeta(Provider::Anthropic, ['cacheType' => 'ephemeral']), ]) ->generate(); expect($response->usage->cacheWriteInputTokens)->toBe(200); expect($response->usage->cacheReadInputTokens)->ToBe(100); -}); \ No newline at end of file +}); diff --git a/tests/Providers/Anthropic/MessageMapTest.php b/tests/Providers/Anthropic/MessageMapTest.php index 7b17821..0da1f16 100644 --- a/tests/Providers/Anthropic/MessageMapTest.php +++ b/tests/Providers/Anthropic/MessageMapTest.php @@ -160,13 +160,13 @@ [ 'type' => 'text', 'text' => 'Who are you?', - 'cache_control' => ['type' => 'ethemeral'], + 'cache_control' => ['type' => 'ephemeral'], ], ], ]]); })->with([ - 'ethemeral', - AnthropicCacheType::ethemeral, + 'ephemeral', + AnthropicCacheType::ephemeral, ]); it('sets the cache type on an AssistantMessage if cacheType providerMeta is set on message using an enum', function (mixed $cacheType): void { @@ -178,13 +178,13 @@ [ 'type' => 'text', 'text' => 'Who are you?', - 'cache_control' => ['type' => AnthropicCacheType::ethemeral->name], + 'cache_control' => ['type' => AnthropicCacheType::ephemeral->name], ], ], ]]); })->with([ - 'ethemeral', - AnthropicCacheType::ethemeral, + 'ephemeral', + AnthropicCacheType::ephemeral, ]); it('sets the cache type on a SystemMessage if cacheType providerMeta is set on message using an enum', function (): void {})->todo('This test will need adding when the multiple system prompts PR gets merged.'); diff --git a/tests/Providers/Anthropic/ToolMapTest.php b/tests/Providers/Anthropic/ToolMapTest.php index 70fe9a1..0de144d 100644 --- a/tests/Providers/Anthropic/ToolMapTest.php +++ b/tests/Providers/Anthropic/ToolMapTest.php @@ -53,9 +53,9 @@ ], 'required' => ['query'], ], - 'cache_control' => ['type' => 'ethemeral'], + 'cache_control' => ['type' => 'ephemeral'], ]]); })->with([ - 'ethemeral', - AnthropicCacheType::ethemeral, + 'ephemeral', + AnthropicCacheType::ephemeral, ]);