baikai-typesafe
TypeSafe System One judgments for Baikai. Install baikai-typesafe with baikai.
Register Baikai.Provider.TypeSafe.Api.typesafeProvider explicitly, select
Baikai.Models.Generated.typesafe_jev_latest, send contextOf [userData state],
and set Options.responseFormat to JsonSchema (jsonSchemaFormat "ticket" schema).
Use flattenAssistantData to read chosen values, complete distributions and
provider confidence. Both complete and synthetic streaming calls work.
Set TYPESAFE_API_KEY for the official host. Custom base URLs require an explicit
Options.apiKey source; model and option header overrides are case-insensitive.
Generation, reasoning, tool choice, speed, system prompts and history are refused
before dispatch. Clear generation defaults after routing with isJudgmentOnly.
See the repository guide at docs/user/typesafe-judgments.md and the compiled
CAP-27 example in docs/capabilities/typesafe-judgments.md for schema declarations,
probabilities, typed errors, base overrides, persistence and consumer migration.
The provider depends on released typesafe-hs ^>=0.1.0.0, uses core transport
classification and runs no retry loop. Answer evidence is content, independent of
optional per-call evidence.
TypeSafe judgments
Add baikai-typesafe ^>=0.1.0.0 and baikai ^>=0.9.0 to the Cabal
dependencies. Both packages are available on Hackage.
The provider uses the released typesafe-hs ^>=0.1.0.0 wire client without a
checkout override.
Register Baikai.Provider.TypeSafe.Api.typesafeProvider with
registerApiProviderWith on your explicit registry. Select
Baikai.Models.Generated.typesafe_jev_latest or typesafe_jev_preview.
isJudgmentOnly model queries the catalog fact; provider names and jev- prefixes
are not routing rules.
Supply contextOf [userData state] with a JSON string, object or array, or one
user text message. Put a JsonSchema (jsonSchemaFormat "ticket" schemaValue)
in Options.responseFormat. The schema must be an object with nonempty
properties. A boolean asks a predicate; a distinct string enum asks a choice
(1ā255 labels); an integer enum containing exactly 0 to Nā1 asks a score
(2ā10 levels). Described anyOf or oneOf const branches attach choice/level
criteria, including true/false predicate criteria. Property descriptions become
instructions, defaulting to the property name. Instructions and descriptions
must be text, objects or arrays, with null allowed only for optional criteria.
Missing score descriptions use their decimal indices.
Question order follows required when it lists every property exactly once;
otherwise it is ascending property key. All properties are answered. Unsupported
schema constraints are refused by path. additionalProperties, when supplied,
must be false. JsonSchemaFormat.name and strict are local metadata.
A complete example is the repository CAP-27 record; its shape
compiles in baikai-smoke:test:doc-shapes. The exact three-question request and
response are in baikai-typesafe/test/fixtures/ and are exercised against a local
HTTP fixture by the provider's offline suite.
The official host resolves TYPESAFE_API_KEY; an explicit Options.apiKey wins.
Custom gateways require an explicit source, including ApiKeyEnv "TYPESAFE_API_KEY" if forwarding that credential is intentional. Override
Model.baseUrl with a root or trailing /v1; gateway prefixes are retained.
Header precedence is provider defaults, model headers, then option headers,
case-insensitively. Redirects are disabled. A positive timeoutMs bounds the
whole call including body reading; cancellation closes the response. There are
no internal retries.
Read flattenAssistantData (response ^. #message . #content). Each block carries
value, optional probabilities, optional confidence, and
method = Just "provider_classification". Predicates use true at probability
ā„0.5; choices preserve the selected label even when it is not the argmax;
TypeSafe scores preserve the reported expected score, including fractions.
Neither confidence nor score is derived locally. Distributions need not sum to
one. Baikai checks finite values, declared answer names and keys, required wire
fields and score legends before emitting data.
Both complete and stream dispatch work. The wire call is non-streaming; events
are EventStart, DataStart, DataEnd, EventDone, or an error terminal without
a data success event. Local unsupported inputs return non-retryable
InvalidRequest with UnsupportedFeature path; the recognized upstream
unknown-model error supplies UnsupportedModel id. Malformed replies are
DecodeFailure. HTTP status and transport failures use core classification.
Every explicit generation, sampling, reasoning, speed and tool-choice control
is refused, including explicit standard speed. An absent control, empty stop
sequences and CacheRetentionNone pass. System prompts, tools and multi-turn
history are refused. Transport options, metadata and evidence stay available;
metadata remains local. Unknown catalog prices are unavailable estimates.
Answer probabilities and confidence are content. They survive named
Baikai.Response.JSON.responseToJSON / responseFromJSON, terminal traces, call
logs and OpenTelemetry even without call evidence opt-in. Optional call evidence
separately records the actual request, observed model, usage and
x-typesafe-request-id; it never substitutes a requested model for an observation.
For mori://shinzui/shikumi/plans/63-declare-decision-outputs-and-route-them-to-system-one-models,
route on isJudgmentOnly before generative structured-output capability checks,
clear post-routing generation defaults, send one UserData, and retain
AssistantData in the consumer's existing response codec. Compare its schema
reader against compileJudgments, including the question-order rule. Do not add
conflicting Response instances or reuse cached call evidence as a fresh
observation. Cached answers can retain their distributions after removing
per-call evidence.
The live suite skips unless explicitly selected, even when a key exists:
cabal test baikai-smoke:test:typesafe-live
cabal test baikai-smoke:test:typesafe-live --test-options='--live'
The second command performs one paid call and requires a nonempty key. Offline
fixture success is separate from live verification.
Minimal request
This uses the same public calls compiled by the doc-shapes and selected live suites:
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE OverloadedStrings #-}
module Main (main) where
import Baikai
import Baikai.Models.Generated (typesafe_jev_latest)
import Baikai.Provider.TypeSafe.Api (typesafeProvider)
import Control.Lens ((&), (.~), (^.))
import Data.Generics.Labels ()
import Data.Aeson qualified as Aeson
import Data.Text (Text)
main :: IO ()
main = do
registry <- newProviderRegistry
registerApiProviderWith registry typesafeProvider
let questionSchema = Aeson.object
[ "type" Aeson..= ("object" :: Text)
, "properties" Aeson..= Aeson.object
[ "urgent" Aeson..= Aeson.object
[ "type" Aeson..= ("boolean" :: Text)
, "description" Aeson..= ("Is service blocked?" :: Text)
]
]
, "additionalProperties" Aeson..= False
]
state = Aeson.object ["ticket" Aeson..= ("Checkout is unavailable." :: Text)]
context = contextOf [userData state]
options = emptyOptions & #responseFormat .~ Just (JsonSchema (jsonSchemaFormat "ticket" questionSchema))
response <- completeRequestWith registry typesafe_jev_latest context options
case responseError response of
Just err -> print err
Nothing -> print (flattenAssistantData (response ^. #message . #content))