From 05213dc00ac41e1ba2eaa4e35a0e76ffaa6213c1 Mon Sep 17 00:00:00 2001 From: Felix Arntz Date: Wed, 26 Nov 2025 15:37:06 -0800 Subject: [PATCH] Allow specifying optional provider credentials URL in provider metadata. --- .../Anthropic/AnthropicProvider.php | 3 +- .../Google/GoogleProvider.php | 3 +- .../OpenAi/OpenAiProvider.php | 3 +- src/Providers/DTO/ProviderMetadata.php | 33 +++++++++++++++++-- .../Providers/DTO/ProviderMetadataTest.php | 30 +++++++++++++++-- 5 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/ProviderImplementations/Anthropic/AnthropicProvider.php b/src/ProviderImplementations/Anthropic/AnthropicProvider.php index 91038d31..3d817769 100644 --- a/src/ProviderImplementations/Anthropic/AnthropicProvider.php +++ b/src/ProviderImplementations/Anthropic/AnthropicProvider.php @@ -62,7 +62,8 @@ protected static function createProviderMetadata(): ProviderMetadata return new ProviderMetadata( 'anthropic', 'Anthropic', - ProviderTypeEnum::cloud() + ProviderTypeEnum::cloud(), + 'https://console.anthropic.com/settings/keys' ); } diff --git a/src/ProviderImplementations/Google/GoogleProvider.php b/src/ProviderImplementations/Google/GoogleProvider.php index 5d721979..72ccd632 100644 --- a/src/ProviderImplementations/Google/GoogleProvider.php +++ b/src/ProviderImplementations/Google/GoogleProvider.php @@ -65,7 +65,8 @@ protected static function createProviderMetadata(): ProviderMetadata return new ProviderMetadata( 'google', 'Google', - ProviderTypeEnum::cloud() + ProviderTypeEnum::cloud(), + 'https://aistudio.google.com/app/api-keys' ); } diff --git a/src/ProviderImplementations/OpenAi/OpenAiProvider.php b/src/ProviderImplementations/OpenAi/OpenAiProvider.php index 6857feea..412e0e35 100644 --- a/src/ProviderImplementations/OpenAi/OpenAiProvider.php +++ b/src/ProviderImplementations/OpenAi/OpenAiProvider.php @@ -71,7 +71,8 @@ protected static function createProviderMetadata(): ProviderMetadata return new ProviderMetadata( 'openai', 'OpenAI', - ProviderTypeEnum::cloud() + ProviderTypeEnum::cloud(), + 'https://platform.openai.com/api-keys' ); } diff --git a/src/Providers/DTO/ProviderMetadata.php b/src/Providers/DTO/ProviderMetadata.php index fe1643ca..a1d4fe54 100644 --- a/src/Providers/DTO/ProviderMetadata.php +++ b/src/Providers/DTO/ProviderMetadata.php @@ -18,7 +18,8 @@ * @phpstan-type ProviderMetadataArrayShape array{ * id: string, * name: string, - * type: string + * type: string, + * credentialsUrl?: ?string * } * * @extends AbstractDataTransferObject @@ -28,6 +29,7 @@ class ProviderMetadata extends AbstractDataTransferObject public const KEY_ID = 'id'; public const KEY_NAME = 'name'; public const KEY_TYPE = 'type'; + public const KEY_CREDENTIALS_URL = 'credentialsUrl'; /** * @var string The provider's unique identifier. @@ -44,6 +46,11 @@ class ProviderMetadata extends AbstractDataTransferObject */ protected ProviderTypeEnum $type; + /** + * @var string|null The URL where users can get credentials. + */ + protected ?string $credentialsUrl; + /** * Constructor. * @@ -52,12 +59,14 @@ class ProviderMetadata extends AbstractDataTransferObject * @param string $id The provider's unique identifier. * @param string $name The provider's display name. * @param ProviderTypeEnum $type The provider type. + * @param string|null $credentialsUrl The URL where users can get credentials. */ - public function __construct(string $id, string $name, ProviderTypeEnum $type) + public function __construct(string $id, string $name, ProviderTypeEnum $type, ?string $credentialsUrl = null) { $this->id = $id; $this->name = $name; $this->type = $type; + $this->credentialsUrl = $credentialsUrl; } /** @@ -96,6 +105,18 @@ public function getType(): ProviderTypeEnum return $this->type; } + /** + * Gets the credentials URL. + * + * @since 0.1.0 + * + * @return string|null The credentials URL. + */ + public function getCredentialsUrl(): ?string + { + return $this->credentialsUrl; + } + /** * {@inheritDoc} * @@ -119,6 +140,10 @@ public static function getJsonSchema(): array 'enum' => ProviderTypeEnum::getValues(), 'description' => 'The provider type (cloud, server, or client).', ], + self::KEY_CREDENTIALS_URL => [ + 'type' => 'string', + 'description' => 'The URL where users can get credentials.', + ], ], 'required' => [self::KEY_ID, self::KEY_NAME, self::KEY_TYPE], ]; @@ -137,6 +162,7 @@ public function toArray(): array self::KEY_ID => $this->id, self::KEY_NAME => $this->name, self::KEY_TYPE => $this->type->value, + self::KEY_CREDENTIALS_URL => $this->credentialsUrl, ]; } @@ -152,7 +178,8 @@ public static function fromArray(array $array): self return new self( $array[self::KEY_ID], $array[self::KEY_NAME], - ProviderTypeEnum::from($array[self::KEY_TYPE]) + ProviderTypeEnum::from($array[self::KEY_TYPE]), + $array[self::KEY_CREDENTIALS_URL] ?? null ); } } diff --git a/tests/unit/Providers/DTO/ProviderMetadataTest.php b/tests/unit/Providers/DTO/ProviderMetadataTest.php index bf54cfd4..3b0b18d2 100644 --- a/tests/unit/Providers/DTO/ProviderMetadataTest.php +++ b/tests/unit/Providers/DTO/ProviderMetadataTest.php @@ -33,6 +33,27 @@ public function testConstructorAndGetters(): void $this->assertEquals($name, $metadata->getName()); $this->assertSame($type, $metadata->getType()); $this->assertTrue($metadata->getType()->isCloud()); + $this->assertNull($metadata->getCredentialsUrl()); + } + + /** + * Tests constructor with credentials URL. + * + * @return void + */ + public function testConstructorWithCredentialsUrl(): void + { + $id = 'openai'; + $name = 'OpenAI'; + $type = ProviderTypeEnum::cloud(); + $credentialsUrl = 'https://platform.openai.com/account/api-keys'; + + $metadata = new ProviderMetadata($id, $name, $type, $credentialsUrl); + + $this->assertEquals($id, $metadata->getId()); + $this->assertEquals($name, $metadata->getName()); + $this->assertSame($type, $metadata->getType()); + $this->assertEquals($credentialsUrl, $metadata->getCredentialsUrl()); } /** @@ -78,11 +99,13 @@ public function testGetJsonSchema(): void $this->assertArrayHasKey(ProviderMetadata::KEY_ID, $schema['properties']); $this->assertArrayHasKey(ProviderMetadata::KEY_NAME, $schema['properties']); $this->assertArrayHasKey(ProviderMetadata::KEY_TYPE, $schema['properties']); + $this->assertArrayHasKey(ProviderMetadata::KEY_CREDENTIALS_URL, $schema['properties']); // Check property types $this->assertEquals('string', $schema['properties'][ProviderMetadata::KEY_ID]['type']); $this->assertEquals('string', $schema['properties'][ProviderMetadata::KEY_NAME]['type']); $this->assertEquals('string', $schema['properties'][ProviderMetadata::KEY_TYPE]['type']); + $this->assertEquals('string', $schema['properties'][ProviderMetadata::KEY_CREDENTIALS_URL]['type']); // Check enum values for type $this->assertArrayHasKey('enum', $schema['properties'][ProviderMetadata::KEY_TYPE]); @@ -110,7 +133,8 @@ public function testToArray(): void $this->assertEquals('anthropic', $array[ProviderMetadata::KEY_ID]); $this->assertEquals('Anthropic', $array[ProviderMetadata::KEY_NAME]); $this->assertEquals('cloud', $array[ProviderMetadata::KEY_TYPE]); - $this->assertCount(3, $array); + $this->assertNull($array[ProviderMetadata::KEY_CREDENTIALS_URL]); + $this->assertCount(4, $array); } /** @@ -123,7 +147,8 @@ public function testFromArray(): void $data = [ ProviderMetadata::KEY_ID => 'custom-provider', ProviderMetadata::KEY_NAME => 'Custom Provider', - ProviderMetadata::KEY_TYPE => 'server' + ProviderMetadata::KEY_TYPE => 'server', + ProviderMetadata::KEY_CREDENTIALS_URL => 'https://example.com/credentials', ]; $metadata = ProviderMetadata::fromArray($data); @@ -132,6 +157,7 @@ public function testFromArray(): void $this->assertEquals('custom-provider', $metadata->getId()); $this->assertEquals('Custom Provider', $metadata->getName()); $this->assertTrue($metadata->getType()->isServer()); + $this->assertEquals('https://example.com/credentials', $metadata->getCredentialsUrl()); } /**