packages feed

openai 2.2.0 → 2.2.1

raw patch · 6 files changed

+245/−3 lines, 6 filesdep ~basenew-component:exe:chat-completions-stream-examplePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: base

API changes (from Hackage documentation)

+ OpenAI.V1: [createChatCompletionStreamTyped] :: Methods -> CreateChatCompletion -> (Either Text ChatCompletionStreamEvent -> IO ()) -> IO ()
+ OpenAI.V1: [createChatCompletionStream] :: Methods -> CreateChatCompletion -> (Either Text Value -> IO ()) -> IO ()
+ OpenAI.V1.Chat.Completions: ChatCompletionChunk :: Text -> Vector ChunkChoice -> POSIXTime -> Model -> Maybe ServiceTier -> Maybe Text -> Text -> Maybe (Usage CompletionTokensDetails PromptTokensDetails) -> ChatCompletionChunk
+ OpenAI.V1.Chat.Completions: ChunkChoice :: Delta -> Maybe Text -> Natural -> Maybe LogProbs -> ChunkChoice
+ OpenAI.V1.Chat.Completions: Delta :: Maybe Text -> Maybe Text -> Maybe Text -> Maybe (Vector ToolCall) -> Delta
+ OpenAI.V1.Chat.Completions: [delta] :: ChunkChoice -> Delta
+ OpenAI.V1.Chat.Completions: [delta_content] :: Delta -> Maybe Text
+ OpenAI.V1.Chat.Completions: [delta_refusal] :: Delta -> Maybe Text
+ OpenAI.V1.Chat.Completions: [delta_role] :: Delta -> Maybe Text
+ OpenAI.V1.Chat.Completions: [delta_tool_calls] :: Delta -> Maybe (Vector ToolCall)
+ OpenAI.V1.Chat.Completions: [stream] :: CreateChatCompletion -> Maybe Bool
+ OpenAI.V1.Chat.Completions: data ChatCompletionChunk
+ OpenAI.V1.Chat.Completions: data ChunkChoice
+ OpenAI.V1.Chat.Completions: data Delta
+ OpenAI.V1.Chat.Completions: instance Data.Aeson.Types.FromJSON.FromJSON OpenAI.V1.Chat.Completions.ChatCompletionChunk
+ OpenAI.V1.Chat.Completions: instance Data.Aeson.Types.FromJSON.FromJSON OpenAI.V1.Chat.Completions.ChunkChoice
+ OpenAI.V1.Chat.Completions: instance Data.Aeson.Types.FromJSON.FromJSON OpenAI.V1.Chat.Completions.Delta
+ OpenAI.V1.Chat.Completions: instance Data.Aeson.Types.ToJSON.ToJSON OpenAI.V1.Chat.Completions.ChatCompletionChunk
+ OpenAI.V1.Chat.Completions: instance Data.Aeson.Types.ToJSON.ToJSON OpenAI.V1.Chat.Completions.ChunkChoice
+ OpenAI.V1.Chat.Completions: instance Data.Aeson.Types.ToJSON.ToJSON OpenAI.V1.Chat.Completions.Delta
+ OpenAI.V1.Chat.Completions: instance GHC.Generics.Generic OpenAI.V1.Chat.Completions.ChatCompletionChunk
+ OpenAI.V1.Chat.Completions: instance GHC.Generics.Generic OpenAI.V1.Chat.Completions.ChunkChoice
+ OpenAI.V1.Chat.Completions: instance GHC.Generics.Generic OpenAI.V1.Chat.Completions.Delta
+ OpenAI.V1.Chat.Completions: instance GHC.Show.Show OpenAI.V1.Chat.Completions.ChatCompletionChunk
+ OpenAI.V1.Chat.Completions: instance GHC.Show.Show OpenAI.V1.Chat.Completions.ChunkChoice
+ OpenAI.V1.Chat.Completions: instance GHC.Show.Show OpenAI.V1.Chat.Completions.Delta
+ OpenAI.V1.Chat.Completions: type ChatCompletionStreamEvent = ChatCompletionChunk
- OpenAI.V1: Methods :: (CreateSpeech -> IO ByteString) -> (CreateTranscription -> IO TranscriptionObject) -> (CreateTranslation -> IO TranslationObject) -> (CreateChatCompletion -> IO ChatCompletionObject) -> (CreateResponse -> IO ResponseObject) -> (CreateResponse -> (Either Text Value -> IO ()) -> IO ()) -> (CreateEmbeddings -> IO (Vector EmbeddingObject)) -> (CreateResponse -> (Either Text ResponseStreamEvent -> IO ()) -> IO ()) -> (CreateFineTuningJob -> IO JobObject) -> (Maybe Text -> Maybe Natural -> IO (Vector JobObject)) -> (FineTuningJobID -> Maybe Text -> Maybe Natural -> IO (Vector EventObject)) -> (FineTuningJobID -> Maybe Text -> Maybe Natural -> IO (Vector CheckpointObject)) -> (FineTuningJobID -> IO JobObject) -> (FineTuningJobID -> IO JobObject) -> (CreateBatch -> IO BatchObject) -> (BatchID -> IO BatchObject) -> (BatchID -> IO BatchObject) -> (Maybe Text -> Maybe Natural -> IO (Vector BatchObject)) -> (UploadFile -> IO FileObject) -> (Maybe Purpose -> Maybe Natural -> Maybe Order -> Maybe Text -> IO (Vector FileObject)) -> (FileID -> IO FileObject) -> (FileID -> IO DeletionStatus) -> (FileID -> IO ByteString) -> (CreateUpload -> IO (UploadObject (Maybe Void))) -> (UploadID -> AddUploadPart -> IO PartObject) -> (UploadID -> CompleteUpload -> IO (UploadObject FileObject)) -> (UploadID -> IO (UploadObject (Maybe Void))) -> (CreateImage -> IO (Vector ImageObject)) -> (CreateImageEdit -> IO (Vector ImageObject)) -> (CreateImageVariation -> IO (Vector ImageObject)) -> IO (Vector ModelObject) -> (Model -> IO ModelObject) -> (Model -> IO DeletionStatus) -> (CreateModeration -> IO Moderation) -> (CreateAssistant -> IO AssistantObject) -> (Maybe Natural -> Maybe Order -> Maybe Text -> Maybe Text -> IO (Vector AssistantObject)) -> (AssistantID -> IO AssistantObject) -> (AssistantID -> ModifyAssistant -> IO AssistantObject) -> (AssistantID -> IO DeletionStatus) -> (Thread -> IO ThreadObject) -> (ThreadID -> IO ThreadObject) -> (ThreadID -> ModifyThread -> IO ThreadObject) -> (ThreadID -> IO DeletionStatus) -> (ThreadID -> Message -> IO MessageObject) -> (ThreadID -> IO (Vector MessageObject)) -> (ThreadID -> MessageID -> IO MessageObject) -> (ThreadID -> MessageID -> ModifyMessage -> IO MessageObject) -> (ThreadID -> MessageID -> IO DeletionStatus) -> (ThreadID -> Maybe Text -> CreateRun -> IO RunObject) -> (CreateThreadAndRun -> IO RunObject) -> (ThreadID -> Maybe Natural -> Maybe Order -> Maybe Text -> Maybe Text -> IO (Vector RunObject)) -> (ThreadID -> RunID -> IO RunObject) -> (ThreadID -> RunID -> ModifyRun -> IO RunObject) -> (ThreadID -> RunID -> SubmitToolOutputsToRun -> IO RunObject) -> (ThreadID -> RunID -> IO RunObject) -> (ThreadID -> RunID -> Maybe Natural -> Maybe Order -> Maybe Text -> Maybe Text -> Maybe Text -> IO (Vector RunStepObject)) -> (ThreadID -> RunID -> StepID -> Maybe Text -> IO RunStepObject) -> (Text -> IO ResponseObject) -> (Text -> IO ResponseObject) -> (Text -> IO (Vector InputItem)) -> (CreateVectorStore -> IO VectorStoreObject) -> (Maybe Natural -> Maybe Order -> Maybe Text -> Maybe Text -> IO (Vector VectorStoreObject)) -> (VectorStoreID -> IO VectorStoreObject) -> (VectorStoreID -> ModifyVectorStore -> IO VectorStoreObject) -> (VectorStoreID -> IO DeletionStatus) -> (VectorStoreID -> CreateVectorStoreFile -> IO VectorStoreFileObject) -> (VectorStoreID -> Maybe Natural -> Maybe Order -> Maybe Text -> Maybe Text -> Maybe Status -> IO (Vector VectorStoreFileObject)) -> (VectorStoreID -> VectorStoreFileID -> IO VectorStoreFileObject) -> (VectorStoreID -> VectorStoreFileID -> IO DeletionStatus) -> (VectorStoreID -> CreateVectorStoreFileBatch -> IO VectorStoreFilesBatchObject) -> (VectorStoreID -> VectorStoreFileBatchID -> IO VectorStoreFilesBatchObject) -> (VectorStoreID -> VectorStoreFileBatchID -> IO VectorStoreFilesBatchObject) -> (VectorStoreID -> VectorStoreFileBatchID -> Maybe Natural -> Maybe Order -> Maybe Text -> Maybe Text -> Maybe Status -> IO (Vector VectorStoreFilesBatchObject)) -> Methods
+ OpenAI.V1: Methods :: (CreateSpeech -> IO ByteString) -> (CreateTranscription -> IO TranscriptionObject) -> (CreateTranslation -> IO TranslationObject) -> (CreateChatCompletion -> IO ChatCompletionObject) -> (CreateChatCompletion -> (Either Text Value -> IO ()) -> IO ()) -> (CreateChatCompletion -> (Either Text ChatCompletionStreamEvent -> IO ()) -> IO ()) -> (CreateResponse -> IO ResponseObject) -> (CreateResponse -> (Either Text Value -> IO ()) -> IO ()) -> (CreateEmbeddings -> IO (Vector EmbeddingObject)) -> (CreateResponse -> (Either Text ResponseStreamEvent -> IO ()) -> IO ()) -> (CreateFineTuningJob -> IO JobObject) -> (Maybe Text -> Maybe Natural -> IO (Vector JobObject)) -> (FineTuningJobID -> Maybe Text -> Maybe Natural -> IO (Vector EventObject)) -> (FineTuningJobID -> Maybe Text -> Maybe Natural -> IO (Vector CheckpointObject)) -> (FineTuningJobID -> IO JobObject) -> (FineTuningJobID -> IO JobObject) -> (CreateBatch -> IO BatchObject) -> (BatchID -> IO BatchObject) -> (BatchID -> IO BatchObject) -> (Maybe Text -> Maybe Natural -> IO (Vector BatchObject)) -> (UploadFile -> IO FileObject) -> (Maybe Purpose -> Maybe Natural -> Maybe Order -> Maybe Text -> IO (Vector FileObject)) -> (FileID -> IO FileObject) -> (FileID -> IO DeletionStatus) -> (FileID -> IO ByteString) -> (CreateUpload -> IO (UploadObject (Maybe Void))) -> (UploadID -> AddUploadPart -> IO PartObject) -> (UploadID -> CompleteUpload -> IO (UploadObject FileObject)) -> (UploadID -> IO (UploadObject (Maybe Void))) -> (CreateImage -> IO (Vector ImageObject)) -> (CreateImageEdit -> IO (Vector ImageObject)) -> (CreateImageVariation -> IO (Vector ImageObject)) -> IO (Vector ModelObject) -> (Model -> IO ModelObject) -> (Model -> IO DeletionStatus) -> (CreateModeration -> IO Moderation) -> (CreateAssistant -> IO AssistantObject) -> (Maybe Natural -> Maybe Order -> Maybe Text -> Maybe Text -> IO (Vector AssistantObject)) -> (AssistantID -> IO AssistantObject) -> (AssistantID -> ModifyAssistant -> IO AssistantObject) -> (AssistantID -> IO DeletionStatus) -> (Thread -> IO ThreadObject) -> (ThreadID -> IO ThreadObject) -> (ThreadID -> ModifyThread -> IO ThreadObject) -> (ThreadID -> IO DeletionStatus) -> (ThreadID -> Message -> IO MessageObject) -> (ThreadID -> IO (Vector MessageObject)) -> (ThreadID -> MessageID -> IO MessageObject) -> (ThreadID -> MessageID -> ModifyMessage -> IO MessageObject) -> (ThreadID -> MessageID -> IO DeletionStatus) -> (ThreadID -> Maybe Text -> CreateRun -> IO RunObject) -> (CreateThreadAndRun -> IO RunObject) -> (ThreadID -> Maybe Natural -> Maybe Order -> Maybe Text -> Maybe Text -> IO (Vector RunObject)) -> (ThreadID -> RunID -> IO RunObject) -> (ThreadID -> RunID -> ModifyRun -> IO RunObject) -> (ThreadID -> RunID -> SubmitToolOutputsToRun -> IO RunObject) -> (ThreadID -> RunID -> IO RunObject) -> (ThreadID -> RunID -> Maybe Natural -> Maybe Order -> Maybe Text -> Maybe Text -> Maybe Text -> IO (Vector RunStepObject)) -> (ThreadID -> RunID -> StepID -> Maybe Text -> IO RunStepObject) -> (Text -> IO ResponseObject) -> (Text -> IO ResponseObject) -> (Text -> IO (Vector InputItem)) -> (CreateVectorStore -> IO VectorStoreObject) -> (Maybe Natural -> Maybe Order -> Maybe Text -> Maybe Text -> IO (Vector VectorStoreObject)) -> (VectorStoreID -> IO VectorStoreObject) -> (VectorStoreID -> ModifyVectorStore -> IO VectorStoreObject) -> (VectorStoreID -> IO DeletionStatus) -> (VectorStoreID -> CreateVectorStoreFile -> IO VectorStoreFileObject) -> (VectorStoreID -> Maybe Natural -> Maybe Order -> Maybe Text -> Maybe Text -> Maybe Status -> IO (Vector VectorStoreFileObject)) -> (VectorStoreID -> VectorStoreFileID -> IO VectorStoreFileObject) -> (VectorStoreID -> VectorStoreFileID -> IO DeletionStatus) -> (VectorStoreID -> CreateVectorStoreFileBatch -> IO VectorStoreFilesBatchObject) -> (VectorStoreID -> VectorStoreFileBatchID -> IO VectorStoreFilesBatchObject) -> (VectorStoreID -> VectorStoreFileBatchID -> IO VectorStoreFilesBatchObject) -> (VectorStoreID -> VectorStoreFileBatchID -> Maybe Natural -> Maybe Order -> Maybe Text -> Maybe Text -> Maybe Status -> IO (Vector VectorStoreFilesBatchObject)) -> Methods
- OpenAI.V1.Chat.Completions: CreateChatCompletion :: Vector (Message (Vector Content)) -> Model -> Maybe Bool -> Maybe (Map Text Text) -> Maybe Double -> Maybe (Map Word Int) -> Maybe Bool -> Maybe Word -> Maybe Natural -> Maybe Natural -> Maybe (Vector Modality) -> Maybe Prediction -> Maybe AudioParameters -> Maybe Double -> Maybe ReasoningEffort -> Maybe ResponseFormat -> Maybe Integer -> Maybe (AutoOr ServiceTier) -> Maybe (Vector Text) -> Maybe Double -> Maybe Double -> Maybe (Vector Tool) -> Maybe ToolChoice -> Maybe Bool -> Maybe Text -> Maybe WebSearchOptions -> CreateChatCompletion
+ OpenAI.V1.Chat.Completions: CreateChatCompletion :: Vector (Message (Vector Content)) -> Model -> Maybe Bool -> Maybe (Map Text Text) -> Maybe Double -> Maybe (Map Word Int) -> Maybe Bool -> Maybe Word -> Maybe Natural -> Maybe Natural -> Maybe (Vector Modality) -> Maybe Prediction -> Maybe AudioParameters -> Maybe Double -> Maybe ReasoningEffort -> Maybe ResponseFormat -> Maybe Integer -> Maybe (AutoOr ServiceTier) -> Maybe (Vector Text) -> Maybe Bool -> Maybe Double -> Maybe Double -> Maybe (Vector Tool) -> Maybe ToolChoice -> Maybe Bool -> Maybe Text -> Maybe WebSearchOptions -> CreateChatCompletion
- OpenAI.V1.Chat.Completions: [choices] :: ChatCompletionObject -> Vector Choice
+ OpenAI.V1.Chat.Completions: [choices] :: ChatCompletionChunk -> Vector ChunkChoice
- OpenAI.V1.Chat.Completions: [created] :: ChatCompletionObject -> POSIXTime
+ OpenAI.V1.Chat.Completions: [created] :: ChatCompletionChunk -> POSIXTime
- OpenAI.V1.Chat.Completions: [finish_reason] :: Choice -> Text
+ OpenAI.V1.Chat.Completions: [finish_reason] :: ChunkChoice -> Maybe Text
- OpenAI.V1.Chat.Completions: [index] :: Choice -> Natural
+ OpenAI.V1.Chat.Completions: [index] :: ChunkChoice -> Natural
- OpenAI.V1.Chat.Completions: [logprobs] :: Choice -> Maybe LogProbs
+ OpenAI.V1.Chat.Completions: [logprobs] :: ChunkChoice -> Maybe LogProbs
- OpenAI.V1.Chat.Completions: [model] :: ChatCompletionObject -> Model
+ OpenAI.V1.Chat.Completions: [model] :: ChatCompletionChunk -> Model
- OpenAI.V1.Chat.Completions: [object] :: ChatCompletionObject -> Text
+ OpenAI.V1.Chat.Completions: [object] :: ChatCompletionChunk -> Text
- OpenAI.V1.Chat.Completions: [service_tier] :: ChatCompletionObject -> Maybe ServiceTier
+ OpenAI.V1.Chat.Completions: [service_tier] :: ChatCompletionChunk -> Maybe ServiceTier
- OpenAI.V1.Chat.Completions: [system_fingerprint] :: ChatCompletionObject -> Maybe Text
+ OpenAI.V1.Chat.Completions: [system_fingerprint] :: ChatCompletionChunk -> Maybe Text
- OpenAI.V1.Chat.Completions: [usage] :: ChatCompletionObject -> Usage CompletionTokensDetails PromptTokensDetails
+ OpenAI.V1.Chat.Completions: [usage] :: ChatCompletionChunk -> Maybe (Usage CompletionTokensDetails PromptTokensDetails)

