@@ -94,44 +94,42 @@ public function getRequiredOptions(): array
9494    /** 
9595     * Checks whether the given model metadata meets these requirements. 
9696     * 
97-      * @since 0.2.0  
97+      * @since n.e.x.t  
9898     * 
9999     * @param ModelMetadata $metadata The model metadata to check against. 
100100     * @return bool True if the model meets all requirements, false otherwise. 
101101     */ 
102102    public  function  areMetBy (ModelMetadata $ metadatabool 
103103    {
104-         // Check if all required capabilities are supported 
104+         // Create lookup maps for better performance (instead of nested foreach loops) 
105+         $ capabilitiesMap
106+         foreach  ($ metadatagetSupportedCapabilities () as  $ capability
107+             $ capabilitiesMap$ capabilityvalue ] = $ capability
108+         }
109+ 
110+         $ optionsMap
111+         foreach  ($ metadatagetSupportedOptions () as  $ option
112+             $ optionsMap$ optiongetName ()->value ] = $ option
113+         }
114+ 
115+         // Check if all required capabilities are supported using map lookup 
105116        foreach  ($ this requiredCapabilities  as  $ requiredCapability
106-             $ supportedfalse ;
107-             foreach  ($ metadatagetSupportedCapabilities () as  $ supportedCapability
108-                 if  ($ supportedCapabilityequals ($ requiredCapability
109-                     $ supportedtrue ;
110-                     break ;
111-                 }
112-             }
113-             if  (!$ supported
117+             if  (!isset ($ capabilitiesMap$ requiredCapabilityvalue ])) {
114118                return  false ;
115119            }
116120        }
117121
118122        // Check if all required options are supported with the specified values 
119123        foreach  ($ this requiredOptions  as  $ requiredOption
120-             $ optionSupportedfalse ;
121-             $ supportedOptions$ metadatagetSupportedOptions ();
122- 
123-             foreach  ($ supportedOptionsas  $ supportedOption
124-                 if  ($ supportedOptiongetName ()->equals ($ requiredOptiongetName ())) {
125-                     // Check if the required value is supported by this option 
126-                     if  ($ supportedOptionisSupportedValue ($ requiredOptiongetValue ())) {
127-                         $ optionSupportedtrue ;
128-                         break ;
129-                     }
130-                 }
124+             // Use map lookup instead of linear search 
125+             if  (!isset ($ optionsMap$ requiredOptiongetName ()->value ])) {
126+                 return  false ;
131127            }
132128
133-             // If no supported options at all, this is only OK if we have no required options 
134-             if  (!$ optionSupported
129+             $ supportedOption$ optionsMap$ requiredOptiongetName ()->value ];
130+ 
131+             // Check if the required value is supported by this option 
132+             if  (!$ supportedOptionisSupportedValue ($ requiredOptiongetValue ())) {
135133                return  false ;
136134            }
137135        }
@@ -142,7 +140,7 @@ public function areMetBy(ModelMetadata $metadata): bool
142140    /** 
143141     * Creates ModelRequirements from prompt data and model configuration. 
144142     * 
145-      * @since 0.2.0  
143+      * @since n.e.x.t  
146144     * 
147145     * @param CapabilityEnum $capability The capability the model must support. 
148146     * @param list<Message> $messages The messages in the conversation. 
@@ -193,8 +191,41 @@ public static function fromPromptData(CapabilityEnum $capability, array $message
193191            }
194192        }
195193
196-         // 
197-         // Convert ModelConfig to RequiredOptions (moved from ModelConfig::toRequiredOptions) 
194+         // Convert ModelConfig to RequiredOptions 
195+         $ requiredOptionsself ::toRequiredOptions ($ modelConfig
196+ 
197+         // Add additional options based on message analysis 
198+         if  ($ hasFunctionMessageParts
199+             $ requiredOptionsself ::includeInRequiredOptions (
200+                 $ requiredOptions
201+                 new  RequiredOption (OptionEnum::functionDeclarations (), true )
202+             );
203+         }
204+ 
205+         // Add input modalities if we have any inputs 
206+         if  (!empty ($ inputModalities
207+             // Remove duplicates 
208+             $ inputModalitiesarray_unique ($ inputModalitiesSORT_REGULAR );
209+             $ requiredOptionsself ::includeInRequiredOptions (
210+                 $ requiredOptions
211+                 new  RequiredOption (OptionEnum::inputModalities (), array_values ($ inputModalities
212+             );
213+         }
214+ 
215+         // Step 6: Return new ModelRequirements 
216+         return  new  self ($ capabilities$ requiredOptions
217+     }
218+ 
219+     /** 
220+      * Converts ModelConfig to an array of RequiredOptions. 
221+      * 
222+      * @since n.e.x.t 
223+      * 
224+      * @param ModelConfig $modelConfig The model configuration. 
225+      * @return list<RequiredOption> The required options. 
226+      */ 
227+     private  static  function  toRequiredOptions (ModelConfig $ modelConfigarray 
228+     {
198229        $ requiredOptions
199230
200231        // Map properties that have corresponding OptionEnum values 
@@ -261,20 +292,87 @@ public static function fromPromptData(CapabilityEnum $capability, array $message
261292            );
262293        }
263294
264-         // Step 5: Add additional options based on message analysis 
265-         if  ($ hasFunctionMessageParts
295+         // Handle properties without OptionEnum values as custom options 
296+         if  ($ modelConfiggetStopSequences () !== null ) {
297+             $ requiredOptionsnew  RequiredOption (OptionEnum::stopSequences (), $ modelConfiggetStopSequences ());
298+         }
299+ 
300+         if  ($ modelConfiggetPresencePenalty () !== null ) {
301+             $ requiredOptionsnew  RequiredOption (OptionEnum::presencePenalty (), $ modelConfiggetPresencePenalty ());
302+         }
303+ 
304+         if  ($ modelConfiggetFrequencyPenalty () !== null ) {
305+             $ requiredOptionsnew  RequiredOption (
306+                 OptionEnum::frequencyPenalty (),
307+                 $ modelConfiggetFrequencyPenalty ()
308+             );
309+         }
310+ 
311+         if  ($ modelConfiggetLogprobs () !== null ) {
312+             $ requiredOptionsnew  RequiredOption (OptionEnum::logprobs (), $ modelConfiggetLogprobs ());
313+         }
314+ 
315+         if  ($ modelConfiggetTopLogprobs () !== null ) {
316+             $ requiredOptionsnew  RequiredOption (OptionEnum::topLogprobs (), $ modelConfiggetTopLogprobs ());
317+         }
318+ 
319+         if  ($ modelConfiggetFunctionDeclarations () !== null ) {
266320            $ requiredOptionsnew  RequiredOption (OptionEnum::functionDeclarations (), true );
267321        }
268322
269-         // Add input modalities if we have any inputs 
270-         if  (!empty ($ inputModalities
271-             // Remove duplicates 
272-             $ inputModalitiesarray_unique ($ inputModalitiesSORT_REGULAR );
273-             $ requiredOptionsnew  RequiredOption (OptionEnum::inputModalities (), array_values ($ inputModalities
323+         if  ($ modelConfiggetWebSearch () !== null ) {
324+             $ requiredOptionsnew  RequiredOption (OptionEnum::webSearch (), true );
274325        }
275326
276-         // Step 6: Return new ModelRequirements 
277-         return  new  self ($ capabilities$ requiredOptions
327+         if  ($ modelConfiggetOutputFileType () !== null ) {
328+             $ requiredOptionsnew  RequiredOption (OptionEnum::outputFileType (), $ modelConfiggetOutputFileType ());
329+         }
330+ 
331+         if  ($ modelConfiggetOutputMediaOrientation () !== null ) {
332+             $ requiredOptionsnew  RequiredOption (
333+                 OptionEnum::outputMediaOrientation (),
334+                 $ modelConfiggetOutputMediaOrientation ()
335+             );
336+         }
337+ 
338+         if  ($ modelConfiggetOutputMediaAspectRatio () !== null ) {
339+             $ requiredOptionsnew  RequiredOption (
340+                 OptionEnum::outputMediaAspectRatio (),
341+                 $ modelConfiggetOutputMediaAspectRatio ()
342+             );
343+         }
344+ 
345+         // Add custom options as individual RequiredOptions 
346+         foreach  ($ modelConfiggetCustomOptions () as  $ key$ value
347+             $ requiredOptionsnew  RequiredOption (OptionEnum::customOptions (), [$ key$ value
348+         }
349+ 
350+         return  $ requiredOptions
351+     }
352+ 
353+     /** 
354+      * Includes a RequiredOption in the array, ensuring no duplicates based on option name. 
355+      * 
356+      * @since n.e.x.t 
357+      * 
358+      * @param list<RequiredOption> $requiredOptions The existing required options. 
359+      * @param RequiredOption $newOption The new option to include. 
360+      * @return list<RequiredOption> The updated required options array. 
361+      */ 
362+     private  static  function  includeInRequiredOptions (array  $ requiredOptionsRequiredOption $ newOptionarray 
363+     {
364+         // Check if we already have this option name 
365+         foreach  ($ requiredOptionsas  $ index$ existingOption
366+             if  ($ existingOptiongetName ()->equals ($ newOptiongetName ())) {
367+                 // Replace existing option with new one 
368+                 $ requiredOptions$ index$ newOption
369+                 return  $ requiredOptions
370+             }
371+         }
372+ 
373+         // Option not found, add it 
374+         $ requiredOptions$ newOption
375+         return  $ requiredOptions
278376    }
279377
280378    /** 
0 commit comments