Repository: echolabsdev/prism (php)

Issue:
Can't use o1 with structured outputs
Hey :-)
When using structured outputs in OpenAI, a system message gets automatically appended to add the schema. However, the o1 family does not allow system messages. I wasn't sure if you were aware of this, so feel free to close the issue if you were! Also, happy to help with the implementation!

Pull request description:
Handle o1 Model Structured Output
## Description

Closes #124 

From everything that I can find o1 series models do not support structured output. This PR introduces an exception when trying to use these models with structured output.

Patch:
diff --git a/src/Providers/OpenAI/Support/StructuredModeResolver.php b/src/Providers/OpenAI/Support/StructuredModeResolver.php
index 26d6edb..161359a 100644
--- a/src/Providers/OpenAI/Support/StructuredModeResolver.php
+++ b/src/Providers/OpenAI/Support/StructuredModeResolver.php
@@ -4,17 +4,22 @@ declare(strict_types=1);
 
 namespace EchoLabs\Prism\Providers\OpenAI\Support;
 
-use EchoLabs\Prism\Enums\StructuredMode as StructuredModeEnum;
+use EchoLabs\Prism\Enums\StructuredMode;
+use EchoLabs\Prism\Exceptions\PrismException;
 
 class StructuredModeResolver
 {
-    public static function forModel(string $model): StructuredModeEnum
+    public static function forModel(string $model): StructuredMode
     {
+        if (self::unsupported($model)) {
+            throw new PrismException(sprintf('Structured output is not supported for %s', $model));
+        }
+
         if (self::supportsStructuredMode($model)) {
-            return StructuredModeEnum::Structured;
+            return StructuredMode::Structured;
         }
 
-        return StructuredModeEnum::Json;
+        return StructuredMode::Json;
     }
 
     protected static function supportsStructuredMode(string $model): bool
@@ -36,4 +41,13 @@ class StructuredModeResolver
 
         return $model === 'gpt-3.5-turbo';
     }
+
+    protected static function unsupported(string $model): bool
+    {
+        return in_array($model, [
+            'o1',
+            'o1-mini',
+            'o1-preview',
+        ]);
+    }
 }


Test patch:
diff --git a/tests/Providers/OpenAI/StructuredTest.php b/tests/Providers/OpenAI/StructuredTest.php
index 89b26cd..c5ee638 100644
--- a/tests/Providers/OpenAI/StructuredTest.php
+++ b/tests/Providers/OpenAI/StructuredTest.php
@@ -181,3 +181,28 @@ it('throws an exception when there is a refusal', function (): void {
         return true;
     });
 });
+
+it('throws an exception for o1 models', function (string $model): void {
+    $this->expectException(PrismException::class);
+    $this->expectExceptionMessage(sprintf('Structured output is not supported for %s', $model));
+
+    $schema = new ObjectSchema(
+        'output',
+        'the output object',
+        [
+            new StringSchema('weather', 'The weather forecast'),
+            new StringSchema('game_time', 'The tigers game time'),
+            new BooleanSchema('coat_required', 'whether a coat is required'),
+        ],
+    );
+
+    Prism::structured()
+        ->using(Provider::OpenAI, $model)
+        ->withSchema($schema)
+        ->withPrompt('What time is the tigers game today and should I wear a coat?')
+        ->generate();
+})->with([
+    'o1',
+    'o1-mini',
+    'o1-preview',
+]);