From d69b546d154a682fd01ff62f68f6b7138c3e90cb Mon Sep 17 00:00:00 2001 From: Matthew Batchelder Date: Mon, 14 Jul 2025 21:54:26 -0400 Subject: [PATCH 1/6] Update namespaces in architecture to domain-based Reorganized classes into more specific namespaces to match #21. Moved message-related classes, file types, models, and enums into their appropriate sub-namespaces to improve code organization and follow single responsibility principle. --- docs/ARCHITECTURE.md | 348 ++++++++++++++++++++++++------------------- 1 file changed, 197 insertions(+), 151 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index aae59d1..b10e32e 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -460,7 +460,9 @@ direction LR +generateSpeechOperation(string|MessagePart|MessagePart[]|Message|Message[] $prompt, AiModel $model) GenerativeAiOperation$ +generateEmbeddingsOperation(string[]|Message[] $input, AiModel $model) EmbeddingOperation$ } + } + namespace AiClientNamespace.Builders { class PromptBuilder { +withText(string $text) self +withInlineImage(string $base64Blob, string $mimeType) @@ -523,18 +525,12 @@ direction LR +get() Message } } - namespace AiClientNamespace.Types { + namespace AiClientNamespace.Messages { class Message { +getRole() MessageRole +getParts() MessagePart[] +getJsonSchema() array< string, mixed >$ } - class UserMessage { - } - class ModelMessage { - } - class SystemMessage { - } class MessagePart { +getType() MessagePartType +getText() string? @@ -544,23 +540,30 @@ direction LR +getFunctionResponse() FunctionResponse? +getJsonSchema() array< string, mixed >$ } - class File { + class ModelMessage { } - class InlineFile { - +getMimeType() string - +getBase64Data() string - +getJsonSchema() array< string, mixed >$ + class SystemMessage { } - class RemoteFile { - +getMimeType() string - +getUrl() string - +getJsonSchema() array< string, mixed >$ + class UserMessage { } - class LocalFile { - +getMimeType() string - +getPath() string - +getJsonSchema() array< string, mixed >$ + } + + namespace AiClientNamespace.Messages.Enums { + class MessagePartType { + TEXT + INLINE_FILE + REMOTE_FILE + FUNCTION_CALL + FUNCTION_RESPONSE } + class MessageRole { + USER + MODEL + SYSTEM + } + } + + namespace AiClientNamespace.Messages.Functions { class FunctionCall { +getId() string +getName() string @@ -573,31 +576,46 @@ direction LR +getResponse() mixed +getJsonSchema() array< string, mixed >$ } - class Embedding { - +getVector() float[] - +getDimension() int + } + + namespace AiClientNamespace.Files { + class InlineFile { + +getMimeType() string + +getBase64Data() string + +getJsonSchema() array< string, mixed >$ } - class Operation { - +getId() string - +getState() OperationState + class LocalFile { + +getMimeType() string + +getPath() string +getJsonSchema() array< string, mixed >$ } - class GenerativeAiOperation { - +getId() string - +getState() OperationState - +getResult() GenerativeAiResult + class RemoteFile { + +getMimeType() string + +getUrl() string +getJsonSchema() array< string, mixed >$ } - class EmbeddingOperation { - +getId() string - +getState() OperationState - +getResult() EmbeddingResult + } + + namespace AiClientNamespace.Files.Contracts { + class File { + } + } + + namespace AiClientNamespace.Providers.Models { + class Candidate { + +getMessage() Message + +getFinishReason() FinishReason + +getTokenCount() int +getJsonSchema() array< string, mixed >$ } - class Result { + class Embedding { + +getVector() float[] + +getDimension() int + } + class GenerativeAiOperation { +getId() string - +getTokenUsage() TokenUsage - +getProviderMetadata() array< string, mixed > + +getState() OperationState + +getResult() GenerativeAiResult +getJsonSchema() array< string, mixed >$ } class GenerativeAiResult { @@ -618,6 +636,12 @@ direction LR +toVideoFiles() File[] +toMessages() Message[] } + class EmbeddingOperation { + +getId() string + +getState() OperationState + +getResult() EmbeddingResult + +getJsonSchema() array< string, mixed >$ + } class EmbeddingResult { +getId() string +getEmbeddings() Embedding[] @@ -625,12 +649,6 @@ direction LR +getProviderMetadata() array< string, mixed > +getJsonSchema() array< string, mixed >$ } - class Candidate { - +getMessage() Message - +getFinishReason() FinishReason - +getTokenCount() int - +getJsonSchema() array< string, mixed >$ - } class TokenUsage { +getPromptTokens() int +getCompletionTokens() int @@ -638,18 +656,28 @@ direction LR +getJsonSchema() array< string, mixed >$ } } - namespace AiClientNamespace.Types.Enums { - class MessageRole { - USER - MODEL - SYSTEM + + namespace AiClientNamespace.Providers.Models.Contracts { + class Operation { + +getId() string + +getState() OperationState + +getJsonSchema() array< string, mixed >$ } - class MessagePartType { + class Result { + +getId() string + +getTokenUsage() TokenUsage + +getProviderMetadata() array< string, mixed > + +getJsonSchema() array< string, mixed >$ + } + } + + namespace AiClientNamespace.Enums { + class AiModality { TEXT - INLINE_FILE - REMOTE_FILE - FUNCTION_CALL - FUNCTION_RESPONSE + DOCUMENT + IMAGE + AUDIO + VIDEO } class FinishReason { STOP @@ -665,21 +693,8 @@ direction LR FAILED CANCELED } - class AiModality { - TEXT - DOCUMENT - IMAGE - AUDIO - VIDEO - } } namespace AiClientNamespace.Util { - class MessageUtil { - +toText(Message $message) string$ - +toImageFile(Message $message) File$ - +toAudioFile(Message $message) File$ - +toVideoFile(Message $message) File$ - } class CandidatesUtil { +toTexts(Candidate[] $candidates) string[]$ +toImageFiles(Candidate[] $candidates) File[]$ @@ -690,6 +705,12 @@ direction LR +toFirstAudioFile(Candidate[] $candidates) File$ +toFirstVideoFile(Candidate[] $candidates) File$ } + class MessageUtil { + +toText(Message $message) string$ + +toImageFile(Message $message) File$ + +toAudioFile(Message $message) File$ + +toVideoFile(Message $message) File$ + } class RequirementsUtil { +inferRequirements(Message[] $messages, AiModelConfig $modelConfig) AiModelRequirements$ } @@ -757,6 +778,17 @@ config: classDiagram direction LR namespace AiClientNamespace.Providers { + class AiProviderMetadata { + +getId() string + +getName() string + +getType() AiProviderType + +getJsonSchema() array< string, mixed >$ + } + class AiProviderModelsMetadata { + +getProvider() AiProviderMetadata + +getModels() AiModelMetadata[] + +getJsonSchema() array< string, mixed >$ + } class AiProviderRegistry { +registerProvider(string $className) void +hasProvider(string $idOrClassName) bool @@ -768,65 +800,23 @@ direction LR } } namespace AiClientNamespace.Providers.Contracts { + class AiModelMetadataDirectory { + +listModelMetadata() AiModelMetadata[] + +hasModelMetadata(string $modelId) bool + +getModelMetadata(string $modelId) AiModelMetadata + } class AiProvider { +metadata() AiProviderMetadata$ +model(string $modelId, AiModelConfig|array< string, mixed > $modelConfig) AiModel$ +availability() AiProviderAvailability$ +modelMetadataDirectory() AiModelMetadataDirectory$ } - class AiModel { - +metadata() AiModelMetadata - +setConfig(AiModelConfig $config) void - +getConfig() AiModelConfig - } class AiProviderAvailability { +isConfigured() bool } - class AiModelMetadataDirectory { - +listModelMetadata() AiModelMetadata[] - +hasModelMetadata(string $modelId) bool - +getModelMetadata(string $modelId) AiModelMetadata - } - class WithGenerativeAiOperations { - +getOperation(string $operationId) GenerativeAiOperation - } - class WithEmbeddingOperations { - +getOperation(string $operationId) EmbeddingOperation - } - class AiTextGenerationModel { - +generateTextResult(Message[] $prompt) GenerativeAiResult - +streamGenerateTextResult(Message[] $prompt) Generator< GenerativeAiResult > - } - class AiImageGenerationModel { - +generateImageResult(Message[] $prompt) GenerativeAiResult - } - class AiTextToSpeechConversionModel { - +convertTextToSpeechResult(Message[] $prompt) GenerativeAiResult - } - class AiSpeechGenerationModel { - +generateSpeechResult(Message[] $prompt) GenerativeAiResult - } - class AiEmbeddingGenerationModel { - +generateEmbeddingsResult(Message[] $input) EmbeddingResult - } - class AiTextGenerationOperationModel { - +generateTextOperation(Message[] $prompt) GenerativeAiOperation - } - class AiImageGenerationOperationModel { - +generateImageOperation(Message[] $prompt) GenerativeAiOperation - } - class AiTextToSpeechConversionOperationModel { - +convertTextToSpeechOperation(Message[] $prompt) GenerativeAiOperation - } - class AiSpeechGenerationOperationModel { - +generateSpeechOperation(Message[] $prompt) GenerativeAiOperation - } - class AiEmbeddingGenerationOperationModel { - +generateEmbeddingsOperation(Message[] $input) EmbeddingOperation - } - class WithHttpClient { - +setHttpClient(HttpClient $client) void - +getHttpClient() HttpClient + class Authentication { + +authenticate(RequestInterface $request) void + +getJsonSchema() array< string, mixed >$ } class HttpClient { +send(RequestInterface $request, array< string, mixed > $options) ResponseInterface @@ -836,34 +826,19 @@ direction LR +setAuthentication(Authentication $authentication) void +getAuthentication() Authentication } - class Authentication { - +authenticate(RequestInterface $request) void - +getJsonSchema() array< string, mixed >$ - } - } - namespace AiClientNamespace.Providers.Types { - class AiProviderMetadata { - +getId() string - +getName() string - +getType() AiProviderType - +getJsonSchema() array< string, mixed >$ - } - class AiModelMetadata { - +getId() string - +getName() string - +getSupportedCapabilities() AiCapability[] - +getSupportedOptions() AiSupportedOption[] - +getJsonSchema() array< string, mixed >$ + class WithEmbeddingOperations { + +getOperation(string $operationId) EmbeddingOperation } - class AiProviderModelsMetadata { - +getProvider() AiProviderMetadata - +getModels() AiModelMetadata[] - +getJsonSchema() array< string, mixed >$ + class WithGenerativeAiOperations { + +getOperation(string $operationId) GenerativeAiOperation } - class AiModelRequirements { - getRequiredCapabilities() AiCapability[] - getRequiredOptions() AiRequiredOption[] + class WithHttpClient { + +setHttpClient(HttpClient $client) void + +getHttpClient() HttpClient } + } + + namespace AiClientNamespace.Providers.Models { class AiModelConfig { +setOutputModalities(AiModality[] $modalities) void +getOutputModalities() AiModality[] @@ -890,6 +865,74 @@ direction LR +getTools() Tool[] +getJsonSchema() array< string, mixed >$ } + class AiModelMetadata { + +getId() string + +getName() string + +getSupportedCapabilities() AiCapability[] + +getSupportedOptions() AiSupportedOption[] + +getJsonSchema() array< string, mixed >$ + } + class AiModelRequirements { + getRequiredCapabilities() AiCapability[] + getRequiredOptions() AiRequiredOption[] + } + } + + namespace AiClientNamespace.Providers.Models.Contracts { + class AiModel { + +metadata() AiModelMetadata + +setConfig(AiModelConfig $config) void + +getConfig() AiModelConfig + } + } + + namespace AiClientNamespace.Providers.Models.EmbeddingGeneration.Contracts { + class AiEmbeddingGenerationModel { + +generateEmbeddingsResult(Message[] $input) EmbeddingResult + } + class AiEmbeddingGenerationOperationModel { + +generateEmbeddingsOperation(Message[] $input) EmbeddingOperation + } + } + + namespace AiClientNamespace.Providers.Models.ImageGeneration.Contracts { + class AiImageGenerationModel { + +generateImageResult(Message[] $prompt) GenerativeAiResult + } + class AiImageGenerationOperationModel { + +generateImageOperation(Message[] $prompt) GenerativeAiOperation + } + } + + namespace AiClientNamespace.Providers.Models.SpeechGeneration.Contracts { + class AiSpeechGenerationModel { + +generateSpeechResult(Message[] $prompt) GenerativeAiResult + } + class AiSpeechGenerationOperationModel { + +generateSpeechOperation(Message[] $prompt) GenerativeAiOperation + } + } + + namespace AiClientNamespace.Providers.Models.TextGeneration.Contracts { + class AiTextGenerationModel { + +generateTextResult(Message[] $prompt) GenerativeAiResult + +streamGenerateTextResult(Message[] $prompt) Generator< GenerativeAiResult > + } + class AiTextGenerationOperationModel { + +generateTextOperation(Message[] $prompt) GenerativeAiOperation + } + } + + namespace AiClientNamespace.Providers.Models.TextToSpeechConversion.Contracts { + class AiTextToSpeechConversionModel { + +convertTextToSpeechResult(Message[] $prompt) GenerativeAiResult + } + class AiTextToSpeechConversionOperationModel { + +convertTextToSpeechOperation(Message[] $prompt) GenerativeAiOperation + } + } + + namespace AiClientNamespace.Providers.Tools { class Tool { +getType() ToolType +getFunctionDeclarations() FunctionDeclaration[]? @@ -907,6 +950,9 @@ direction LR +getDisallowedDomains() string[] +getJsonSchema() array< string, mixed >$ } + } + + namespace AiClientNamespace.Providers.Options { class AiSupportedOption { +getName() string +isSupportedValue(mixed $value) bool @@ -919,16 +965,7 @@ direction LR +getJsonSchema() array< string, mixed >$ } } - namespace AiClientNamespace.Providers.Types.Enums { - class AiProviderType { - CLOUD - SERVER - CLIENT - } - class ToolType { - FUNCTION_DECLARATIONS - WEB_SEARCH - } + namespace AiClientNamespace.Providers.Enums { class AiCapability { TEXT_GENERATION IMAGE_GENERATION @@ -951,6 +988,15 @@ direction LR OUTPUT_MIME_TYPE OUTPUT_SCHEMA } + class AiProviderType { + CLOUD + SERVER + CLIENT + } + class ToolType { + FUNCTION_DECLARATIONS + WEB_SEARCH + } } namespace AiClientNamespace.Providers.Util { class AiCapabilitiesUtil { From d347c7a7ad69576b16088bc0f5cf4675304c3701 Mon Sep 17 00:00:00 2001 From: Matthew Batchelder Date: Tue, 15 Jul 2025 15:26:03 -0400 Subject: [PATCH 2/6] Renaming namespaces, classes, interfaces, and enums --- docs/ARCHITECTURE.md | 847 ++++++++++++++++++++++--------------------- 1 file changed, 433 insertions(+), 414 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index b10e32e..e25f2fd 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -21,13 +21,13 @@ The following examples indicate how this SDK could eventually be used. ##### Fluent API ```php -$text = AiClient::prompt('Write a 2-verse poem about PHP.') +$text = Client::prompt('Write a 2-verse poem about PHP.') ->generateText(); ``` ##### Traditional API ```php -$text = AiClient::generateTextResult( +$text = Client::generateTextResult( 'Write a 2-verse poem about PHP.' )->toText(); ``` @@ -36,14 +36,14 @@ $text = AiClient::generateTextResult( ##### Fluent API ```php -$text = AiClient::prompt('Write a 2-verse poem about PHP.') +$text = Client::prompt('Write a 2-verse poem about PHP.') ->usingModel(Google::model('gemini-2.5-flash')) ->generateText(); ``` ##### Traditional API ```php -$text = AiClient::generateTextResult( +$text = Client::generateTextResult( 'Write a 2-verse poem about PHP.', Google::model('gemini-2.5-flash') )->toText(); @@ -53,18 +53,18 @@ $text = AiClient::generateTextResult( ##### Fluent API ```php -$texts = AiClient::prompt('Write a 2-verse poem about PHP.') +$texts = Client::prompt('Write a 2-verse poem about PHP.') ->usingModel(Anthropic::model('claude-3.7-sonnet')) ->generateTexts(4); ``` ##### Traditional API ```php -$texts = AiClient::generateTextResult( +$texts = Client::generateTextResult( 'Write a 2-verse poem about PHP.', Anthropic::model( 'claude-3.7-sonnet', - [AiOption::CANDIDATE_COUNT => 4] + [OptionEnum::CANDIDATE_COUNT => 4] ) )->toTexts(); ``` @@ -73,20 +73,20 @@ $texts = AiClient::generateTextResult( ##### Fluent API ```php -$imageFile = AiClient::prompt('Generate an illustration of the PHP elephant in the Carribean sea.') +$imageFile = Client::prompt('Generate an illustration of the PHP elephant in the Carribean sea.') ->usingProvider('openai') ->generateImage(); ``` ##### Traditional API ```php -$modelsMetadata = AiClient::defaultRegistry()->findProviderModelsMetadataForSupport( +$modelsMetadata = Client::defaultRegistry()->findProviderModelsMetadataForSupport( 'openai', - new AiModelRequirements([AiCapability::IMAGE_GENERATION]) + new ModelRequirements([CapabilityEnum::IMAGE_GENERATION]) ); -$imageFile = AiClient::generateImageResult( +$imageFile = Client::generateImageResult( 'Generate an illustration of the PHP elephant in the Carribean sea.', - AiClient::defaultRegistry()->getProviderModel( + Client::defaultRegistry()->getProviderModel( 'openai', $modelsMetadata[0]->getId() ) @@ -97,18 +97,18 @@ $imageFile = AiClient::generateImageResult( ##### Fluent API ```php -$imageFile = AiClient::prompt('Generate an illustration of the PHP elephant in the Carribean sea.') +$imageFile = Client::prompt('Generate an illustration of the PHP elephant in the Carribean sea.') ->generateImage(); ``` ##### Traditional API ```php -$providerModelsMetadata = AiClient::defaultRegistry()->findModelsMetadataForSupport( - new AiModelRequirements([AiCapability::IMAGE_GENERATION]) +$providerModelsMetadata = Client::defaultRegistry()->findModelsMetadataForSupport( + new ModelRequirements([CapabilityEnum::IMAGE_GENERATION]) ); -$imageFile = AiClient::generateImageResult( +$imageFile = Client::generateImageResult( 'Generate an illustration of the PHP elephant in the Carribean sea.', - AiClient::defaultRegistry()->getProviderModel( + Client::defaultRegistry()->getProviderModel( $providerModelsMetadata[0]->getProvider()->getId(), $providerModelsMetadata[0]->getModels()[0]->getId() ) @@ -121,13 +121,13 @@ _Note: This does effectively the exact same as [the first code example](#generat ##### Fluent API ```php -$providerModelsMetadata = AiClient::defaultRegistry()->findModelsMetadataForSupport( - new AiModelRequirements([AiCapability::TEXT_GENERATION]) +$providerModelsMetadata = Client::defaultRegistry()->findModelsMetadataForSupport( + new ModelRequirements([CapabilityEnum::TEXT_GENERATION]) ); -$text = AiClient::prompt('Write a 2-verse poem about PHP.') +$text = Client::prompt('Write a 2-verse poem about PHP.') ->withModel( - AiClient::defaultRegistry()->getProviderModel( + Client::defaultRegistry()->getProviderModel( $providerModelsMetadata[0]->getProvider()->getId(), $providerModelsMetadata[0]->getModels()[0]->getId() ) @@ -137,12 +137,12 @@ $text = AiClient::prompt('Write a 2-verse poem about PHP.') ##### Traditional API ```php -$providerModelsMetadata = AiClient::defaultRegistry()->findModelsMetadataForSupport( - new AiModelRequirements([AiCapability::TEXT_GENERATION]) +$providerModelsMetadata = Client::defaultRegistry()->findModelsMetadataForSupport( + new ModelRequirements([CapabilityEnum::TEXT_GENERATION]) ); -$text = AiClient::generateTextResult( +$text = Client::generateTextResult( 'Write a 2-verse poem about PHP.', - AiClient::defaultRegistry()->getProviderModel( + Client::defaultRegistry()->getProviderModel( $providerModelsMetadata[0]->getProvider()->getId(), $providerModelsMetadata[0]->getModels()[0]->getId() ) @@ -151,18 +151,18 @@ $text = AiClient::generateTextResult( #### Generate text with an image as additional input using any suitable model from any provider -_Note: Since this omits the model parameter, the SDK will automatically determine which models are suitable and use any of them, similar to [the first code example](#generate-text-using-any-suitable-model-from-any-provider-most-basic-example). Since it knows the input includes an image, it can internally infer that the model needs to not only support `AiCapability::TEXT_GENERATION`, but also `AiOption::INPUT_MODALITIES => ['text', 'image']`._ +_Note: Since this omits the model parameter, the SDK will automatically determine which models are suitable and use any of them, similar to [the first code example](#generate-text-using-any-suitable-model-from-any-provider-most-basic-example). Since it knows the input includes an image, it can internally infer that the model needs to not only support `CapabilityEnum::TEXT_GENERATION`, but also `OptionEnum::INPUT_MODALITIES => ['text', 'image']`._ ##### Fluent API ```php -$text = AiClient::prompt('Generate alternative text for this image.') +$text = Client::prompt('Generate alternative text for this image.') ->withInlineImage($base64Blob, 'image/png') ->generateText(); ``` ##### Traditional API ```php -$text = AiClient::generateTextResult( +$text = Client::generateTextResult( [ [ 'text' => 'Generate alternative text for this image.', @@ -177,11 +177,11 @@ $text = AiClient::generateTextResult( #### Generate text with chat history using any suitable model from any provider -_Note: Similarly to the previous example, even without specifying the model here, the SDK will be able to infer required model capabilities because it can detect that multiple chat messages are passed. Therefore it will internally only consider models that support `AiCapability::TEXT_GENERATION` as well as `AiCapability::CHAT_HISTORY`._ +_Note: Similarly to the previous example, even without specifying the model here, the SDK will be able to infer required model capabilities because it can detect that multiple chat messages are passed. Therefore it will internally only consider models that support `CapabilityEnum::TEXT_GENERATION` as well as `CapabilityEnum::CHAT_HISTORY`._ ##### Fluent API ```php -$text = AiClient::prompt() +$text = Client::prompt() ->withHistory( new UserMessage('Do you spell it WordPress or Wordpress?'), new ModelMessage('The correct spelling is WordPress.'), @@ -192,18 +192,18 @@ $text = AiClient::prompt() ##### Traditional API ```php -$text = AiClient::generateTextResult( +$text = Client::generateTextResult( [ [ - 'role' => MessageRole::USER, + 'role' => MessageRoleEnum::USER, 'parts' => ['text' => 'Do you spell it WordPress or Wordpress?'], ], [ - 'role' => MessageRole::MODEL, + 'role' => MessageRoleEnum::MODEL, 'parts' => ['text' => 'The correct spelling is WordPress.'], ], [ - 'role' => MessageRole::USER, + 'role' => MessageRoleEnum::USER, 'parts' => ['text' => 'Can you repeat that please?'], ], ] @@ -216,7 +216,7 @@ _Note: Unlike the previous two examples, to require JSON output it is necessary ##### Fluent API ```php -$text = AiClient::prompt('Transform the following CSV content into a JSON array of row data.') +$text = Client::prompt('Transform the following CSV content into a JSON array of row data.') ->asJsonResponse() ->usingOutputSchema([ 'type' => 'array', @@ -237,24 +237,24 @@ $text = AiClient::prompt('Transform the following CSV content into a JSON array ##### Traditional API ```php -$providerModelsMetadata = AiClient::defaultRegistry()->findModelsMetadataForSupport( - new AiModelRequirements( - [AiCapability::TEXT_GENERATION], +$providerModelsMetadata = Client::defaultRegistry()->findModelsMetadataForSupport( + new ModelRequirements( + [CapabilityEnum::TEXT_GENERATION], [ // Make sure the model supports JSON output as well as following a given schema. - AiOption::OUTPUT_MIME_TYPE => 'application/json', - AiOption::OUTPUT_SCHEMA => true, + OptionEnum::OUTPUT_MIME_TYPE => 'application/json', + OptionEnum::OUTPUT_SCHEMA => true, ] ) ); -$jsonString = AiClient::generateTextResult( +$jsonString = Client::generateTextResult( 'Transform the following CSV content into a JSON array of row data.', - AiClient::defaultRegistry()->getProviderModel( + Client::defaultRegistry()->getProviderModel( $providerModelsMetadata[0]->getProvider()->getId(), $providerModelsMetadata[0]->getModels()[0]->getId(), [ - AiOption::OUTPUT_MIME_TYPE => 'application/json', - AiOption::OUTPUT_SCHEMA => [ + OptionEnum::OUTPUT_MIME_TYPE => 'application/json', + OptionEnum::OUTPUT_SCHEMA => [ 'type' => 'array', 'items' => [ 'type' => 'object', @@ -293,12 +293,14 @@ config: --- classDiagram direction LR - namespace AiClientNamespace { - class AiClient { + namespace AiClient { + class Client { +prompt(string|Message|null $text = null) PromptBuilder$ +message(?string $text) MessageBuilder$ } + } + namespace AiClient.Builders { class PromptBuilder { +withText(string $text) self +withInlineImage(string $base64Blob, string $mimeType) @@ -310,7 +312,7 @@ direction LR +withFunctionResponse(FunctionResponse $functionResponse) self +withMessageParts(...MessagePart $part) self +withHistory(...Message $messages) self - +usingModel(AiModel $model) self + +usingModel(ModelInterface $model) self +usingSystemInstruction(string|MessagePart[]|Message $systemInstruction) self +usingMaxTokens(int $maxTokens) self +usingTemperature(float $temperature) self @@ -320,7 +322,7 @@ direction LR +usingCandidateCount(int $candidateCount) self +usingOutputMime(string $mimeType) self +usingOutputSchema(array< string, mixed > $schema) self - +usingOutputModalities(...AiModality $modalities) self + +usingOutputModalities(...ModalityEnum $modalities) self +asJsonResponse(?array< string, mixed > $schema) self +generateResult() GenerativeAiResult +generateOperation() GenerativeAiOperation @@ -338,14 +340,14 @@ direction LR +generateText() string +generateTexts(?int $candidateCount) string[] +streamGenerateText() Generator< string > - +generateImage() File - +generateImages(?int $candidateCount) File[] - +convertTextToSpeech() File - +convertTextToSpeeches(?int $candidateCount) File[] - +generateSpeech() File - +generateSpeeches(?int $candidateCount) File[] + +generateImage() FileInterface + +generateImages(?int $candidateCount) FileInterface[] + +convertTextToSpeech() FileInterface + +convertTextToSpeeches(?int $candidateCount) FileInterface[] + +generateSpeech() FileInterface + +generateSpeeches(?int $candidateCount) FileInterface[] +generateEmbeddings() Embedding[] - +getModelRequirements() AiModelRequirements + +getModelRequirements() ModelRequirements +isSupported() bool } @@ -362,8 +364,8 @@ direction LR } } - AiClient .. PromptBuilder : creates - AiClient .. MessageBuilder : creates + Client .. PromptBuilder : creates + Client .. MessageBuilder : creates ``` ### Overview: Traditional method call API for AI implementers @@ -378,21 +380,21 @@ config: --- classDiagram direction LR - namespace AiClientNamespace { - class AiClient { - +generateResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, AiModel $model) GenerativeAiResult$ - +generateOperation(string|MessagePart|MessagePart[]|Message|Message[] $prompt, AiModel $model) GenerativeAiOperation$ - +generateTextResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, AiModel $model) GenerativeAiResult$ - +streamGenerateTextResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, AiModel $model) Generator< GenerativeAiResult >$ - +generateImageResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, AiModel $model) GenerativeAiResult$ - +convertTextToSpeechResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, AiModel $model) GenerativeAiResult$ - +generateSpeechResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, AiModel $model) GenerativeAiResult$ - +generateEmbeddingsResult(string[]|Message[] $input, AiModel $model) EmbeddingResult$ - +generateTextOperation(string|MessagePart|MessagePart[]|Message|Message[] $prompt, AiModel $model) GenerativeAiOperation$ - +generateImageOperation(string|MessagePart|MessagePart[]|Message|Message[] $prompt, AiModel $model) GenerativeAiOperation$ - +convertTextToSpeechOperation(string|MessagePart|MessagePart[]|Message|Message[] $prompt, AiModel $model) GenerativeAiOperation$ - +generateSpeechOperation(string|MessagePart|MessagePart[]|Message|Message[] $prompt, AiModel $model) GenerativeAiOperation$ - +generateEmbeddingsOperation(string[]|Message[] $input, AiModel $model) EmbeddingOperation$ + namespace AiClient { + class Client { + +generateResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) GenerativeAiResult$ + +generateOperation(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) GenerativeAiOperation$ + +generateTextResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) GenerativeAiResult$ + +streamGenerateTextResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) Generator< GenerativeAiResult >$ + +generateImageResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) GenerativeAiResult$ + +convertTextToSpeechResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) GenerativeAiResult$ + +generateSpeechResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) GenerativeAiResult$ + +generateEmbeddingsResult(string[]|Message[] $input, ModelInterface $model) EmbeddingResult$ + +generateTextOperation(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) GenerativeAiOperation$ + +generateImageOperation(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) GenerativeAiOperation$ + +convertTextToSpeechOperation(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) GenerativeAiOperation$ + +generateSpeechOperation(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) GenerativeAiOperation$ + +generateEmbeddingsOperation(string[]|Message[] $input, ModelInterface $model) EmbeddingOperation$ } } ``` @@ -409,25 +411,25 @@ config: --- classDiagram direction LR - namespace AiClientNamespace { - class AiClient { - +defaultRegistry() AiProviderRegistry$ - +isConfigured(AiProviderAvailability $availability) bool$ + namespace AiClient { + class Client { + +defaultRegistry() ProviderRegistry$ + +isConfigured(ProviderAvailabilityInterface $availability) bool$ } } - namespace AiClientNamespace.Providers { - class AiProviderRegistry { + namespace AiClient.Providers { + class ProviderRegistry { +registerProvider(string $className) void +hasProvider(string $idOrClassName) bool +getProviderClassName(string $id) string +isProviderConfigured(string $idOrClassName) bool - +getProviderModel(string $idOrClassName, string $modelId, AiModelConfig|array< string, mixed > $modelConfig) AiModel - +findProviderModelsMetadataForSupport(string $idOrClassName, AiModelRequirements $modelRequirements) AiModelMetadata[] - +findModelsMetadataForSupport(AiModelRequirements $modelRequirements) AiProviderModelMetadata[] + +getProviderModel(string $idOrClassName, string $modelId, ModelConfig|array< string, mixed > $modelConfig) Model + +findProviderModelsMetadataForSupport(string $idOrClassName, ModelRequirements $modelRequirements) ModelMetadata[] + +findModelsMetadataForSupport(ModelRequirements $modelRequirements) ProviderModelMetadata[] } } - AiClient "1" o-- "1..*" AiProviderRegistry + Client "1" o-- "1..*" ProviderRegistry ``` ### Details: Class diagram for AI implementers @@ -440,29 +442,29 @@ config: --- classDiagram direction LR - namespace AiClientNamespace { - class AiClient { + namespace AiClient { + class Client { +prompt(string|Message|null $text = null) PromptBuilder$ +message(?string $text) MessageBuilder$ - +defaultRegistry() AiProviderRegistry$ - +isConfigured(AiProviderAvailability $availability) bool$ - +generateResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, AiModel $model) GenerativeAiResult$ - +generateOperation(string|MessagePart|MessagePart[]|Message|Message[] $prompt, AiModel $model) GenerativeAiOperation$ - +generateTextResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, AiModel $model) GenerativeAiResult$ - +streamGenerateTextResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, AiModel $model) Generator< GenerativeAiResult >$ - +generateImageResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, AiModel $model) GenerativeAiResult$ - +convertTextToSpeechResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, AiModel $model) GenerativeAiResult$ - +generateSpeechResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, AiModel $model) GenerativeAiResult$ - +generateEmbeddingsResult(string[]|Message[] $input, AiModel $model) EmbeddingResult$ - +generateTextOperation(string|MessagePart|MessagePart[]|Message|Message[] $prompt, AiModel $model) GenerativeAiOperation$ - +generateImageOperation(string|MessagePart|MessagePart[]|Message|Message[] $prompt, AiModel $model) GenerativeAiOperation$ - +convertTextToSpeechOperation(string|MessagePart|MessagePart[]|Message|Message[] $prompt, AiModel $model) GenerativeAiOperation$ - +generateSpeechOperation(string|MessagePart|MessagePart[]|Message|Message[] $prompt, AiModel $model) GenerativeAiOperation$ - +generateEmbeddingsOperation(string[]|Message[] $input, AiModel $model) EmbeddingOperation$ + +defaultRegistry() ProviderRegistry$ + +isConfigured(ProviderAvailabilityInterface $availability) bool$ + +generateResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) GenerativeAiResult$ + +generateOperation(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) GenerativeAiOperation$ + +generateTextResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) GenerativeAiResult$ + +streamGenerateTextResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) Generator< GenerativeAiResult >$ + +generateImageResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) GenerativeAiResult$ + +convertTextToSpeechResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) GenerativeAiResult$ + +generateSpeechResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) GenerativeAiResult$ + +generateEmbeddingsResult(string[]|Message[] $input, ModelInterface $model) EmbeddingResult$ + +generateTextOperation(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) GenerativeAiOperation$ + +generateImageOperation(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) GenerativeAiOperation$ + +convertTextToSpeechOperation(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) GenerativeAiOperation$ + +generateSpeechOperation(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) GenerativeAiOperation$ + +generateEmbeddingsOperation(string[]|Message[] $input, ModelInterface $model) EmbeddingOperation$ } } - namespace AiClientNamespace.Builders { + namespace AiClient.Builders { class PromptBuilder { +withText(string $text) self +withInlineImage(string $base64Blob, string $mimeType) @@ -474,7 +476,7 @@ direction LR +withFunctionResponse(FunctionResponse $functionResponse) self +withMessageParts(...MessagePart $part) self +withHistory(...Message $messages) self - +usingModel(AiModel $model) self + +usingModel(ModelInterface $model) self +usingSystemInstruction(string|MessagePart[]|Message $systemInstruction) self +usingMaxTokens(int $maxTokens) self +usingTemperature(float $temperature) self @@ -484,7 +486,7 @@ direction LR +usingCandidateCount(int $candidateCount) self +usingOutputMime(string $mimeType) self +usingOutputSchema(array< string, mixed > $schema) self - +usingOutputModalities(...AiModality $modalities) self + +usingOutputModalities(...ModalityEnum $modalities) self +asJsonResponse(?array< string, mixed > $schema) self +generateResult() GenerativeAiResult +generateOperation() GenerativeAiOperation @@ -502,14 +504,14 @@ direction LR +generateText() string +generateTexts(?int $candidateCount) string[] +streamGenerateText() Generator< string > - +generateImage() File - +generateImages(?int $candidateCount) File[] - +convertTextToSpeech() File - +convertTextToSpeeches(?int $candidateCount) File[] - +generateSpeech() File - +generateSpeeches(?int $candidateCount) File[] + +generateImage() FileInterface + +generateImages(?int $candidateCount) FileInterface[] + +convertTextToSpeech() FileInterface + +convertTextToSpeeches(?int $candidateCount) FileInterface[] + +generateSpeech() FileInterface + +generateSpeeches(?int $candidateCount) FileInterface[] +generateEmbeddings() Embedding[] - +getModelRequirements() AiModelRequirements + +getModelRequirements() ModelRequirements +isSupported() bool } @@ -525,14 +527,45 @@ direction LR +get() Message } } - namespace AiClientNamespace.Messages { + + namespace AiClient.Embeddings.DTO { + class Embedding { + +getVector() float[] + +getDimension() int + } + } + + namespace AiClient.Files.Contracts { + class FileInterface { + } + } + + namespace AiClient.Files.DTO { + class InlineFile { + +getMimeType() string + +getBase64Data() string + +getJsonSchema() array< string, mixed >$ + } + class LocalFile { + +getMimeType() string + +getPath() string + +getJsonSchema() array< string, mixed >$ + } + class RemoteFile { + +getMimeType() string + +getUrl() string + +getJsonSchema() array< string, mixed >$ + } + } + + namespace AiClient.Messages.DTO { class Message { - +getRole() MessageRole + +getRole() MessageRoleEnum +getParts() MessagePart[] +getJsonSchema() array< string, mixed >$ } class MessagePart { - +getType() MessagePartType + +getType() MessagePartTypeEnum +getText() string? +getInlineFile() InlineFile? +getRemoteFile() RemoteFile? @@ -548,74 +581,89 @@ direction LR } } - namespace AiClientNamespace.Messages.Enums { - class MessagePartType { + namespace AiClient.Messages.Enums { + class MessagePartTypeEnum { TEXT INLINE_FILE REMOTE_FILE FUNCTION_CALL FUNCTION_RESPONSE } - class MessageRole { + class MessageRoleEnum { USER MODEL SYSTEM } } - namespace AiClientNamespace.Messages.Functions { - class FunctionCall { + namespace AiClient.Operations.DTO { + class EmbeddingOperation { +getId() string - +getName() string - +getArgs() array< string, mixed > + +getState() OperationStateEnum + +getResult() EmbeddingResult +getJsonSchema() array< string, mixed >$ } - class FunctionResponse { + class GenerativeAiOperation { +getId() string - +getName() string - +getResponse() mixed + +getState() OperationStateEnum + +getResult() GenerativeAiResult +getJsonSchema() array< string, mixed >$ } } - namespace AiClientNamespace.Files { - class InlineFile { - +getMimeType() string - +getBase64Data() string + namespace AiClient.Providers.Models.Contracts { + class OperationInterface { + +getId() string + +getState() OperationStateEnum +getJsonSchema() array< string, mixed >$ } - class LocalFile { - +getMimeType() string - +getPath() string - +getJsonSchema() array< string, mixed >$ + } + + namespace AiClient.Provider.Models.Enums { + class ModalityEnum { + TEXT + DOCUMENT + IMAGE + AUDIO + VIDEO } - class RemoteFile { - +getMimeType() string - +getUrl() string - +getJsonSchema() array< string, mixed >$ + class FinishReasonEnum { + STOP + LENGTH + CONTENT_FILTER + TOOL_CALLS + ERROR + } + class OperationStateEnum { + STARTING + PROCESSING + SUCCEEDED + FAILED + CANCELED } } - namespace AiClientNamespace.Files.Contracts { - class File { + namespace AiClient.Results.Contracts { + class ResultInterface { + +getId() string + +getTokenUsage() TokenUsage + +getProviderMetadata() array< string, mixed > + +getJsonSchema() array< string, mixed >$ } } - namespace AiClientNamespace.Providers.Models { + namespace AiClient.Results.DTO { class Candidate { +getMessage() Message - +getFinishReason() FinishReason + +getFinishReason() FinishReasonEnum +getTokenCount() int +getJsonSchema() array< string, mixed >$ } - class Embedding { - +getVector() float[] - +getDimension() int - } - class GenerativeAiOperation { + class EmbeddingResult { +getId() string - +getState() OperationState - +getResult() GenerativeAiResult + +getEmbeddings() Embedding[] + +getTokenUsage() TokenUsage + +getProviderMetadata() array< string, mixed > +getJsonSchema() array< string, mixed >$ } class GenerativeAiResult { @@ -626,29 +674,16 @@ direction LR +getJsonSchema() array< string, mixed >$ %% The following utility methods transform the result candidates into a specific shape. +toText() string - +toImageFile() File - +toAudioFile() File - +toVideoFile() File + +toImageFile() FileInterface + +toAudioFile() FileInterface + +toVideoFile() FileInterface +toMessage() Message +toTexts() string[] - +toImageFiles() File[] - +toAudioFiles() File[] - +toVideoFiles() File[] + +toImageFiles() FileInterface[] + +toAudioFiles() FileInterface[] + +toVideoFiles() FileInterface[] +toMessages() Message[] } - class EmbeddingOperation { - +getId() string - +getState() OperationState - +getResult() EmbeddingResult - +getJsonSchema() array< string, mixed >$ - } - class EmbeddingResult { - +getId() string - +getEmbeddings() Embedding[] - +getTokenUsage() TokenUsage - +getProviderMetadata() array< string, mixed > - +getJsonSchema() array< string, mixed >$ - } class TokenUsage { +getPromptTokens() int +getCompletionTokens() int @@ -657,82 +692,60 @@ direction LR } } - namespace AiClientNamespace.Providers.Models.Contracts { - class Operation { + namespace AiClient.Tools.DTO { + class FunctionCall { +getId() string - +getState() OperationState + +getName() string + +getArgs() array< string, mixed > +getJsonSchema() array< string, mixed >$ } - class Result { + class FunctionResponse { +getId() string - +getTokenUsage() TokenUsage - +getProviderMetadata() array< string, mixed > + +getName() string + +getResponse() mixed +getJsonSchema() array< string, mixed >$ } } - namespace AiClientNamespace.Enums { - class AiModality { - TEXT - DOCUMENT - IMAGE - AUDIO - VIDEO - } - class FinishReason { - STOP - LENGTH - CONTENT_FILTER - TOOL_CALLS - ERROR - } - class OperationState { - STARTING - PROCESSING - SUCCEEDED - FAILED - CANCELED - } - } - namespace AiClientNamespace.Util { + namespace AiClient.Util { class CandidatesUtil { +toTexts(Candidate[] $candidates) string[]$ - +toImageFiles(Candidate[] $candidates) File[]$ - +toAudioFiles(Candidate[] $candidates) File[]$ - +toVideoFiles(Candidate[] $candidates) File[]$ + +toImageFiles(Candidate[] $candidates) FileInterface[]$ + +toAudioFiles(Candidate[] $candidates) FileInterface[]$ + +toVideoFiles(Candidate[] $candidates) FileInterface[]$ +toFirstText(Candidate[] $candidates) string$ - +toFirstImageFile(Candidate[] $candidates) File$ - +toFirstAudioFile(Candidate[] $candidates) File$ - +toFirstVideoFile(Candidate[] $candidates) File$ + +toFirstImageFile(Candidate[] $candidates) FileInterface$ + +toFirstAudioFile(Candidate[] $candidates) FileInterface$ + +toFirstVideoFile(Candidate[] $candidates) FileInterface$ } class MessageUtil { +toText(Message $message) string$ - +toImageFile(Message $message) File$ - +toAudioFile(Message $message) File$ - +toVideoFile(Message $message) File$ + +toImageFile(Message $message) FileInterface$ + +toAudioFile(Message $message) FileInterface$ + +toVideoFile(Message $message) FileInterface$ } class RequirementsUtil { - +inferRequirements(Message[] $messages, AiModelConfig $modelConfig) AiModelRequirements$ + +inferRequirements(Message[] $messages, ModelConfig $modelConfig) ModelRequirements$ } } - <> File - <> Operation - <> Result - <> MessageRole - <> MessagePartType - <> FinishReason - <> OperationState - <> AiModality - - AiClient .. Message : receives - AiClient .. MessagePart : receives - AiClient .. PromptBuilder : creates - AiClient .. MessageBuilder : creates - AiClient .. GenerativeAiResult : creates - AiClient .. EmbeddingResult : creates - AiClient .. GenerativeAiOperation : creates - AiClient .. EmbeddingOperation : creates + <> FileInterface + <> OperationInterface + <> ResultInterface + <> MessageRoleEnum + <> MessagePartTypeEnum + <> FinishReasonEnum + <> OperationStateEnum + <> ModalityEnum + + Client .. Message : receives + Client .. MessagePart : receives + Client .. PromptBuilder : creates + Client .. MessageBuilder : creates + Client .. GenerativeAiResult : creates + Client .. EmbeddingResult : creates + Client .. GenerativeAiOperation : creates + Client .. EmbeddingOperation : creates PromptBuilder .. GenerativeAiResult : creates PromptBuilder .. EmbeddingResult : creates PromptBuilder .. GenerativeAiOperation : creates @@ -750,21 +763,21 @@ direction LR EmbeddingResult "1" o-- "1..*" Embedding EmbeddingResult "1" o-- "1" TokenUsage Candidate "1" o-- "1" Message - Message ..> MessageRole - MessagePart ..> MessagePartType - Operation ..> OperationState - GenerativeAiOperation ..> OperationState - Candidate ..> FinishReason - File <|-- InlineFile - File <|-- RemoteFile - File <|-- LocalFile + Message ..> MessageRoleEnum + MessagePart ..> MessagePartTypeEnum + OperationInterface ..> OperationStateEnum + GenerativeAiOperation ..> OperationStateEnum + Candidate ..> FinishReasonEnum + FileInterface <|-- InlineFile + FileInterface <|-- RemoteFile + FileInterface <|-- LocalFile Message <|-- UserMessage Message <|-- ModelMessage Message <|-- SystemMessage - Operation <|-- GenerativeAiOperation - Operation <|-- EmbeddingOperation - Result <|-- GenerativeAiResult - Result <|-- EmbeddingResult + OperationInterface <|-- GenerativeAiOperation + OperationInterface <|-- EmbeddingOperation + ResultInterface <|-- GenerativeAiResult + ResultInterface <|-- EmbeddingResult ``` ### Details: Class diagram for AI extenders @@ -777,71 +790,95 @@ config: --- classDiagram direction LR - namespace AiClientNamespace.Providers { - class AiProviderMetadata { - +getId() string - +getName() string - +getType() AiProviderType - +getJsonSchema() array< string, mixed >$ - } - class AiProviderModelsMetadata { - +getProvider() AiProviderMetadata - +getModels() AiModelMetadata[] - +getJsonSchema() array< string, mixed >$ - } - class AiProviderRegistry { + namespace AiClient.Providers { + class ProviderRegistry { +registerProvider(string $className) void +hasProvider(string $idOrClassName) bool +getProviderClassName(string $id) string +isProviderConfigured(string $idOrClassName) bool - +getProviderModel(string $idOrClassName, string $modelId, AiModelConfig|array< string, mixed > $modelConfig) AiModel - +findProviderModelsMetadataForSupport(string $idOrClassName, AiModelRequirements $modelRequirements) AiModelMetadata[] - +findModelsMetadataForSupport(AiModelRequirements $modelRequirements) AiProviderModelMetadata[] + +getProviderModel(string $idOrClassName, string $modelId, ModelConfig|array< string, mixed > $modelConfig) ModelInterface + +findProviderModelsMetadataForSupport(string $idOrClassName, ModelRequirements $modelRequirements) ModelMetadata[] + +findModelsMetadataForSupport(ModelRequirements $modelRequirements) AiProviderModelMetadata[] } } - namespace AiClientNamespace.Providers.Contracts { - class AiModelMetadataDirectory { - +listModelMetadata() AiModelMetadata[] + + namespace AiClient.Providers.Contracts { + class AuthenticationInterface { + +authenticate(RequestInterface $request) void + +getJsonSchema() array< string, mixed >$ + } + class HttpClientInterface { + +send(RequestInterface $request, array< string, mixed > $options) ResponseInterface + +request(string $method, string $uri, array< string, mixed > $options) ResponseInterface + } + class ModelMetadataDirectoryInterface { + +listModelMetadata() ModelMetadata[] +hasModelMetadata(string $modelId) bool - +getModelMetadata(string $modelId) AiModelMetadata + +getModelMetadata(string $modelId) ModelMetadata } - class AiProvider { - +metadata() AiProviderMetadata$ - +model(string $modelId, AiModelConfig|array< string, mixed > $modelConfig) AiModel$ - +availability() AiProviderAvailability$ - +modelMetadataDirectory() AiModelMetadataDirectory$ + class ProviderInterface { + +metadata() ProviderMetadata$ + +model(string $modelId, ModelConfig|array< string, mixed > $modelConfig) ModelInterface$ + +availability() ProviderAvailabilityInterface$ + +modelMetadataDirectory() ModelMetadataDirectoryInterface$ } - class AiProviderAvailability { + class ProviderAvailabilityInterface { +isConfigured() bool } - class Authentication { - +authenticate(RequestInterface $request) void + } + + namespace AiClient.Providers.DTO { + class ProviderMetadata { + +getId() string + +getName() string + +getType() ProviderTypeEnum +getJsonSchema() array< string, mixed >$ } - class HttpClient { - +send(RequestInterface $request, array< string, mixed > $options) ResponseInterface - +request(string $method, string $uri, array< string, mixed > $options) ResponseInterface + class ProviderModelsMetadata { + +getProvider() ProviderMetadata + +getModels() ModelMetadata[] + +getJsonSchema() array< string, mixed >$ } - class WithAuthentication { - +setAuthentication(Authentication $authentication) void - +getAuthentication() Authentication + } + + namespace AiClient.Providers.Enums { + class ProviderTypeEnum { + CLOUD + SERVER + CLIENT } - class WithEmbeddingOperations { + class ToolTypeEnum { + FUNCTION_DECLARATIONS + WEB_SEARCH + } + } + + namespace AiClient.Providers.Models.Contracts { + class ModelInterface { + +metadata() ModelMetadata + +setConfig(ModelConfig $config) void + +getConfig() ModelConfig + } + class WithAuthenticationInterface { + +setAuthentication(AuthenticationInterface $authentication) void + +getAuthentication() AuthenticationInterface + } + class WithEmbeddingOperationsInterface { +getOperation(string $operationId) EmbeddingOperation } - class WithGenerativeAiOperations { + class WithGenerativeAiOperationsInterface { +getOperation(string $operationId) GenerativeAiOperation } - class WithHttpClient { - +setHttpClient(HttpClient $client) void - +getHttpClient() HttpClient + class WithHttpClientInterface { + +setHttpClient(HttpClientInterface $client) void + +getHttpClient() HttpClientInterface } } - namespace AiClientNamespace.Providers.Models { - class AiModelConfig { - +setOutputModalities(AiModality[] $modalities) void - +getOutputModalities() AiModality[] + namespace AiClient.Providers.Models.DTO { + class ModelConfig { + +setOutputModalities(ModalityEnum[] $modalities) void + +getOutputModalities() ModalityEnum[] +setSystemInstruction(string|MessagePart|MessagePart[]|Message $systemInstruction) void +getSystemInstruction() Message? +setCandidateCount(int $candidateCount) void @@ -865,86 +902,121 @@ direction LR +getTools() Tool[] +getJsonSchema() array< string, mixed >$ } - class AiModelMetadata { + class ModelMetadata { +getId() string +getName() string - +getSupportedCapabilities() AiCapability[] - +getSupportedOptions() AiSupportedOption[] + +getSupportedCapabilities() CapabilityEnum[] + +getSupportedOptions() SupportedOption[] +getJsonSchema() array< string, mixed >$ } - class AiModelRequirements { - getRequiredCapabilities() AiCapability[] - getRequiredOptions() AiRequiredOption[] + class ModelRequirements { + getRequiredCapabilities() CapabilityEnum[] + getRequiredOptions() RequiredOption[] + } + class SupportedOption { + +getName() string + +isSupportedValue(mixed $value) bool + +getSupportedValues() mixed[] + +getJsonSchema() array< string, mixed >$ + } + class RequiredOption { + +getName() string + +getValue() mixed + +getJsonSchema() array< string, mixed >$ } } - namespace AiClientNamespace.Providers.Models.Contracts { - class AiModel { - +metadata() AiModelMetadata - +setConfig(AiModelConfig $config) void - +getConfig() AiModelConfig + namespace AiClient.Providers.Models.Enums { + class CapabilityEnum { + TEXT_GENERATION + IMAGE_GENERATION + TEXT_TO_SPEECH_CONVERSION + SPEECH_GENERATION + MUSIC_GENERATION + VIDEO_GENERATION + EMBEDDING_GENERATION + CHAT_HISTORY + } + class OptionEnum { + INPUT_MODALITIES + OUTPUT_MODALITIES + SYSTEM_INSTRUCTION + CANDIDATE_COUNT + MAX_TOKENS + TEMPERATURE + TOP_K + TOP_P + OUTPUT_MIME_TYPE + OUTPUT_SCHEMA } } - namespace AiClientNamespace.Providers.Models.EmbeddingGeneration.Contracts { - class AiEmbeddingGenerationModel { + namespace AiClient.Providers.Models.EmbeddingGeneration.Contracts { + class EmbeddingGenerationModelInterface { +generateEmbeddingsResult(Message[] $input) EmbeddingResult } - class AiEmbeddingGenerationOperationModel { + class EmbeddingGenerationOperationModelInterface { +generateEmbeddingsOperation(Message[] $input) EmbeddingOperation } } - namespace AiClientNamespace.Providers.Models.ImageGeneration.Contracts { - class AiImageGenerationModel { + namespace AiClient.Providers.Models.ImageGeneration.Contracts { + class ImageGenerationModelInterface { +generateImageResult(Message[] $prompt) GenerativeAiResult } - class AiImageGenerationOperationModel { + class ImageGenerationOperationModelInterface { +generateImageOperation(Message[] $prompt) GenerativeAiOperation } } - namespace AiClientNamespace.Providers.Models.SpeechGeneration.Contracts { - class AiSpeechGenerationModel { + namespace AiClient.Providers.Models.SpeechGeneration.Contracts { + class SpeechGenerationModelInterface { +generateSpeechResult(Message[] $prompt) GenerativeAiResult } - class AiSpeechGenerationOperationModel { + class SpeechGenerationOperationModelInterface { +generateSpeechOperation(Message[] $prompt) GenerativeAiOperation } } - namespace AiClientNamespace.Providers.Models.TextGeneration.Contracts { - class AiTextGenerationModel { + namespace AiClient.Providers.Models.TextGeneration.Contracts { + class TextGenerationModelInterface { +generateTextResult(Message[] $prompt) GenerativeAiResult +streamGenerateTextResult(Message[] $prompt) Generator< GenerativeAiResult > } - class AiTextGenerationOperationModel { + class TextGenerationOperationModelInterface { +generateTextOperation(Message[] $prompt) GenerativeAiOperation } } - namespace AiClientNamespace.Providers.Models.TextToSpeechConversion.Contracts { - class AiTextToSpeechConversionModel { + namespace AiClient.Providers.Models.TextToSpeechConversion.Contracts { + class TextToSpeechConversionModelInterface { +convertTextToSpeechResult(Message[] $prompt) GenerativeAiResult } - class AiTextToSpeechConversionOperationModel { + class TextToSpeechConversionOperationModelInterface { +convertTextToSpeechOperation(Message[] $prompt) GenerativeAiOperation } } - namespace AiClientNamespace.Providers.Tools { - class Tool { - +getType() ToolType - +getFunctionDeclarations() FunctionDeclaration[]? - +getWebSearch() WebSearch? - +getJsonSchema() array< string, mixed >$ + namespace AiClient.Providers.Models.Util { + class CapabilitiesUtil { + +getSupportedCapabilities(ModelInterface|string $modelClass) CapabilityEnum[]$ + +getSupportedOptions(ModelInterface|string $modelClass) SupportedOption[]$ } + } + + namespace AiClient.Tools.DTO { class FunctionDeclaration { +getName() string +getDescription() string +getParameters() mixed +getJsonSchema() array< string, mixed >$ } + class Tool { + +getType() ToolType + +getFunctionDeclarations() FunctionDeclaration[]? + +getWebSearch() WebSearch? + +getJsonSchema() array< string, mixed >$ + } class WebSearch { +getAllowedDomains() string[] +getDisallowedDomains() string[] @@ -952,112 +1024,59 @@ direction LR } } - namespace AiClientNamespace.Providers.Options { - class AiSupportedOption { - +getName() string - +isSupportedValue(mixed $value) bool - +getSupportedValues() mixed[] - +getJsonSchema() array< string, mixed >$ - } - class AiRequiredOption { - +getName() string - +getValue() mixed - +getJsonSchema() array< string, mixed >$ - } - } - namespace AiClientNamespace.Providers.Enums { - class AiCapability { - TEXT_GENERATION - IMAGE_GENERATION - TEXT_TO_SPEECH_CONVERSION - SPEECH_GENERATION - MUSIC_GENERATION - VIDEO_GENERATION - EMBEDDING_GENERATION - CHAT_HISTORY - } - class AiOption { - INPUT_MODALITIES - OUTPUT_MODALITIES - SYSTEM_INSTRUCTION - CANDIDATE_COUNT - MAX_TOKENS - TEMPERATURE - TOP_K - TOP_P - OUTPUT_MIME_TYPE - OUTPUT_SCHEMA - } - class AiProviderType { - CLOUD - SERVER - CLIENT - } - class ToolType { - FUNCTION_DECLARATIONS - WEB_SEARCH - } - } - namespace AiClientNamespace.Providers.Util { - class AiCapabilitiesUtil { - +getSupportedCapabilities(AiModel|string $modelClass) AiCapability[]$ - +getSupportedOptions(AiModel|string $modelClass) AiSupportedOption[]$ - } - } - - <> AiProvider - <> AiModel - <> AiProviderAvailability - <> AiModelMetadataDirectory - <> WithGenerativeAiOperations - <> WithEmbeddingOperations - <> AiTextGenerationModel - <> AiImageGenerationModel - <> AiTextToSpeechConversionModel - <> AiSpeechGenerationModel - <> AiEmbeddingGenerationModel - <> AiTextGenerationOperationModel - <> AiImageGenerationOperationModel - <> AiTextToSpeechConversionOperationModel - <> AiSpeechGenerationOperationModel - <> AiEmbeddingGenerationOperationModel - <> WithHttpClient - <> HttpClient - <> WithAuthentication - <> Authentication - <> AiCapability - <> AiOption - <> AiProviderType - - AiProvider .. AiModel : creates - AiProvider "1" *-- "1" AiProviderMetadata - AiProvider "1" *-- "1" AiProviderAvailability - AiProvider "1" *-- "1" AiModelMetadataDirectory - AiModel "1" *-- "1" AiModelMetadata - AiModel "1" *-- "1" AiModelConfig - AiProviderModelsMetadata "1" o-- "1" AiProviderMetadata - AiProviderModelsMetadata "1" o-- "1..*" AiModelMetadata - AiProviderRegistry "1" o-- "0..*" AiProvider - AiProviderRegistry "1" o-- "0..*" AiProviderMetadata - AiModelMetadataDirectory "1" o-- "1..*" AiModelMetadata - AiModelMetadata "1" o-- "1..*" AiCapability - AiModelMetadata "1" o-- "0..*" AiSupportedOption - AiModelRequirements "1" o-- "1..*" AiCapability - AiModelRequirements "1" o-- "0..*" AiRequiredOption - AiModelConfig "1" o-- "0..*" Tool + <> ProviderInterface + <> ModelInterface + <> ProviderAvailabilityInterface + <> ModelMetadataDirectoryInterface + <> WithGenerativeAiOperationsInterface + <> WithEmbeddingOperationsInterface + <> TextGenerationModelInterface + <> ImageGenerationModelInterface + <> TextToSpeechConversionModelInterface + <> SpeechGenerationModelInterface + <> EmbeddingGenerationModelInterface + <> TextGenerationOperationModelInterface + <> ImageGenerationOperationModelInterface + <> TextToSpeechConversionOperationModelInterface + <> SpeechGenerationOperationModelInterface + <> EmbeddingGenerationOperationModelInterface + <> WithHttpClientInterface + <> HttpClientInterface + <> WithAuthenticationInterface + <> AuthenticationInterface + <> CapabilityEnum + <> OptionEnum + <> ProviderTypeEnum + + ProviderInterface .. ModelInterface : creates + ProviderInterface "1" *-- "1" ProviderMetadata + ProviderInterface "1" *-- "1" ProviderAvailabilityInterface + ProviderInterface "1" *-- "1" ModelMetadataDirectoryInterface + ModelInterface "1" *-- "1" ModelMetadata + ModelInterface "1" *-- "1" ModelConfig + ProviderModelsMetadata "1" o-- "1" ProviderMetadata + ProviderModelsMetadata "1" o-- "1..*" ModelMetadata + ProviderRegistry "1" o-- "0..*" ProviderInterface + ProviderRegistry "1" o-- "0..*" ProviderMetadata + ModelMetadataDirectoryInterface "1" o-- "1..*" ModelMetadata + ModelMetadata "1" o-- "1..*" CapabilityEnum + ModelMetadata "1" o-- "0..*" SupportedOption + ModelRequirements "1" o-- "1..*" CapabilityEnum + ModelRequirements "1" o-- "0..*" RequiredOption + ModelConfig "1" o-- "0..*" Tool Tool "1" o-- "0..*" FunctionDeclaration Tool "1" o-- "0..1" WebSearch - AiProviderMetadata ..> AiProviderType - AiModelMetadata ..> AiCapability - AiModelMetadata ..> AiSupportedOption - AiModel <|-- AiTextGenerationModel - AiModel <|-- AiImageGenerationModel - AiModel <|-- AiTextToSpeechConversionModel - AiModel <|-- AiSpeechGenerationModel - AiModel <|-- AiEmbeddingGenerationModel - AiModel <|-- AiTextGenerationOperationModel - AiModel <|-- AiImageGenerationOperationModel - AiModel <|-- AiTextToSpeechConversionOperationModel - AiModel <|-- AiSpeechGenerationOperationModel - AiModel <|-- AiEmbeddingGenerationOperationModel + ProviderMetadata ..> ProviderTypeEnum + ModelMetadata ..> CapabilityEnum + ModelMetadata ..> SupportedOption + ModelInterface <|-- TextGenerationModelInterface + ModelInterface <|-- ImageGenerationModelInterface + ModelInterface <|-- TextToSpeechConversionModelInterface + ModelInterface <|-- SpeechGenerationModelInterface + ModelInterface <|-- EmbeddingGenerationModelInterface + ModelInterface <|-- TextGenerationOperationModelInterface + ModelInterface <|-- ImageGenerationOperationModelInterface + ModelInterface <|-- TextToSpeechConversionOperationModelInterface + ModelInterface <|-- SpeechGenerationOperationModelInterface + ModelInterface <|-- EmbeddingGenerationOperationModelInterface ``` From 50f61ce7a46ff6f80eeee856e8734cf92f85f1a8 Mon Sep 17 00:00:00 2001 From: Matthew Batchelder Date: Tue, 15 Jul 2025 16:11:12 -0400 Subject: [PATCH 3/6] Resolving some namespace typos --- docs/ARCHITECTURE.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index e25f2fd..22e1d20 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -596,6 +596,14 @@ direction LR } } + namespace AiClient.Operations.Contracts { + class OperationInterface { + +getId() string + +getState() OperationStateEnum + +getJsonSchema() array< string, mixed >$ + } + } + namespace AiClient.Operations.DTO { class EmbeddingOperation { +getId() string @@ -611,15 +619,7 @@ direction LR } } - namespace AiClient.Providers.Models.Contracts { - class OperationInterface { - +getId() string - +getState() OperationStateEnum - +getJsonSchema() array< string, mixed >$ - } - } - - namespace AiClient.Provider.Models.Enums { + namespace AiClient.Providers.Models.Enums { class ModalityEnum { TEXT DOCUMENT From 6d80be6fd346b39dce026bddd0b3ece3de8a83bc Mon Sep 17 00:00:00 2001 From: Matthew Batchelder Date: Thu, 17 Jul 2025 08:59:20 -0400 Subject: [PATCH 4/6] Use `AiClient` as the client class to avoid potential overlap with other libraries --- docs/ARCHITECTURE.md | 152 +++++++++++++++++++++---------------------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 22e1d20..4d5daba 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -21,13 +21,13 @@ The following examples indicate how this SDK could eventually be used. ##### Fluent API ```php -$text = Client::prompt('Write a 2-verse poem about PHP.') +$text = AiClient::prompt('Write a 2-verse poem about PHP.') ->generateText(); ``` ##### Traditional API ```php -$text = Client::generateTextResult( +$text = AiClient::generateTextResult( 'Write a 2-verse poem about PHP.' )->toText(); ``` @@ -36,14 +36,14 @@ $text = Client::generateTextResult( ##### Fluent API ```php -$text = Client::prompt('Write a 2-verse poem about PHP.') +$text = AiClient::prompt('Write a 2-verse poem about PHP.') ->usingModel(Google::model('gemini-2.5-flash')) ->generateText(); ``` ##### Traditional API ```php -$text = Client::generateTextResult( +$text = AiClient::generateTextResult( 'Write a 2-verse poem about PHP.', Google::model('gemini-2.5-flash') )->toText(); @@ -53,14 +53,14 @@ $text = Client::generateTextResult( ##### Fluent API ```php -$texts = Client::prompt('Write a 2-verse poem about PHP.') +$texts = AiClient::prompt('Write a 2-verse poem about PHP.') ->usingModel(Anthropic::model('claude-3.7-sonnet')) ->generateTexts(4); ``` ##### Traditional API ```php -$texts = Client::generateTextResult( +$texts = AiClient::generateTextResult( 'Write a 2-verse poem about PHP.', Anthropic::model( 'claude-3.7-sonnet', @@ -73,20 +73,20 @@ $texts = Client::generateTextResult( ##### Fluent API ```php -$imageFile = Client::prompt('Generate an illustration of the PHP elephant in the Carribean sea.') +$imageFile = AiClient::prompt('Generate an illustration of the PHP elephant in the Carribean sea.') ->usingProvider('openai') ->generateImage(); ``` ##### Traditional API ```php -$modelsMetadata = Client::defaultRegistry()->findProviderModelsMetadataForSupport( +$modelsMetadata = AiClient::defaultRegistry()->findProviderModelsMetadataForSupport( 'openai', new ModelRequirements([CapabilityEnum::IMAGE_GENERATION]) ); -$imageFile = Client::generateImageResult( +$imageFile = AiClient::generateImageResult( 'Generate an illustration of the PHP elephant in the Carribean sea.', - Client::defaultRegistry()->getProviderModel( + AiClient::defaultRegistry()->getProviderModel( 'openai', $modelsMetadata[0]->getId() ) @@ -97,18 +97,18 @@ $imageFile = Client::generateImageResult( ##### Fluent API ```php -$imageFile = Client::prompt('Generate an illustration of the PHP elephant in the Carribean sea.') +$imageFile = AiClient::prompt('Generate an illustration of the PHP elephant in the Carribean sea.') ->generateImage(); ``` ##### Traditional API ```php -$providerModelsMetadata = Client::defaultRegistry()->findModelsMetadataForSupport( +$providerModelsMetadata = AiClient::defaultRegistry()->findModelsMetadataForSupport( new ModelRequirements([CapabilityEnum::IMAGE_GENERATION]) ); -$imageFile = Client::generateImageResult( +$imageFile = AiClient::generateImageResult( 'Generate an illustration of the PHP elephant in the Carribean sea.', - Client::defaultRegistry()->getProviderModel( + AiClient::defaultRegistry()->getProviderModel( $providerModelsMetadata[0]->getProvider()->getId(), $providerModelsMetadata[0]->getModels()[0]->getId() ) @@ -121,13 +121,13 @@ _Note: This does effectively the exact same as [the first code example](#generat ##### Fluent API ```php -$providerModelsMetadata = Client::defaultRegistry()->findModelsMetadataForSupport( +$providerModelsMetadata = AiClient::defaultRegistry()->findModelsMetadataForSupport( new ModelRequirements([CapabilityEnum::TEXT_GENERATION]) ); -$text = Client::prompt('Write a 2-verse poem about PHP.') +$text = AiClient::prompt('Write a 2-verse poem about PHP.') ->withModel( - Client::defaultRegistry()->getProviderModel( + AiClient::defaultRegistry()->getProviderModel( $providerModelsMetadata[0]->getProvider()->getId(), $providerModelsMetadata[0]->getModels()[0]->getId() ) @@ -137,12 +137,12 @@ $text = Client::prompt('Write a 2-verse poem about PHP.') ##### Traditional API ```php -$providerModelsMetadata = Client::defaultRegistry()->findModelsMetadataForSupport( +$providerModelsMetadata = AiClient::defaultRegistry()->findModelsMetadataForSupport( new ModelRequirements([CapabilityEnum::TEXT_GENERATION]) ); -$text = Client::generateTextResult( +$text = AiClient::generateTextResult( 'Write a 2-verse poem about PHP.', - Client::defaultRegistry()->getProviderModel( + AiClient::defaultRegistry()->getProviderModel( $providerModelsMetadata[0]->getProvider()->getId(), $providerModelsMetadata[0]->getModels()[0]->getId() ) @@ -155,14 +155,14 @@ _Note: Since this omits the model parameter, the SDK will automatically determin ##### Fluent API ```php -$text = Client::prompt('Generate alternative text for this image.') +$text = AiClient::prompt('Generate alternative text for this image.') ->withInlineImage($base64Blob, 'image/png') ->generateText(); ``` ##### Traditional API ```php -$text = Client::generateTextResult( +$text = AiClient::generateTextResult( [ [ 'text' => 'Generate alternative text for this image.', @@ -181,7 +181,7 @@ _Note: Similarly to the previous example, even without specifying the model here ##### Fluent API ```php -$text = Client::prompt() +$text = AiClient::prompt() ->withHistory( new UserMessage('Do you spell it WordPress or Wordpress?'), new ModelMessage('The correct spelling is WordPress.'), @@ -192,7 +192,7 @@ $text = Client::prompt() ##### Traditional API ```php -$text = Client::generateTextResult( +$text = AiClient::generateTextResult( [ [ 'role' => MessageRoleEnum::USER, @@ -216,7 +216,7 @@ _Note: Unlike the previous two examples, to require JSON output it is necessary ##### Fluent API ```php -$text = Client::prompt('Transform the following CSV content into a JSON array of row data.') +$text = AiClient::prompt('Transform the following CSV content into a JSON array of row data.') ->asJsonResponse() ->usingOutputSchema([ 'type' => 'array', @@ -237,7 +237,7 @@ $text = Client::prompt('Transform the following CSV content into a JSON array of ##### Traditional API ```php -$providerModelsMetadata = Client::defaultRegistry()->findModelsMetadataForSupport( +$providerModelsMetadata = AiClient::defaultRegistry()->findModelsMetadataForSupport( new ModelRequirements( [CapabilityEnum::TEXT_GENERATION], [ @@ -247,9 +247,9 @@ $providerModelsMetadata = Client::defaultRegistry()->findModelsMetadataForSuppor ] ) ); -$jsonString = Client::generateTextResult( +$jsonString = AiClient::generateTextResult( 'Transform the following CSV content into a JSON array of row data.', - Client::defaultRegistry()->getProviderModel( + AiClient::defaultRegistry()->getProviderModel( $providerModelsMetadata[0]->getProvider()->getId(), $providerModelsMetadata[0]->getModels()[0]->getId(), [ @@ -293,14 +293,14 @@ config: --- classDiagram direction LR - namespace AiClient { - class Client { + namespace AiClientNamespace { + class AiClient { +prompt(string|Message|null $text = null) PromptBuilder$ +message(?string $text) MessageBuilder$ } } - namespace AiClient.Builders { + namespace AiClientNamespace.Builders { class PromptBuilder { +withText(string $text) self +withInlineImage(string $base64Blob, string $mimeType) @@ -364,8 +364,8 @@ direction LR } } - Client .. PromptBuilder : creates - Client .. MessageBuilder : creates + AiClient .. PromptBuilder : creates + AiClient .. MessageBuilder : creates ``` ### Overview: Traditional method call API for AI implementers @@ -380,8 +380,8 @@ config: --- classDiagram direction LR - namespace AiClient { - class Client { + namespace AiClientNamespace { + class AiClient { +generateResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) GenerativeAiResult$ +generateOperation(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) GenerativeAiOperation$ +generateTextResult(string|MessagePart|MessagePart[]|Message|Message[] $prompt, ModelInterface $model) GenerativeAiResult$ @@ -411,13 +411,13 @@ config: --- classDiagram direction LR - namespace AiClient { - class Client { + namespace AiClientNamespace { + class AiClient { +defaultRegistry() ProviderRegistry$ +isConfigured(ProviderAvailabilityInterface $availability) bool$ } } - namespace AiClient.Providers { + namespace AiClientNamespace.Providers { class ProviderRegistry { +registerProvider(string $className) void +hasProvider(string $idOrClassName) bool @@ -429,7 +429,7 @@ direction LR } } - Client "1" o-- "1..*" ProviderRegistry + AiClient "1" o-- "1..*" ProviderRegistry ``` ### Details: Class diagram for AI implementers @@ -442,8 +442,8 @@ config: --- classDiagram direction LR - namespace AiClient { - class Client { + namespace AiClientNamespace { + class AiClient { +prompt(string|Message|null $text = null) PromptBuilder$ +message(?string $text) MessageBuilder$ +defaultRegistry() ProviderRegistry$ @@ -464,7 +464,7 @@ direction LR } } - namespace AiClient.Builders { + namespace AiClientNamespace.Builders { class PromptBuilder { +withText(string $text) self +withInlineImage(string $base64Blob, string $mimeType) @@ -528,19 +528,19 @@ direction LR } } - namespace AiClient.Embeddings.DTO { + namespace AiClientNamespace.Embeddings.DTO { class Embedding { +getVector() float[] +getDimension() int } } - namespace AiClient.Files.Contracts { + namespace AiClientNamespace.Files.Contracts { class FileInterface { } } - namespace AiClient.Files.DTO { + namespace AiClientNamespace.Files.DTO { class InlineFile { +getMimeType() string +getBase64Data() string @@ -558,7 +558,7 @@ direction LR } } - namespace AiClient.Messages.DTO { + namespace AiClientNamespace.Messages.DTO { class Message { +getRole() MessageRoleEnum +getParts() MessagePart[] @@ -581,7 +581,7 @@ direction LR } } - namespace AiClient.Messages.Enums { + namespace AiClientNamespace.Messages.Enums { class MessagePartTypeEnum { TEXT INLINE_FILE @@ -596,7 +596,7 @@ direction LR } } - namespace AiClient.Operations.Contracts { + namespace AiClientNamespace.Operations.Contracts { class OperationInterface { +getId() string +getState() OperationStateEnum @@ -604,7 +604,7 @@ direction LR } } - namespace AiClient.Operations.DTO { + namespace AiClientNamespace.Operations.DTO { class EmbeddingOperation { +getId() string +getState() OperationStateEnum @@ -619,7 +619,7 @@ direction LR } } - namespace AiClient.Providers.Models.Enums { + namespace AiClientNamespace.Providers.Models.Enums { class ModalityEnum { TEXT DOCUMENT @@ -643,7 +643,7 @@ direction LR } } - namespace AiClient.Results.Contracts { + namespace AiClientNamespace.Results.Contracts { class ResultInterface { +getId() string +getTokenUsage() TokenUsage @@ -652,7 +652,7 @@ direction LR } } - namespace AiClient.Results.DTO { + namespace AiClientNamespace.Results.DTO { class Candidate { +getMessage() Message +getFinishReason() FinishReasonEnum @@ -692,7 +692,7 @@ direction LR } } - namespace AiClient.Tools.DTO { + namespace AiClientNamespace.Tools.DTO { class FunctionCall { +getId() string +getName() string @@ -707,7 +707,7 @@ direction LR } } - namespace AiClient.Util { + namespace AiClientNamespace.Util { class CandidatesUtil { +toTexts(Candidate[] $candidates) string[]$ +toImageFiles(Candidate[] $candidates) FileInterface[]$ @@ -738,14 +738,14 @@ direction LR <> OperationStateEnum <> ModalityEnum - Client .. Message : receives - Client .. MessagePart : receives - Client .. PromptBuilder : creates - Client .. MessageBuilder : creates - Client .. GenerativeAiResult : creates - Client .. EmbeddingResult : creates - Client .. GenerativeAiOperation : creates - Client .. EmbeddingOperation : creates + AiClient .. Message : receives + AiClient .. MessagePart : receives + AiClient .. PromptBuilder : creates + AiClient .. MessageBuilder : creates + AiClient .. GenerativeAiResult : creates + AiClient .. EmbeddingResult : creates + AiClient .. GenerativeAiOperation : creates + AiClient .. EmbeddingOperation : creates PromptBuilder .. GenerativeAiResult : creates PromptBuilder .. EmbeddingResult : creates PromptBuilder .. GenerativeAiOperation : creates @@ -790,7 +790,7 @@ config: --- classDiagram direction LR - namespace AiClient.Providers { + namespace AiClientNamespace.Providers { class ProviderRegistry { +registerProvider(string $className) void +hasProvider(string $idOrClassName) bool @@ -802,7 +802,7 @@ direction LR } } - namespace AiClient.Providers.Contracts { + namespace AiClientNamespace.Providers.Contracts { class AuthenticationInterface { +authenticate(RequestInterface $request) void +getJsonSchema() array< string, mixed >$ @@ -827,7 +827,7 @@ direction LR } } - namespace AiClient.Providers.DTO { + namespace AiClientNamespace.Providers.DTO { class ProviderMetadata { +getId() string +getName() string @@ -841,7 +841,7 @@ direction LR } } - namespace AiClient.Providers.Enums { + namespace AiClientNamespace.Providers.Enums { class ProviderTypeEnum { CLOUD SERVER @@ -853,7 +853,7 @@ direction LR } } - namespace AiClient.Providers.Models.Contracts { + namespace AiClientNamespace.Providers.Models.Contracts { class ModelInterface { +metadata() ModelMetadata +setConfig(ModelConfig $config) void @@ -875,7 +875,7 @@ direction LR } } - namespace AiClient.Providers.Models.DTO { + namespace AiClientNamespace.Providers.Models.DTO { class ModelConfig { +setOutputModalities(ModalityEnum[] $modalities) void +getOutputModalities() ModalityEnum[] @@ -926,7 +926,7 @@ direction LR } } - namespace AiClient.Providers.Models.Enums { + namespace AiClientNamespace.Providers.Models.Enums { class CapabilityEnum { TEXT_GENERATION IMAGE_GENERATION @@ -951,7 +951,7 @@ direction LR } } - namespace AiClient.Providers.Models.EmbeddingGeneration.Contracts { + namespace AiClientNamespace.Providers.Models.EmbeddingGeneration.Contracts { class EmbeddingGenerationModelInterface { +generateEmbeddingsResult(Message[] $input) EmbeddingResult } @@ -960,7 +960,7 @@ direction LR } } - namespace AiClient.Providers.Models.ImageGeneration.Contracts { + namespace AiClientNamespace.Providers.Models.ImageGeneration.Contracts { class ImageGenerationModelInterface { +generateImageResult(Message[] $prompt) GenerativeAiResult } @@ -969,7 +969,7 @@ direction LR } } - namespace AiClient.Providers.Models.SpeechGeneration.Contracts { + namespace AiClientNamespace.Providers.Models.SpeechGeneration.Contracts { class SpeechGenerationModelInterface { +generateSpeechResult(Message[] $prompt) GenerativeAiResult } @@ -978,7 +978,7 @@ direction LR } } - namespace AiClient.Providers.Models.TextGeneration.Contracts { + namespace AiClientNamespace.Providers.Models.TextGeneration.Contracts { class TextGenerationModelInterface { +generateTextResult(Message[] $prompt) GenerativeAiResult +streamGenerateTextResult(Message[] $prompt) Generator< GenerativeAiResult > @@ -988,7 +988,7 @@ direction LR } } - namespace AiClient.Providers.Models.TextToSpeechConversion.Contracts { + namespace AiClientNamespace.Providers.Models.TextToSpeechConversion.Contracts { class TextToSpeechConversionModelInterface { +convertTextToSpeechResult(Message[] $prompt) GenerativeAiResult } @@ -997,14 +997,14 @@ direction LR } } - namespace AiClient.Providers.Models.Util { + namespace AiClientNamespace.Providers.Models.Util { class CapabilitiesUtil { +getSupportedCapabilities(ModelInterface|string $modelClass) CapabilityEnum[]$ +getSupportedOptions(ModelInterface|string $modelClass) SupportedOption[]$ } } - namespace AiClient.Tools.DTO { + namespace AiClientNamespace.Tools.DTO { class FunctionDeclaration { +getName() string +getDescription() string From 2a8916ade84cd49116bdea91042f16e553340869 Mon Sep 17 00:00:00 2001 From: Matthew Batchelder Date: Thu, 17 Jul 2025 09:08:52 -0400 Subject: [PATCH 5/6] Distribute Providers Models Enums to more applicable places in the implementer API area. Resolve alphabetization issues. Replicate Tools in both Implementer and Extender areas --- docs/ARCHITECTURE.md | 81 +++++++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 28 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 4d5daba..0416c70 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -535,6 +535,16 @@ direction LR } } + namespace AiClientNamespace.Enums { + class ModalityEnum { + TEXT + DOCUMENT + IMAGE + AUDIO + VIDEO + } + } + namespace AiClientNamespace.Files.Contracts { class FileInterface { } @@ -604,6 +614,16 @@ direction LR } } + namespace AiClientNamespace.Operations.Enums { + class OperationStateEnum { + STARTING + PROCESSING + SUCCEEDED + FAILED + CANCELED + } + } + namespace AiClientNamespace.Operations.DTO { class EmbeddingOperation { +getId() string @@ -619,14 +639,16 @@ direction LR } } - namespace AiClientNamespace.Providers.Models.Enums { - class ModalityEnum { - TEXT - DOCUMENT - IMAGE - AUDIO - VIDEO + namespace AiClientNamespace.Results.Contracts { + class ResultInterface { + +getId() string + +getTokenUsage() TokenUsage + +getProviderMetadata() array< string, mixed > + +getJsonSchema() array< string, mixed >$ } + } + + namespace AiClientNamespace.Results.Enums { class FinishReasonEnum { STOP LENGTH @@ -634,22 +656,6 @@ direction LR TOOL_CALLS ERROR } - class OperationStateEnum { - STARTING - PROCESSING - SUCCEEDED - FAILED - CANCELED - } - } - - namespace AiClientNamespace.Results.Contracts { - class ResultInterface { - +getId() string - +getTokenUsage() TokenUsage - +getProviderMetadata() array< string, mixed > - +getJsonSchema() array< string, mixed >$ - } } namespace AiClientNamespace.Results.DTO { @@ -699,12 +705,29 @@ direction LR +getArgs() array< string, mixed > +getJsonSchema() array< string, mixed >$ } + class FunctionDeclaration { + +getName() string + +getDescription() string + +getParameters() mixed + +getJsonSchema() array< string, mixed >$ + } class FunctionResponse { +getId() string +getName() string +getResponse() mixed +getJsonSchema() array< string, mixed >$ } + class Tool { + +getType() ToolType + +getFunctionDeclarations() FunctionDeclaration[]? + +getWebSearch() WebSearch? + +getJsonSchema() array< string, mixed >$ + } + class WebSearch { + +getAllowedDomains() string[] + +getDisallowedDomains() string[] + +getJsonSchema() array< string, mixed >$ + } } namespace AiClientNamespace.Util { @@ -778,6 +801,8 @@ direction LR OperationInterface <|-- EmbeddingOperation ResultInterface <|-- GenerativeAiResult ResultInterface <|-- EmbeddingResult + Tool "1" o-- "0..*" FunctionDeclaration + Tool "1" o-- "0..1" WebSearch ``` ### Details: Class diagram for AI extenders @@ -913,15 +938,15 @@ direction LR getRequiredCapabilities() CapabilityEnum[] getRequiredOptions() RequiredOption[] } - class SupportedOption { + class RequiredOption { +getName() string - +isSupportedValue(mixed $value) bool - +getSupportedValues() mixed[] + +getValue() mixed +getJsonSchema() array< string, mixed >$ } - class RequiredOption { + class SupportedOption { +getName() string - +getValue() mixed + +isSupportedValue(mixed $value) bool + +getSupportedValues() mixed[] +getJsonSchema() array< string, mixed >$ } } From 2ed4ce68e68c1ab641bee96ed436e17bbb44223e Mon Sep 17 00:00:00 2001 From: Matthew Batchelder Date: Thu, 17 Jul 2025 16:22:16 -0400 Subject: [PATCH 6/6] Move ModalityEnum, alphabetize namespaces --- docs/ARCHITECTURE.md | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 0416c70..00f0978 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -535,16 +535,6 @@ direction LR } } - namespace AiClientNamespace.Enums { - class ModalityEnum { - TEXT - DOCUMENT - IMAGE - AUDIO - VIDEO - } - } - namespace AiClientNamespace.Files.Contracts { class FileInterface { } @@ -604,6 +594,13 @@ direction LR MODEL SYSTEM } + class ModalityEnum { + TEXT + DOCUMENT + IMAGE + AUDIO + VIDEO + } } namespace AiClientNamespace.Operations.Contracts { @@ -648,16 +645,6 @@ direction LR } } - namespace AiClientNamespace.Results.Enums { - class FinishReasonEnum { - STOP - LENGTH - CONTENT_FILTER - TOOL_CALLS - ERROR - } - } - namespace AiClientNamespace.Results.DTO { class Candidate { +getMessage() Message @@ -698,6 +685,16 @@ direction LR } } + namespace AiClientNamespace.Results.Enums { + class FinishReasonEnum { + STOP + LENGTH + CONTENT_FILTER + TOOL_CALLS + ERROR + } + } + namespace AiClientNamespace.Tools.DTO { class FunctionCall { +getId() string