packages feed

baikai-claude 0.7.1.1 → 0.7.2.0

raw patch · 9 files changed

+195/−38 lines, 9 filesdep ~baikaiPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: baikai

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -7,6 +7,91 @@  ## [Unreleased] +## [baikai 0.9.0.0] - 2026-10-25++### Added++- `Baikai.Judgment` compiles closed-set schemas into ordered questions, refuses+  generation controls and validates neutral answers without normalizing provider+  probabilities or deriving confidence and expected scores.+- `UserData`, `AssistantData`/`DataContent`, user-data message helpers, atomic+  data events, and named full-response JSON codecs preserve structured answers.+- `TypeSafeSystemOne`, catalog-owned `OutputKind`/`isJudgmentOnly`, `InputData`,+  and `typesafe_jev_latest`/`typesafe_jev_preview`. Legacy model JSON defaults to+  generative output. Register the new `baikai-typesafe` provider explicitly.++### Changed (breaking)++- Public content/event sums and model, error, trace and log records gain fields+  or constructors. Update exhaustive matches and record construction on upgrade.+- Terminal traces and both call-log paths preserve structured answer payloads.+  Evidence schema 2.6 includes structured response commitments and typed request+  problems; existing digest rules are unchanged.++## [baikai-typesafe 0.1.0.0] - 2026-10-25++### Added++- Initial explicitly registered TypeSafe System One provider using the released+  `typesafe-hs ^>=0.1.0.0` wire client. Strict request and response validation,+  atomic synthetic streaming, truthful call evidence, bounded HTTP calls and an+  opt-in live test. No retry policy is embedded.+- Installation, schema, refusal and consumer migration guide, plus CAP-27.++## [baikai-claude 0.7.2.0] - 2026-10-25++### Changed++- Require `baikai ^>=0.9.0`, encode user data as canonical JSON text, and refuse+  structured assistant history before dispatch with a typed field path.++### Fixed++- The offline cancellation fixture waits until the response reader is active+  before cancelling, eliminating a fixed-startup-delay race under build load.++## [baikai-openai 0.7.2.0] - 2026-10-25++### Changed++- Require `baikai ^>=0.9.0`, encode user data as canonical JSON text, and refuse+  structured assistant history before dispatch with a typed field path across+  Chat Completions, Responses and batch CLI calls.++### Fixed++- The offline cancellation fixture waits until the response reader is active+  before cancelling, eliminating a fixed-startup-delay race under build load.++## [baikai-trace-otel 0.4.1.0] - 2026-10-25++### Added++- Export structured answer data as canonical JSON under+  `baikai.response.structured_data`, on success and failure terminals.++### Changed++- Require `baikai ^>=0.9.0` for the expanded trace protocol.++## [baikai-effectful 0.4.0.4] - 2026-10-25++### Changed++- Require `baikai ^>=0.9.0`. Dependency-only update; no package API change.++## [baikai-kit 0.4.0.2] - 2026-10-25++### Changed++- Require `baikai ^>=0.9.0`. Dependency-only update; no package API change.++## [baikai-agent 0.2.0.3] - 2026-10-25++### Changed++- Require `baikai ^>=0.9.0`. Dependency-only update; no package API change.+ ## [baikai 0.8.0.0] - 2026-10-10  ### Added
baikai-claude.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.4 name: baikai-claude-version: 0.7.1.1+version: 0.7.2.0 synopsis: Anthropic Claude providers for the baikai abstraction description:   Anthropic backends for baikai: the Messages API over SSE, the claude -p batch@@ -72,7 +72,7 @@   autogen-modules: Paths_baikai_claude   build-depends:     aeson ^>=2.2,-    baikai ^>=0.8.0,+    baikai ^>=0.9.0,     base >=4.20 && <5,     base16-bytestring ^>=1.0,     base64-bytestring ^>=1.2,@@ -106,6 +106,7 @@     CliEvidenceSpec     CliProcessFixture     Contract+    DataInputSpec     ErrorClassSpec     EvidenceSpec     FableContractsSpec@@ -125,7 +126,7 @@    build-depends:     aeson,-    baikai ^>=0.8.0,+    baikai ^>=0.9.0,     baikai-claude,     base >=4.20 && <5,     bytestring,
src/Baikai/Provider/Claude/Cli.hs view
@@ -50,6 +50,7 @@ import Baikai.Api (Api (..)) import Baikai.Content (AssistantContent (..), TextContent (..)) import Baikai.Context (Context)+import Baikai.Context qualified as Context import Baikai.Error (BaikaiError, decodeError, processError, providerError) import Baikai.Evidence qualified as Ev import Baikai.Evidence.Build qualified as Build@@ -70,6 +71,7 @@ import Baikai.ThinkingLevel (ThinkingLevel (ThinkingMinimal), renderThinkingLevel) import Baikai.Usage (Usage, zeroUsage) import Control.Exception (SomeException, displayException, fromException)+import Control.Exception qualified import Control.Lens ((&), (.~), (^.)) import Data.Aeson qualified as Aeson import Data.ByteString qualified as BS@@ -220,6 +222,7 @@  runClaudeCli :: ClaudeCliConfig -> Model -> Context -> Options -> IO Resp.Response runClaudeCli cfg m ctx opts = do+  either Control.Exception.throwIO pure (Context.refuseAssistantDataHistory ctx)   let (exe, args) = claudeCliCommand cfg m ctx opts   start <- getCurrentTime   executed <-
src/Baikai/Provider/Claude/Internal/Request.hs view
@@ -23,6 +23,8 @@ import Baikai.Compat (AnthropicMessagesCompat (..), AnthropicThinkingStyle (..)) import Baikai.Content qualified as Content import Baikai.Context (Context (..))+import Baikai.Context qualified as Context+import Baikai.Error qualified as Error import Baikai.Evidence   ( ThinkingAdjustment (..),     ThinkingMode (..),@@ -79,6 +81,7 @@ mapRequest ::   Model -> Context -> Options -> Either Text (Messages.CreateMessage, ThinkingTranslation) mapRequest m ctx opts = do+  either (Left . Error.message) pure (Context.refuseAssistantDataHistory ctx)   case opts ^. #toolChoice of     Just Tool.ToolChoiceRequired | not (anthropicMessagesCompatFor m).supportsForcedToolChoice -> unsupportedForcedChoice     Just (Tool.ToolChoiceSpecific _) | not (anthropicMessagesCompatFor m).supportsForcedToolChoice -> unsupportedForcedChoice@@ -616,6 +619,7 @@     | Text.null t -> Nothing     | otherwise ->         Just Messages.Content_Text {Messages.text = t, Messages.cache_control = Nothing}+  Content.UserData v -> userContentToBlock (Content.UserText (Content.TextContent (Content.canonicalDataText v)))   Content.UserImage img ->     Just       Messages.Content_Image@@ -649,6 +653,7 @@                 Messages.signature = sig               }         Nothing -> Nothing+  Content.AssistantData _ -> Nothing   Content.AssistantToolCall tc ->     Just       Messages.Content_Tool_Use
src/Baikai/Provider/Claude/Internal/Stream.hs view
@@ -32,6 +32,7 @@ import Baikai.CacheRetention (CacheRetention (..)) import Baikai.Content qualified as Content import Baikai.Context (Context (..))+import Baikai.Context qualified as Context import Baikai.Cost (CostEstimateReason (CacheDurationNotReported, SpeedNotReported), estimateCost) import Baikai.Cost.Pricing qualified as Pricing import Baikai.Error (BaikaiError, contentFiltered, invalidRequest, providerError)@@ -208,37 +209,39 @@  prepareCall ::   Model -> Context -> Options -> IO (Either BaikaiError ClaudeCall)-prepareCall m ctx opts = do-  case mapRequest m ctx opts of-    Left e -> pure (Left (invalidRequest e))-    Right (req, translation) -> do-      let url = resolvedBaseUrl m-          compat = anthropicMessagesCompatFor m-          version = Just "2023-06-01"-      -- Checked before the key is resolved, so a base URL baikai will-      -- not send to never causes a credential to be read out of the-      -- environment. The message names the problem and what to write-      -- instead; it renders the URL without its userinfo or query, so an-      -- error reaching a log cannot carry a key someone put in either.-      case Url.baseUrlProblem url of-        Just problem ->-          pure (Left (invalidRequest ("Model.baseUrl is not usable: " <> problem)))-        Nothing -> do-          key <- Transport.resolveKey url opts-          env <- Transport.getClientEnvCached url-          let body = streamRequestBody compat ctx opts req-              headers = Transport.requestHeaders key version compat ctx m opts-          pure-            ( Right-                ClaudeCall-                  { clientEnv = env,-                    requestHeaders = headers,-                    timeoutMs = opts ^. #timeoutMs,-                    requestBody = body,-                    baseUrl = url,-                    thinking = translation-                  }-            )+prepareCall m ctx opts+  | Left e <- Context.refuseAssistantDataHistory ctx = pure (Left e)+  | otherwise = do+      case mapRequest m ctx opts of+        Left e -> pure (Left (invalidRequest e))+        Right (req, translation) -> do+          let url = resolvedBaseUrl m+              compat = anthropicMessagesCompatFor m+              version = Just "2023-06-01"+          -- Checked before the key is resolved, so a base URL baikai will+          -- not send to never causes a credential to be read out of the+          -- environment. The message names the problem and what to write+          -- instead; it renders the URL without its userinfo or query, so an+          -- error reaching a log cannot carry a key someone put in either.+          case Url.baseUrlProblem url of+            Just problem ->+              pure (Left (invalidRequest ("Model.baseUrl is not usable: " <> problem)))+            Nothing -> do+              key <- Transport.resolveKey url opts+              env <- Transport.getClientEnvCached url+              let body = streamRequestBody compat ctx opts req+                  headers = Transport.requestHeaders key version compat ctx m opts+              pure+                ( Right+                    ClaudeCall+                      { clientEnv = env,+                        requestHeaders = headers,+                        timeoutMs = opts ^. #timeoutMs,+                        requestBody = body,+                        baseUrl = url,+                        thinking = translation+                      }+                )  -- | Worker body: drive the SDK's typed callback, forwarding events onto -- the frame queue. Any synchronous exception is converted into a
src/Baikai/Provider/Claude/Transport.hs view
@@ -149,7 +149,8 @@       httpStatus = Nothing,       retryAfterSeconds = Nothing,       exitCode = Nothing,-      refusalCategory = Nothing+      refusalCategory = Nothing,+      requestProblem = Nothing     }  -- | Apply caller overrides over the provider's own headers.
+ test/DataInputSpec.hs view
@@ -0,0 +1,54 @@+module DataInputSpec (tests) where++import Baikai+import Baikai.Prelude+import Baikai.Provider.Claude.Cli qualified as Cli+import Baikai.Provider.Claude.Internal.Request qualified as R+import Baikai.Provider.Claude.Internal.Stream qualified as S+import Control.Exception (try)+import Data.Aeson qualified as A+import Data.ByteString.Lazy.Char8 qualified as BL+import Data.IORef+import Data.Text qualified as T+import Data.Vector qualified as V+import Streamly.Data.Stream qualified as Stream+import Test.Tasty+import Test.Tasty.HUnit++modelFixture :: Model+modelFixture = emptyModel & #modelId .~ "fixture" & #api .~ AnthropicMessages++dataFixture :: A.Value+dataFixture = A.object ["z" A..= [1 :: Int, 2], "a" A..= ("日本語" :: T.Text)]++history :: Context+history = contextOf [AssistantMessage ((emptyResponse ^. #message) & #content .~ V.singleton (AssistantData (DataContent A.Null Nothing Nothing Nothing)))]++tests :: TestTree+tests =+  testGroup+    "structured input and history"+    [ testCase "actual wire request contains canonical JSON in block position" $ do+        let ctx = contextOf [UserMessage (UserPayload (V.fromList [UserText (TextContent "before"), UserData dataFixture, UserText (TextContent "after")]) Nothing)]+        req <- either (assertFailure . T.unpack) pure (R.mapRequest modelFixture ctx emptyOptions)+        let wire = A.toJSON (fst req)+            bytes = BL.unpack (A.encode wire)+            jsonText = BL.unpack (A.encode (canonicalDataText dataFixture))+        assertBool ("structured text missing: " <> bytes) (T.pack jsonText `T.isInfixOf` T.pack bytes),+      testCase "AnthropicMessages refuses assistant data with zero driver calls" $ do+        calls <- newIORef (0 :: Int)+        let driver _ _ _ = modifyIORef' calls (+ 1)+        es <- Stream.toList (S.claudeMessagesStreamWith driver modelFixture history emptyOptions)+        readIORef calls >>= (@?= 0)+        case [e | EventError p <- es, Just e <- [p ^. #errorInfo]] of+          [e] -> e ^. #requestProblem @?= Just (UnsupportedFeature "messages[0].content[0]")+          _ -> assertFailure (show es),+      testCase "CLI request carries JSON and refuses data history before spawning" $ do+        let cfg = Cli.defaultClaudeCliConfig & #executable .~ "/nonexistent-baikai-data-test"+            (_, args) = Cli.claudeCliCommand cfg modelFixture (contextOf [userData dataFixture]) emptyOptions+        assertBool "canonical JSON reaches argument vector" (any (T.isInfixOf (canonicalDataText dataFixture) . T.pack) args)+        result <- try ((Cli.claudeCliProvider cfg ^. #complete) modelFixture history emptyOptions) :: IO (Either BaikaiError Response)+        case result of+          Left e -> e ^. #requestProblem @?= Just (UnsupportedFeature "messages[0].content[0]")+          Right r -> assertFailure (show r)+    ]
test/LifecycleSpec.hs view
@@ -100,11 +100,14 @@                 (claudeMessagesStreamWith (countingDriver reads' closedRef (Just gate)) testModel emptyContext testOptions)             )         putMVar outcome (r :: Either SomeException [AssistantMessageEvent])-    threadDelay 100000+    -- Wait for the driver to enter its bracket and reach the blocked read.+    -- A startup delay can cancel before a response exists under build load.+    ready <- pollFor 200 10000 ((>= 4) <$> readIORef reads')     throwTo tid ThreadKilled+    r <- takeMVar outcome+    assertBool "consumer reached the blocked response read before cancellation" ready     released <- pollFor 100 10000 (readIORef closedRef)     assertBool "cancellation releases the connection without a GC" released-    r <- takeMVar outcome     case r of       Left e | Just ThreadKilled <- fromException e -> pure ()       other -> assertFailure ("expected the drained thread to die by ThreadKilled, got: " <> show (fmap length other))
test/Main.hs view
@@ -29,6 +29,7 @@ import Data.Generics.Labels () import Data.Text qualified as Text import Data.Vector qualified as Vector+import DataInputSpec qualified import ErrorClassSpec qualified import EvidenceSpec qualified import FableContractsSpec qualified@@ -53,7 +54,8 @@   defaultMain $     testGroup       "Baikai.Provider.Claude"-      [ commandRenderingTest,+      [ DataInputSpec.tests,+        commandRenderingTest,         effortRenderingTests,         safetyRefusalTest,         safetyStillRendersTest,