packages feed

agentic-0.2.0.0: src/Agentic/Schema.hs

-- | The schema of a 'Agentic.Contract.Contract'. It's richer than any one
-- provider's wire format; provider packages lower it to what they accept.
module Agentic.Schema
  ( Schema (..)
  , Shape (..)
  , Field (..)
  , Variant (..)
  , Format (..)
  , schemaOf
  , documentSchema
  , typeLabel
  , titled
  ) where

import Data.Text (Text)

data Schema = Schema
  { title :: Maybe Text
    -- ^ The type's name, e.g. @Joke@. Providers use it to name schemas.
  , doc :: Maybe Text
  , checks :: [Text]
    -- ^ Constraints the wire schemas can't express, stated for the model and
    -- checked locally.
  , shape :: Shape
  }
  deriving (Eq, Show)

data Shape
  = SObject [Field]
  | SSum [Variant]
    -- ^ A tagged union: each variant is an object with a @tag@ field.
  | SEnum [(Text, Maybe Text)]
    -- ^ A choice of labels, each with an optional description.
  | SArray Schema
  | SNullable Schema
  | SString (Maybe Format)
  | SInteger
  | SNumber
  | SBool
  | SNull
  deriving (Eq, Show)

data Field = Field
  { fieldName :: Text
  , fieldSchema :: Schema
  , fieldRequired :: Bool
  }
  deriving (Eq, Show)

data Variant = Variant
  { variantTag :: Text
  , variantDoc :: Maybe Text
  , variantFields :: [Field]
  }
  deriving (Eq, Show)

data Format = DateTime | Date | Email | Uri | Uuid
  deriving (Eq, Show)

schemaOf :: Shape -> Schema
schemaOf = Schema Nothing Nothing []

documentSchema :: Text -> Schema -> Schema
documentSchema d s = s {doc = Just d}

-- | Name the schema's type, unless it already has a name.
titled :: Text -> Schema -> Schema
titled t s = s {title = maybe (Just t) Just (title s)}

-- | A short label for display, e.g. in 'Agentic.Describe.describe'.
typeLabel :: Schema -> Text
typeLabel s = maybe (structural (shape s)) id (title s)
  where
    structural = \case
      SObject _ -> "object"
      SSum [] -> "sum"
      SSum vs -> "sum of " <> joinTags (map variantTag vs)
      SEnum ls -> "one of " <> joinTags (map fst ls)
      SArray inner -> "[" <> typeLabel inner <> "]"
      SNullable inner -> typeLabel inner <> "?"
      SString _ -> "text"
      SInteger -> "integer"
      SNumber -> "number"
      SBool -> "bool"
      SNull -> "()"
    joinTags ts = mconcat (zipWith (<>) ("" : repeat "|") ts)