packages feed

baikai-0.1.0.0: src/Baikai/StopReason.hs

{-# LANGUAGE LambdaCase #-}

-- | Why the model stopped generating.
--
-- A small closed sum populated on every 'Baikai.Message.AssistantMessage'.
-- API providers map their per-vendor stop reason onto this enum; CLI
-- providers populate @Stop@ on success and @ErrorReason@ when the
-- subprocess reports an error.
--
-- Constructor encoding on the wire is snake-case: @"stop"@, @"length"@,
-- @"tool_use"@, @"error"@, @"aborted"@. @ErrorReason@ is renamed to
-- @"error"@ so the Haskell name does not clash with @Prelude.Either.Left@
-- callers and the wire shape stays terse.
module Baikai.StopReason (StopReason (..)) where

import Data.Aeson
  ( FromJSON (parseJSON),
    Options (..),
    ToJSON (toJSON),
    defaultOptions,
    genericParseJSON,
    genericToJSON,
  )
import Data.Char (toLower)
import GHC.Generics (Generic)

data StopReason
  = Stop
  | Length
  | ToolUse
  | ErrorReason
  | Aborted
  deriving stock (Eq, Show, Generic)

stopReasonOptions :: Options
stopReasonOptions =
  defaultOptions
    { constructorTagModifier = \case
        "ErrorReason" -> "error"
        s -> camelToSnake s
    }
  where
    camelToSnake :: String -> String
    camelToSnake [] = []
    camelToSnake (c : cs) = toLower c : go cs
      where
        go [] = []
        go (x : xs)
          | x `elem` ['A' .. 'Z'] = '_' : toLower x : go xs
          | otherwise = x : go xs

instance FromJSON StopReason where parseJSON = genericParseJSON stopReasonOptions

instance ToJSON StopReason where toJSON = genericToJSON stopReasonOptions