diff --git a/src/Relay.php b/src/Relay.php index cca3b53..a8fc269 100644 --- a/src/Relay.php +++ b/src/Relay.php @@ -6,6 +6,7 @@ use Illuminate\Support\Facades\Cache; use Prism\Prism\Contracts\Schema; +use Prism\Prism\Schema\AnyOfSchema; use Prism\Prism\Schema\ArraySchema; use Prism\Prism\Schema\BooleanSchema; use Prism\Prism\Schema\EnumSchema; @@ -326,7 +327,7 @@ protected function getSchemeParameters(array $properties, string $definitionName $parameters = []; foreach ($properties as $name => $property) { - $parameter = $this->getSchemeParameter($name, $property, $definitionName); + $parameter = $this->getSchemeParameter((string) $name, $property, $definitionName); if ($parameter instanceof Schema) { $parameters[] = $parameter; } @@ -340,7 +341,7 @@ protected function getSchemeParameters(array $properties, string $definitionName * * @throws RelayException */ - protected function getSchemeParameter(string $name, array $property, string $definitionName): Schema|null + protected function getSchemeParameter(string $name, array $property, string $definitionName): ?Schema { if ($property === []) { return null; @@ -348,6 +349,14 @@ protected function getSchemeParameter(string $name, array $property, string $def $type = data_get($property, 'type'); $description = $this->getParameterDescription($name, $property, $definitionName); + + if ($type === null && isset($property['anyOf'])) { + $type = 'anyOf'; + $itemsSchema = $this->getSchemeParameters(data_get($property, 'anyOf', []), $definitionName); + + return new AnyOfSchema($itemsSchema, $name, $description); + } + $itemsSchema = $this->getSchemeParameter('', data_get($property, 'items', []), $definitionName); return match ($type) { diff --git a/tests/TestDoubles/RelayFake.php b/tests/TestDoubles/RelayFake.php index 58a747d..201f3b7 100644 --- a/tests/TestDoubles/RelayFake.php +++ b/tests/TestDoubles/RelayFake.php @@ -182,6 +182,28 @@ protected function fetchToolDefinitions(): array 'required' => ['script'], ], ], + [ + 'name' => 'union_tool', + 'description' => 'A tool with union parameter', + 'inputSchema' => [ + 'type' => 'object', + 'properties' => [ + 'nameOrId' => [ + 'anyOf' => [ + [ + 'type' => 'string', + 'description' => 'Name', + ], + [ + 'type' => 'number', + 'description' => 'ID', + ], + ], + ], + ], + 'required' => ['nameOrId'], + ], + ], ]; } diff --git a/tests/Unit/RelayTest.php b/tests/Unit/RelayTest.php index e2c4347..f9d70c5 100644 --- a/tests/Unit/RelayTest.php +++ b/tests/Unit/RelayTest.php @@ -5,6 +5,7 @@ namespace Tests\Unit; use Illuminate\Support\Facades\Cache; +use Prism\Prism\Schema\AnyOfSchema; use Prism\Prism\Tool; use Prism\Relay\Exceptions\ServerConfigurationException; use Prism\Relay\Exceptions\ToolDefinitionException; @@ -86,7 +87,7 @@ $tools = $relay->tools(); // Test we have the tools we expect - expect($tools)->toHaveCount(6); + expect($tools)->toHaveCount(7); }); it('handles different parameter types correctly in tools', function (): void { @@ -128,3 +129,29 @@ expect($tools)->toBeArray() ->and($tools !== [])->toBeTrue(); }); + +it('supports mapping any of schemas', function (): void { + $relay = new RelayFake($this->serverName); + + // Call tools() to create handlers + $tools = $relay->tools(); + + $tool = $tools[6]; + $anyOf = $tool->parameters()['nameOrId']; + + expect($anyOf) + ->toBeInstanceOf(AnyOfSchema::class) + ->and($anyOf->toArray())->toBe([ + 'anyOf' => [ + [ + 'description' => 'Name', + 'type' => 'string', + ], + [ + 'description' => 'ID', + 'type' => 'number', + ], + ], + 'description' => 'Parameter nameOrId for union_tool', + ]); +});