diff --git a/src/Schema/Elicitation/ElicitationSchema.php b/src/Schema/Elicitation/ElicitationSchema.php index 36d130af..c9065fb7 100644 --- a/src/Schema/Elicitation/ElicitationSchema.php +++ b/src/Schema/Elicitation/ElicitationSchema.php @@ -133,6 +133,26 @@ private static function resolveArrayType(array $data): AbstractSchemaDefinition throw new InvalidArgumentException('Array type must have "items" with either "enum" or "anyOf".'); } + /** + * Return the canonical response content for accepting this elicitation with its declared defaults. + * + * @return array + */ + public function extractDefaults(): array + { + $defaults = []; + + foreach ($this->properties as $name => $property) { + $definition = $property->jsonSerialize(); + + if (\array_key_exists('default', $definition)) { + $defaults[$name] = $definition['default']; + } + } + + return $defaults; + } + /** * @return array{ * type: string, diff --git a/tests/Conformance/client.php b/tests/Conformance/client.php index 9832f47d..15cdd8ed 100644 --- a/tests/Conformance/client.php +++ b/tests/Conformance/client.php @@ -52,10 +52,10 @@ ->setLogger($logger); /** - * Accepts every elicitation with an empty payload. + * Accepts every form elicitation with its declared defaults. * - * Enough for the scenarios here, which check that the client asked and echoed - * correctly rather than what a user would have typed. + * ElicitationSchema::extractDefaults() is the canonical accept-with-defaults + * path when the user does not provide explicit field values. */ $acceptElicitation = new class($logger) implements RequestHandlerInterface { public function __construct(private readonly Psr\Log\LoggerInterface $logger) @@ -69,9 +69,14 @@ public function supports(Request $request): bool public function handle(Request $request): Response { - $this->logger->info('Received elicitation request, accepting with empty content'); + if (!$request instanceof ElicitRequest || null === $request->requestedSchema) { + throw new RuntimeException('Expected a form elicitation request with a requested schema.'); + } - return new Response($request->getId(), new ElicitResult(ElicitAction::Accept, [])); + $content = $request->requestedSchema->extractDefaults(); + $this->logger->info(sprintf('Received elicitation request, accepting with %d defaults', count($content))); + + return new Response($request->getId(), new ElicitResult(ElicitAction::Accept, $content)); } }; diff --git a/tests/Unit/Schema/Elicitation/ElicitationSchemaTest.php b/tests/Unit/Schema/Elicitation/ElicitationSchemaTest.php index 3117de90..1b2ab147 100644 --- a/tests/Unit/Schema/Elicitation/ElicitationSchemaTest.php +++ b/tests/Unit/Schema/Elicitation/ElicitationSchemaTest.php @@ -67,6 +67,39 @@ public function testConstructorWithMultipleTypes(): void $this->assertInstanceOf(EnumSchemaDefinition::class, $schema->properties['rating']); } + public function testExtractDefaults(): void + { + $schema = ElicitationSchema::fromArray([ + 'type' => 'object', + 'properties' => [ + 'name' => ['type' => 'string', 'title' => 'Name', 'default' => 'Ada'], + 'age' => ['type' => 'integer', 'title' => 'Age', 'default' => 0], + 'score' => ['type' => 'number', 'title' => 'Score', 'default' => 95.5], + 'color' => ['type' => 'string', 'title' => 'Color', 'enum' => ['red', 'blue'], 'default' => 'blue'], + 'plan' => [ + 'type' => 'string', + 'title' => 'Plan', + 'oneOf' => [ + ['const' => 'free', 'title' => 'Free'], + ['const' => 'pro', 'title' => 'Pro'], + ], + 'default' => 'pro', + ], + 'subscribe' => ['type' => 'boolean', 'title' => 'Subscribe', 'default' => false], + 'withoutDefault' => ['type' => 'string', 'title' => 'Without default'], + ], + ]); + + $this->assertSame([ + 'name' => 'Ada', + 'age' => 0, + 'score' => 95.5, + 'color' => 'blue', + 'plan' => 'pro', + 'subscribe' => false, + ], $schema->extractDefaults()); + } + public function testConstructorWithEmptyProperties(): void { $this->expectException(InvalidArgumentException::class);