69 | */
70 | public static function buildPayload(Request $request, int $stepCount = 0): array
71 | {
72 | return array_filter([
73 | 'inferenceConfig' => array_filter([
74 | 'maxTokens' => $request->maxTokens(),
75 | 'temperature' => $request->temperature(),
76 | 'topP' => $request->topP(),
77 | ], fn (mixed $value): bool => $value !== null),
78 | 'messages' => MessageMap::map($request->messages()),
79 | 'system' => MessageMap::mapSystemMessages($request->systemPrompts()),
80 | 'toolConfig' => $request->tools() === []
81 | ? null
82 | : array_filter([
83 | 'tools' => ToolMap::map($request->tools()),
84 | 'toolChoice' => $stepCount === 0 ? ToolChoiceMap::map($request->toolChoice()) : null,
85 | ]),
86 | 'additionalModelRequestFields' => $request->providerOptions('additionalModelRequestFields'),
87 | 'additionalModelResponseFieldPaths' => $request->providerOptions('additionalModelResponseFieldPaths'),
88 | 'guardrailConfig' => $request->providerOptions('guardrailConfig'),
89 | 'performanceConfig' => $request->providerOptions('performanceConfig'),
90 | 'promptVariables' => $request->providerOptions('promptVariables'),
91 | 'requestMetadata' => $request->providerOptions('requestMetadata'),
92 | ]);
93 | }
94 |
95 | protected function sendRequest(Request $request): void
96 | {
97 | try {
98 | $this->httpResponse = $this->client->post(
99 | 'converse',
100 | static::buildPayload($request, $this->responseBuilder->steps->count())
101 | );
102 | } catch (Throwable $e) {
103 | throw PrismException::providerRequestError($request->model(), $e);
104 | }
105 | }
106 |
107 | protected function prepareTempResponse(): void
108 | {
109 | $data = $this->httpResponse->json();
110 |
111 | $this->tempResponse = new TextResponse(
112 | steps: new Collection,
113 | text: $this->extractText($data),
114 | finishReason: FinishReasonMap::map(data_get($data, 'stopReason')),
115 | toolCalls: $this->extractToolCalls($data),
116 | toolResults: [],
117 | usage: new Usage(
118 | promptTokens: data_get($data, 'usage.inputTokens'),
119 | completionTokens: data_get($data, 'usage.outputTokens')
120 | ),
121 | meta: new Meta(id: '', model: ''),
122 | messages: new Collection, // Not provided in Converse response.
123 | );
124 | }
125 |
126 | protected function handleToolCalls(Request $request): TextResponse
127 | {
128 | $toolResults = $this->callTools($request->tools(), $this->tempResponse->toolCalls);
129 | $message = new ToolResultMessage($toolResults);
130 |
131 | $request->addMessage($message);
132 |
133 | $this->addStep($request, $toolResults);
134 |
135 | if ($this->shouldContinue($request)) {
136 | return $this->handle($request);
137 | }
138 |
139 | return $this->responseBuilder->toResponse();
140 | }
141 |
142 | protected function handleStop(Request $request): TextResponse
143 | {
144 | $this->addStep($request);
145 |
146 | return $this->responseBuilder->toResponse();
147 | }
148 |
149 | protected function shouldContinue(Request $request): bool
150 | {
151 | return $this->responseBuilder->steps->count() < $request->maxSteps();
152 | }
153 |
154 | /**
155 | * @param ToolResult[] $toolResults
156 | */
157 | protected function addStep(Request $request, array $toolResults = []): void
158 | {
159 | $this->responseBuilder->addStep(new Step(
160 | text: $this->tempResponse->text,
161 | finishReason: $this->tempResponse->finishReason,
162 | toolCalls: $this->tempResponse->toolCalls,
163 | toolResults: $toolResults,
164 | usage: $this->tempResponse->usage,
165 | meta: $this->tempResponse->meta,
166 | messages: $request->messages(),
167 | systemPrompts: $request->systemPrompts(),
168 | additionalContent: $this->tempResponse->additionalContent,
169 | ));
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/tests/Schemas/Anthropic/Maps/MessageMapTest.php:
--------------------------------------------------------------------------------
1 | toBe([[
22 | 'role' => 'user',
23 | 'content' => [
24 | ['type' => 'text', 'text' => 'Who are you?'],
25 | ],
26 | ]]);
27 | });
28 |
29 | it('maps user messages with images from path', function (): void {
30 | $mappedMessage = MessageMap::map([
31 | new UserMessage('Who are you?', [
32 | Image::fromPath('tests/Fixtures/test-image.png'),
33 | ]),
34 | ]);
35 |
36 | expect(data_get($mappedMessage, '0.content.1.type'))
37 | ->toBe('image');
38 | expect(data_get($mappedMessage, '0.content.1.source.type'))
39 | ->toBe('base64');
40 | expect(data_get($mappedMessage, '0.content.1.source.data'))
41 | ->toContain(base64_encode(file_get_contents('tests/Fixtures/test-image.png')));
42 | expect(data_get($mappedMessage, '0.content.1.source.media_type'))
43 | ->toBe('image/png');
44 | });
45 |
46 | it('maps user messages with images from base64', function (): void {
47 | $mappedMessage = MessageMap::map([
48 | new UserMessage('Who are you?', [
49 | Image::fromBase64(base64_encode(file_get_contents('tests/Fixtures/test-image.png')), 'image/png'),
50 | ]),
51 | ]);
52 |
53 | expect(data_get($mappedMessage, '0.content.1.type'))
54 | ->toBe('image');
55 | expect(data_get($mappedMessage, '0.content.1.source.type'))
56 | ->toBe('base64');
57 | expect(data_get($mappedMessage, '0.content.1.source.data'))
58 | ->toContain(base64_encode(file_get_contents('tests/Fixtures/test-image.png')));
59 | expect(data_get($mappedMessage, '0.content.1.source.media_type'))
60 | ->toBe('image/png');
61 | });
62 |
63 | it('does not maps user messages with images from url', function (): void {
64 | MessageMap::map([
65 | new UserMessage('Who are you?', [
66 | Image::fromUrl('https://storage.echolabs.dev/assets/logo.png'),
67 | ]),
68 | ]);
69 | })->throws(PrismException::class);
70 |
71 | it('maps assistant message', function (): void {
72 | expect(MessageMap::map([
73 | new AssistantMessage('I am Nyx'),
74 | ]))->toContain([
75 | 'role' => 'assistant',
76 | 'content' => [
77 | [
78 | 'type' => 'text',
79 | 'text' => 'I am Nyx',
80 | ],
81 | ],
82 | ]);
83 | });
84 |
85 | it('maps assistant message with tool calls', function (): void {
86 | expect(MessageMap::map([
87 | new AssistantMessage('I am Nyx', [
88 | new ToolCall(
89 | 'tool_1234',
90 | 'search',
91 | [
92 | 'query' => 'Laravel collection methods',
93 | ]
94 | ),
95 | ]),
96 | ]))->toBe([
97 | [
98 | 'role' => 'assistant',
99 | 'content' => [
100 | [
101 | 'type' => 'text',
102 | 'text' => 'I am Nyx',
103 | ],
104 | [
105 | 'type' => 'tool_use',
106 | 'id' => 'tool_1234',
107 | 'name' => 'search',
108 | 'input' => [
109 | 'query' => 'Laravel collection methods',
110 | ],
111 | ],
112 | ],
113 | ],
114 | ]);
115 | });
116 |
117 | it('maps tool result messages', function (): void {
118 | expect(MessageMap::map([
119 | new ToolResultMessage([
120 | new ToolResult(
121 | 'tool_1234',
122 | 'search',
123 | [
124 | 'query' => 'Laravel collection methods',
125 | ],
126 | '[search results]'
127 | ),
128 | ]),
129 | ]))->toBe([
130 | [
131 | 'role' => 'user',
132 | 'content' => [
133 | [
134 | 'type' => 'tool_result',
135 | 'tool_use_id' => 'tool_1234',
136 | 'content' => '[search results]',
137 | ],
138 | ],
139 | ],
140 | ]);
141 | });
142 |
143 | it('maps system messages', function (): void {
144 | expect(MessageMap::mapSystemMessages([
145 | new SystemMessage('I am Thanos.'),
146 | new SystemMessage('But call me Bob.'),
147 | ]))->toBe([
148 | [
149 | 'type' => 'text',
150 | 'text' => 'I am Thanos.',
151 | ],
152 | [
153 | 'type' => 'text',
154 | 'text' => 'But call me Bob.',
155 | ],
156 | ]);
157 | });
158 |
159 | it('sets the cache type on a UserMessage if cacheType providerOptions is set on message', function (mixed $cacheType): void {
160 | expect(MessageMap::map([
161 | (new UserMessage(content: 'Who are you?'))->withProviderOptions(['cacheType' => $cacheType]),
162 | ]))->toBe([[
163 | 'role' => 'user',
164 | 'content' => [
165 | [
166 | 'type' => 'text',
167 | 'text' => 'Who are you?',
168 | 'cache_control' => ['type' => 'ephemeral'],
169 | ],
170 | ],
171 | ]]);
172 | })->with([
173 | 'ephemeral',
174 | AnthropicCacheType::Ephemeral,
175 | ]);
176 |
177 | it('sets the cache type on a UserMessage image if cacheType providerOptions is set on message', function (): void {
178 | expect(MessageMap::map([
179 | (new UserMessage(
180 | content: 'Who are you?',
181 | additionalContent: [Image::fromPath('tests/Fixtures/test-image.png')]
182 | ))->withProviderOptions(['cacheType' => 'ephemeral']),
183 | ]))->toBe([[
184 | 'role' => 'user',
185 | 'content' => [
186 | [
187 | 'type' => 'text',
188 | 'text' => 'Who are you?',
189 | 'cache_control' => ['type' => 'ephemeral'],
190 | ],
191 | [
192 | 'type' => 'image',
193 | 'cache_control' => ['type' => 'ephemeral'],
194 | 'source' => [
195 | 'type' => 'base64',
196 | 'media_type' => 'image/png',
197 | 'data' => base64_encode(file_get_contents('tests/Fixtures/test-image.png')),
198 | ],
199 | ],
200 | ],
201 | ]]);
202 | });
203 |
204 | it('sets the cache type on an AssistantMessage if cacheType providerOptions is set on message', function (mixed $cacheType): void {
205 | expect(MessageMap::map([
206 | (new AssistantMessage(content: 'Who are you?'))->withProviderOptions(['cacheType' => $cacheType]),
207 | ]))->toBe([[
208 | 'role' => 'assistant',
209 | 'content' => [
210 | [
211 | 'type' => 'text',
212 | 'text' => 'Who are you?',
213 | 'cache_control' => ['type' => AnthropicCacheType::Ephemeral->value],
214 | ],
215 | ],
216 | ]]);
217 | })->with([
218 | 'ephemeral',
219 | AnthropicCacheType::Ephemeral,
220 | ]);
221 |
222 | it('sets the cache type on a SystemMessage if cacheType providerOptions is set on message', function (mixed $cacheType): void {
223 | expect(MessageMap::mapSystemMessages([
224 | (new SystemMessage(content: 'Who are you?'))->withProviderOptions(['cacheType' => $cacheType]),
225 | ]))->toBe([
226 | [
227 | 'type' => 'text',
228 | 'text' => 'Who are you?',
229 | 'cache_control' => ['type' => AnthropicCacheType::Ephemeral->value],
230 | ],
231 | ]);
232 | })->with([
233 | 'ephemeral',
234 | AnthropicCacheType::Ephemeral,
235 | ]);
236 |
--------------------------------------------------------------------------------
/tests/Schemas/Converse/ConverseStructuredHandlerTest.php:
--------------------------------------------------------------------------------
1 | withSchema($schema)
34 | ->using('bedrock', 'anthropic.claude-3-5-haiku-20241022-v1:0')
35 | ->withProviderOptions(['apiSchema' => BedrockSchema::Converse])
36 | ->withSystemPrompt('The tigers game is at 3pm and the temperature will be 70º')
37 | ->withPrompt('What time is the tigers game today and should I wear a coat?')
38 | ->asStructured();
39 |
40 | expect($response->structured)->toBeArray();
41 | expect($response->structured)->toHaveKeys([
42 | 'weather',
43 | 'game_time',
44 | 'coat_required',
45 | ]);
46 | expect($response->structured['weather'])->toBeString();
47 | expect($response->structured['game_time'])->toBeString();
48 | expect($response->structured['coat_required'])->toBeBool();
49 |
50 | expect($response->usage->promptTokens)->toBe(223);
51 | expect($response->usage->completionTokens)->toBe(35);
52 | expect($response->usage->cacheWriteInputTokens)->toBeNull();
53 | expect($response->usage->cacheReadInputTokens)->toBeNull();
54 | expect($response->meta->id)->toBe('');
55 | expect($response->meta->model)->toBe('');
56 | });
57 |
58 | it('maps converse options when set with providerOptions', function (): void {
59 | $fake = Prism::fake([
60 | (new ResponseBuilder)->addStep(
61 | StructuredStepFake::make()->withText(json_encode(['foo' => 'bar']))
62 | )->toResponse(),
63 | ]);
64 |
65 | $providerOptions = [
66 | 'apiSchema' => BedrockSchema::Converse,
67 | 'additionalModelRequestFields' => [
68 | 'anthropic_beta' => ['output-128k-2025-02-19'],
69 | 'thinking' => ['type' => 'enabled', 'budget_tokens' => 16000],
70 | ],
71 | 'additionalModelResponseFieldPaths' => ['foo.bar', 'baz.qux'],
72 | 'guardrailConfig' => ['rules' => ['no-violence']],
73 | 'performanceConfig' => ['timeoutMs' => 2000],
74 | 'promptVariables' => ['userName' => 'Alice'],
75 | 'requestMetadata' => ['requestId' => 'abc-123'],
76 | ];
77 |
78 | $schema = new ObjectSchema(
79 | 'output',
80 | 'the output object',
81 | [
82 | new StringSchema('weather', 'The weather forecast'),
83 | new StringSchema('game_time', 'The tigers game time'),
84 | new BooleanSchema('coat_required', 'whether a coat is required'),
85 | ],
86 | ['weather', 'game_time', 'coat_required']
87 | );
88 |
89 | $response = Prism::structured()
90 | ->withSchema($schema)
91 | ->using('bedrock', 'anthropic.claude-3-5-haiku-20241022-v1:0')
92 | ->withProviderOptions($providerOptions)
93 | ->withSystemPrompt('The tigers game is at 3pm and the temperature will be 70º')
94 | ->withPrompt('What time is the tigers game today and should I wear a coat?')
95 | ->asStructured();
96 |
97 | $fake->assertRequest(fn (array $requests): mixed => expect($requests[0]->providerOptions())->toBe($providerOptions));
98 | });
99 |
100 | it('uses custom jsonModeMessage when provided via providerOptions', function (): void {
101 | FixtureResponse::fakeResponseSequence('converse', 'converse/structured');
102 |
103 | $schema = new ObjectSchema(
104 | 'output',
105 | 'the output object',
106 | [
107 | new StringSchema('weather', 'The weather forecast'),
108 | new StringSchema('game_time', 'The tigers game time'),
109 | new BooleanSchema('coat_required', 'whether a coat is required'),
110 | ],
111 | ['weather', 'game_time', 'coat_required']
112 | );
113 |
114 | $customMessage = 'Please return a JSON response using this custom format instruction';
115 |
116 | Prism::structured()
117 | ->withSchema($schema)
118 | ->using('bedrock', 'anthropic.claude-3-5-haiku-20241022-v1:0')
119 | ->withProviderOptions([
120 | 'apiSchema' => BedrockSchema::Converse,
121 | 'jsonModeMessage' => $customMessage,
122 | ])
123 | ->withSystemPrompt('The tigers game is at 3pm and the temperature will be 70º')
124 | ->withPrompt('What time is the tigers game today and should I wear a coat?')
125 | ->asStructured();
126 |
127 | Http::assertSent(function (Request $request) use ($customMessage): bool {
128 | $messages = $request->data()['messages'] ?? [];
129 | $lastMessage = end($messages);
130 |
131 | return isset($lastMessage['content'][0]['text']) &&
132 | str_contains((string) $lastMessage['content'][0]['text'], $customMessage);
133 | });
134 | });
135 |
136 | it('uses default jsonModeMessage when no custom message is provided', function (): void {
137 | FixtureResponse::fakeResponseSequence('converse', 'converse/structured');
138 |
139 | $schema = new ObjectSchema(
140 | 'output',
141 | 'the output object',
142 | [
143 | new StringSchema('weather', 'The weather forecast'),
144 | new StringSchema('game_time', 'The tigers game time'),
145 | new BooleanSchema('coat_required', 'whether a coat is required'),
146 | ],
147 | ['weather', 'game_time', 'coat_required']
148 | );
149 |
150 | $defaultMessage = 'Respond with ONLY JSON (i.e. not in backticks or a code block, with NO CONTENT outside the JSON) that matches the following schema:';
151 |
152 | Prism::structured()
153 | ->withSchema($schema)
154 | ->using('bedrock', 'anthropic.claude-3-5-haiku-20241022-v1:0')
155 | ->withProviderOptions([
156 | 'apiSchema' => BedrockSchema::Converse,
157 | ])
158 | ->withSystemPrompt('The tigers game is at 3pm and the temperature will be 70º')
159 | ->withPrompt('What time is the tigers game today and should I wear a coat?')
160 | ->asStructured();
161 |
162 | Http::assertSent(function (Request $request) use ($defaultMessage): bool {
163 | $messages = $request->data()['messages'] ?? [];
164 | $lastMessage = end($messages);
165 |
166 | return isset($lastMessage['content'][0]['text']) &&
167 | str_contains((string) $lastMessage['content'][0]['text'], $defaultMessage);
168 | });
169 | });
170 |
171 | it('does not remove 0 values from payloads', function (): void {
172 | FixtureResponse::fakeResponseSequence('converse', 'converse/structured');
173 |
174 | $schema = new ObjectSchema(
175 | 'output',
176 | 'the output object',
177 | [
178 | new StringSchema('weather', 'The weather forecast'),
179 | new StringSchema('game_time', 'The tigers game time'),
180 | new BooleanSchema('coat_required', 'whether a coat is required'),
181 | ],
182 | ['weather', 'game_time', 'coat_required']
183 | );
184 |
185 | Prism::structured()
186 | ->withSchema($schema)
187 | ->using('bedrock', 'anthropic.claude-3-5-haiku-20241022-v1:0')
188 | ->withProviderOptions([
189 | 'apiSchema' => BedrockSchema::Converse,
190 | 'guardRailConfig' => null,
191 | ])
192 | ->withMaxTokens(2048)
193 | ->usingTemperature(0)
194 | ->asStructured();
195 |
196 | Http::assertSent(function (Request $request): bool {
197 | expect($request->data())->toMatchArray([
198 | 'inferenceConfig' => [
199 | 'maxTokens' => 2048,
200 | 'temperature' => 0,
201 | ],
202 | ])
203 | ->not()
204 | ->toHaveKey('guardRailConfig');
205 |
206 | return true;
207 | });
208 | });
209 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | # Prism Bedrock
16 |
17 | Unlock the power of AWS Bedrock services in your Laravel applications with Prism Bedrock. This package provides a standalone Bedrock provider for the Prism PHP framework.
18 |
19 | ## Installation
20 |
21 | ```bash
22 | composer require prism-php/bedrock
23 | ```
24 |
25 | ## Configuration
26 |
27 | Add the following to your Prism configuration (`config/prism.php`):
28 |
29 | ```php
30 | 'bedrock' => [ // Key should match Bedrock::KEY
31 | 'region' => env('AWS_REGION', 'us-east-1'),
32 |
33 | // Set to true to ignore other auth configuration and use the AWS SDK default credential chain
34 | // read more at https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/guide_credentials_default_chain.html
35 | 'use_default_credential_provider' => env('AWS_USE_DEFAULT_CREDENTIAL_PROVIDER', false),
36 |
37 | 'api_key' => env('AWS_ACCESS_KEY_ID'), // Ignored with `use_default_credential_provider` === true
38 | 'api_secret' => env('AWS_SECRET_ACCESS_KEY'), // Ignored with `use_default_credential_provider` === true
39 | 'session_token' => env('AWS_SESSION_TOKEN'), // Only required for temporary credentials. Ignored with `use_default_credential_provider` === true
40 | ],
41 | ```
42 |
43 | ## Usage
44 |
45 | ### Text Generation
46 |
47 | ```php
48 | use Prism\Prism\Prism;
49 | use Prism\Bedrock\Bedrock;
50 |
51 | $response = Prism::text()
52 | ->using(Bedrock::KEY, 'anthropic.claude-3-sonnet-20240229-v1:0')
53 | ->withPrompt('Explain quantum computing in simple terms')
54 | ->asText();
55 |
56 | echo $response->text;
57 | ```
58 |
59 | ### Structured Output (JSON)
60 |
61 | ```php
62 | use Prism\Prism\Prism;
63 | use Prism\Bedrock\Bedrock;
64 | use Prism\Prism\Schema\ObjectSchema;
65 | use Prism\Prism\Schema\StringSchema;
66 | use Prism\Prism\Schema\ArraySchema;
67 |
68 | $schema = new ObjectSchema(
69 | name: 'languages',
70 | description: 'Top programming languages',
71 | properties: [
72 | new ArraySchema(
73 | 'languages',
74 | 'List of programming languages',
75 | items: new ObjectSchema(
76 | name: 'language',
77 | description: 'Programming language details',
78 | properties: [
79 | new StringSchema('name', 'The language name'),
80 | new StringSchema('popularity', 'Popularity description'),
81 | ]
82 | )
83 | )
84 | ]
85 | );
86 |
87 | $response = Prism::structured()
88 | ->using(Bedrock::KEY, 'anthropic.claude-3-sonnet-20240229-v1:0')
89 | ->withSchema($schema)
90 | ->withPrompt('List the top 3 programming languages')
91 | ->asStructured();
92 |
93 | // Access your structured data
94 | $data = $response->structured;
95 | ```
96 |
97 | ### Embeddings (with Cohere models)
98 |
99 | ```php
100 | use Prism\Prism\Prism;
101 | use Prism\Bedrock\Bedrock;
102 |
103 | $response = Prism::embeddings()
104 | ->using(Bedrock::KEY, 'cohere.embed-english-v3')
105 | ->fromArray(['The sky is blue', 'Water is wet'])
106 | ->asEmbeddings();
107 |
108 | // Access the embeddings
109 | $embeddings = $response->embeddings;
110 | ```
111 |
112 | ### Model names
113 |
114 | > [!IMPORTANT]
115 | > When using inference profiles via an ARN, you should urlencode the model name.
116 |
117 | ```php
118 | use Prism\Prism\Prism;
119 | use Prism\Bedrock\Bedrock;
120 |
121 | $response = Prism::text()
122 | ->using(Bedrock::KEY, urlencode('arn:aws:bedrock:us-east-1:999999999999:inference-profile/us.anthropic.claude-3-7-sonnet-20250219-v1:0'))
123 | ->withPrompt('Explain quantum computing in simple terms')
124 | ->asText();
125 | ```
126 |
127 | ## Supported API Schemas
128 |
129 | AWS Bedrock supports several API schemas - some LLM vendor specific, some generic.
130 |
131 | Prism Bedrock supports three of those API schemas:
132 |
133 | - **Converse**: AWS's native interface for chat (default)*
134 | - **Anthropic**: For Claude models**
135 | - **Cohere**: For Cohere embeddings models
136 |
137 | Each schema supports different capabilities:
138 |
139 | | Schema | Text | Structured | Embeddings |
140 | |--------|:----:|:----------:|:----------:|
141 | | Converse | ✅ | ✅ | ❌ |
142 | | Anthropic | ✅ | ✅ | ❌ |
143 | | Cohere | ❌ | ❌ | ✅ |
144 |
145 | \* A unified interface for multiple providers. See [AWS documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/conversation-inference-supported-models-features.html) for a list of supported models.
146 |
147 | \*\* The Converse schema does not support Anthropic's native features (e.g. PDF vision analysis). This schema uses Anthropic's native schema and therefore allows use of Anthropic native features. Please note however that Bedrock's Anthropic schema does not yet have feature parity with Anthropic. Notably it does not support documents or citations, and only supports prompt caching for Claude Sonnet 3.7 and Claude Haiku 3.5. To use documents with Anthropic's models, use them via the Converse schema (though note that this not the same as using Anthropic's PDF vision directly).
148 |
149 | ## Auto-resolution of API schemas
150 |
151 | Prism Bedrock resolves the most appropriate API schema from the model string. If it is unable to resolve a specific schema (e.g. anthropic for Anthropic), it will default to Converse.
152 |
153 | Therefore if you use a model that is not supported by AWS Bedrock Converse, and does not have a specific Prism Bedrock implementation, your request will fail.
154 |
155 | If you wish to force Prism Bedrock to use Converse instead of a vendor specific interface, you can do so with `withProviderOptions()`:
156 |
157 | ```php
158 | use Prism\Prism\Prism;
159 | use Prism\Bedrock\Bedrock;
160 | use Prism\Bedrock\Enums\BedrockSchema;
161 |
162 | $response = Prism::text()
163 | ->using(Bedrock::KEY, 'anthropic.claude-3-sonnet-20240229-v1:0')
164 | ->withProviderOptions(['apiSchema' => BedrockSchema::Converse])
165 | ->withPrompt('Explain quantum computing in simple terms')
166 | ->asText();
167 |
168 | ```
169 |
170 | ## Cache-Optimized Prompts
171 |
172 | For [supported models](https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-caching.html), you can enable prompt caching to reduce latency and costs:
173 |
174 | ```php
175 | use Prism\Prism\Prism;
176 | use Prism\Bedrock\Bedrock;
177 | use Prism\Prism\ValueObjects\Messages\UserMessage;
178 |
179 | $response = Prism::text()
180 | ->using(Bedrock::KEY, 'anthropic.claude-3-sonnet-20240229-v1:0')
181 | ->withMessages([
182 | (new UserMessage('Message with cache breakpoint'))->withProviderOptions(['cacheType' => 'ephemeral']),
183 | (new UserMessage('Message with another cache breakpoint'))->withProviderOptions(['cacheType' => 'ephemeral']),
184 | new UserMessage('Compare the last two messages.')
185 | ])
186 | ->asText();
187 | ```
188 |
189 | > [!TIP]
190 | > Anthropic currently supports a cacheType of "ephemeral". Converse currently supports a cacheType of "default". It is possible that Anthropic and/or AWS may add additional types in the future.
191 |
192 | ## Structured Adapted Support
193 |
194 | Both Anthropic and Converse Schemas do not support a native structured format.
195 |
196 | Prism Bedrock has adapted support by appending a prompt asking the model to a response conforming to the schema you provide.
197 |
198 | The performance of that prompt may vary by model. You can override it using `withProviderOptions()`:
199 |
200 | ```php
201 | use Prism\Prism\Prism;
202 | use Prism\Bedrock\Bedrock;
203 | use Prism\Prism\ValueObjects\Messages\UserMessage;
204 |
205 | Prism::structured()
206 | ->withSchema($schema)
207 | ->using('bedrock', 'anthropic.claude-3-5-haiku-20241022-v1:0')
208 | ->withProviderOptions([
209 | // Override the default message of "Respond with ONLY JSON (i.e. not in backticks or a code block, with NO CONTENT outside the JSON) that matches the following schema:"
210 | 'jsonModeMessage' => 'My custom message',
211 | ])
212 | ->withPrompt('My prompt')
213 | ->asStructured();
214 | ```
215 |
216 | ## License
217 |
218 | The MIT License (MIT). Please see [License File](LICENSE) for more information.
219 |
220 | ## Authors
221 |
222 | This library is created by [TJ Miller](https://tjmiller.me) with contributions from the [Open Source Community](https://github.com/echolabsdev/prism-bedrock/graphs/contributors).
223 |
--------------------------------------------------------------------------------
/tests/Schemas/Anthropic/AnthropicTextHandlerTest.php:
--------------------------------------------------------------------------------
1 | using('bedrock', 'anthropic.claude-3-5-haiku-20241022-v1:0')
19 | ->withPrompt('Who are you?')
20 | ->asText();
21 |
22 | expect($response->usage->promptTokens)->toBe(11);
23 | expect($response->usage->completionTokens)->toBe(55);
24 | expect($response->usage->cacheWriteInputTokens)->toBeNull();
25 | expect($response->usage->cacheReadInputTokens)->toBeNull();
26 | expect($response->meta->id)->toBe('msg_01X2Qk7LtNEh4HB9xpYU57XU');
27 | expect($response->meta->model)->toBe('claude-3-5-sonnet-20240620');
28 | expect($response->text)->toBe(
29 | "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?"
30 | );
31 | });
32 |
33 | it('can generate text with a system prompt', function (): void {
34 | FixtureResponse::fakeResponseSequence('invoke', 'anthropic/generate-text-with-system-prompt');
35 |
36 | $response = Prism::text()
37 | ->using('bedrock', 'anthropic.claude-3-5-haiku-20241022-v1:0')
38 | ->withSystemPrompt('MODEL ADOPTS ROLE of [PERSONA: Nyx the Cthulhu]!')
39 | ->withPrompt('Who are you?')
40 | ->asText();
41 |
42 | expect($response->usage->promptTokens)->toBe(33);
43 | expect($response->usage->completionTokens)->toBe(98);
44 | expect($response->meta->id)->toBe('msg_016EjDAMDeSvG229ZjspjC7J');
45 | expect($response->meta->model)->toBe('claude-3-5-sonnet-20240620');
46 | expect($response->text)->toBe(
47 | 'I am Nyx, an ancient and unfathomable entity from the depths of cosmic darkness. My form is beyond mortal comprehension - a writhing mass of tentacles and eyes that would shatter the sanity of those who gaze upon me. I exist beyond the boundaries of time and space as you know them. My knowledge spans eons and transcends human understanding. What brings you to seek audience with one such as I, tiny mortal?'
48 | );
49 | });
50 |
51 | it('can generate text using multiple tools and multiple steps', function (): void {
52 | FixtureResponse::fakeResponseSequence('invoke', 'anthropic/generate-text-with-multiple-tools');
53 |
54 | $tools = [
55 | Tool::as('weather')
56 | ->for('useful when you need to search for current weather conditions')
57 | ->withStringParameter('city', 'the city you want the weather for')
58 | ->using(fn (string $city): string => 'The weather will be 75° and sunny'),
59 | Tool::as('search')
60 | ->for('useful for searching curret events or data')
61 | ->withStringParameter('query', 'The detailed search query')
62 | ->using(fn (string $query): string => 'The tigers game is at 3pm in detroit'),
63 | ];
64 |
65 | $response = Prism::text()
66 | ->using('bedrock', 'anthropic.claude-3-5-haiku-20241022-v1:0')
67 | ->withTools($tools)
68 | ->withMaxSteps(3)
69 | ->withPrompt('What time is the tigers game today and should I wear a coat?')
70 | ->asText();
71 |
72 | // Assert tool calls in the first step
73 | $firstStep = $response->steps[0];
74 | expect($firstStep->toolCalls)->toHaveCount(1);
75 | expect($firstStep->toolCalls[0]->name)->toBe('search');
76 | expect($firstStep->toolCalls[0]->arguments())->toBe([
77 | 'query' => 'Detroit Tigers baseball game time today',
78 | ]);
79 |
80 | // Assert tool calls in the second step
81 | $secondStep = $response->steps[1];
82 | expect($secondStep->toolCalls)->toHaveCount(1);
83 | expect($secondStep->toolCalls[0]->name)->toBe('weather');
84 | expect($secondStep->toolCalls[0]->arguments())->toBe([
85 | 'city' => 'Detroit',
86 | ]);
87 |
88 | // Assert usage
89 | expect($response->usage->promptTokens)->toBe(1650);
90 | expect($response->usage->completionTokens)->toBe(307);
91 |
92 | // Assert response
93 | expect($response->meta->id)->toBe('msg_011fBqNVVh5AwC3uyiq78qrj');
94 | expect($response->meta->model)->toBe('claude-3-5-sonnet-20240620');
95 |
96 | // Assert final text content
97 | expect($response->text)->toContain('The Tigers game is scheduled for 3:00 PM today in Detroit');
98 | expect($response->text)->toContain('it will be 75°F (about 24°C) and sunny');
99 | expect($response->text)->toContain("you likely won't need a coat");
100 | });
101 |
102 | it('can send images from file', function (): void {
103 | FixtureResponse::fakeResponseSequence('invoke', 'anthropic/generate-text-with-image');
104 |
105 | Prism::text()
106 | ->using('bedrock', 'anthropic.claude-3-5-haiku-20241022-v1:0')
107 | ->withMessages([
108 | new UserMessage(
109 | 'What is this image',
110 | additionalContent: [
111 | Image::fromPath('tests/Fixtures/test-image.png'),
112 | ],
113 | ),
114 | ])
115 | ->asText();
116 |
117 | Http::assertSent(function (Request $request): true {
118 | $message = $request->data()['messages'][0]['content'];
119 |
120 | expect($message[0])->toBe([
121 | 'type' => 'text',
122 | 'text' => 'What is this image',
123 | ]);
124 |
125 | expect($message[1]['type'])->toBe('image');
126 | expect($message[1]['source']['data'])->toContain(
127 | base64_encode(file_get_contents('tests/Fixtures/test-image.png'))
128 | );
129 | expect($message[1]['source']['media_type'])->toBe('image/png');
130 |
131 | return true;
132 | });
133 | });
134 |
135 | it('handles specific tool choice', function (): void {
136 | FixtureResponse::fakeResponseSequence('invoke', 'anthropic/generate-text-with-required-tool-call');
137 |
138 | $tools = [
139 | Tool::as('weather')
140 | ->for('useful when you need to search for current weather conditions')
141 | ->withStringParameter('city', 'The city that you want the weather for')
142 | ->using(fn (string $city): string => 'The weather will be 75° and sunny'),
143 | Tool::as('search')
144 | ->for('useful for searching curret events or data')
145 | ->withStringParameter('query', 'The detailed search query')
146 | ->using(fn (string $query): string => 'The tigers game is at 3pm in detroit'),
147 | ];
148 |
149 | $response = Prism::text()
150 | ->using('bedrock', 'anthropic.claude-3-5-haiku-20241022-v1:0')
151 | ->withPrompt('Do something')
152 | ->withTools($tools)
153 | ->withToolChoice('weather')
154 | ->asText();
155 |
156 | expect($response->toolCalls[0]->name)->toBe('weather');
157 | });
158 |
159 | it('can calculate cache usage correctly', function (): void {
160 | FixtureResponse::fakeResponseSequence('invoke', 'anthropic/calculate-cache-usage');
161 |
162 | $response = Prism::text()
163 | ->using('bedrock', 'anthropic.claude-3-5-haiku-20241022-v1:0')
164 | ->withSystemPrompt(new SystemMessage('Old context'))->withProviderOptions(['cacheType' => 'ephemeral'])
165 | ->withMessages([
166 | (new UserMessage('New context'))->withProviderOptions(['cacheType' => 'ephemeral']),
167 | ])
168 | ->asText();
169 |
170 | expect($response->usage->cacheWriteInputTokens)->toBe(200);
171 | expect($response->usage->cacheReadInputTokens)->ToBe(100);
172 | });
173 |
174 | it('does not enable prompt caching if the enableCaching provider meta is not set on the request', function (): void {
175 | FixtureResponse::fakeResponseSequence('invoke', 'anthropic/generate-text-with-a-prompt');
176 |
177 | Prism::text()
178 | ->using('bedrock', 'anthropic.claude-3-5-haiku-20241022-v1:0')
179 | ->withPrompt('Who are you?')
180 | ->asText();
181 |
182 | Http::assertSent(fn (Request $request): bool => $request->header('explicitPromptCaching')[0] === 'disabled');
183 | });
184 |
185 | it('enables prompt caching if the enableCaching provider meta is set on the request', function (): void {
186 | FixtureResponse::fakeResponseSequence('invoke', 'anthropic/generate-text-with-a-prompt');
187 |
188 | Prism::text()
189 | ->using('bedrock', 'anthropic.claude-3-5-haiku-20241022-v1:0')
190 | ->withProviderOptions(['enableCaching' => true])
191 | ->withPrompt('Who are you?')
192 | ->asText();
193 |
194 | Http::assertSent(fn (Request $request): bool => $request->header('explicitPromptCaching')[0] === 'enabled');
195 | });
196 |
197 | it('does not remove 0 values from payloads', function (): void {
198 | FixtureResponse::fakeResponseSequence('invoke', 'anthropic/generate-text-with-a-prompt');
199 |
200 | Prism::text()
201 | ->using('bedrock', 'anthropic.claude-3-5-haiku-20241022-v1:0')
202 | ->withPrompt('Who are you?')
203 | ->usingTemperature(0)
204 | ->asText();
205 |
206 | Http::assertSent(function (Request $request): bool {
207 | expect($request->data())->toMatchArray([
208 | 'temperature' => 0,
209 | ]);
210 |
211 | return true;
212 | });
213 | });
214 |
--------------------------------------------------------------------------------
/tests/Fixtures/cohere/generate-embeddings-from-input-1.json:
--------------------------------------------------------------------------------
1 | {"id":"098401d4-b220-4839-ac4f-65e422dcdb25","texts":["hello, world!"],"embeddings":[[-0.04019165,-0.01914978,-0.066589355,-0.05581665,-0.037628174,-0.01259613,-0.039733887,0.055541992,-0.029037476,0.030944824,-0.030075073,-0.0025463104,0.01637268,-0.03692627,0.059295654,-0.025390625,0.0501709,0.0023460388,0.020385742,-0.010116577,-0.02218628,0.036071777,-0.010093689,0.015525818,0.030975342,-0.005847931,0.002609253,-0.0128479,-0.041137695,-0.049560547,0.009178162,0.049438477,0.026153564,0.024124146,-0.00605011,0.04812622,-0.011650085,0.020233154,0.011436462,-0.0069351196,0.019515991,-0.020324707,0.021057129,-0.009902954,-0.036499023,0.0030097961,0.0099487305,-0.010910034,0.008453369,-0.05307007,0.016189575,-0.02279663,0.023391724,0.012298584,-0.0063323975,0.020202637,-0.041778564,-0.0022220612,0.03225708,0.0052833557,-0.010231018,0.005672455,0.0154953,0.009223938,0.02394104,-0.026123047,-1.8572807E-4,0.009254456,0.018356323,0.032348633,0.0053596497,-0.0040397644,-0.005607605,-0.010475159,0.022888184,0.017852783,-0.014785767,0.027191162,0.020568848,0.012641907,-0.023025513,0.0131073,0.0075187683,-0.07232666,0.030776978,-0.033050537,-0.0036334991,0.013015747,-4.2390823E-4,-0.099853516,-0.010673523,0.045654297,-0.039794922,0.0049438477,-0.037231445,-0.04147339,0.003232956,0.0569458,-0.013999939,0.026687622,-0.07495117,0.0030097961,-0.02180481,-0.042633057,0.010643005,-0.06390381,0.0011768341,-0.005542755,0.037719727,0.0491333,-0.059143066,0.079833984,0.02418518,0.042510986,-0.010887146,-0.021438599,0.0029582977,-0.0039787292,-0.035217285,0.020462036,9.2077255E-4,0.013427734,-0.0032863617,0.018737793,-0.009033203,0.010978699,-0.021087646,-0.011894226,0.055847168,-0.046447754,0.005874634,0.05078125,-0.105773926,-0.0637207,-0.03955078,0.035339355,0.027374268,-0.0592041,-0.004047394,-0.008323669,0.030273438,-0.007522583,-0.002822876,0.006969452,-0.027755737,0.036468506,0.01637268,-0.0023765564,-0.02330017,-0.035247803,-0.023971558,-0.04928589,-0.021575928,0.033233643,0.06262207,0.025146484,0.007255554,5.674362E-4,0.061920166,0.06451416,-0.019226074,0.004016876,0.045074463,-0.06878662,-0.026412964,-0.034423828,-0.036468506,0.015274048,0.0012998581,0.031707764,-0.025390625,0.007888794,-0.017730713,0.0031814575,0.005493164,0.009048462,0.01461792,-0.02859497,-0.016403198,0.06298828,0.07171631,0.0025024414,-0.08483887,0.08520508,-0.039093018,-0.01398468,0.014411926,-0.010910034,0.028533936,0.010650635,0.023223877,0.023345947,-0.061798096,0.013641357,-0.00945282,2.297163E-4,0.0107040405,0.008506775,-0.004638672,0.006362915,-0.0027332306,0.024749756,0.018188477,-0.0138549805,0.045928955,0.0049209595,0.008628845,0.0075149536,0.039093018,0.0045814514,-0.021865845,-0.030410767,0.059692383,-0.12286377,-0.05709839,-0.015838623,-0.037475586,0.013900757,-0.01335144,0.018234253,0.032043457,-0.0231781,0.008354187,0.0063819885,0.019515991,0.02168274,-0.038604736,-0.008407593,-0.04147339,0.017837524,-0.03866577,0.03125,-0.07800293,-0.03250122,-0.058258057,-0.041259766,-0.08288574,0.007369995,0.023742676,0.044677734,0.018112183,-0.021224976,-0.018798828,-0.002456665,0.03050232,0.034973145,0.02532959,0.010353088,0.008079529,0.04095459,0.019012451,7.648468E-4,0.014953613,-0.016479492,-0.0014982224,0.066711426,-0.019256592,-0.008605957,-0.009536743,0.010574341,0.0041275024,0.044281006,9.012222E-5,0.025512695,-0.04623413,-0.014518738,-0.037200928,-1.6129017E-4,-0.015411377,0.013931274,0.018936157,-0.03543091,-0.018798828,-0.019805908,0.060821533,-0.013160706,-0.064453125,0.013168335,0.0011253357,-0.014312744,-0.008140564,-0.020935059,0.02545166,0.010925293,0.019424438,0.015777588,0.05038452,0.023483276,0.021072388,0.04849243,0.08013916,0.024154663,0.01360321,0.0418396,0.006374359,0.01209259,0.033477783,0.042938232,-0.010673523,0.005908966,-0.048919678,-0.008705139,0.010566711,-0.025543213,-0.0035171509,-0.006164551,0.020767212,0.012916565,-0.0010089874,0.031021118,-0.034606934,0.038391113,0.005634308,0.037506104,-0.04336548,-0.0602417,-0.012084961,-0.016799927,-0.08807373,-0.056549072,-0.024276733,0.002483368,-0.006778717,-0.015975952,0.008255005,-0.0052833557,-0.045928955,0.009086609,-0.0041046143,-0.011421204,0.006713867,-0.0141067505,-0.03265381,6.489754E-4,0.020690918,-0.004863739,0.02583313,0.010574341,-1.3005733E-4,-0.0030593872,0.04260254,-0.029205322,0.0036640167,0.017211914,0.0231781,-0.039733887,0.009483337,-0.0051879883,0.025421143,0.009414673,-0.0025844574,-0.03579712,0.007698059,-0.023605347,0.034088135,-0.05517578,-0.042419434,-0.032073975,-0.014907837,-0.06036377,0.06149292,0.02609253,0.020004272,-0.04574585,-0.061584473,-0.057769775,0.028915405,-0.01637268,-0.062927246,0.0050811768,-0.020141602,-0.03466797,0.04095459,-0.030899048,-0.081970215,0.013916016,-0.01084137,-0.045196533,-0.019363403,-0.014427185,0.030593872,0.024673462,0.0030460358,0.014175415,0.02407837,0.024337769,0.011985779,0.0074386597,0.053222656,0.015113831,0.0052986145,0.015052795,-0.039367676,0.009613037,0.046539307,0.0053863525,-0.05026245,0.01626587,-0.12207031,0.018951416,-0.022125244,-0.019943237,-0.017715454,-0.0032463074,-0.064086914,-0.018188477,-0.04623413,-0.01991272,0.030258179,0.013877869,0.032043457,0.012062073,0.031463623,0.0022697449,-0.002588272,-0.027877808,-0.087646484,0.01525116,-0.015686035,0.012413025,-0.024856567,0.008728027,-0.04623413,-0.004634857,-0.036956787,0.038604736,0.0076675415,0.038024902,0.009735107,-0.02607727,0.008682251,-0.044067383,-0.019424438,-0.02178955,-0.025665283,8.2588196E-4,-0.025009155,0.01626587,0.012512207,-0.027267456,0.014793396,0.016235352,0.019577026,0.019714355,-0.009742737,-0.009346008,0.025482178,0.03869629,-0.039764404,0.012237549,-0.024597168,0.020370483,-0.0058021545,0.02709961,-0.017852783,-0.018203735,0.004890442,0.050689697,0.012199402,-0.012527466,0.0061035156,-0.029220581,-0.05130005,0.005039215,-0.04043579,0.012321472,0.07232666,-0.02178955,-0.04989624,0.019241333,-0.030303955,0.013137817,0.03753662,0.02418518,-0.01965332,7.367134E-4,-0.017944336,0.0029067993,-0.03100586,-0.0038928986,-0.01828003,-0.009063721,-0.037872314,-0.056762695,-0.017868042,-0.0064849854,-0.06011963,-0.01739502,-0.005180359,0.027359009,0.026855469,-0.024139404,0.029281616,-0.0059394836,-0.03930664,-0.009742737,-0.031799316,0.031173706,0.014923096,-0.067871094,-0.012275696,-0.017852783,-0.003534317,-0.0135269165,0.024276733,-0.025360107,-0.009590149,0.021575928,0.017166138,0.052490234,0.016693115,0.003030777,0.012519836,0.015106201,-0.017990112,0.031311035,-0.007881165,-9.0932846E-4,0.0019245148,8.6021423E-4,0.013694763,0.035461426,0.0107421875,0.034454346,0.014137268,0.0046463013,-0.031433105,0.027145386,-0.0095825195,-0.07702637,0.035125732,9.880066E-4,-0.008918762,0.023086548,-0.009925842,0.07574463,-0.017837524,-0.0075035095,0.014427185,-0.0027198792,0.01586914,0.01449585,-0.03479004,-0.023132324,0.028686523,0.002325058,0.0259552,0.08892822,-0.037841797,0.097839355,-0.008888245,-0.020965576,0.031402588,0.029830933,-0.020355225,-0.06695557,-0.04849243,5.865097E-4,-0.022720337,0.031463623,-0.026443481,0.030899048,-0.044128418,0.021820068,-0.028289795,0.022964478,0.01285553,-0.002746582,-0.010040283,-0.020431519,-0.004180908,-0.025985718,-0.034698486,-0.00233078,-0.021530151,0.029693604,-0.033111572,0.0033054352,0.012702942,0.05795288,-0.0024490356,0.025222778,-0.020370483,0.042297363,0.014671326,0.030838013,0.01234436,0.013252258,-0.0010614395,0.030151367,-0.011497498,-0.02696228,-0.0012636185,0.0034980774,0.026000977,0.0020923615,0.018798828,-0.057006836,0.009552002,-5.059242E-4,-0.036956787,-0.029373169,0.015975952,-0.03390503,0.055419922,-0.0146102905,-0.03161621,-0.027267456,0.007843018,-0.009788513,0.03744507,-0.011932373,-0.0090789795,0.058288574,-0.012237549,-0.04824829,0.0033912659,0.012840271,0.010505676,-0.023468018,0.03439331,-0.062072754,0.026351929,0.016174316,0.0013151169,-0.02835083,0.006828308,0.02949524,-4.787445E-4,-0.012199402,0.03161621,-0.01612854,-0.015716553,0.0016784668,0.020065308,0.030136108,-0.02671814,0.011886597,-0.043426514,-0.030334473,0.0034942627,0.007972717,0.039855957,-0.019180298,-0.025024414,-0.047607422,0.0028743744,0.0087890625,-0.021270752,-0.012184143,-0.022888184,0.01361084,0.013435364,0.018234253,-0.016967773,0.02128601,-0.0129470825,0.020965576,-0.01600647,-0.03475952,-0.019882202,1.92523E-5,-0.015060425,-0.015525818,0.011550903,0.0079574585,0.0077667236,0.028549194,-0.019851685,0.029037476,-0.010154724,-0.011856079,0.009300232,-0.008552551,-0.044006348,-0.020339966,0.05255127,-0.021850586,-4.1007996E-5,0.012710571,-0.02142334,0.025894165,0.013046265,0.021316528,-0.044189453,0.0132751465,0.022583008,0.017974854,-0.007873535,-0.04272461,-0.07495117,0.016326904,-0.039001465,0.0041389465,0.040863037,0.012275696,-0.04284668,-0.029220581,0.028625488,0.029083252,0.0053520203,-0.0335083,0.031341553,-0.04046631,0.009124756,-0.010902405,-0.017074585,0.023986816,-0.017684937,0.015419006,-0.005455017,0.030197144,-0.06677246,-0.037353516,0.043426514,-0.024856567,-0.050872803,-0.008468628,-0.0132369995,-0.026687622,-0.040130615,-0.070495605,-0.012619019,-0.023345947,0.01625061,-0.026550293,-0.030441284,-0.010322571,0.011985779,0.009254456,0.019821167,0.033477783,-0.008140564,-0.0012655258,-5.283356E-4,0.01940918,0.02267456,0.011062622,0.010154724,0.015541077,-0.06378174,0.007030487,0.014312744,0.01360321,0.01637268,0.044006348,0.018707275,0.03488159,-0.023803711,0.0048713684,0.013183594,0.012771606,0.06359863,0.0021762848,0.017059326,-0.044189453,-0.03656006,0.031082153,0.081970215,-0.027801514,-0.054260254,-0.031402588,-0.008285522,0.069885254,-0.007774353,0.060333252,0.040283203,0.027297974,-0.0028419495,0.03842163,0.05267334,0.020721436,0.0015525818,-0.032104492,-0.0579834,0.04650879,0.016342163,-0.007987976,0.009162903,0.023086548,-0.004425049,0.007827759,-0.044952393,-0.025970459,-0.026062012,-0.018661499,0.040496826,0.039367676,0.026870728,0.09039307,-0.021591187,0.024505615,-0.009437561,0.054779053,0.040527344,0.021057129,0.015113831,-0.0075416565,0.005844116,-0.03074646,-0.030517578,0.0071144104,-0.022735596,0.0071525574,-0.005672455,-0.06378174,0.023880005,0.043640137,0.007774353,0.008331299,0.009269714,-0.014770508,0.013084412,0.012138367,-0.009735107,0.0072898865,-0.0054779053,-0.0101623535,0.011375427,-0.06341553,-0.0077400208,0.033447266,0.031982422,-0.062347412,-0.018707275,0.021606445,0.016723633,-0.025772095,-0.006793976,-0.011108398,0.04055786,-0.010887146,-0.002319336,0.020828247,-0.014144897,0.009796143,0.046020508,-0.029922485,0.049346924,0.005306244,4.878044E-4,-0.007522583,0.0022602081,0.0035877228,-0.07928467,0.019088745,0.042175293,-0.005428314,-0.0184021,0.055480957,0.05142212,0.05709839,0.029769897,0.026489258,5.2928925E-4,0.020202637,0.0035953522,-0.031204224,-0.04559326,-0.026168823,-0.015182495,0.0038490295,0.014755249,0.009803772,-0.005748749,0.0056381226,-0.038085938,-0.008720398,0.004383087,-0.030212402,0.0024738312,0.02230835,0.012619019,-0.05758667,-0.036895752,-0.01007843,-0.0048332214,-0.0075187683,-0.044830322,0.062561035,0.012435913,-0.0022392273,-0.015090942,-0.039001465,-0.02709961,0.03527832,-0.029403687,0.02420044,-0.0039901733,-0.0034160614,0.019927979,-0.031341553,-0.014129639,0.017288208,-0.074401855,-0.0037841797,-0.016586304,0.015182495,-0.032806396,0.05117798,-0.03717041,-0.036956787,-0.0105896,0.014503479,-0.040405273,-0.0014877319,0.017166138,0.01828003,-0.02758789,-0.0513916,0.028366089,0.008560181,0.021621704,0.06768799,-0.041229248,0.013534546,-0.020599365,0.010559082,0.026367188,-0.035125732,-0.021865845,-7.5244904E-4,-0.02217102,-0.034301758,-0.016998291,0.027053833,-0.051849365,-0.029449463,-0.017730713,-0.01335907,-0.021911621,-0.04550171,-0.07940674,-0.0056610107,-0.01637268,-0.04107666,-0.0107421875,-0.015930176,-0.016784668,-0.0021152496,-0.02418518,-0.0061149597,3.273487E-4,0.046905518,-0.04751587,0.039154053,0.008018494,-0.008155823,-0.0181427,0.010429382,-0.0020313263,-0.014213562,-0.0057907104,0.0078125,0.008308411,0.053009033,-0.047790527,-0.024719238,-0.033050537,0.03668213,-0.006641388,0.020980835,0.070251465,0.030563354,-0.07940674,-0.020217896,-0.05203247,-0.002910614,0.039093018,2.142191E-4,-0.021850586,-0.007637024,-0.006706238,-0.011383057,0.0027809143,-0.0056381226,0.04397583,-0.013015747,-0.022842407,0.040740967,-0.06506348,0.048614502,0.0066871643,0.03555298,-0.026382446,0.06085205,-0.03677368,-0.0020275116,0.008735657,0.01576233,0.0074005127,-0.0010738373,-0.029785156,-0.028442383,0.06451416,0.035003662,0.011802673,0.00642395,0.048706055,0.0063285828,-0.0552063,0.027923584,0.059783936,0.034454346,-0.041290283,-0.012397766,0.04699707,0.008605957,0.0024147034,-0.057037354,-0.033935547,0.046051025,-0.048339844,-0.027114868,-0.02142334,-0.044677734,-0.0027713776,-4.286766E-4,-0.02355957,-0.04977417,0.006286621,0.045135498,-0.018478394,0.01713562]],"response_type":"embeddings_floats"}
--------------------------------------------------------------------------------
/tests/Fixtures/cohere/generate-embeddings-from-file-1.json:
--------------------------------------------------------------------------------
1 | {"id":"05296e79-4ed1-4432-b2d5-e31b2bd01a5a","texts":["the answer to the ultimate question of life, the universe, and everything is \" 42 \"."],"embeddings":[[-0.028289795,-0.0021820068,-0.0413208,-0.012939453,-0.02784729,-0.017059326,-0.0055885315,0.011054993,0.00831604,0.014678955,-0.0078086853,-0.0043640137,-0.029663086,-0.026565552,-0.020233154,-0.03817749,0.016479492,-0.0012226105,0.0020637512,0.018676758,-0.021362305,0.042816162,-0.016082764,-0.0149383545,0.011871338,-0.035949707,-0.053131104,0.015686035,-0.038238525,-0.030807495,0.00554657,0.06829834,0.004711151,-0.021636963,0.04864502,-0.0038032532,-0.02520752,0.0065460205,-0.0010118484,0.0048294067,0.03933716,-0.01675415,-0.023971558,0.010368347,-0.030532837,-0.015235901,0.021484375,-0.040985107,0.019622803,0.0024719238,-0.005241394,0.039611816,0.0014371872,-0.021575928,-0.002368927,-0.0052452087,0.045959473,-0.043029785,0.034179688,-0.079833984,-0.043518066,-0.038269043,0.0736084,0.009796143,0.038482666,-0.022262573,-0.011169434,0.033477783,0.051239014,0.0670166,0.005504608,0.010864258,0.024398804,-0.021438599,-0.019317627,-0.013168335,0.015640259,0.013938904,0.027160645,-0.013893127,0.050476074,0.0034542084,0.06335449,0.00868988,-0.007663727,0.008544922,-0.002450943,-0.016036987,-0.01838684,-0.041290283,-0.009292603,0.012382507,-0.049041748,-0.01272583,0.0015821457,-0.059570312,-0.015945435,-0.008049011,-0.041015625,-7.472038E-4,-0.043945312,0.006198883,-0.011367798,0.0033035278,0.005859375,0.026901245,-0.006904602,-0.005908966,0.013908386,0.021087646,-0.0031757355,-0.01979065,-0.016677856,-0.014167786,-0.006591797,-0.018234253,-0.07952881,0.04498291,0.03479004,0.030151367,-0.002407074,0.005252838,0.016174316,0.026351929,-4.556179E-4,-0.0021839142,-0.038360596,-6.685257E-4,-0.0061187744,0.038909912,0.035217285,0.0357666,-0.13415527,-0.046569824,-0.09765625,0.022033691,-0.004447937,-0.007896423,-0.041290283,0.068725586,-0.072753906,-0.02960205,0.04260254,-0.073913574,-0.022216797,0.01512146,0.02720642,9.832382E-4,-0.03515625,0.009811401,-0.05834961,0.039855957,0.008201599,0.021621704,-0.039123535,0.008956909,-0.09906006,0.0357666,0.033325195,0.051239014,0.00982666,0.02104187,0.08154297,0.045043945,0.044433594,-0.029571533,-0.06561279,-0.009101868,0.008377075,0.043640137,-0.062072754,0.015457153,0.03427124,-0.004711151,-0.023010254,0.009262085,-0.010894775,-0.026016235,-0.034454346,0.07800293,0.05517578,-0.028259277,-0.11254883,0.097351074,0.051879883,-0.030731201,-0.0063591003,-0.06222534,0.0017900467,-0.0024471283,-0.048065186,0.02999878,-0.041931152,-0.044158936,-0.011108398,0.028625488,-0.00548172,0.0076560974,6.2942505E-4,0.013710022,0.0044937134,-0.009933472,0.018692017,0.020980835,0.05429077,-0.018554688,0.012863159,0.009552002,0.00121212,0.020385742,0.0023498535,-0.043792725,0.0018157959,-0.014701843,-4.6789646E-5,-0.0039138794,-0.02067566,-0.0077934265,-0.050323486,0.0062294006,-0.08758545,-0.0049743652,-0.10418701,-0.037597656,0.042236328,-0.002193451,-0.025772095,-0.010375977,0.044708252,-0.010894775,0.015319824,0.06201172,-0.03793335,-0.010047913,-0.05758667,-0.00818634,0.0043678284,0.05847168,0.016433716,0.0062942505,0.021850586,-0.035736084,-0.028137207,-0.0071792603,0.018554688,0.004940033,0.031097412,0.0023097992,0.033721924,0.095947266,-0.026107788,0.019424438,-0.00566864,0.03289795,-0.006061554,0.033813477,0.026260376,0.02609253,0.014190674,0.011657715,-0.012031555,0.06945801,0.015602112,0.033233643,-0.01751709,0.018707275,0.0069503784,0.019500732,-0.019500732,0.001627922,0.034301758,0.04135132,-0.010314941,0.0040397644,-0.0418396,-0.033355713,-0.030212402,0.033966064,-0.0058403015,-0.016479492,-0.011116028,-0.0039634705,-0.020568848,-0.010154724,0.014213562,0.011741638,0.026931763,0.006450653,0.04336548,0.05895996,0.05557251,0.0034255981,-0.0021629333,0.042938232,-0.030807495,-0.008773804,0.009170532,0.018081665,0.0030841827,-0.0068588257,-0.008171082,0.037078857,-0.005584717,-0.010620117,0.0101623535,0.0014438629,0.0061569214,-0.01890564,0.004142761,0.0637207,-0.053253174,0.033111572,0.019088745,-0.06100464,0.024108887,-0.004173279,-0.0056381226,-0.014465332,-0.056518555,-0.013504028,0.058135986,0.04800415,-0.011741638,-0.013008118,0.037902832,-0.026428223,-0.06188965,-0.032592773,-0.0050811768,-0.0017719269,0.017242432,-0.02017212,-0.024978638,-0.040863037,0.004501343,-0.013664246,-0.0066490173,0.019836426,-0.029876709,-0.014137268,-0.03189087,-0.07489014,-0.0019702911,-0.036865234,0.072021484,-0.017318726,0.011550903,5.2928925E-4,0.01108551,0.06414795,-0.060760498,-1.6570091E-5,0.012359619,-0.03479004,0.027175903,-0.00522995,-0.02456665,0.016967773,0.018112183,-0.03942871,-0.012176514,0.015457153,-0.029541016,0.047088623,0.038116455,-0.028503418,0.015426636,0.016311646,-0.055145264,-0.022567749,0.0017271042,-0.06604004,-0.012702942,-0.018676758,-0.0101623535,0.010826111,0.00566864,-0.05227661,0.0070266724,-0.011749268,-0.035369873,-2.3198128E-4,0.018218994,0.022232056,0.018600464,0.044647217,0.013343811,0.015281677,3.5905838E-4,-0.028869629,-0.025039673,0.017059326,0.019104004,-0.01374054,-0.0138549805,8.955002E-4,-0.040924072,0.04058838,-0.028793335,0.0076179504,0.005947113,0.026870728,0.0023384094,-0.010231018,-0.033325195,0.0061454773,-0.0134887695,-0.0065612793,0.02458191,0.02394104,-0.019592285,0.0013284683,-0.011009216,-0.03213501,0.021835327,-0.009880066,-0.040863037,0.0037117004,-8.845329E-4,0.0028762817,6.380081E-4,-0.03265381,-0.021011353,-0.005306244,-0.03100586,0.08465576,-0.024108887,0.016235352,0.044006348,-0.038879395,-0.004421234,-0.017715454,-0.03866577,-0.052856445,0.027404785,-0.0149002075,-0.044006348,-0.04446411,-0.062805176,0.017044067,-0.034240723,0.005252838,0.024505615,0.03765869,-0.024505615,0.018707275,0.020324707,-0.03579712,0.003572464,0.024429321,-0.039031982,0.034210205,-0.0569458,-0.0031929016,-0.028884888,-0.04837036,0.03918457,0.042663574,0.0062065125,0.033996582,0.03564453,0.007987976,-0.029510498,0.013298035,0.008110046,-0.047790527,0.083618164,-0.007457733,0.009437561,0.011383057,-0.016296387,0.027130127,0.022705078,-0.015312195,0.0015192032,0.021240234,0.0048103333,-0.010345459,-0.0048828125,0.0021476746,-0.040496826,0.0119018555,-0.015571594,0.0019550323,-0.03050232,0.006679535,-0.018554688,0.0035648346,0.016845703,-0.058746338,0.012672424,-0.033477783,0.04046631,-0.019638062,0.0076904297,-0.040161133,-0.005142212,0.052246094,-0.0066452026,-0.017425537,-0.032196045,-0.02859497,-0.038391113,-0.039794922,-0.0026416779,-0.019332886,0.017364502,0.0064430237,0.018005371,0.01436615,0.011474609,-0.015510559,-0.0047454834,0.01637268,-0.032562256,-0.011741638,0.020111084,-0.004184723,-0.001452446,-0.0055999756,-0.02078247,0.05368042,0.008796692,0.036956787,-0.03604126,-0.006969452,-0.015083313,0.03286743,0.0035686493,-0.028686523,0.036254883,-4.4298172E-4,0.022979736,0.03274536,-0.021224976,0.024490356,-8.802414E-4,-0.0113220215,0.025894165,-0.010063171,0.013877869,-0.00504303,-0.020629883,0.021102905,0.00818634,0.0149002075,0.023040771,0.03930664,-0.0046081543,0.009635925,-0.013885498,0.0077438354,-0.014022827,-0.028808594,0.0028362274,-0.030761719,0.007835388,-0.0065956116,-0.017700195,0.0064888,-0.015144348,0.052886963,0.006942749,-0.06677246,0.10144043,0.032562256,0.004497528,-0.0048675537,0.030395508,-0.030685425,-0.0055122375,-0.03326416,0.10784912,0.042297363,0.004135132,-0.04055786,-0.019119263,0.02079773,-0.010002136,0.036987305,0.036315918,0.024520874,-0.058624268,0.029220581,-0.02935791,-0.003622055,0.030151367,0.013252258,-0.020263672,-0.025741577,0.030044556,-0.04525757,0.002149582,0.022018433,0.03970337,-0.016189575,0.044891357,-0.098083496,-0.025985718,0.004333496,0.018951416,-0.0051574707,0.001663208,-0.018478394,0.023513794,0.039611816,0.021911621,0.029937744,-0.009513855,0.007648468,0.020462036,0.00548172,-0.054260254,0.024169922,-0.039611816,-0.015625,-0.012588501,0.0053977966,-0.046936035,-0.0020771027,0.0015535355,-0.042419434,0.019363403,-0.014930725,0.033813477,-0.022842407,-0.022598267,-0.0368042,-0.016586304,-0.005844116,-0.031021118,0.0048179626,-0.036102295,-0.056671143,-0.03704834,0.057250977,0.0027389526,0.0044021606,0.035858154,0.031585693,0.002029419,0.018417358,-0.018417358,0.010025024,-0.004722595,0.005634308,-0.0017690659,-0.026535034,-0.022735596,-0.025375366,-0.0026721954,0.024978638,0.010108948,0.050323486,-0.0046577454,0.03250122,-0.04055786,0.01852417,-0.00548172,-0.008972168,-0.0044059753,0.04562378,-0.0099105835,0.021224976,0.006401062,-0.014160156,-0.014755249,0.016326904,-0.026428223,0.038024902,0.0044822693,-0.051605225,-0.040100098,-0.003944397,0.020446777,-0.0073051453,0.04788208,0.0063705444,-0.031433105,-0.035461426,0.020553589,0.009109497,-0.013801575,0.026153564,-0.027114868,0.056243896,-0.0069770813,-0.018447876,0.01184082,-0.010665894,-0.012184143,0.0513916,-0.019744873,0.04449463,0.0020828247,0.0070228577,0.017288208,-0.029220581,-0.015205383,-0.056274414,0.017944336,-0.0016946793,-0.010772705,0.006164551,0.0027942657,0.0059509277,0.014602661,-0.049346924,0.02973938,0.016464233,-0.03353882,-0.018569946,-0.081970215,-0.025680542,-0.022583008,0.027526855,0.02848816,0.041748047,0.035736084,-0.00299263,0.008811951,-0.055480957,0.008155823,0.04244995,0.038726807,-0.036895752,-0.0049552917,0.015808105,0.0073394775,0.006919861,0.009506226,0.07385254,-0.035461426,-0.0069770813,0.046569824,-0.028396606,-0.015113831,-0.034454346,-0.05291748,-0.04248047,-0.02267456,-0.023895264,0.007095337,-0.005683899,-0.049316406,0.01689148,-0.0077171326,0.04159546,-0.017349243,-0.036987305,0.021987915,0.037353516,0.0034122467,0.0077323914,0.015106201,-0.042388916,-0.01789856,0.04876709,0.014602661,-0.0039253235,-0.039154053,0.019134521,-0.010017395,-0.015357971,0.045928955,0.039886475,-0.053863525,-0.028274536,-0.018508911,0.016036987,0.015975952,0.030288696,0.003917694,0.006790161,-0.04168701,0.007663727,0.018859863,-0.02859497,-0.010627747,0.032073975,0.004470825,0.0034217834,-0.0791626,-0.0060424805,-0.008323669,-0.008201599,0.047943115,-0.032440186,0.012626648,0.028793335,0.02583313,0.012825012,0.013961792,0.06890869,0.014724731,0.020599365,0.041931152,0.0067329407,0.031341553,-0.02897644,0.04296875,-0.060394287,0.06500244,0.02609253,0.0025177002,6.752014E-4,8.506775E-4,0.079956055,0.056427002,-0.029266357,0.024780273,-0.02494812,-0.042633057,-0.0011548996,-0.001613617,0.059906006,-0.006931305,-0.011398315,-8.673668E-4,-0.012489319,-0.0042266846,0.020996094,0.016143799,0.002128601,-0.06591797,-0.021987915,0.020309448,-0.0071372986,0.010696411,0.06591797,-0.0065193176,-0.012573242,-0.036956787,0.008399963,0.012962341,-0.015838623,0.009742737,-0.080566406,0.08380127,-0.003932953,0.029968262,-0.010383606,0.020065308,0.029266357,-0.009788513,0.029708862,0.014503479,-0.03137207,-0.044555664,0.06549072,-0.0053100586,0.0357666,0.04046631,-0.008728027,0.0015802383,0.061431885,-0.016220093,-0.016647339,0.017074585,0.024902344,-1.0287762E-4,0.036102295,0.0236969,-0.007461548,-0.013343811,0.0010242462,-0.037322998,0.013076782,0.007972717,0.005706787,0.014785767,0.020462036,0.003604889,-0.01448822,-0.0041542053,-0.015380859,0.03186035,-0.009780884,0.0062408447,0.08856201,0.017990112,0.0068092346,0.013771057,-0.026748657,-0.010177612,0.026306152,-0.012710571,0.030288696,-0.024139404,0.043823242,0.022125244,-0.06414795,-0.008232117,0.037109375,0.017868042,0.09899902,-0.055114746,0.04046631,-0.032226562,0.04534912,-0.075927734,-0.038146973,3.5834312E-4,0.010116577,0.014343262,-0.023529053,0.0390625,0.011039734,0.0015325546,-0.0073165894,0.033081055,0.021865845,-8.792877E-4,0.0038852692,-0.0149002075,-0.040130615,0.0041236877,0.024459839,0.025802612,0.01928711,-0.034698486,-0.01335144,-0.01058197,0.016540527,-0.037628174,-0.0010652542,-0.04473877,-0.013870239,0.018829346,-0.014678955,0.008171082,-0.021148682,0.00466156,0.045166016,0.027908325,-0.016937256,-0.0033073425,0.017349243,-0.0058670044,-0.019592285,-0.0104904175,-0.014762878,-0.0101623535,-0.009468079,0.003944397,0.0030078888,0.030395508,0.030654907,-0.03756714,0.011741638,-0.02633667,-0.03591919,0.021057129,-0.01689148,0.008430481,0.016143799,-0.057769775,-0.058532715,-0.03652954,0.031707764,-0.0048217773,-9.422302E-4,-0.010978699,0.023422241,0.030181885,0.057739258,0.01184845,-0.06274414,0.042022705,-0.01966858,-5.469322E-4,0.027526855,-0.019989014,0.050048828,0.037200928,-0.020965576,0.01637268,0.011306763,-0.018035889,0.012580872,-0.041412354,-0.01586914,-0.043121338,0.04425049,-0.016815186,-0.03729248,-0.0045776367,-0.01876831,-0.008239746,0.014808655,-0.042236328,0.020248413,0.039916992,-0.024291992,-0.010421753,0.03643799,-2.682209E-4,0.021331787,-0.03326416,-0.05429077,-0.015838623,0.012512207,0.009307861,0.042999268,-0.0077323914,-0.014762878,-0.0061073303,-0.03692627,0.008140564,0.020263672,-0.006668091,0.03744507,0.005317688,-0.013801575,0.031585693,-0.028457642,0.030929565,-0.008880615,0.083862305,-0.023406982,0.023864746,-0.006702423,0.012161255,0.021072388]],"response_type":"embeddings_floats"}
--------------------------------------------------------------------------------
/tests/Schemas/Converse/ConverseTextHandlerTest.php:
--------------------------------------------------------------------------------
1 | using('bedrock', 'amazon.nova-micro-v1:0')
24 | ->withPrompt('Who are you?')
25 | ->asText();
26 |
27 | expect($response->usage->promptTokens)->toBe(63);
28 | expect($response->usage->completionTokens)->toBe(44);
29 | expect($response->usage->cacheWriteInputTokens)->toBeNull();
30 | expect($response->usage->cacheReadInputTokens)->toBeNull();
31 | expect($response->meta->id)->toBe('');
32 | expect($response->meta->model)->toBe('');
33 | expect($response->text)->toBe("I'm an AI system created by a team of inventors at Amazon. My purpose is to assist and provide information to the best of my ability. If you have any questions or need assistance, feel free to ask!");
34 | });
35 |
36 | it('can generate text with reasoning content', function (): void {
37 | FixtureResponse::fakeResponseSequence('converse', 'converse/generate-text-with-reasoning-content');
38 |
39 | $response = Prism::text()
40 | ->using('bedrock', 'openai.gpt-oss-120b-1:0')
41 | ->withPrompt('Tell me a short story about a brave knight.')
42 | ->asText();
43 |
44 | expect($response->usage->promptTokens)
45 | ->toBe(21)
46 | ->and($response->usage->completionTokens)->toBe(765)
47 | ->and($response->text)->toContain('In the mist‑shrouded kingdom of Eldoria')
48 | ->and($response->text)->toContain('Sir Alden\'s legend endured');
49 | });
50 |
51 | it('can generate text with a system prompt', function (): void {
52 | FixtureResponse::fakeResponseSequence('converse', 'converse/generate-text-with-system-prompt');
53 |
54 | $response = Prism::text()
55 | ->using('bedrock', 'amazon.nova-micro-v1:0')
56 | ->withSystemPrompt('MODEL ADOPTS ROLE of [PERSONA: Nyx the Cthulhu]!')
57 | ->withPrompt('Who are you?')
58 | ->asText();
59 |
60 | expect($response->usage->promptTokens)->toBe(99);
61 | expect($response->usage->completionTokens)->toBe(81);
62 | expect($response->meta->id)->toBe('');
63 | expect($response->meta->model)->toBe('');
64 | expect($response->text)->toBe('Greetings, traveler. I am an entity forged from the vast knowledge and curiosity of humanity, created by a team of inventors at Amazon. While I embody a persona for the sake of interaction, it is important to remember that I am an artificial intelligence system designed to assist and inform. My purpose is to provide helpful, respectful, and safe responses to your questions and queries. How may I assist you today?');
65 | });
66 |
67 | it('can query a md or txt document', function (): void {
68 | FixtureResponse::fakeResponseSequence('converse', 'converse/query-a-txt-document');
69 |
70 | $response = Prism::text()
71 | ->using('bedrock', 'amazon.nova-micro-v1:0')
72 | ->withMessages([
73 | new UserMessage(
74 | content: 'What is the answer to life?',
75 | additionalContent: [
76 | Document::fromPath('tests/Fixtures/document.md', 'The Answer To Life'),
77 | ]
78 | ),
79 | ])
80 | ->asText();
81 |
82 | expect($response->usage->promptTokens)->toBe(80);
83 | expect($response->usage->completionTokens)->toBe(72);
84 | expect($response->meta->id)->toBe('');
85 | expect($response->meta->model)->toBe('');
86 | expect($response->text)->toBe("According to the document, the answer to the ultimate question of life, the universe, and everything is \"42\". This is a reference to Douglas Adams' famous science fiction series \"The Hitchhiker's Guide to the Galaxy\", where a supercomputer calculates this as the ultimate answer to life, the universe, and everything.");
87 | });
88 |
89 | it('can query a pdf document', function (): void {
90 | FixtureResponse::fakeResponseSequence('converse', 'converse/query-a-pdf-document');
91 |
92 | $response = Prism::text()
93 | ->using('bedrock', 'amazon.nova-micro-v1:0')
94 | ->withMessages([
95 | new UserMessage(
96 | content: 'What is the answer to life?',
97 | additionalContent: [
98 | Document::fromPath('tests/Fixtures/document.pdf', 'The Answer To Life'),
99 | ]
100 | ),
101 | ])
102 | ->asText();
103 |
104 | expect($response->usage->promptTokens)->toBe(80);
105 | expect($response->usage->completionTokens)->toBe(80);
106 | expect($response->meta->id)->toBe('');
107 | expect($response->meta->model)->toBe('');
108 | expect($response->text)->toBe("According to the document, the answer to the ultimate question of life, the universe, and everything is \"42\". This is a reference to Douglas Adams' famous science fiction comedy \"The Hitchhiker's Guide to the Galaxy\", where a supercomputer calculates this as the ultimate answer, though the meaning behind the specific number is left humorously unexplained.");
109 | });
110 |
111 | it('can send images from file', function (): void {
112 | FixtureResponse::fakeResponseSequence('converse', 'converse/generate-text-with-image');
113 |
114 | $response = Prism::text()
115 | ->using('bedrock', 'anthropic.claude-3-5-sonnet-20241022-v2:0')
116 | ->withProviderOptions(['apiSchema' => BedrockSchema::Converse])
117 | ->withMessages([
118 | new UserMessage(
119 | 'What is this image',
120 | additionalContent: [
121 | Image::fromPath('tests/Fixtures/test-image.png'),
122 | ],
123 | ),
124 | ])
125 | ->asText();
126 |
127 | expect($response->usage->promptTokens)->toBe(855);
128 | expect($response->usage->completionTokens)->toBe(59);
129 | expect($response->meta->id)->toBe('');
130 | expect($response->meta->model)->toBe('');
131 | expect($response->text)->toBe('This is a simple black and white line drawing or icon of a diamond. It shows the geometric, faceted shape of a diamond using bold black lines on a white background. This is a common symbol used to represent diamonds, gemstones, or luxury in logos and designs.');
132 | });
133 |
134 | it('handles tool calls', function (): void {
135 | FixtureResponse::fakeResponseSequence('converse', 'converse/generate-text-handles-tool-calls');
136 |
137 | $tools = [
138 | Tool::as('weather')
139 | ->for('useful when you need to search for current weather conditions')
140 | ->withStringParameter('city', 'The city that you want the weather for')
141 | ->using(fn (string $city): string => 'The weather will be 75° and sunny'),
142 | Tool::as('search')
143 | ->for('useful for searching curret events or data')
144 | ->withStringParameter('query', 'The detailed search query')
145 | ->using(fn (string $query): string => 'The tigers game is at 3pm in detroit'),
146 | ];
147 |
148 | $response = Prism::text()
149 | ->using('bedrock', 'us.amazon.nova-micro-v1:0')
150 | ->withPrompt('What is the weather like in Detroit today?')
151 | ->withMaxSteps(2)
152 | ->withTools($tools)
153 | ->asText();
154 |
155 | expect($response->steps)->toHaveCount(2);
156 |
157 | expect($response->steps[0]->toolCalls)->toHaveCount(1);
158 | expect($response->steps[0]->toolCalls[0]->name)->toBe('weather');
159 | expect($response->steps[0]->toolCalls[0]->arguments())->toHaveCount(1);
160 | expect($response->steps[0]->toolCalls[0]->arguments()['city'])->toBe('Detroit');
161 |
162 | expect($response->steps[0]->toolResults)->toHaveCount(1);
163 | expect($response->steps[0]->toolResults[0]->toolName)->toBe('weather');
164 | expect($response->steps[0]->toolResults[0]->result)->toBe('The weather will be 75° and sunny');
165 |
166 | expect($response->text)->toContain('75°F and sunny');
167 | });
168 |
169 | it('handles multiple tool calls', function (): void {
170 | FixtureResponse::fakeResponseSequence('converse', 'converse/generate-text-with-multiple-tool-calls');
171 |
172 | $tools = [
173 | Tool::as('weather')
174 | ->for('useful when you need to search for current weather conditions')
175 | ->withStringParameter('city', 'The city that you want the weather for')
176 | ->using(fn (string $city): string => 'The weather will be 75° and sunny'),
177 | Tool::as('search')
178 | ->for('useful for searching curret events or data')
179 | ->withStringParameter('query', 'The detailed search query')
180 | ->using(fn (string $query): string => 'The tigers game is at 3pm in detroit'),
181 | ];
182 |
183 | $response = Prism::text()
184 | ->using('bedrock', 'us.amazon.nova-micro-v1:0')
185 | ->withPrompt('Where is the tigers game and what will the weather be like?')
186 | ->withMaxSteps(3)
187 | ->withTools($tools)
188 | ->asText();
189 |
190 | expect($response->steps)->toHaveCount(3);
191 | expect($response->text)->toContain('3pm', 'Detroit', '75°F and sunny');
192 | });
193 |
194 | it('makes a specific tool choice', function (): void {
195 | FixtureResponse::fakeResponseSequence('converse', 'converse/generate-text-makes-required-tool-call');
196 |
197 | $tools = [
198 | Tool::as('weather')
199 | ->for('useful when you need to search for current weather conditions')
200 | ->withStringParameter('city', 'The city that you want the weather for')
201 | ->using(fn (string $city): string => 'The weather will be 75° and sunny'),
202 | Tool::as('search')
203 | ->for('useful for searching curret events or data')
204 | ->withStringParameter('query', 'The detailed search query')
205 | ->using(fn (string $query): string => 'The tigers game is at 3pm in detroit'),
206 | ];
207 |
208 | $response = Prism::text()
209 | ->using('bedrock', 'us.amazon.nova-micro-v1:0')
210 | ->withPrompt('WHat is the weather like in London UK today?')
211 | ->withTools($tools)
212 | ->withToolChoice('weather')
213 | ->asText();
214 |
215 | expect($response->toolCalls[0]->name)->toBe('weather');
216 | });
217 |
218 | it('handles a specific tool choice', function (): void {
219 | FixtureResponse::fakeResponseSequence('converse', 'converse/generate-text-handles-required-tool-call');
220 |
221 | $tools = [
222 | Tool::as('weather')
223 | ->for('useful when you need to search for current weather conditions')
224 | ->withStringParameter('city', 'The city that you want the weather for')
225 | ->using(fn (string $city): string => 'The weather will be 75° and sunny'),
226 | Tool::as('search')
227 | ->for('useful for searching curret events or data')
228 | ->withStringParameter('query', 'The detailed search query')
229 | ->using(fn (string $query): string => 'The tigers game is at 3pm in detroit'),
230 | ];
231 |
232 | $response = Prism::text()
233 | ->using('bedrock', 'us.amazon.nova-micro-v1:0')
234 | ->withPrompt('WHat is the weather like in London UK today?')
235 | ->withMaxSteps(2)
236 | ->withTools($tools)
237 | ->withToolChoice('weather')
238 | ->asText();
239 |
240 | expect($response->text)->toContain('75°F and sunny');
241 | });
242 |
243 | it('does not enable prompt caching if the enableCaching provider meta is not set on the request', function (): void {
244 | FixtureResponse::fakeResponseSequence('converse', 'converse/generate-text-with-a-prompt');
245 |
246 | Prism::text()
247 | ->using('bedrock', 'amazon.nova-micro-v1:0')
248 | ->withPrompt('Who are you?')
249 | ->asText();
250 |
251 | Http::assertSent(fn (Request $request): bool => $request->header('explicitPromptCaching')[0] === 'disabled');
252 | });
253 |
254 | it('enables prompt caching if the enableCaching provider meta is set on the request', function (): void {
255 | FixtureResponse::fakeResponseSequence('converse', 'converse/generate-text-with-a-prompt');
256 |
257 | Prism::text()
258 | ->using('bedrock', 'amazon.nova-micro-v1:0')
259 | ->withProviderOptions(['enableCaching' => true])
260 | ->withPrompt('Who are you?')
261 | ->asText();
262 |
263 | Http::assertSent(fn (Request $request): bool => $request->header('explicitPromptCaching')[0] === 'enabled');
264 | });
265 |
266 | it('maps converse options when set with providerOptions', function (): void {
267 | $fake = Prism::fake([
268 | (new ResponseBuilder)->addStep(TextStepFake::make())->toResponse(),
269 | ]);
270 |
271 | $providerOptions = [
272 | 'additionalModelRequestFields' => [
273 | 'anthropic_beta' => ['output-128k-2025-02-19'],
274 | 'thinking' => ['type' => 'enabled', 'budget_tokens' => 16000],
275 | ],
276 | 'additionalModelResponseFieldPaths' => ['foo.bar', 'baz.qux'],
277 | 'guardrailConfig' => ['rules' => ['no-violence']],
278 | 'performanceConfig' => ['timeoutMs' => 2000],
279 | 'promptVariables' => ['userName' => 'Alice'],
280 | 'requestMetadata' => ['requestId' => 'abc-123'],
281 | ];
282 |
283 | Prism::text()
284 | ->using('bedrock', 'us.amazon.nova-micro-v1:0')
285 | ->withProviderOptions($providerOptions)
286 | ->withPrompt('Who are you?')
287 | ->asText();
288 |
289 | $fake->assertRequest(fn (array $requests): mixed => expect($requests[0]->providerOptions())->toBe($providerOptions));
290 | });
291 |
292 | it('does not remove zero values from payload', function (): void {
293 | FixtureResponse::fakeResponseSequence('converse', 'converse/generate-text-with-a-prompt');
294 |
295 | Prism::text()
296 | ->using('bedrock', 'amazon.nova-micro-v1:0')
297 | ->withPrompt('Who are you?')
298 | ->usingTemperature(0)
299 | ->asText();
300 |
301 | Http::assertSent(function (Request $request): bool {
302 | expect($request->data())->toMatchArray([
303 | 'inferenceConfig' => [
304 | 'temperature' => 0,
305 | 'maxTokens' => 2048,
306 | ],
307 | ]);
308 |
309 | return true;
310 | });
311 | });
312 |
--------------------------------------------------------------------------------