Skip to content

Commit eef847e

Browse files
committed
Rename features/capabilities to capabilities/options and simplify model discovery via AiModelRequirements objects that can be automatically inferred from message and config objects.
1 parent 3346bdd commit eef847e

File tree

2 files changed

+71
-41
lines changed

2 files changed

+71
-41
lines changed

docs/ARCHITECTURE.md

Lines changed: 69 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ This document outlines the architecture for the PHP AI Client. It is critical th
66

77
The API design at a high level is heavily inspired by the [Vercel AI SDK](https://github.com/vercel/ai), which is widely used in the NodeJS ecosystem and one of the very few comprehensive AI client SDKs available.
88

9-
The main additional aspect that the Vercel AI SDK does not cater for easily is for a developer to use AI in a way that the choice of provider remains with the user. To clarify with an example: Instead of "Generate text with Google's model `gemini-2.5-flash`", go with "Generate text using any provider model that supports text generation and multimodal input". In other words, there needs to be a mechanism that allows finding any configured model that supports the given set of required AI features and capabilities.
9+
The main additional aspect that the Vercel AI SDK does not cater for easily is for a developer to use AI in a way that the choice of provider remains with the user. To clarify with an example: Instead of "Generate text with Google's model `gemini-2.5-flash`", go with "Generate text using any provider model that supports text generation and multimodal input". In other words, there needs to be a mechanism that allows finding any configured model that supports the given set of required AI capabilities and options.
1010

1111
### Code examples
1212

@@ -36,7 +36,7 @@ $texts = Ai::generateTextResult(
3636
'Write a 2-verse poem about PHP.',
3737
Anthropic::model(
3838
'claude-3.7-sonnet',
39-
[TextGenerationConfig::CANDIDATE_COUNT => 4]
39+
[AiOption::CANDIDATE_COUNT => 4]
4040
)
4141
)->toTexts();
4242
```
@@ -46,7 +46,7 @@ $texts = Ai::generateTextResult(
4646
```php
4747
$modelsMetadata = Ai::defaultRegistry()->findProviderModelsMetadataForSupport(
4848
'openai',
49-
AiFeature::IMAGE_GENERATION
49+
AiCapability::IMAGE_GENERATION
5050
);
5151
$imageFile = Ai::generateImageResult(
5252
'Generate an illustration of the PHP elephant in the Carribean sea.',
@@ -61,7 +61,7 @@ $imageFile = Ai::generateImageResult(
6161

6262
```php
6363
$providerModelsMetadata = Ai::defaultRegistry()->findModelsMetadataForSupport(
64-
AiFeature::IMAGE_GENERATION
64+
AiCapability::IMAGE_GENERATION
6565
);
6666
$imageFile = Ai::generateImageResult(
6767
'Generate an illustration of the PHP elephant in the Carribean sea.',
@@ -78,7 +78,7 @@ _Note: This does effectively the exact same as [the first code example](#generat
7878

7979
```php
8080
$providerModelsMetadata = Ai::defaultRegistry()->findModelsMetadataForSupport(
81-
AiFeature::TEXT_GENERATION
81+
AiCapability::TEXT_GENERATION
8282
);
8383
$text = Ai::generateTextResult(
8484
'Write a 2-verse poem about PHP.',
@@ -91,7 +91,7 @@ $text = Ai::generateTextResult(
9191

9292
#### Generate text with an image as additional input using any suitable model from any provider
9393

94-
_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 `AiFeature::TEXT_GENERATION`, but also `TextGenerationConfig::INPUT_MODALITIES => ['text', 'image']`._
94+
_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']`._
9595

9696
```php
9797
$text = Ai::generateTextResult(
@@ -109,7 +109,7 @@ $text = Ai::generateTextResult(
109109

110110
#### Generate text with chat history using any suitable model from any provider
111111

112-
_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 `AiFeature::TEXT_GENERATION` as well as `TextGenerationConfig::CHAT_HISTORY`._
112+
_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`._
113113

114114
```php
115115
$text = Ai::generateTextResult(
@@ -136,11 +136,11 @@ _Note: Unlike the previous two examples, to require JSON output it is necessary
136136

137137
```php
138138
$providerModelsMetadata = Ai::defaultRegistry()->findModelsMetadataForSupport(
139-
AiFeature::TEXT_GENERATION,
139+
AiCapability::TEXT_GENERATION,
140140
[
141141
// Make sure the model supports JSON output as well as following a given schema.
142-
TextGenerationConfig::OUTPUT_MIME_TYPE => 'application/json',
143-
TextGenerationConfig::OUTPUT_SCHEMA => true,
142+
AiOption::OUTPUT_MIME_TYPE => 'application/json',
143+
AiOption::OUTPUT_SCHEMA => true,
144144
]
145145
);
146146
$jsonString = Ai::generateTextResult(
@@ -149,19 +149,17 @@ $jsonString = Ai::generateTextResult(
149149
$providerModelsMetadata[0]->getProvider()->getId(),
150150
$providerModelsMetadata[0]->getModels()[0]->getId(),
151151
[
152-
AiModelConfig::GENERATION_CONFIG => [
153-
TextGenerationConfig::OUTPUT_MIME_TYPE => 'application/json',
154-
TextGenerationConfig::OUTPUT_SCHEMA => [
155-
'type' => 'array',
156-
'items' => [
157-
'type' => 'object',
158-
'properties' => [
159-
'name' => [
160-
'type' => 'string',
161-
],
162-
'age' => [
163-
'type' => 'integer',
164-
],
152+
AiOption::OUTPUT_MIME_TYPE => 'application/json',
153+
AiOption::OUTPUT_SCHEMA => [
154+
'type' => 'array',
155+
'items' => [
156+
'type' => 'object',
157+
'properties' => [
158+
'name' => [
159+
'type' => 'string',
160+
],
161+
'age' => [
162+
'type' => 'integer',
165163
],
166164
],
167165
],
@@ -175,7 +173,7 @@ $jsonString = Ai::generateTextResult(
175173

176174
```php
177175
$providerModelsMetadata = Ai::defaultRegistry()->findModelsMetadataForSupport(
178-
AiFeature::EMBEDDING_GENERATION
176+
AiCapability::EMBEDDING_GENERATION
179177
);
180178
$embeddings = Ai::generateEmbeddingsResult(
181179
[
@@ -253,6 +251,8 @@ direction LR
253251
+convertTextToSpeech() File
254252
+generateSpeech() File
255253
+generateEmbeddings() Embedding[]
254+
+getModelRequirements() AiModelRequirements
255+
+isSupported() bool
256256
}
257257
258258
class MessageBuilder {
@@ -327,9 +327,9 @@ direction LR
327327
+hasProvider(string $idOrClassName) bool
328328
+getProviderClassName(string $id) string
329329
+isProviderConfigured(string $idOrClassName) bool
330-
+getProviderModel(string $idOrClassName, string $modelId, AiModelConfig|array $modelConfig) AiModel
331-
+findProviderModelsMetadataForSupport(string $idOrClassName, AiFeature $feature, array<string, mixed > $capabilities) AiModelMetadata[]
332-
+findModelsMetadataForSupport(AiFeature $feature, array<string, mixed > $capabilities) AiProviderModelMetadata[]
330+
+getProviderModel(string $idOrClassName, string $modelId, AiModelConfig|array< string, mixed > $modelConfig) AiModel
331+
+findProviderModelsMetadataForSupport(string $idOrClassName, AiModelRequirements $modelRequirements) AiModelMetadata[]
332+
+findModelsMetadataForSupport(AiModelRequirements $modelRequirements) AiProviderModelMetadata[]
333333
}
334334
}
335335
@@ -404,6 +404,8 @@ direction LR
404404
+convertTextToSpeech() File
405405
+generateSpeech() File
406406
+generateEmbeddings() Embedding[]
407+
+getModelRequirements() AiModelRequirements
408+
+isSupported() bool
407409
}
408410
409411
class MessageBuilder {
@@ -579,6 +581,9 @@ direction LR
579581
+toFirstAudioFile(Candidate[] $candidates) File$
580582
+toFirstVideoFile(Candidate[] $candidates) File$
581583
}
584+
class RequirementsUtil {
585+
+inferRequirements(Message[] $messages, AiModelConfig $modelConfig) AiModelRequirements$
586+
}
582587
}
583588
584589
<<interface>> File
@@ -645,9 +650,9 @@ direction LR
645650
+hasProvider(string $idOrClassName) bool
646651
+getProviderClassName(string $id) string
647652
+isProviderConfigured(string $idOrClassName) bool
648-
+getProviderModel(string $idOrClassName, string $modelId, AiModelConfig|array $modelConfig) AiModel
649-
+findProviderModelsMetadataForSupport(string $idOrClassName, AiFeature $feature, array<string, mixed > $capabilities) AiModelMetadata[]
650-
+findModelsMetadataForSupport(AiFeature $feature, array<string, mixed > $capabilities) AiProviderModelMetadata[]
653+
+getProviderModel(string $idOrClassName, string $modelId, AiModelConfig|array< string, mixed > $modelConfig) AiModel
654+
+findProviderModelsMetadataForSupport(string $idOrClassName, AiModelRequirements $modelRequirements) AiModelMetadata[]
655+
+findModelsMetadataForSupport(AiModelRequirements $modelRequirements) AiProviderModelMetadata[]
651656
}
652657
}
653658
namespace Ai.Providers.Contracts {
@@ -661,7 +666,6 @@ direction LR
661666
+metadata() AiModelMetadata
662667
+setConfig(AiModelConfig $config) void
663668
+getConfig() AiModelConfig
664-
+getSupportedCapabilities() AiCapability[]$
665669
}
666670
class AiProviderAvailability {
667671
+isConfigured() bool
@@ -735,15 +739,19 @@ direction LR
735739
class AiModelMetadata {
736740
+getId() string
737741
+getName() string
738-
+getSupportedFeatures() AiFeature[]
739742
+getSupportedCapabilities() AiCapability[]
743+
+getSupportedOptions() AiSupportedOption[]
740744
+getJsonSchema() array< string, mixed >$
741745
}
742746
class AiProviderModelsMetadata {
743747
+getProvider() AiProviderMetadata
744748
+getModels() AiModelMetadata[]
745749
+getJsonSchema() array< string, mixed >$
746750
}
751+
class AiModelRequirements {
752+
getRequiredCapabilities() AiCapability[]
753+
getRequiredOptions() AiRequiredOption[]
754+
}
747755
class AiModelConfig {
748756
+setSystemInstruction(string|MessagePart|MessagePart[]|Message $systemInstruction) void
749757
+getSystemInstruction() Message?
@@ -787,12 +795,17 @@ direction LR
787795
+getDisallowedDomains() string[]
788796
+getJsonSchema() array< string, mixed >$
789797
}
790-
class AiCapability {
791-
+isSupported() bool
798+
class AiSupportedOption {
799+
+getName() string
792800
+isSupportedValue(mixed $value) bool
793801
+getSupportedValues() mixed[]
794802
+getJsonSchema() array< string, mixed >$
795803
}
804+
class AiRequiredOption {
805+
+getName() string
806+
+getValue() mixed
807+
+getJsonSchema() array< string, mixed >$
808+
}
796809
}
797810
namespace Ai.Providers.Enums {
798811
class AiProviderType {
@@ -804,20 +817,31 @@ direction LR
804817
FUNCTION_DECLARATIONS
805818
WEB_SEARCH
806819
}
807-
class AiFeature {
820+
class AiCapability {
808821
TEXT_GENERATION
809822
IMAGE_GENERATION
810823
TEXT_TO_SPEECH
811824
SPEECH_GENERATION
812825
MUSIC_GENERATION
813826
VIDEO_GENERATION
814827
EMBEDDING_GENERATION
828+
CHAT_HISTORY
829+
}
830+
class AiOption {
831+
INPUT_MODALITIES
832+
OUTPUT_MODALITIES
833+
CANDIDATE_COUNT
834+
TEMPERATURE
835+
TOP_K
836+
TOP_P
837+
OUTPUT_MIME_TYPE
838+
OUTPUT_SCHEMA
815839
}
816840
}
817841
namespace Ai.Providers.Util {
818-
class AiFeaturesUtil {
819-
+getSupportedFeatures(AiModel|string $modelClass) AiFeature[]$
842+
class AiCapabilitiesUtil {
820843
+getSupportedCapabilities(AiModel|string $modelClass) AiCapability[]$
844+
+getSupportedOptions(AiModel|string $modelClass) AiSupportedOption[]$
821845
}
822846
}
823847
@@ -842,7 +866,8 @@ direction LR
842866
<<interface>> WithAuthentication
843867
<<interface>> Authentication
844868
<<interface>> GenerationConfig
845-
<<Enumeration>> AiFeature
869+
<<Enumeration>> AiCapability
870+
<<Enumeration>> AiOption
846871
<<Enumeration>> AiProviderType
847872
848873
AiProvider .. AiModel : creates
@@ -856,14 +881,17 @@ direction LR
856881
AiProviderRegistry "1" o-- "0..*" AiProvider
857882
AiProviderRegistry "1" o-- "0..*" AiProviderMetadata
858883
AiModelMetadataDirectory "1" o-- "1..*" AiModelMetadata
859-
AiModelMetadata "1" o-- "1..*" AiFeature
860-
AiModelMetadata "1" o-- "0..*" AiCapability
884+
AiModelMetadata "1" o-- "1..*" AiCapability
885+
AiModelMetadata "1" o-- "0..*" AiSupportedOption
886+
AiModelRequirements "1" o-- "1..*" AiCapability
887+
AiModelRequirements "1" o-- "0..*" AiRequiredOption
861888
AiModelConfig "1" o-- "0..1" GenerationConfig
862889
AiModelConfig "1" o-- "0..*" Tool
863890
Tool "1" o-- "0..*" FunctionDeclaration
864891
Tool "1" o-- "0..1" WebSearch
865892
AiProviderMetadata ..> AiProviderType
866-
AiModelMetadata ..> AiFeature
893+
AiModelMetadata ..> AiCapability
894+
AiModelMetadata ..> AiSupportedOption
867895
AiModel <|-- AiTextGenerationModel
868896
AiModel <|-- AiImageGenerationModel
869897
AiModel <|-- AiTextToSpeechConversionModel

docs/GLOSSARY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
This glossary defines common terms relevant for the PHP AI Client and related projects.
44

55
* **Agent**: An autonomous system that can perceive its environment, make decisions, and take actions to achieve specific goals, often leveraging AI models.
6+
* **AI Capability**: A single string that denotes an AI feature, such as text generation or image generation.
7+
* **AI Option**: A parameter that can be passed to a model, such as temperature or output MIME type.
68
* **Generative AI**: Overaching term describing AI models that generate content as requested in a prompt.
79
* **MCP**: The "Model Context Protocol", a proposed standard for connecting AI assistants to the systems where data lives.
810
* **Message**: A single message, either a user prompt, a model response, or a system prompt—optionally containing of multiple message parts.

0 commit comments

Comments
 (0)