From b40987514434ab131392d4d228b05e44dc17d183 Mon Sep 17 00:00:00 2001 From: Felix Arntz Date: Sun, 10 Aug 2025 20:07:05 -0500 Subject: [PATCH 1/4] Update operations handling in accordance with revised interfaces, use generic interface as return type to be future proof. --- docs/ARCHITECTURE.md | 23 +++++++++++-------- .../ProviderOperationsHandlerInterface.php | 6 ++--- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 00f0978..229446a 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -826,26 +826,32 @@ direction LR namespace AiClientNamespace.Providers.Contracts { class AuthenticationInterface { - +authenticate(RequestInterface $request) void + +authenticate(Request $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 + +send(Request $request, array< string, mixed > $options) Response + +request(string $method, string $uri, array< string, mixed > $options) Response } class ModelMetadataDirectoryInterface { +listModelMetadata() ModelMetadata[] +hasModelMetadata(string $modelId) bool +getModelMetadata(string $modelId) ModelMetadata } + class ProviderAvailabilityInterface { + +isConfigured() bool + } class ProviderInterface { +metadata() ProviderMetadata$ +model(string $modelId, ModelConfig|array< string, mixed > $modelConfig) ModelInterface$ +availability() ProviderAvailabilityInterface$ +modelMetadataDirectory() ModelMetadataDirectoryInterface$ } - class ProviderAvailabilityInterface { - +isConfigured() bool + class ProviderOperationsHandlerInterface { + +getOperation(string $operationId) OperationInterface + } + class ProviderWithOperationsHandlerInterface { + +operationsHandler() ProviderOperationsHandlerInterface$ } } @@ -888,9 +894,6 @@ direction LR class WithEmbeddingOperationsInterface { +getOperation(string $operationId) EmbeddingOperation } - class WithGenerativeAiOperationsInterface { - +getOperation(string $operationId) GenerativeAiOperation - } class WithHttpClientInterface { +setHttpClient(HttpClientInterface $client) void +getHttpClient() HttpClientInterface @@ -1050,7 +1053,8 @@ direction LR <> ModelInterface <> ProviderAvailabilityInterface <> ModelMetadataDirectoryInterface - <> WithGenerativeAiOperationsInterface + <> ProviderOperationsHandlerInterface + <> ProviderWithOperationsHandlerInterface <> WithEmbeddingOperationsInterface <> TextGenerationModelInterface <> ImageGenerationModelInterface @@ -1074,6 +1078,7 @@ direction LR ProviderInterface "1" *-- "1" ProviderMetadata ProviderInterface "1" *-- "1" ProviderAvailabilityInterface ProviderInterface "1" *-- "1" ModelMetadataDirectoryInterface + ProviderWithOperationsHandlerInterface "1" *-- "1" ProviderOperationsHandlerInterface ModelInterface "1" *-- "1" ModelMetadata ModelInterface "1" *-- "1" ModelConfig ProviderModelsMetadata "1" o-- "1" ProviderMetadata diff --git a/src/Providers/Contracts/ProviderOperationsHandlerInterface.php b/src/Providers/Contracts/ProviderOperationsHandlerInterface.php index a53563b..c712376 100644 --- a/src/Providers/Contracts/ProviderOperationsHandlerInterface.php +++ b/src/Providers/Contracts/ProviderOperationsHandlerInterface.php @@ -5,7 +5,7 @@ namespace WordPress\AiClient\Providers\Contracts; use InvalidArgumentException; -use WordPress\AiClient\Operations\DTO\GenerativeAiOperation; +use WordPress\AiClient\Operations\Contracts\OperationInterface; /** * Interface for handling provider-level operations. @@ -24,8 +24,8 @@ interface ProviderOperationsHandlerInterface * @since n.e.x.t * * @param string $operationId Operation identifier. - * @return GenerativeAiOperation The operation. + * @return OperationInterface The operation. * @throws InvalidArgumentException If operation not found. */ - public function getOperation(string $operationId): GenerativeAiOperation; + public function getOperation(string $operationId): OperationInterface; } From 85eea9c74ebebecb5b9d7f95dbf140edbb204f4c Mon Sep 17 00:00:00 2001 From: Felix Arntz Date: Sun, 10 Aug 2025 20:13:41 -0500 Subject: [PATCH 2/4] Update architecture to have correctly outline revised file API layer. --- docs/ARCHITECTURE.md | 95 +++++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 55 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 229446a..d7f4134 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -304,7 +304,6 @@ direction LR class PromptBuilder { +withText(string $text) self +withInlineImage(string $base64Blob, string $mimeType) - +withLocalImage(string $path, string $mimeType) +withRemoteImage(string $uri, string $mimeType) +withImageFile(File $file) self +withAudioFile(File $file) self @@ -340,12 +339,12 @@ direction LR +generateText() string +generateTexts(?int $candidateCount) string[] +streamGenerateText() Generator< string > - +generateImage() FileInterface - +generateImages(?int $candidateCount) FileInterface[] - +convertTextToSpeech() FileInterface - +convertTextToSpeeches(?int $candidateCount) FileInterface[] - +generateSpeech() FileInterface - +generateSpeeches(?int $candidateCount) FileInterface[] + +generateImage() File + +generateImages(?int $candidateCount) File[] + +convertTextToSpeech() File + +convertTextToSpeeches(?int $candidateCount) File[] + +generateSpeech() File + +generateSpeeches(?int $candidateCount) File[] +generateEmbeddings() Embedding[] +getModelRequirements() ModelRequirements +isSupported() bool @@ -468,7 +467,6 @@ direction LR class PromptBuilder { +withText(string $text) self +withInlineImage(string $base64Blob, string $mimeType) - +withLocalImage(string $path, string $mimeType) +withRemoteImage(string $uri, string $mimeType) +withImageFile(File $file) self +withAudioFile(File $file) self @@ -504,12 +502,12 @@ direction LR +generateText() string +generateTexts(?int $candidateCount) string[] +streamGenerateText() Generator< string > - +generateImage() FileInterface - +generateImages(?int $candidateCount) FileInterface[] - +convertTextToSpeech() FileInterface - +convertTextToSpeeches(?int $candidateCount) FileInterface[] - +generateSpeech() FileInterface - +generateSpeeches(?int $candidateCount) FileInterface[] + +generateImage() File + +generateImages(?int $candidateCount) File[] + +convertTextToSpeech() File + +convertTextToSpeeches(?int $candidateCount) File[] + +generateSpeech() File + +generateSpeeches(?int $candidateCount) File[] +generateEmbeddings() Embedding[] +getModelRequirements() ModelRequirements +isSupported() bool @@ -535,26 +533,20 @@ direction LR } } - namespace AiClientNamespace.Files.Contracts { - class FileInterface { - } - } - namespace AiClientNamespace.Files.DTO { - class InlineFile { - +getMimeType() string - +getBase64Data() string - +getJsonSchema() array< string, mixed >$ - } - class LocalFile { + class File { + +getFileType() FileTypeEnum +getMimeType() string - +getPath() string + +getUrl() ?string + +getBase64Data() ?string +getJsonSchema() array< string, mixed >$ } - class RemoteFile { - +getMimeType() string - +getUrl() string - +getJsonSchema() array< string, mixed >$ + } + + namespace AiClientNamespace.Files.Enums { + class FileTypeEnum { + INLINE + REMOTE } } @@ -567,8 +559,7 @@ direction LR class MessagePart { +getType() MessagePartTypeEnum +getText() string? - +getInlineFile() InlineFile? - +getRemoteFile() RemoteFile? + +getFile() File? +getFunctionCall() FunctionCall? +getFunctionResponse() FunctionResponse? +getJsonSchema() array< string, mixed >$ @@ -584,8 +575,7 @@ direction LR namespace AiClientNamespace.Messages.Enums { class MessagePartTypeEnum { TEXT - INLINE_FILE - REMOTE_FILE + FILE FUNCTION_CALL FUNCTION_RESPONSE } @@ -667,14 +657,14 @@ direction LR +getJsonSchema() array< string, mixed >$ %% The following utility methods transform the result candidates into a specific shape. +toText() string - +toImageFile() FileInterface - +toAudioFile() FileInterface - +toVideoFile() FileInterface + +toImageFile() File + +toAudioFile() File + +toVideoFile() File +toMessage() Message +toTexts() string[] - +toImageFiles() FileInterface[] - +toAudioFiles() FileInterface[] - +toVideoFiles() FileInterface[] + +toImageFiles() File[] + +toAudioFiles() File[] + +toVideoFiles() File[] +toMessages() Message[] } class TokenUsage { @@ -730,26 +720,25 @@ direction LR namespace AiClientNamespace.Util { class CandidatesUtil { +toTexts(Candidate[] $candidates) string[]$ - +toImageFiles(Candidate[] $candidates) FileInterface[]$ - +toAudioFiles(Candidate[] $candidates) FileInterface[]$ - +toVideoFiles(Candidate[] $candidates) FileInterface[]$ + +toImageFiles(Candidate[] $candidates) File[]$ + +toAudioFiles(Candidate[] $candidates) File[]$ + +toVideoFiles(Candidate[] $candidates) File[]$ +toFirstText(Candidate[] $candidates) string$ - +toFirstImageFile(Candidate[] $candidates) FileInterface$ - +toFirstAudioFile(Candidate[] $candidates) FileInterface$ - +toFirstVideoFile(Candidate[] $candidates) FileInterface$ + +toFirstImageFile(Candidate[] $candidates) File$ + +toFirstAudioFile(Candidate[] $candidates) File$ + +toFirstVideoFile(Candidate[] $candidates) File$ } class MessageUtil { +toText(Message $message) string$ - +toImageFile(Message $message) FileInterface$ - +toAudioFile(Message $message) FileInterface$ - +toVideoFile(Message $message) FileInterface$ + +toImageFile(Message $message) File$ + +toAudioFile(Message $message) File$ + +toVideoFile(Message $message) File$ } class RequirementsUtil { +inferRequirements(Message[] $messages, ModelConfig $modelConfig) ModelRequirements$ } } - <> FileInterface <> OperationInterface <> ResultInterface <> MessageRoleEnum @@ -772,8 +761,7 @@ direction LR PromptBuilder .. EmbeddingOperation : creates MessageBuilder .. Message : creates Message "1" *-- "1..*" MessagePart - MessagePart "1" o-- "0..1" InlineFile - MessagePart "1" o-- "0..1" RemoteFile + MessagePart "1" o-- "0..1" File MessagePart "1" o-- "0..1" FunctionCall MessagePart "1" o-- "0..1" FunctionResponse GenerativeAiOperation "1" o-- "0..1" GenerativeAiResult @@ -788,9 +776,6 @@ direction LR OperationInterface ..> OperationStateEnum GenerativeAiOperation ..> OperationStateEnum Candidate ..> FinishReasonEnum - FileInterface <|-- InlineFile - FileInterface <|-- RemoteFile - FileInterface <|-- LocalFile Message <|-- UserMessage Message <|-- ModelMessage Message <|-- SystemMessage From 8a200f7de140876423a42ded65421677bdcec289 Mon Sep 17 00:00:00 2001 From: Felix Arntz Date: Sun, 10 Aug 2025 20:16:53 -0500 Subject: [PATCH 3/4] Fix architecture as well as FunctionResponse class implementation to correctly define ID and name return types as string or null. --- docs/ARCHITECTURE.md | 8 ++++---- src/Tools/DTO/FunctionCall.php | 2 +- src/Tools/DTO/FunctionResponse.php | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index d7f4134..94c09b6 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -687,8 +687,8 @@ direction LR namespace AiClientNamespace.Tools.DTO { class FunctionCall { - +getId() string - +getName() string + +getId() ?string + +getName() ?string +getArgs() array< string, mixed > +getJsonSchema() array< string, mixed >$ } @@ -699,8 +699,8 @@ direction LR +getJsonSchema() array< string, mixed >$ } class FunctionResponse { - +getId() string - +getName() string + +getId() ?string + +getName() ?string +getResponse() mixed +getJsonSchema() array< string, mixed >$ } diff --git a/src/Tools/DTO/FunctionCall.php b/src/Tools/DTO/FunctionCall.php index 9363235..51371a5 100644 --- a/src/Tools/DTO/FunctionCall.php +++ b/src/Tools/DTO/FunctionCall.php @@ -65,7 +65,7 @@ public function __construct(?string $id = null, ?string $name = null, array $arg * * @since n.e.x.t * - * @return string|null The unique identifier. + * @return string|null The function call ID. */ public function getId(): ?string { diff --git a/src/Tools/DTO/FunctionResponse.php b/src/Tools/DTO/FunctionResponse.php index 36307af..1078ddc 100644 --- a/src/Tools/DTO/FunctionResponse.php +++ b/src/Tools/DTO/FunctionResponse.php @@ -59,9 +59,9 @@ public function __construct(string $id, string $name, $response) * * @since n.e.x.t * - * @return string The function call ID. + * @return string|null The function call ID. */ - public function getId(): string + public function getId(): ?string { return $this->id; } @@ -71,9 +71,9 @@ public function getId(): string * * @since n.e.x.t * - * @return string The function name. + * @return string|null The function name. */ - public function getName(): string + public function getName(): ?string { return $this->name; } From dd245b17211a48c1d0119edb473e9c80bbde7678 Mon Sep 17 00:00:00 2001 From: Felix Arntz Date: Sun, 10 Aug 2025 20:29:24 -0500 Subject: [PATCH 4/4] Revise proposed HTTP infrastructure as part of extenders API. --- docs/ARCHITECTURE.md | 61 +++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 94c09b6..897b7c9 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -810,14 +810,6 @@ direction LR } namespace AiClientNamespace.Providers.Contracts { - class AuthenticationInterface { - +authenticate(Request $request) void - +getJsonSchema() array< string, mixed >$ - } - class HttpClientInterface { - +send(Request $request, array< string, mixed > $options) Response - +request(string $method, string $uri, array< string, mixed > $options) Response - } class ModelMetadataDirectoryInterface { +listModelMetadata() ModelMetadata[] +hasModelMetadata(string $modelId) bool @@ -866,23 +858,52 @@ direction LR } } + namespace AiClientNamespace.Providers.Http.Contracts { + class HttpTransporterInterface { + +send(Request $request) Response + } + class RequestAuthenticationInterface { + +authenticate(Request $request) void + +getJsonSchema() array< string, mixed >$ + } + class WithHttpTransporterInterface { + +setHttpTransporter(HttpTransporterInterface $transporter) void + +getHttpTransporter() HttpTransporterInterface + } + class WithRequestAuthenticationInterface { + +setRequestAuthentication(RequestAuthenticationInterface $authentication) void + +getRequestAuthentication() RequestAuthenticationInterface + } + } + + namespace AiClientNamespace.Providers.Http.DTO { + class Request { + +getMethod() string + +getUri() string + +getHeaders() array< string, string[] > + +getBody() ?string + +getData() ?array< string, mixed > + +getJsonSchema() array< string, mixed >$ + } + + class Response { + +getStatusCode() int + +getHeaders() array< string, string[] > + +getBody() ?string + +getData() ?array< string, mixed > + +getJsonSchema() array< string, mixed >$ + } + } + namespace AiClientNamespace.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 WithHttpClientInterface { - +setHttpClient(HttpClientInterface $client) void - +getHttpClient() HttpClientInterface - } } namespace AiClientNamespace.Providers.Models.DTO { @@ -1051,10 +1072,10 @@ direction LR <> TextToSpeechConversionOperationModelInterface <> SpeechGenerationOperationModelInterface <> EmbeddingGenerationOperationModelInterface - <> WithHttpClientInterface - <> HttpClientInterface - <> WithAuthenticationInterface - <> AuthenticationInterface + <> HttpTransporterInterface + <> WithHttpTransporterInterface + <> RequestAuthenticationInterface + <> WithRequestAuthenticationInterface <> CapabilityEnum <> OptionEnum <> ProviderTypeEnum