Files

CHANGELOG.md view
@@ -1,3 +1,7 @@+2.2.1:++- [Add Chat Completion Streaming Support](https://github.com/MercuryTechnologies/openai/pull/78)+ 2.2.0:  - Add structured reasoning support to `OpenAI.V1.Responses`, including the `Reasoning`, `ReasoningEffort`, and `ReasoningSummary` types, plus the `ServiceTier` alias.
+ examples/chat-completions-stream-example/Main.hs view
@@ -0,0 +1,90 @@+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE NamedFieldPuns        #-}+{-# LANGUAGE OverloadedLists       #-}+{-# LANGUAGE OverloadedStrings     #-}++module Main where++import System.Environment (getEnv)+import System.IO (hFlush, hPutStrLn, stderr, stdout)++import qualified Data.Text as T+import qualified Data.Text.IO as TIO+import qualified OpenAI.V1 as V1+import qualified OpenAI.V1.Chat.Completions as Chat++main :: IO ()+main = do+    key <- T.pack <$> getEnv "OPENAI_KEY"+    env <- V1.getClientEnv "https://api.openai.com"++    let V1.Methods{ createChatCompletionStreamTyped } = V1.makeMethods env key Nothing Nothing++    let onEvent (Left err) = hPutStrLn stderr ("stream error: " <> T.unpack err)+        onEvent (Right chunk) = case chunk of+            -- Print content deltas as they arrive+            Chat.ChatCompletionChunk{ Chat.choices = cs } ->+                mapM_ printChoice cs+              where+                printChoice Chat.ChunkChoice{ Chat.delta = d } = case Chat.delta_content d of+                    Just content -> TIO.putStr content >> hFlush stdout+                    Nothing -> pure ()++    -- 1) Simple haiku example+    putStrLn "Example 1: Simple haiku"+    putStrLn "========================"+    let reqHaiku = Chat._CreateChatCompletion+            { Chat.messages =+                [ Chat.User+                    { Chat.content = [ Chat.Text{ Chat.text = "Write a short haiku about the sea." } ]+                    , Chat.name = Nothing+                    }+                ]+            , Chat.model = "gpt-5-mini"+            }++    createChatCompletionStreamTyped reqHaiku onEvent+    putStrLn "\n"++    putStrLn "--------------------------------"++    -- 2) Conversation example+    putStrLn "Example 2: Multi-turn conversation"+    putStrLn "===================================="+    let reqConversation = Chat._CreateChatCompletion+            { Chat.messages =+                [ Chat.System+                    { Chat.content = [ Chat.Text{ Chat.text = "You are a helpful assistant that explains concepts simply." } ]+                    , Chat.name = Nothing+                    }+                , Chat.User+                    { Chat.content = [ Chat.Text{ Chat.text = "What is quantum computing in simple terms?" } ]+                    , Chat.name = Nothing+                    }+                ]+            , Chat.model = "gpt-5-mini"+            , Chat.temperature = Just 0.7+            }++    createChatCompletionStreamTyped reqConversation onEvent+    putStrLn "\n"++    putStrLn "--------------------------------"++    -- 3) Code generation example+    putStrLn "Example 3: Code generation"+    putStrLn "=========================="+    let reqCode = Chat._CreateChatCompletion+            { Chat.messages =+                [ Chat.User+                    { Chat.content = [ Chat.Text{ Chat.text = "Write a Python function that calculates fibonacci numbers recursively." } ]+                    , Chat.name = Nothing+                    }+                ]+            , Chat.model = "gpt-5-mini"+            , Chat.temperature = Just 0.3+            }++    createChatCompletionStreamTyped reqCode onEvent+    putStrLn "\n"+
openai.cabal view
@@ -1,6 +1,6 @@ cabal-version:      2.4 name:               openai-version:            2.2.0+version:            2.2.1 synopsis:           Servant bindings to OpenAI description:        This package provides comprehensive and type-safe bindings                     to OpenAI, providing both a Servant interface and@@ -125,6 +125,16 @@     hs-source-dirs:   examples/openai-example     main-is:          Main.hs     build-depends:    base+                    , openai+                    , text+    ghc-options:      -Wall++executable chat-completions-stream-example+    default-language: Haskell2010+    hs-source-dirs:   examples/chat-completions-stream-example+    main-is:          Main.hs+    build-depends:    base+                    , aeson                     , openai                     , text     ghc-options:      -Wall
src/OpenAI/V1.hs view
@@ -338,6 +338,22 @@                 Aeson.Error msg -> onEvent (Left (Text.pack msg))                 Aeson.Success e -> onEvent (Right e) +    -- Streaming implementation for chat completions+    createChatCompletionStream req onEvent = do+        let req' = req{ Chat.Completions.stream = Just True }+        ssePostJSON "/v1/chat/completions" req' onEvent++    createChatCompletionStreamTyped+        :: CreateChatCompletion+        -> (Either Text Chat.Completions.ChatCompletionStreamEvent -> IO ())+        -> IO ()+    createChatCompletionStreamTyped req onEvent =+        createChatCompletionStream req $ \ev -> case ev of+            Left err -> onEvent (Left err)+            Right val -> case Aeson.fromJSON val of+                Aeson.Error msg -> onEvent (Left (Text.pack msg))+                Aeson.Success e -> onEvent (Right e)+     ssePostJSON :: ToJSON a                 => String                 -> a@@ -465,6 +481,14 @@     , createTranscription :: CreateTranscription -> IO TranscriptionObject     , createTranslation :: CreateTranslation -> IO TranslationObject     , createChatCompletion :: CreateChatCompletion -> IO ChatCompletionObject+    , createChatCompletionStream+        :: CreateChatCompletion+        -> (Either Text Aeson.Value -> IO ())+        -> IO ()+    , createChatCompletionStreamTyped+        :: CreateChatCompletion+        -> (Either Text Chat.Completions.ChatCompletionStreamEvent -> IO ())+        -> IO ()     , createResponse :: CreateResponse -> IO ResponseObject     , createResponseStream         :: CreateResponse
src/OpenAI/V1/Chat/Completions.hs view
@@ -1,6 +1,6 @@ -- | @\/v1\/chat\/completions@ ----- Streaming results are not yet supported+-- Streaming is not implemented here; module OpenAI.V1.Chat.Completions     ( -- * Main types       CreateChatCompletion(..)@@ -10,6 +10,11 @@     , Message(..)     , messageToContent     , Content(..)+      -- * Streaming types+    , ChatCompletionChunk(..)+    , ChunkChoice(..)+    , Delta(..)+    , ChatCompletionStreamEvent       -- * Other types     , InputAudio(..)     , ImageURL(..)@@ -298,6 +303,7 @@     , seed :: Maybe Integer     , service_tier :: Maybe (AutoOr ServiceTier)     , stop :: Maybe (Vector Text)+    , stream :: Maybe Bool     , temperature :: Maybe Double     , top_p :: Maybe Double     , tools :: Maybe (Vector Tool)@@ -333,6 +339,7 @@     , seed = Nothing     , service_tier = Nothing     , stop = Nothing+    , stream = Nothing     , temperature = Nothing     , top_p = Nothing     , tools = Nothing@@ -394,6 +401,50 @@     , usage :: Usage CompletionTokensDetails PromptTokensDetails     } deriving stock (Generic, Show)       deriving anyclass (FromJSON, ToJSON)++-- | Delta message content for streaming+data Delta = Delta+    { delta_content :: Maybe Text+    , delta_refusal :: Maybe Text+    , delta_role :: Maybe Text+    , delta_tool_calls :: Maybe (Vector ToolCall)+    } deriving stock (Generic, Show)++deltaOptions :: Options+deltaOptions = aesonOptions+    { fieldLabelModifier = stripPrefix "delta_"+    }++instance FromJSON Delta where+    parseJSON = genericParseJSON deltaOptions++instance ToJSON Delta where+    toJSON = genericToJSON deltaOptions++-- | A streaming choice chunk+data ChunkChoice = ChunkChoice+    { delta :: Delta+    , finish_reason :: Maybe Text+    , index :: Natural+    , logprobs :: Maybe LogProbs+    } deriving stock (Generic, Show)+      deriving anyclass (FromJSON, ToJSON)++-- | Chat completion chunk (streaming response)+data ChatCompletionChunk = ChatCompletionChunk+    { id :: Text+    , choices :: Vector ChunkChoice+    , created :: POSIXTime+    , model :: Model+    , service_tier :: Maybe ServiceTier+    , system_fingerprint :: Maybe Text+    , object :: Text+    , usage :: Maybe (Usage CompletionTokensDetails PromptTokensDetails)+    } deriving stock (Generic, Show)+      deriving anyclass (FromJSON, ToJSON)++-- | Type alias for streaming events (currently just chunks)+type ChatCompletionStreamEvent = ChatCompletionChunk  -- | Servant API type API =
tasty/Main.hs view
@@ -14,7 +14,7 @@ import OpenAI.V1.Audio.Translations (CreateTranslation(..)) import OpenAI.V1.AutoOr (AutoOr(..)) import OpenAI.V1.Batches (BatchObject(..), CreateBatch(..))-import OpenAI.V1.Chat.Completions (CreateChatCompletion(..), Modality(..))+import OpenAI.V1.Chat.Completions (CreateChatCompletion(..), Modality(..), ChatCompletionChunk(..), ChunkChoice(..), delta_content) import OpenAI.V1.Embeddings (CreateEmbeddings(..), EncodingFormat(..)) import OpenAI.V1.Files (FileObject(..), Order(..), UploadFile(..)) import OpenAI.V1.Images.Edits (CreateImageEdit(..))@@ -178,6 +178,7 @@                   seed = Nothing,                   service_tier = Nothing,                   stop = Nothing,+                  stream = Nothing,                   temperature = Nothing,                   top_p = Nothing,                   tools = Nothing,@@ -218,6 +219,7 @@                   seed = Nothing,                   service_tier = Nothing,                   stop = Nothing,+                  stream = Nothing,                   temperature = Nothing,                   top_p = Nothing,                   tools = Nothing,@@ -279,6 +281,7 @@                   seed = Just 0,                   service_tier = Just Auto,                   stop = Just [">>>"],+                  stream = Nothing,                   temperature = Just 1,                   top_p = Just 1,                   tools =@@ -302,6 +305,65 @@            return () +  let chatCompletionStreamingHaikuTest = do+        HUnit.testCase "Create chat completion - streaming haiku" do+              let req =+                    CreateChatCompletion+                        { messages =+                            [ Completions.User+                                { content = ["Hello, world!"],+                                  name = Nothing+                                }+                            ],+                          model = chatModel,+                          store = Nothing,+                          metadata = Nothing,+                          frequency_penalty = Nothing,+                          logit_bias = Nothing,+                          logprobs = Nothing,+                          top_logprobs = Nothing,+                          max_completion_tokens = Nothing,+                          n = Nothing,+                          modalities = Nothing,+                          prediction = Nothing,+                          audio = Nothing,+                          presence_penalty = Nothing,+                          reasoning_effort = Nothing,+                          response_format = Nothing,+                          seed = Nothing,+                          service_tier = Nothing,+                          stop = Nothing,+                          stream = Nothing,+                          temperature = Nothing,+                          top_p = Nothing,+                          tools = Nothing,+                          tool_choice = Nothing,+                          parallel_tool_calls = Nothing,+                          user = Nothing,+                          web_search_options = Nothing+                        }++              acc <- IORef.newIORef (Text.empty)+              done <- Concurrent.newEmptyMVar++              let onEvent (Left _err) = Concurrent.putMVar done ()+                  onEvent (Right ev) = case ev of+                    ChatCompletionChunk{ choices = cs } ->+                        mapM_ accChoice cs+                      where+                        accChoice ChunkChoice{ delta = d } = case delta_content d of+                            Just content -> IORef.modifyIORef' acc (<> content)+                            Nothing -> Concurrent.putMVar done ()++              createChatCompletionStreamTyped req onEvent++              _ <- Concurrent.takeMVar done+              text <- IORef.readIORef acc+              HUnit.assertBool "Expected non-empty streamed text" (not (Text.null text))++              return ()+          +   let embeddingsTest = do         HUnit.testCase "Create embedding" do           _ <-@@ -1039,6 +1101,7 @@                completionsMinimalTest,                completionsMinimalReasoningTest,                completionsMaximalTest,+               chatCompletionStreamingHaikuTest,                embeddingsTest,                fineTuningTest,                batchesTest,