Skip to content

Commit 14d5ccf

Browse files
committed
Fix data types of enum values in Json Schema
1 parent a40908d commit 14d5ccf

File tree

5 files changed

+58
-7
lines changed

5 files changed

+58
-7
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\AI\Fixtures\StructuredOutput;
13+
14+
use Symfony\AI\Platform\Contract\JsonSchema\Attribute\With;
15+
16+
class ExampleDto
17+
{
18+
public function __construct(
19+
public string $name,
20+
#[With(enum: [7, 19])] public int $taxRate,
21+
#[With(enum: ['Foo', 'Bar', null])] public ?string $category,
22+
) {
23+
}
24+
}

src/platform/phpstan.dist.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ parameters:
77
paths:
88
- src/
99
- tests/
10+
treatPhpDocTypesAsCertain: false
1011
ignoreErrors:
1112
-
1213
message: "#^Method .*::test.*\\(\\) has no return type specified\\.$#"

src/platform/src/Contract/JsonSchema/Attribute/With.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
final readonly class With
2121
{
2222
/**
23-
* @param list<int|string>|null $enum
24-
* @param string|int|string[]|null $const
23+
* @param list<int|float|string|null>|null $enum
24+
* @param string|int|string[]|null $const
2525
*/
2626
public function __construct(
2727
// can be used by many types
@@ -53,8 +53,9 @@ public function __construct(
5353
public ?bool $dependentRequired = null,
5454
) {
5555
if (\is_array($enum)) {
56-
if (array_filter($enum, fn ($item) => \is_string($item)) !== $enum) {
57-
throw new InvalidArgumentException('All enum values must be strings.');
56+
/* @phpstan-ignore-next-line function.alreadyNarrowedType */
57+
if (array_filter($enum, fn (mixed $item) => null === $item || \is_int($item) || \is_float($item) || \is_string($item)) !== $enum) {
58+
throw new InvalidArgumentException('All enum values must be float, integer, strings, or null.');
5859
}
5960
}
6061

src/platform/tests/Contract/JsonSchema/Attribute/ToolParameterTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ public function testValidEnum()
2626
$this->assertSame($enum, $toolParameter->enum);
2727
}
2828

29-
public function testInvalidEnumContainsNonString()
29+
public function testInvalidEnumContainsInvalidType()
3030
{
3131
$this->expectException(InvalidArgumentException::class);
32-
$enum = ['value1', 2];
33-
new With(enum: $enum);
32+
$enum = ['value1', new \stdClass()];
33+
new With(enum: $enum); /* @phpstan-ignore-line argument.type */
3434
}
3535

3636
public function testValidConstString()

src/platform/tests/Contract/JsonSchema/FactoryTest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use PHPUnit\Framework\Attributes\CoversClass;
1515
use PHPUnit\Framework\Attributes\UsesClass;
1616
use PHPUnit\Framework\TestCase;
17+
use Symfony\AI\Fixtures\StructuredOutput\ExampleDto;
1718
use Symfony\AI\Fixtures\StructuredOutput\MathReasoning;
1819
use Symfony\AI\Fixtures\StructuredOutput\Step;
1920
use Symfony\AI\Fixtures\StructuredOutput\User;
@@ -240,4 +241,28 @@ public function testBuildPropertiesForStepClass()
240241

241242
$this->assertSame($expected, $actual);
242243
}
244+
245+
public function testBuildPropertiesForExampleDto()
246+
{
247+
$expected = [
248+
'type' => 'object',
249+
'properties' => [
250+
'name' => ['type' => 'string'],
251+
'taxRate' => [
252+
'type' => 'integer',
253+
'enum' => [7, 19],
254+
],
255+
'category' => [
256+
'type' => ['string', 'null'],
257+
'enum' => ['Foo', 'Bar', null],
258+
],
259+
],
260+
'required' => ['name', 'taxRate'],
261+
'additionalProperties' => false,
262+
];
263+
264+
$actual = $this->factory->buildProperties(ExampleDto::class);
265+
266+
$this->assertSame($expected, $actual);
267+
}
243268
}

0 commit comments

Comments
 (0)