typesafe-hs: Wire types and servant client for the TypeSafe System One API

[ ai, bsd3, library, web ] [ Propose Tags ] [ Report a vulnerability ]

Haskell types, deterministic request encoding and lossless response decoding for the TypeSafe System One API, mirroring the vendored OpenAPI 0.2.0 document, plus servant routes and authenticated client methods. Applications own retries, failure classification, credentials, logging and timeout policy.


[Skip to Readme]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

  • No Candidates
Versions [RSS] 0.1.0.0
Change log CHANGELOG.md
Dependencies aeson (>=2.2 && <2.3), base (>=4.20 && <5), bytestring (>=0.12 && <0.13), containers (>=0.7 && <0.8), http-client-tls (>=0.3.5 && <0.5), http-types (>=0.12 && <0.13), scientific (>=0.3 && <0.4), servant (>=0.20.3 && <0.21), servant-client (>=0.20 && <0.21), servant-client-core (>=0.20.3 && <0.22), text (>=2.1 && <2.2), time (>=1.14 && <1.15), vector (>=0.13 && <0.14) [details]
Tested with ghc ==9.12.4
License BSD-3-Clause
Copyright Copyright (c) 2026 Nadeem Bitar
Author Nadeem Bitar
Maintainer nadeem@gmail.com
Uploaded by shinzui at 2026-10-25T11:40:23Z
Category AI, Web
Home page https://github.com/shinzui/typesafe-hs
Bug tracker https://github.com/shinzui/typesafe-hs/issues
Source repo head: git clone https://github.com/shinzui/typesafe-hs.git
Distributions
Reverse Dependencies 1 direct, 0 indirect [details]
Downloads 0 total (0 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs uploaded by user
Build status unknown [no reports yet]

Readme for typesafe-hs-0.1.0.0

[back to package description]

typesafe-hs

Haskell wire types, deterministic JSON codecs and a servant client for TypeSafe's System One API. Version 0.1.0.0 targets the vendored OpenAPI 0.2.0 document fetched on 2026-10-24, including all 21 schemas, box questions, inline image assets and the model listing.

Use GHC 9.12.4. Add typesafe-hs ^>=0.1 to your application's Cabal dependencies. TypeSafe.Wire exports the wire surface; TypeSafe.V1 exports the shared servant API, named routes and authenticated methods. The example also imports bytestring, containers, text and vector, so list those dependencies in your application.

The example prints the exact request bytes and calls the API. Credential lookup belongs to the application. The same module is compiled by the test suite; tests exercise its pure request construction without making a live API call.

{-# LANGUAGE GHC2024 #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}

module TypeSafe.ReadmeExample (main, request) where

import Data.ByteString.Lazy.Char8 qualified as LBS
import Data.Map.Strict qualified as Map
import Data.Text qualified as Text
import Data.Vector qualified as Vector
import System.Environment (lookupEnv)
import TypeSafe.V1
import TypeSafe.Wire

request :: SystemOneRequest
request =
  SystemOneRequest
    { model = jevLatest,
      state = ContentText "Checkout is unavailable.",
      questions =
        Vector.singleton
          ("urgent", QuestionNoul (NoulQuestion (Just (ContentText "Is service blocked?")) Nothing)),
      assets = Map.empty
    }

main :: IO ()
main = do
  LBS.putStrLn (encodeSystemOneRequest request)
  key <- maybe (fail "Set TYPESAFE_API_KEY") (pure . Text.pack) =<< lookupEnv "TYPESAFE_API_KEY"
  env <- getClientEnv defaultBaseUrl
  let methods = makeMethods env key
  response <- methods.createSystemOne request
  print response.answers
  print response.usage.inputTokens

The client accepts a caller-supplied servant ClientEnv. getClientEnv is a convenience using the TLS manager's defaults; construct your own environment to configure its manager. Failures throw servant-client's unchanged ClientError, preserving the raw status, headers and bytes in FailureResponse. parseErrorBody is a separate pure helper.

The library adds no retries, status classification, credential or base-URL environment lookup, logging, or timeout policy beyond the supplied manager. JSON bodies support inline images via Asset.dataBase64; multipart uploads are deferred. Enable image or long-context headers with createSystemOneWith and DangerZone.

Request questions and choice criteria encode in vector order. encodeSystemOneRequest returns the exact bytes servant sends. Duplicate names and labels are preserved and reported by duplicateQuestionNames and duplicateChoiceLabels; validate them before sending. Decoding JSON objects does not recover declaration order. Optional nullable content is omitted for Nothing; a choice-criteria value of Nothing encodes as JSON null.

Probabilities, confidences and scores remain Scientific, including extreme exponents. Required keys must be present, integral counts must fit Int, and unknown question or answer tags remain explicit QuestionOther or AnswerOther values. Wire decoders leave semantic validation to the caller. ValidationError.input is the current API's optional string preview.

Fields use plain names and the library exports no field selector functions such as model, state or left. Enable OverloadedRecordDot to read fields. Wire types derive Generic, so applications can also use generic-lens #label access and updates by importing Data.Generics.Labels (); the library takes no lens dependency.

Run nix develop -c cabal test all for codec, golden, loopback, README and OpenAPI conformance checks. scripts/check-spec-drift.sh fetches and compares the published document, returning 0 for current, 1 for drift and 2 for a fetch or parse error. It writes only with --write. To assess another document without replacing the baseline, run the tests with TYPESAFE_OPENAPI_SPEC=/path/to/openapi.json.