Skip to content

Commit 98054e6

Browse files
committed
Add support for tool_calls on the chat completion endpoint
1 parent 03a24a6 commit 98054e6

19 files changed

+428
-11
lines changed

README.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,60 @@ $response->usage->totalTokens; // 21
220220
$response->toArray(); // ['id' => 'chatcmpl-6pMyfj1HF4QXnfvjtfzvufZSQq6Eq', ...]
221221
```
222222

223+
Creates a completion for the chat message with a tool call.
224+
225+
```php
226+
$response = $client->chat()->create([
227+
'model' => 'gpt-3.5-turbo-0613',
228+
'messages' => [
229+
['role' => 'user', 'content' => 'What\'s the weather like in Boston?'],
230+
],
231+
'tools' => [
232+
[
233+
'type' => 'function',
234+
'function' => [
235+
'name' => 'get_current_weather',
236+
'description' => 'Get the current weather in a given location',
237+
'parameters' => [
238+
'type' => 'object',
239+
'properties' => [
240+
'location' => [
241+
'type' => 'string',
242+
'description' => 'The city and state, e.g. San Francisco, CA',
243+
],
244+
'unit' => [
245+
'type' => 'string',
246+
'enum' => ['celsius', 'fahrenheit']
247+
],
248+
],
249+
'required' => ['location'],
250+
],
251+
],
252+
]
253+
]
254+
]);
255+
256+
$response->id; // 'chatcmpl-6pMyfj1HF4QXnfvjtfzvufZSQq6Eq'
257+
$response->object; // 'chat.completion'
258+
$response->created; // 1677701073
259+
$response->model; // 'gpt-3.5-turbo-0613'
260+
261+
foreach ($response->choices as $result) {
262+
$result->index; // 0
263+
$result->message->role; // 'assistant'
264+
$result->message->content; // null
265+
$result->message->toolCalls[0]->id; // 'call_123'
266+
$result->message->toolCalls[0]->type; // 'function'
267+
$result->message->toolCalls[0]->function->name; // 'get_current_weather'
268+
$result->message->toolCalls[0]->function->arguments; // "{\n \"location\": \"Boston, MA\"\n}"
269+
$result->finishReason; // 'tool_calls'
270+
}
271+
272+
$response->usage->promptTokens; // 82,
273+
$response->usage->completionTokens; // 18,
274+
$response->usage->totalTokens; // 100
275+
```
276+
223277
Creates a completion for the chat message with a function call.
224278

225279
```php

src/Resources/Chat.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public function create(array $parameters): CreateResponse
2929

3030
$payload = Payload::create('chat/completions', $parameters);
3131

32-
/** @var Response<array{id: string, object: string, created: int, model: string, choices: array<int, array{index: int, message: array{role: string, content: ?string, function_call: ?array{name: string, arguments: string}}, finish_reason: string|null}>, usage: array{prompt_tokens: int, completion_tokens: int|null, total_tokens: int}}> $response */
32+
/** @var Response<array{id: string, object: string, created: int, model: string, system_fingerprint?: string, choices: array<int, array{index: int, message: array{role: string, content: ?string, function_call: ?array{name: string, arguments: string}, tool_calls: ?array<int, array{id: string, type: string, function: array{name: string, arguments: string}}>}, finish_reason: string|null}>, usage: array{prompt_tokens: int, completion_tokens: int|null, total_tokens: int}}> $response */
3333
$response = $this->transporter->requestObject($payload);
3434

3535
return CreateResponse::from($response->data(), $response->meta());

src/Responses/Chat/CreateResponse.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@
1212
use OpenAI\Testing\Responses\Concerns\Fakeable;
1313

1414
/**
15-
* @implements ResponseContract<array{id: string, object: string, created: int, model: string, choices: array<int, array{index: int, message: array{role: string, content: string|null, function_call?: array{name: string, arguments: string}}, finish_reason: string|null}>, usage: array{prompt_tokens: int, completion_tokens: int|null, total_tokens: int}}>
15+
* @implements ResponseContract<array{id: string, object: string, created: int, model: string, system_fingerprint?: string, choices: array<int, array{index: int, message: array{role: string, content: string|null, function_call?: array{name: string, arguments: string}, tool_calls?: array<int, array{id: string, type: string, function: array{name: string, arguments: string}}>}, finish_reason: string|null}>, usage: array{prompt_tokens: int, completion_tokens: int|null, total_tokens: int}}>
1616
*/
1717
final class CreateResponse implements ResponseContract, ResponseHasMetaInformationContract
1818
{
1919
/**
20-
* @use ArrayAccessible<array{id: string, object: string, created: int, model: string, choices: array<int, array{index: int, message: array{role: string, content: string|null, function_call?: array{name: string, arguments: string}}, finish_reason: string|null}>, usage: array{prompt_tokens: int, completion_tokens: int|null, total_tokens: int}}>
20+
* @use ArrayAccessible<array{id: string, object: string, created: int, model: string, system_fingerprint?: string, choices: array<int, array{index: int, message: array{role: string, content: string|null, function_call?: array{name: string, arguments: string}, tool_calls?: array<int, array{id: string, type: string, function: array{name: string, arguments: string}}>}, finish_reason: string|null}>, usage: array{prompt_tokens: int, completion_tokens: int|null, total_tokens: int}}>
2121
*/
2222
use ArrayAccessible;
2323

@@ -32,6 +32,7 @@ private function __construct(
3232
public readonly string $object,
3333
public readonly int $created,
3434
public readonly string $model,
35+
public readonly ?string $systemFingerprint,
3536
public readonly array $choices,
3637
public readonly CreateResponseUsage $usage,
3738
private readonly MetaInformation $meta,
@@ -41,7 +42,7 @@ private function __construct(
4142
/**
4243
* Acts as static factory, and returns a new Response instance.
4344
*
44-
* @param array{id: string, object: string, created: int, model: string, choices: array<int, array{index: int, message: array{role: string, content: ?string, function_call: ?array{name: string, arguments: string}}, finish_reason: string|null}>, usage: array{prompt_tokens: int, completion_tokens: int|null, total_tokens: int}} $attributes
45+
* @param array{id: string, object: string, created: int, model: string, system_fingerprint?: string, choices: array<int, array{index: int, message: array{role: string, content: ?string, function_call: ?array{name: string, arguments: string}, tool_calls: ?array<int, array{id: string, type: string, function: array{name: string, arguments: string}}>}, finish_reason: string|null}>, usage: array{prompt_tokens: int, completion_tokens: int|null, total_tokens: int}} $attributes
4546
*/
4647
public static function from(array $attributes, MetaInformation $meta): self
4748
{
@@ -54,6 +55,7 @@ public static function from(array $attributes, MetaInformation $meta): self
5455
$attributes['object'],
5556
$attributes['created'],
5657
$attributes['model'],
58+
$attributes['system_fingerprint'] ?? null,
5759
$choices,
5860
CreateResponseUsage::from($attributes['usage']),
5961
$meta,
@@ -65,16 +67,17 @@ public static function from(array $attributes, MetaInformation $meta): self
6567
*/
6668
public function toArray(): array
6769
{
68-
return [
70+
return array_filter([
6971
'id' => $this->id,
7072
'object' => $this->object,
7173
'created' => $this->created,
7274
'model' => $this->model,
75+
'system_fingerprint' => $this->systemFingerprint,
7376
'choices' => array_map(
7477
static fn (CreateResponseChoice $result): array => $result->toArray(),
7578
$this->choices,
7679
),
7780
'usage' => $this->usage->toArray(),
78-
];
81+
], fn (mixed $value): bool => ! is_null($value));
7982
}
8083
}

src/Responses/Chat/CreateResponseChoice.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ private function __construct(
1414
}
1515

1616
/**
17-
* @param array{index: int, message: array{role: string, content: ?string, function_call: ?array{name: string, arguments: string}}, finish_reason: string|null} $attributes
17+
* @param array{index: int, message: array{role: string, content: ?string, function_call: ?array{name: string, arguments: string}, tool_calls: ?array<int, array{id: string, type: string, function: array{name: string, arguments: string}}>}, finish_reason: string|null} $attributes
1818
*/
1919
public static function from(array $attributes): self
2020
{
@@ -26,7 +26,7 @@ public static function from(array $attributes): self
2626
}
2727

2828
/**
29-
* @return array{index: int, message: array{role: string, content: string|null, function_call?: array{name: string, arguments: string}}, finish_reason: string|null}
29+
* @return array{index: int, message: array{role: string, content: string|null, function_call?: array{name: string, arguments: string}, tool_calls?: array<int, array{id: string, type: string, function: array{name: string, arguments: string}}>}, finish_reason: string|null}
3030
*/
3131
public function toArray(): array
3232
{

src/Responses/Chat/CreateResponseFunctionCall.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
namespace OpenAI\Responses\Chat;
66

7+
/**
8+
* @deprecated
9+
*/
710
final class CreateResponseFunctionCall
811
{
912
private function __construct(

src/Responses/Chat/CreateResponseMessage.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,36 @@
66

77
final class CreateResponseMessage
88
{
9+
/**
10+
* @param array<int, CreateResponseToolCall> $toolCalls
11+
*/
912
private function __construct(
1013
public readonly string $role,
1114
public readonly ?string $content,
15+
public readonly array $toolCalls,
1216
public readonly ?CreateResponseFunctionCall $functionCall,
1317
) {
1418
}
1519

1620
/**
17-
* @param array{role: string, content: ?string, function_call: ?array{name: string, arguments: string}} $attributes
21+
* @param array{role: string, content: ?string, function_call: ?array{name: string, arguments: string}, tool_calls: ?array<int, array{id: string, type: string, function: array{name: string, arguments: string}}>} $attributes
1822
*/
1923
public static function from(array $attributes): self
2024
{
25+
$toolCalls = array_map(fn (array $result): CreateResponseToolCall => CreateResponseToolCall::from(
26+
$result
27+
), $attributes['tool_calls'] ?? []);
28+
2129
return new self(
2230
$attributes['role'],
2331
$attributes['content'] ?? null,
32+
$toolCalls,
2433
isset($attributes['function_call']) ? CreateResponseFunctionCall::from($attributes['function_call']) : null,
2534
);
2635
}
2736

2837
/**
29-
* @return array{role: string, content: string|null, function_call?: array{name: string, arguments: string}}
38+
* @return array{role: string, content: string|null, function_call?: array{name: string, arguments: string}, tool_calls?: array<int, array{id: string, type: string, function: array{name: string, arguments: string}}>}
3039
*/
3140
public function toArray(): array
3241
{
@@ -39,6 +48,10 @@ public function toArray(): array
3948
$data['function_call'] = $this->functionCall->toArray();
4049
}
4150

51+
if ($this->toolCalls !== []) {
52+
$data['tool_calls'] = array_map(fn (CreateResponseToolCall $toolCall): array => $toolCall->toArray(), $this->toolCalls);
53+
}
54+
4255
return $data;
4356
}
4457
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenAI\Responses\Chat;
6+
7+
final class CreateResponseToolCall
8+
{
9+
private function __construct(
10+
public readonly string $id,
11+
public readonly string $type,
12+
public readonly CreateResponseToolCallFunction $function,
13+
) {
14+
}
15+
16+
/**
17+
* @param array{id: string, type: string, function: array{name: string, arguments: string}} $attributes
18+
*/
19+
public static function from(array $attributes): self
20+
{
21+
return new self(
22+
$attributes['id'],
23+
$attributes['type'],
24+
CreateResponseToolCallFunction::from($attributes['function']),
25+
);
26+
}
27+
28+
/**
29+
* @return array{id: string, type: string, function: array{name: string, arguments: string}}
30+
*/
31+
public function toArray(): array
32+
{
33+
return [
34+
'id' => $this->id,
35+
'type' => $this->type,
36+
'function' => $this->function->toArray(),
37+
];
38+
}
39+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenAI\Responses\Chat;
6+
7+
final class CreateResponseToolCallFunction
8+
{
9+
private function __construct(
10+
public readonly string $name,
11+
public readonly string $arguments,
12+
) {
13+
}
14+
15+
/**
16+
* @param array{name: string, arguments: string} $attributes
17+
*/
18+
public static function from(array $attributes): self
19+
{
20+
return new self(
21+
$attributes['name'],
22+
$attributes['arguments'],
23+
);
24+
}
25+
26+
/**
27+
* @return array{name: string, arguments: string}
28+
*/
29+
public function toArray(): array
30+
{
31+
return [
32+
'name' => $this->name,
33+
'arguments' => $this->arguments,
34+
];
35+
}
36+
}

src/Responses/Chat/CreateStreamedResponseDelta.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,30 @@
66

77
final class CreateStreamedResponseDelta
88
{
9+
/**
10+
* @param array<int, CreateStreamedResponseToolCall> $toolCalls
11+
*/
912
private function __construct(
1013
public readonly ?string $role,
1114
public readonly ?string $content,
15+
public readonly array $toolCalls,
1216
public readonly ?CreateStreamedResponseFunctionCall $functionCall,
1317
) {
1418
}
1519

1620
/**
17-
* @param array{role?: string, content?: string, function_call?: array{name?: ?string, arguments?: ?string}} $attributes
21+
* @param array{role?: string, content?: string, function_call?: array{name?: ?string, arguments?: ?string}, tool_calls?: array<int, array{id?: string, type?: string, function: array{name?: string, arguments: string}}>} $attributes
1822
*/
1923
public static function from(array $attributes): self
2024
{
25+
$toolCalls = array_map(fn (array $result): CreateStreamedResponseToolCall => CreateStreamedResponseToolCall::from(
26+
$result
27+
), $attributes['tool_calls'] ?? []);
28+
2129
return new self(
2230
$attributes['role'] ?? null,
2331
$attributes['content'] ?? null,
32+
$toolCalls,
2433
isset($attributes['function_call']) ? CreateStreamedResponseFunctionCall::from($attributes['function_call']) : null,
2534
);
2635
}
@@ -40,6 +49,10 @@ public function toArray(): array
4049
$data['function_call'] = $this->functionCall->toArray();
4150
}
4251

52+
if ($this->toolCalls !== []) {
53+
$data['tool_calls'] = array_map(fn (CreateStreamedResponseToolCall $toolCall): array => $toolCall->toArray(), $this->toolCalls);
54+
}
55+
4356
return $data;
4457
}
4558
}

src/Responses/Chat/CreateStreamedResponseFunctionCall.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
namespace OpenAI\Responses\Chat;
66

7+
/**
8+
* @deprecated
9+
*/
710
final class CreateStreamedResponseFunctionCall
811
{
912
private function __construct(

0 commit comments

Comments
 (0)