packages feed

baikai-0.5.0.0: CHANGELOG.md

# Changelog

All notable changes to baikai are recorded here.

The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [baikai 0.5.0.0] - 2026-08-05

### Added

- `baikai`: new exposed module `Baikai.Agent`, the provider-neutral vocabulary
  for an **unattended coding-agent run** — a run with no terminal and no human,
  which owns its own tool loop, may change files inside directories the caller
  authorized, and returns a process result rather than a `Response`. It defines
  `AgentRunRequest` (with a required `workingDir`), `AgentRunResult`, the
  `AgentCapability` profile (`read-only`, `edit-workspace`, `full-access`),
  `AgentSafety`, the `AgentOutputMode` and `AgentCapturedOutput` output
  discipline, the `AgentCommand` renderer/runner boundary with an explicit
  prompt transport, and the `AgentRenderError` / `AgentRunFailure` taxonomies.

- `baikai`: the operator policy ceiling — `AgentCeiling`,
  `defaultAgentCeiling`, `CeilingViolation`, and the pure `applyAgentCeiling`.
  It returns a request unchanged when it is within the ceiling and reports
  every violation when it is not; it never clamps an over-broad request to the
  permitted value. The default ceiling permits read-only and edit-workspace
  authority and refuses full access and raw provider arguments.

  `Baikai.Agent` itself is vocabulary and pure policy algebra only: it spawns no
  process and renders no command-line flags. Those live in the vendor packages
  and in `baikai-agent`, below. The module is deliberately not re-exported from
  the umbrella `Baikai` module, because its field accessors share names with
  `Baikai.Interactive`, so `import Baikai` continues to compile unchanged.

- `baikai`: new exposed module `Baikai.Evidence`, the vocabulary for
  **verifiable model-call evidence** — a record of what actually crossed the
  boundary to a provider, as opposed to what the process was configured to ask
  for. It defines `ModelCallEvidence` and the `evidenceSchemaVersion` string
  consumers pin against, `Observed` (a deliberate non-`Maybe` for a value the
  provider either did or did not report, with no function that supplies a
  default), `ThinkingTranslation` with its `ThinkingMode` and
  `ThinkingAdjustment` enumerations describing what a requested
  reasoning-effort level actually became on the wire and every clamp, collapse,
  or drop applied on the way, `EndpointIdentity` and `TransportKind`,
  `CallStatus`, and the ascending `EvidenceStrength` scale.

  It also provides the canonical hashing core: `canonicalEncode` gives a JSON
  value exactly one byte representation (object keys sorted, no insignificant
  whitespace, numbers normalised so `1`, `1.0`, `1.00`, and `1e0` all encode as
  `1`, and a hand-written string escaper so an aeson upgrade cannot silently
  invalidate a recorded digest); `commitmentDigest` hashes a full request
  envelope, and `configurationDigest` hashes an allow-list projection
  (`configurationProjection`) that keeps configuration and replaces content with
  structural summaries, so two calls that ask the same model the same way about
  different subjects agree. The two digests are separate on purpose: the first
  binds a record to a particular request, the second is safe to compare across
  runs that legitimately differ in content.

  Nothing constructs a `ModelCallEvidence` from a real call yet, and no existing
  behaviour changed. New dependencies: `cryptohash-sha256` and
  `base16-bytestring`, both single-purpose packages chosen over a full
  cryptographic framework.

- `baikai`: `Options` gains an `evidence` field carrying an optional
  `EvidenceRequest` — the caller's run identifier, retry provenance, and how
  strictly they need evidence. A call whose `evidence` is `Nothing`, which is
  every call that does not opt in, behaves exactly as it did before: no digest
  is computed and no evidence is emitted.

- `baikai`: model-call evidence is now **produced and emitted**. A caller who
  sets `Options.evidence` gets exactly one `call_evidence` line per call from
  their trace sink, under every way a call can end: success, provider failure, a
  consumer that abandons the stream (status `aborted`, not `failed` — an abort
  is the consumer's doing and reporting it as a provider failure would
  misattribute it), and dispatch that found no registered handler.

  New exposed module `Baikai.Evidence.Build` bridges the vocabulary to the
  `Model` and `Options` records: `minimalEvidence` and `prepareEvidence` build a
  record, `dispatchEnvelope` supplies the request envelope for the paths where
  no adapter ran, `sanitizeEndpoint` reduces a base URL to scheme/host/port/path
  with the query string and any userinfo dropped wholesale, and `onSinkFailure`
  is the hook a future release replaces to make a strict caller's call fail when
  the trace sink does.

  Every record this release produces has `strength` `requested_only` and every
  provider-observed field set to `"unobserved"`. That is not a placeholder: it
  is a truthful record for a transport that has not yet been taught to observe
  anything. Later releases teach each transport to observe more.

  **A caller who does not opt in pays nothing.** With `Options.evidence` absent
  no digest is computed, no call identifier is generated, no evidence event is
  emitted, and the request envelope is never even forced — the gate lives inside
  the shared builder rather than at each adapter's call site, and the envelope
  parameter is deliberately lazy. Both facts are guarded by tests.

- `baikai`: `TraceEvent` gains a `CallEvidence` constructor, encoded as
  `{"kind":"call_evidence", …}`. A consumer whose pattern match over `TraceEvent`
  is exhaustive must add a branch; one with a wildcard is unaffected. Filter for
  it with `jq 'select(.kind == "call_evidence") | .evidence'`. Note that a trace
  line carries its fields alongside the `kind` discriminator rather than nested
  under a `data` key, and that the evidence record inside spells its own fields
  in snake_case — the two encodings differ deliberately, because an evidence
  record must render an absent field as explicit `null` while a trace line drops
  it to stay small.

- `baikai`: `Baikai.Provider.Cli.Internal` — the module the two subprocess
  providers share — gains the vocabulary for reading what a coding-agent CLI
  reported about its own run. `CodexRunReport` and the new
  `parseCodexJsonlStream :: Stream IO ByteString -> IO CodexRunReport` fold the
  `codex exec --json` event stream into its assistant text, its thread
  identifier, and its token counts, instead of concatenating agent-message text
  and discarding everything else. `ClaudeCliReport` and
  `decodeClaudeCliResult` do the same for `claude -p --output-format json`.
  Every field but the message text is optional, because both tools' event
  schemas have changed across versions and an absent field is a genuine absence
  rather than a parse failure. **Breaking** for anyone calling
  `parseCodexJsonlStream` directly: its result type is no longer `Text`. This is
  an internal module and is documented as outside the PVP guarantee.

- `baikai`: `Baikai.Provider.Cli.Internal` also gains `ExecutableIdentity` and
  `executableIdentity`, which resolve a configured executable name to an
  absolute path and read the tool's own `--version` line. The probe is cached
  per resolved name for the lifetime of the process, because spawning it per
  model call would roughly double the process cost of the cheapest possible
  call, and it is bounded by a two-second timeout so a tool that hangs on
  `--version` cannot wedge a model call. A probe that fails records the version
  as absent rather than failing the call. It is only ever called from inside
  the evidence branch: a caller who asked for no evidence must not pay for a
  process whose only purpose is to describe a tool they were about to run
  anyway.

- `baikai`: `subprocessStrength` and `cliResponseEnvelope`, also in
  `Baikai.Provider.Cli.Internal`. The former derives a subprocess call's
  evidence strength from what the tool reported and **nothing else** — the exit
  status is deliberately not one of its arguments. The latter spells the
  response-commitment envelope with the same three keys, in the same shapes, as
  the two API transports build by hand, so a verifier holding a response can
  recompute the digest without first knowing which transport served it.

- `baikai`: `Baikai.Agent` gains `AgentRunOutcome` and `agentRunOutcome`. It
  pairs what an unattended run did — the existing
  `Either AgentRunFailure AgentRunResult` — with the evidence the runner built
  for it. The evidence is a sibling of the outcome rather than a field on
  `AgentRunResult` because the run that most needs a record is one that did not
  produce a result: a run killed by its own timeout reports
  `Left (RunTimedOut …)`, so a record hanging off the `Right` would be
  unreachable exactly there.

### Fixed

- `baikai`: a `call_evidence` event is now emitted **before** its call's
  terminal `call_finished` or `call_failed`, rather than after. The
  OpenTelemetry sink ends and removes a call's span on the terminal, so under
  the old order its evidence-attribute branch was unreachable from any real
  call and every backend saw a span with no evidence on it — nothing failed,
  the attributes were simply never there. No consumer can have depended on the
  old order, because no consumer has ever seen a `call_evidence` line.

- `baikai`: the `ThinkingFormatOpenAI` Haddock in `Baikai.Compat` listed the
  native `reasoning_effort` vocabulary as `minimal | low | medium | high`, which
  predates `xhigh` and `max`. It now lists all six and states that this shape
  alone sends the canonical baikai level verbatim while the other six clamp
  through `compatibleEffort`. No behaviour changed: the native path's exclusion
  from that clamp is deliberate and is guarded by two named tests in
  `baikai-openai/test/ShapeSpec.hs`. A reader who consulted the comment to
  decide whether `xhigh` was safe to use against OpenAI has until now been told
  something untrue.

### Changed

- **Breaking:** `baikai`: `TerminalPayload` gains an `evidence` field and the two
  terminal smart constructors take it as their new first argument:
  `doneTerminal :: Maybe ModelCallEvidence -> Maybe Text -> StopReason -> Message -> TerminalPayload`
  and `errorTerminal` likewise. `Response` gains the same field. A custom
  provider implementation must pass `Nothing` (or a record it builds through
  `Baikai.Evidence.Build`); a custom `Response` built with the record
  constructor must add `evidence = Nothing`. Code that only pattern-matches on
  these types is unaffected.

- **Breaking:** `baikai`: `CallFinished` gains `cachedInputTokens`,
  `cacheWriteTokens`, `reasoningTokens`, and `totalTokens`. The trace path used
  to drop counts that `Baikai.Cost.Log.CallLogEntry` kept from the same `Usage`
  value, which made the cost log strictly more faithful than the trace.

- **Breaking:** `baikai`: a computed cost of **zero is now reported as zero**
  rather than suppressed, in `CallFinished` and at all three `CallLogEntry`
  construction sites. Previously `usd` was omitted whenever the cost came out at
  zero, so "this call was free" and "baikai could not price this call" were
  indistinguishable — and the subscription-based CLI providers always price at
  zero, so that was the common case rather than a corner. **A cost dashboard
  that treated an absent `usd` as "unpriced" will now count those calls as
  costing zero.** That is the correct reading, but it changes what such a
  dashboard shows.

- **Breaking:** `baikai`: `FromJSON TraceEvent` is written out by hand instead of
  derived. The three pre-existing kinds decode exactly as before; a
  `call_evidence` line fails to parse with a message saying to read it as a
  plain `Data.Aeson.Value`. `ModelCallEvidence` has no `FromJSON` on purpose —
  it embeds a `Cost` whose exact `Rational` amounts encode through an
  approximating `Scientific`, so a decoder would return a different value than
  was encoded — and manufacturing that fidelity would be the precise failure
  this vocabulary exists to eliminate.

- `baikai`: `Baikai.Trace.Sink.renderHuman` renders a `CallEvidence` event as a
  single `EVIDENCE run=… call=… strength=…` line rather than the whole record. A
  human-readable sink is for watching calls go by; the full record is meant to
  be read out of `fileSink` output by a machine.

- `baikai`: call identifiers on the trace path are now globally unique.
  `Baikai.Evidence.newCallId` produces 32 lowercase hexadecimal characters
  carrying 128 bits — 48 bits of Unix time in milliseconds, 48 bits of a
  per-process random seed drawn once from `/dev/urandom`, and a 32-bit counter.
  The previous generator combined the process-start *second* with a
  process-local counter into 16 characters, so two processes started within the
  same second emitted identical identifier sequences; its own documentation
  claimed only per-process uniqueness. Identifiers still sort chronologically
  and are still not secrets.

  `Baikai.Trace.newEventId` keeps its name and signature, delegates to
  `newCallId`, and is now deprecated. Anything that pinned the 16-character
  width — a log parser, a fixture, a column type — must widen to 32.

- `baikai`: `renderCeilingViolation` no longer prints the raw provider arguments
  a `ProviderArgsForbidden` violation carries. It reports how many were
  requested and states that their values are not shown. Raw provider arguments
  are the one part of a job description that can hold a credential — the
  configuration layer classifies the setting secret for that reason — and a
  refusal message that quoted them defeated the classification. The constructor
  keeps its `[Text]` payload so a programmatic caller can still inspect it.

## [baikai-claude 0.5.0.0] - 2026-08-05

### Added

- `baikai-claude`: new exposed module `Baikai.Provider.Claude.Agent` with
  `ClaudeAgentConfig`, `defaultClaudeAgentConfig`, and `claudeAgentCommand`, a
  pure renderer from an unattended `AgentRunRequest` to the `claude` argument
  vector. It maps the capability profile onto `--permission-mode`
  (`plan` / `acceptEdits` / `bypassPermissions`), joins a tool allow-list into
  one `--allowedTools` argument, repeats `--add-dir` per extra directory, always
  emits `-p`, and emits `--no-session-persistence` unless `persistSession` is
  set. The prompt travels on standard input and appears nowhere in the argument
  vector. A request naming a different provider is refused with
  `ProviderMismatch`. Nothing is spawned.

- `baikai-claude`: the Anthropic Messages provider now fills in the evidence
  record it previously left blank. It records the model **Anthropic reported
  running** (read from the `message_start` event, which the adapter already
  decoded for the response id and then discarded), Anthropic's `request-id`
  correlation header, the response id, the token counts Anthropic actually
  reported, and a commitment digest over the assembled response. A field the
  provider did not report stays `"unobserved"` and is never backfilled from the
  request — in particular, a stream that fails before `message_start` reports no
  observed model at all. `strength` is `model_observed` when both the model and a
  correlation identifier arrived, `correlated` when only the identifier did, and
  `requested_only` otherwise; a 2xx status never raises it, because a 200 means
  the request was accepted, not that any particular model ran.
  `fully_observed` is unreachable on this transport, since Anthropic does not
  echo the thinking configuration it applied.

- `baikai-claude`: an evidence record's `thinking` field now describes what the
  caller's reasoning-effort preference actually became on the wire, including
  three downgrades that were previously invisible everywhere in baikai's output:
  asking for thinking on a model that does not advertise `reasoning`
  (`thinking_dropped_unsupported_model`); asking for a level whose token budget
  does not fit under the resolved output-token ceiling
  (`thinking_dropped_budget_exceeded`, carrying both colliding numbers), which is
  reachable by lowering `maxTokens` alone; and asking for `high` on an
  adaptive-thinking model, which sends no effort field and so is
  wire-indistinguishable from taking Anthropic's default depth
  (`effort_omitted`). `minimal` on an adaptive model reports `effort_clamped`,
  because Anthropic's adaptive vocabulary has no `minimal`.

- `baikai-claude`: new exports from `Baikai.Provider.Claude.Sse` —
  `ResponseMetadata` and `capturedHeaderNames` — and from
  `Baikai.Provider.Claude.Api` — `claudeMessagesStreamWith`, `SseDriver`, and
  `anthropicStrength`. Response-header capture is an **allow-list**
  (`request-id`, `x-request-id`, `cf-ray`, in that preference order), not a
  denylist, so a header a future gateway adds is not recorded by default.

- `baikai-claude` and `baikai-openai`: both subprocess providers now fill in the
  evidence record they previously left blank, and both export the translation
  function that describes it — `claudeCliThinking` and `codexCliThinking`. They
  record the session or thread identifier the tool reported, the token counts it
  reported, the model it named when it names one, the resolved executable path
  in place of an endpoint URL, the tool's own `--version` string as the
  implementation version (for this transport the tool *is* the implementation),
  a request commitment over the rendered argument vector, and a response
  commitment over the assembled answer.

  **A zero exit status never raises the strength.** A coding-agent CLI that
  exits zero has demonstrated that it ran and did not crash; it has not stated
  which model served the request. Subprocess calls almost always exit zero, so
  encoding that as corroboration would make the weakest evidence in the system
  look like the strongest. `strength` is `model_observed` only when the tool
  named both an identifier and a model, `correlated` when it named only an
  identifier, and `requested_only` otherwise.

  The two transports differ in how far they can get. `claude` names the model
  that consumed tokens in its result event's `modelUsage` map, complete with a
  context-window variant marker such as `[1m]`, so a Claude CLI run can reach
  `model_observed`. `codex-cli 0.146.0` names no model anywhere in its event
  stream, so **no** Codex CLI run can exceed `correlated` — backfilling the
  `--model` flag baikai passed would report the request as an observation.

- `baikai-claude`: an evidence record's `thinking` field now describes what a
  reasoning-effort request became on the `claude` command line: mode `flag`,
  wire field `--effort`, and an `effort_clamped` adjustment recording the
  `minimal` → `low` collapse, because the tool's `--effort` flag has no
  `minimal`. A caller asking for `minimal` and a caller asking for `low` produce
  byte-identical argument vectors — and therefore identical request commitment
  digests — so the translation is the only place that difference survives.

- **Breaking:** `baikai-claude` and `baikai-openai`: `claudeAgentCommand` and
  `codexAgentCommand` return `(AgentCommand, ThinkingTranslation)` rather than
  `AgentCommand`. The runner deliberately imports no vendor renderer, so it
  cannot derive the translation and has to be handed it. A caller that only
  wants the command writes `fmap fst`. Both modules also export the translation
  function alone — `claudeAgentThinking` and `codexAgentThinking` — for asking
  what a level would become without rendering anything.

### Fixed

- **Loud:** `baikai-claude` and `baikai-openai`: both subprocess providers
  hardcoded `usage = zeroUsage` on every call, so a cost dashboard saw every
  `claude -p` and `codex exec` call as consuming no tokens and costing nothing.
  Both tools report their own token counts and baikai now carries them through,
  normalized into the disjoint `Usage` convention: `claude`'s counts are
  Anthropic-shaped and already disjoint, while `codex` reports OpenAI-style
  inclusive prompt counts, so its cached tokens are subtracted out of
  `inputTokens`. `claude` additionally reports a `total_cost_usd`, which now
  populates `Usage.cost` exactly rather than being reported as zero.

  **A dashboard that read these calls as free will now see real tokens and, for
  `claude`, a real cost.** That is the correction, not a regression — but it
  changes what existing reports show, and totals over historical data will not
  match totals over new data.

- `baikai-claude`: `Response.responseId` was always `Nothing` on the `claude -p`
  transport even though `ClaudeCliResult` decoded the tool's `session_id` one
  screen earlier and then dropped it. It now carries that identifier, on both
  the successful and the failed terminal. `baikai-openai`: the same for
  `codex exec`, whose thread identifier was filtered out of the event stream
  along with everything that was not an `agent_message`. These are the handles
  each vendor's support tooling looks a run up by.

### Changed

- **Breaking:** `baikai-claude`: `Baikai.Provider.Claude.Sse`'s four streaming
  entry points — `claudeSseStream`, `claudeSseStreamValue`,
  `claudeSseStreamValueWithHeaders`, and `sseFromResponse` — take a new
  `ResponseMetadata -> IO ()` callback immediately before the existing per-event
  callback. It fires exactly once, before the first event, on both the success
  and the non-2xx path. Pass `(\_ -> pure ())` to keep the previous behaviour.
  The callback is separate rather than a widening of the per-event one because
  the per-event callback runs once per SSE frame and response-level data does not
  belong on that path.

- **Breaking:** `baikai-claude`: `Baikai.Provider.Claude.Internal.Request`'s
  `mapRequest` now returns
  `Either Text (Messages.CreateMessage, ThinkingTranslation)` and
  `computeThinking` returns `(ThinkingPlan, ThinkingTranslation)`. Take `fst` to
  keep the previous value. This module is exposed for provider tests and
  debugging and its header states it is not covered by PVP compatibility
  guarantees, but the change is recorded here because that is not a licence to
  break a consumer silently.

- **Breaking:** `baikai-claude`: `claudeInteractiveCommand` now returns
  `Either AgentRenderError (FilePath, [String])` and `launchClaudeInteractive`
  returns `IO (Either AgentRenderError InteractiveLaunchResult)`. A request
  whose `safety` is a `CodexSandbox` policy — which Claude Code cannot express
  — is refused with `SafetyNotExpressible AgentClaude`, naming the rejected
  sandbox mode and approval policy and suggesting `ClaudeAllowedTools` or
  `DefaultSafety`. Previously the policy was silently discarded and an
  **unrestricted** Claude session was started and reported as a success. A
  `Left` means no process was started; a `Right` with a non-zero exit code
  means the session ran and exited non-zero. `DefaultSafety` and an empty
  `ClaudeAllowedTools` list still render no safety flag and are never refused,
  and no previously rendered argument vector changed. Callers must handle the
  refusal branch.

## [baikai-openai 0.5.0.0] - 2026-08-05

### Added

- `baikai-openai`: new exposed module `Baikai.Provider.OpenAI.Agent` with
  `CodexAgentConfig`, `defaultCodexAgentConfig`, and `codexAgentCommand`, the
  same renderer for `codex exec`. It maps the capability profile onto
  `--sandbox` (`read-only` / `workspace-write` / `danger-full-access`), emits
  `--cd` for the working root, and defaults `--skip-git-repo-check` and
  `--ephemeral` on. A request carrying a tool allow-list is **refused** with
  `UnsupportedToolRestriction`, because `codex exec` has no such flag and running
  it with unrestricted tools would grant more authority than the caller asked
  for. Nothing is spawned.

- `baikai-openai`: an evidence record's `thinking` field now describes what the
  caller's reasoning-effort preference became on the wire for the specific host
  the call went to, across **all seven** OpenAI-compatible wire shapes. The
  OpenAI-native shape sends the canonical level verbatim and records no
  adjustment, because it expresses every level exactly. The four shapes that
  carry an effort word for a non-native host record `effort_clamped` whenever
  the word differs from the canonical name — `minimal` becomes `low`, and both
  `xhigh` and `max` become `high`. Z.ai and Qwen accept a bare
  `enable_thinking: true` with no depth, so **every** level records
  `effort_collapsed_to_toggle`: a caller asking for `max` and a caller asking
  for `low` produce byte-identical requests there, and only the evidence record
  can tell them apart. A host with no reasoning controls records
  `thinking_dropped_unsupported_host` where the option previously vanished with
  no trace. A forty-two-row table test pins the translation and the shaped
  request body for every shape at every level.

- `baikai-openai`: the Chat Completions provider now fills in the evidence record
  it previously left blank. It records the model **the host reported running**
  (read from the first streamed chunk carrying a top-level `model` field and
  never overwritten by a later one), the host's `x-request-id` correlation
  header, the response id, the token counts the host actually reported, and a
  commitment digest over the assembled response. A field the host did not report
  stays `"unobserved"` and is never backfilled from the request — in particular,
  a call that fails before any chunk arrives reports no observed model at all.
  `strength` is `model_observed` when both the model and a correlation
  identifier arrived, `correlated` when only the identifier did, and
  `requested_only` otherwise; a 2xx status never raises it, because a 200 means
  the request was accepted, not that any particular model ran.
  `fully_observed` is unreachable on this transport, since no host in this
  ecosystem echoes the reasoning configuration it applied.

- `baikai-openai`: new exports from `Baikai.Provider.OpenAI.Sse` —
  `ResponseMetadata` and `capturedHeaderNames` — and from
  `Baikai.Provider.OpenAI.Api` — `openaiChatStreamWith` and `SseDriver`.
  Response-header capture is an **allow-list** (`x-request-id`, `request-id`,
  `x-amzn-requestid`, `x-ms-request-id`, `cf-ray`, in that preference order),
  not a denylist, so a header a future gateway adds is not recorded by default.
  The list is longer than the Anthropic one because this transport speaks to an
  open-ended set of hosts and the gateways commonly in front of them.

- `baikai-openai`: the same field for `codex exec`: mode `flag`, wire field
  `model_reasoning_effort`, and **no** adjustments at any level. Codex is the
  only transport in baikai that expresses all six canonical levels exactly, and
  a test asserts each one reaches the command line verbatim.

### Fixed

- `baikai-openai`: `Response.responseId` was always `Nothing` on the Chat
  Completions transport, although every compatible host sends a top-level `id`
  on every streamed chunk. It now carries the identifier the host reported, on
  both the successful and the failed terminal.

### Changed

- **Breaking:** `baikai-openai`: `Baikai.Provider.OpenAI.Sse`'s four streaming
  entry points — `openaiSseStream`, `openaiSseStreamValue`,
  `openaiSseStreamValueWithHeaders`, and `sseFromResponse` — take a new
  `ResponseMetadata -> IO ()` callback immediately before the existing per-chunk
  callback. It fires exactly once, before the first chunk, on both the success
  and the non-2xx path — a failed call's correlation identifier is if anything
  more valuable than a successful one's. Pass `(\_ -> pure ())` to keep the
  previous behaviour. The callback is separate rather than a widening of the
  per-chunk one because that one runs once per SSE frame and response-level data
  does not belong on that path.

- **Breaking:** `baikai-openai`: `Baikai.Provider.OpenAI.Api`'s `RawChunk` gains
  `model` and `responseId` fields, both `Maybe Text`. Code that pattern-matches
  on `RawChunk` is unaffected; code that constructs one with record syntax must
  add them.

- **Breaking:** `baikai-openai`: `Baikai.Provider.OpenAI.Shape`'s
  `shapeRequestBody`, `streamRequestBody`, and `injectThinkingShape` now return
  `(Aeson.Value, ThinkingTranslation)` instead of a bare body. Take `fst` to
  keep the previous value. The description has to travel out of the shaping step
  because nothing downstream can recompute it: it depends on the host's
  `ThinkingFormat`, which only the compat lookup knows. **No request body
  changed** — every one of the seven shapes puts exactly the same bytes on the
  wire as before.

- **Breaking:** `baikai-openai`: `codexInteractiveCommand` now returns
  `Either AgentRenderError (FilePath, [String])` and `launchCodexInteractive`
  returns `IO (Either AgentRenderError InteractiveLaunchResult)`. A request
  whose `safety` is a non-empty `ClaudeAllowedTools` list — which `codex` has
  no flag for — is refused with `SafetyNotExpressible AgentCodex`, quoting the
  rejected tools and suggesting `CodexSandbox` or `DefaultSafety`. Previously
  the allow-list was silently discarded and Codex was started with its default
  sandbox. The same `Left`/`Right` reading applies, `DefaultSafety` and an
  empty allow-list are never refused, and no previously rendered argument
  vector changed. Callers must handle the refusal branch.

  Both changes make the interactive surface honor the same contract as the new
  unattended surface: a safety policy the chosen provider cannot express fails
  visibly instead of silently becoming a weaker policy. Downstream consumers
  must adapt before upgrading; the known one is `shinzui/seihou`, whose
  `Seihou.CLI.AgentLaunchExec` module builds interactive launch requests.

## [baikai-trace-otel 0.3.0.3] - 2026-08-05

### Added

- `baikai-trace-otel`: the sink attaches an evidence record's salient fields to
  the open span as flat attributes (`baikai.evidence.run_id`,
  `baikai.evidence.call_id`, `baikai.evidence.strength`, the two digests, and
  `gen_ai.response.model` only when the provider actually reported one) rather
  than serialising the record into one blob. A `CallEvidence` event neither
  opens nor closes a span.

### Changed

- `baikai-trace-otel`: widened its `baikai` bound to admit `0.5`. No API change.

## [baikai-effectful 0.3.0.3] - 2026-08-05

### Changed

- Widened its `baikai` bound to admit `0.5`. No API change; the package's
  own surface is untouched.

## [baikai-kit 0.1.0.4] - 2026-08-05

### Changed

- Widened its `baikai` bound to admit `0.5`. No API change; the package's
  own surface is untouched.

## [baikai-agent 0.1.0.0] - 2026-08-05

### Added

- `baikai-agent`: **new package** (`0.1.0.0`) holding the unattended
  coding-agent runner. `Baikai.Agent.Run.runAgentCommand` takes an
  `AgentRunRequest` and an already-rendered `AgentCommand` and spawns the tool
  with no terminal and no human present. It delivers the prompt on standard
  input and closes the handle, drains standard output and standard error
  concurrently so a chatty agent cannot deadlock on a full pipe, retains at most
  `outputLimit` bytes per stream while reading and discarding the excess, and
  honors the three output disciplines. Preconditions run before any spawn: a
  missing working directory is `WorkingDirMissing` and unset or empty declared
  variables are `MissingEnvironment`, listing all of them at once. On timeout
  the child's whole process group is interrupted, given a grace period, and then
  terminated, so the agent's own child processes go with it; the failure reports
  the configured limit. A non-zero exit code is a successful run carrying that
  code, not a failure. The runner consumes an already-rendered `AgentCommand`
  and never imports a vendor renderer, so it is exercised entirely with
  hand-written argument vectors. Its POSIX-signal escalation is conditional on a
  non-Windows build.

- `baikai-agent`: new exposed module `Baikai.Agent.Config`, the layered
  configuration layer. `resolveAgentJob` resolves one named job across five
  layers — built-in defaults, the operator file, the repository file, the
  environment, then command-line overrides, later layers winning — and returns
  the resolved `AgentJob` together with a report attributing every value to the
  file, line, and column it came from. `agentJobRequest` converts a job into an
  `AgentRunRequest`, taking the prompt at call time. `listAgentJobs` enumerates
  configured job names, sorted, each attributed to the highest-precedence scope
  defining it. `defaultAgentConfigPaths` locates
  `$XDG_CONFIG_HOME/baikai/agents.kdl` (or `$HOME/.config/baikai/agents.kdl`)
  and `./.baikai/agents.kdl`, with no upward search through parent directories.

  The **policy ceiling** is loaded by a separate function, `loadAgentCeiling`,
  against a separate source list containing the operator file and nothing else:
  no repository file, environment variable, or command-line override can raise
  it. `applyCeilingToJob` refuses an over-broad request with `CeilingRejected`
  rather than clamping it. With no operator file the ceiling is
  `defaultAgentCeiling`. `safety.provider-args` is classified secret and renders
  as `<redacted>` in any report or structured error.

  New dependencies: `settei`, `settei-env`, `settei-kdl`, and
  `settei-optparse-applicative` (all `^>=0.2`, published on Hackage at
  `0.2.0.0`), plus `containers` and `filepath`. `settei-formats` is deliberately
  excluded, because it bundles Dhall loading and repository configuration is
  untrusted input here.

- `baikai-agent`: the **`baikai` executable**, with the `agent run`,
  `agent show`, and `agent list` commands, and the `Baikai.Agent.Cli` module
  that implements them. A shell script now invokes one stable command, supplies
  a prompt on standard input, and selects Claude Code or Codex entirely through
  configuration.

  `agent run` resolves the named job, caps it against the operator ceiling,
  renders it through the vendor renderer for its provider, and spawns it. The
  agent's own exit code passes through unchanged; Baikai's own failures use 64
  and above following the `sysexits` convention — 64 for a usage error or an
  empty prompt, 69 when the executable could not be started, 70 for malformed
  output, 75 for a timeout, 77 for a policy refusal, and 78 for a configuration
  problem. The prompt comes from `--prompt-stdin`, `--prompt-file`, or
  `--prompt`, which are mutually exclusive, and is decoded as UTF-8 explicitly
  rather than through the handle's locale encoding.

  `agent show` performs the whole pipeline except spawning and prints each
  resolved value with the file, line, and column it came from, the policy
  ceiling in force and where it was read, and the exact argument vector that
  would be spawned — with `<redacted>` in place of any raw provider argument. A
  job whose policy is refused prints its configuration first and then the
  refusal. `agent list` enumerates configured jobs and the scope each came from.

  Every Baikai diagnostic goes to standard error. The agent's own output follows
  the job's output mode, so `response=$(baikai agent run job)` yields the
  agent's answer alone for a capturing job. `--set KEY=VALUE` overrides one
  setting of the selected job through `settei`'s own command-line source, so an
  override is attributed with the same fidelity as a file. `--json` emits
  exactly one JSON object per command.

  New dependencies for `baikai-agent`: `baikai-claude`, `baikai-openai`, and
  `optparse-applicative`. The provider packages are needed only so that
  `renderJobCommand`, the single provider dispatch point in the codebase, can
  reach both renderers. This is the first dependency in the workspace from
  `baikai-agent` onto the provider packages, so `baikai-agent` now publishes
  after all three of `baikai`, `baikai-claude`, and `baikai-openai`.

  The user guide `docs/user/unattended-agent-runs.md` documents the whole
  surface: the three commands with their flags, exit codes, and stream
  discipline; the KDL job format and layer precedence; the operator ceiling and
  redaction; the capability mapping tables for both tools; and a before-and-after
  migration of a script that embeds provider flags today.
  `docs/user/cli-providers.md` and `docs/user/interactive-launches.md` link to
  it, and the capability mapping tables moved there from the latter.

- `baikai-agent`: **an unattended coding-agent run now produces model-call
  evidence.** This surface previously had no observability of any kind: no trace
  sink, no `Response`, no usage, no identifiers. An operator could show that a
  process started, exited, and took some time; they could not show which model
  ran, which reasoning effort was applied, or which agent session the run
  corresponds to in the vendor's records.

  A record carries the run and call identifiers, the resolved executable and its
  own reported version, digests over the request, the requested model and what
  the reasoning-effort request became on the command line, whatever the tool
  reported about itself, the outcome, and an honest strength.

  **A zero exit status never raises the strength.** On this surface that rule
  matters more than anywhere else, because almost every unattended run exits
  zero. A coding agent that exits zero has demonstrated that it ran, not which
  model served it.

  Two things gate what a record can prove, and neither is the default. The job
  must **capture** output — under `inherit` the agent's bytes went to the
  operator's terminal and baikai never held them — and the tool must be
  configured to print a structured format, which means `--output-format json`
  for `claude` or `--json` for `codex exec` through the job's `provider-args`.
  Without both, the tool's session identifier, model, and token counts are
  genuinely unavailable and the record says `"unobserved"` rather than inferring
  anything. A timed-out run records `aborted`; a run that never started records
  nothing at all.

- **Breaking:** `baikai-agent`: `Baikai.Agent.Run.runAgentCommand` takes two new
  leading arguments and returns the new outcome type:
  `Maybe EvidenceRequest -> ThinkingTranslation -> AgentRunRequest -> AgentCommand -> IO AgentRunOutcome`.
  A caller who wants the previous behaviour passes `Nothing` and
  `Baikai.Evidence.noThinkingRequested` and reads the `outcome` field; that path
  is byte-for-byte what it was, and costs what it cost — no digest is computed,
  no call identifier is generated, and the tool is not invoked a second time to
  read its version.

- `baikai-agent`: `baikai agent run` gains `--evidence-file PATH` and
  `--run-id TEXT`. Supplying neither leaves the run on the pre-existing path at
  the pre-existing cost; supplying either turns recording on, with the job's own
  name standing in as the run identifier when only a destination is given. The
  file is written atomically — a staging file beside the destination, then a
  rename — so a reader polling the path never sees a half-written object, and it
  is never appended to. A failed write is reported on standard error and never
  changes the exit code, because the agent's own status is what a calling script
  branches on. `docs/user/unattended-agent-runs.md` documents both options and,
  more importantly, what the record does and does not prove.

- `baikai-agent`: `baikai agent run` gains `--require-evidence STRENGTH`, taking
  `requested_only`, `correlated`, `model_observed`, or `fully_observed` — the
  same words a record's `strength` field spells, so what one record showed can
  be passed back as the next run's requirement. A job whose configuration cannot
  produce evidence of at least that strength is refused before anything is
  spawned, exiting 77 — the code a ceiling violation and an inexpressible safety
  policy already use, so a script branching on 77 needs no new case.

## [baikai-claude 0.4.0.1] - 2026-07-30

### Fixed

- Widened the `crypton` bound from `^>=1.0` to `>=1.0 && <1.2` so consumers can
  build `baikai-claude` alongside packages that require `crypton` 1.1.x (for
  example `pg-migrate-1.1.0.0`), which previously had no solvable build plan.
  The only `crypton` use is `Crypto.Hash` (`Digest`, `SHA256`) in
  `Baikai.Provider.Claude.Transport`, whose API is identical across the 1.0/1.1
  boundary. No API change.

## [baikai 0.4.1.0] - 2026-07-20

### Changed

- Version bump only; no library API or code changes. Released so the umbrella
  release tag `baikai-0.4.1.0` names a fresh core version alongside the breaking
  `baikai-claude` / `baikai-openai` 0.4.0.0 releases, matching the tag
  convention downstream consumers pin against.

## [baikai-claude 0.4.0.0] - 2026-07-20

### Changed

- **Breaking:** `claudeCliCommand` now takes the `Options` record and forwards
  `Options.thinking` to batch `claude -p` as `--effort <level>` (`minimal`
  collapses to `low`, matching the interactive launcher and the claude CLI's
  lack of a `minimal` value). `thinking = Nothing` emits no effort flag, keeping
  existing argv byte-for-byte. The added parameter is a PVP-major signature
  change.

## [baikai-openai 0.4.0.0] - 2026-07-20

### Changed

- **Breaking:** `codexCliCommand` now takes the `Options` record and forwards
  `Options.thinking` to `codex exec` as `-c model_reasoning_effort=<level>` for
  all six effort levels. `thinking = Nothing` emits no override, keeping
  existing argv byte-for-byte. The added parameter is a PVP-major signature
  change.

## [baikai 0.4.0.0] - 2026-07-20

### Added

- Added `ThinkingXHigh` and `ThinkingMax` to the exported `ThinkingLevel`
  vocabulary and added a defaulted `InteractiveLaunchRequest.effort` field.
  Extending the closed sum type is a PVP-major API change for downstream
  exhaustive matches.

## [baikai-claude 0.3.0.2] - 2026-07-20

### Added

- Added `--effort` rendering to interactive Claude Code launches and preserved
  `xhigh` / `max` on native adaptive Anthropic API requests, with larger fixed
  budgets for manual-thinking models.

### Changed

- Bumped the internal `baikai` dependency bound to `^>=0.4.0` for the
  baikai 0.4.0.0 release.

## [baikai-openai 0.3.0.2] - 2026-07-20

### Added

- Added `model_reasoning_effort` overrides to interactive Codex launches and
  preserved `xhigh` / `max` in native OpenAI request JSON; non-native
  OpenAI-compatible request shapes continue to clamp them to `high`.

### Changed

- Bumped the internal `baikai` dependency bound to `^>=0.4.0` for the
  baikai 0.4.0.0 release.

## [baikai-trace-otel 0.3.0.2] - 2026-07-20

### Changed

- Bumped the internal `baikai` dependency bound to `^>=0.4.0` for the
  baikai 0.4.0.0 release. No API changes.

## [baikai-effectful 0.3.0.2] - 2026-07-20

### Changed

- Bumped the internal `baikai` dependency bound to `^>=0.4.0` for the
  baikai 0.4.0.0 release. No API changes.

## [baikai-kit 0.1.0.3] - 2026-07-20

### Changed

- Bumped the internal `baikai` dependency bound to `^>=0.4.0` for the
  baikai 0.4.0.0 release. No API changes.

## [baikai 0.3.1.0] - 2026-07-15

### Added

- Added `claude-sonnet-5` to the Anthropic model catalog (1M context window,
  128k max output, `tool_call` + reasoning).
- Added the `gpt-5.6` family — `gpt-5.6`, `gpt-5.6-luna`, `gpt-5.6-sol`, and
  `gpt-5.6-terra` — to the OpenAI model catalog (chat-completions with
  `tool_call` support).

### Changed

- Corrected `claude-sonnet-4-5` context window to 1M tokens and
  `claude-sonnet-4-6` max output to 128k tokens in the catalog.
- Added PVP-compliant upper bounds to all previously-unbounded library and
  executable dependencies.

## [baikai-claude 0.3.0.1] - 2026-07-15

### Changed

- Added PVP-compliant upper bounds to all previously-unbounded library and
  executable dependencies.

## [baikai-openai 0.3.0.1] - 2026-07-15

### Changed

- Added PVP-compliant upper bounds to all previously-unbounded library and
  executable dependencies.

## [baikai-trace-otel 0.3.0.1] - 2026-07-15

### Changed

- Added PVP-compliant upper bounds to all previously-unbounded library and
  executable dependencies.

## [baikai-effectful 0.3.0.1] - 2026-07-15

### Changed

- Added PVP-compliant upper bounds to all previously-unbounded library and
  executable dependencies.

## [baikai-kit 0.1.0.2] - 2026-07-15

### Changed

- Added PVP-compliant upper bounds to all previously-unbounded library and
  executable dependencies.

## [baikai 0.3.0.0] - 2026-07-03

### Added

- Added the documented record-update bases `emptyOptions`, `emptyContext`,
  `emptyModel`, `emptyResponse`, `emptyTool`, `emptyTextContent`,
  `emptyThinkingContent`, `emptyToolCall`, `emptyImageContent`,
  `emptyEmbeddingModel`, plus zero-valued bases `zeroUsage`, `zeroCost`,
  `zeroCostBreakdown`, and `zeroModelCost`.
- Added `firstEmbedding`, a total accessor for OpenAI-compatible embedding
  responses.
- Added `responseError`, `errorResponse`, `httpError`, and
  `parseRetryAfterSeconds` for the in-band error contract.

### Changed

- **Breaking:** Constructors for evolvable records are no longer exported:
  `Options`, `Context`, `Model`, `OpenAICompletionsCompat`,
  `AnthropicMessagesCompat`, and `InteractiveLaunchRequest` are built from
  exported base values plus record updates.
- **Breaking:** The `_X` base values are deprecated in favor of the new
  `empty*` and `zero*` names; the aliases remain for this release.
- **Breaking:** Removed `unModel`; use `mkModel` or `emptyModel` record
  updates.
- **Breaking:** Renamed `InteractiveLaunchRequest.model` to `modelId`.
- **Breaking:** `Response.latencyMs` and trace event `latencyMs` fields are
  now `Int`.
- **Breaking:** `completeRequest` / `completeRequestWith` no longer throw
  `BaikaiError` for unregistered API tags; they return an error-shaped
  `Response`.
- **Breaking:** CLI providers now report subprocess/decode/provider failures
  in-band as error-shaped `Response`s.
- **Breaking:** `errorTerminal` now requires a `BaikaiError`, enforcing
  structured error details for `EventError` construction sites.
- Documented that `Baikai.Prelude` is a convenience module outside the PVP
  stability contract and that `.Internal` modules have no compatibility
  guarantees.

### Fixed

- Empty embedding `data` arrays now produce a typed `decodeError` instead of
  crashing on an empty vector.
- The model-fetch JSON renderer now delegates string escaping to aeson.
- The model generator now fails on sanitized Haskell identifier collisions
  instead of rendering duplicate bindings.
- Live HTTP status, `Retry-After`, and network-failure classification now
  works on both API providers.
- `content_filter` / Anthropic refusals terminate as classified `EventError`
  terminals, and `liftCompleteToStream` preserves error-shaped responses.

## [baikai-claude 0.3.0.0] - 2026-07-03

### Changed

- **Breaking:** `Baikai.Provider.Claude.ErrorClass` moved to
  `Baikai.Provider.Claude.Internal.ErrorClass`.
- **Breaking:** `mapRequest` and pure request-shaping helpers moved from
  `Baikai.Provider.Claude.Api` to
  `Baikai.Provider.Claude.Internal.Request`.
- **Breaking:** `ClaudeCliConfig` and `ClaudeInteractiveConfig` constructors
  are no longer exported; start from their default config values and update
  fields.
- **Breaking:** CLI and interactive `extraArgs` fields are now `[Text]`.

## [baikai-openai 0.3.0.0] - 2026-07-03

### Changed

- **Breaking:** `Baikai.Provider.OpenAI.ErrorClass` moved to
  `Baikai.Provider.OpenAI.Internal.ErrorClass`.
- **Breaking:** `mapRequest` and pure request-shaping helpers moved from
  `Baikai.Provider.OpenAI.Api` to
  `Baikai.Provider.OpenAI.Internal.Request`.
- **Breaking:** `CodexCliConfig` and `CodexInteractiveConfig` constructors are
  no longer exported; start from their default config values and update fields.
- **Breaking:** CLI and interactive `extraArgs` fields are now `[Text]`.

## [baikai-trace-otel 0.3.0.0] - 2026-07-03

### Changed

- Updated the `baikai` dependency bound to `^>=0.3.0`.
- Adjusted to the core trace event `latencyMs :: Int` type.

## [baikai-effectful 0.3.0.0] - 2026-07-03

### Changed

- Updated the `baikai` dependency bound to `^>=0.3.0`.

## [baikai-kit 0.1.0.1] - 2026-07-03

### Changed

- Updated the `baikai` dependency bound to `^>=0.3.0`.

## [baikai 0.2.0.0] - 2026-06-21

### Added

- `Usage`, `Cost`, and `CostBreakdown` now have `Semigroup`/`Monoid`
  instances that add field-by-field, plus `sumUsage :: Foldable f => f
  Usage -> Usage`, so callers can total per-call usage and cost.
  `reasoningTokens` combines as presence-wins (`Nothing` only when both
  operands are `Nothing`).
- A categorised error model: `BaikaiError` is now a record carrying an
  `ErrorCategory` (`AuthError`, `RateLimited`, `ContextOverflow`,
  `InvalidRequest`, `TransientError`, `DecodeFailure`, `ProcessFailure`,
  `ProviderUnavailable`, `OtherError`), an optional HTTP `httpStatus`, a
  `retryAfterSeconds` hint, and a subprocess `exitCode`. New smart
  constructors (`providerError`, `invalidRequest`, `decodeError`,
  `processError`, `rateLimited`, `authError`, `providerUnavailable`),
  the `isRetryable` predicate, and the pure `classifyHttpStatus` /
  `classifyHttpStatusWithBody` helpers let callers implement retry
  policy without parsing error text. `ErrorCategory` and `BaikaiError`
  serialize to JSON.
- `Response` and the streaming `EventError`'s `TerminalPayload` now
  carry `errorInfo :: Maybe BaikaiError`, so a failed `completeRequest`
  (or a drained stream) exposes the structured category/retry hint
  in-band. `Baikai.Stream.Event` gains `doneTerminal` / `errorTerminal`
  constructors.

### Changed

- **Breaking:** `BaikaiError`'s four flat constructors
  (`ProviderError`, `RequestInvalid`, `DecodeError`, `ProcessError`)
  were replaced by the record above. Migrate by lowercasing to the
  smart constructors — `ProviderError "x"` becomes `providerError "x"`,
  `ProcessError n "x"` becomes `processError n "x"`, etc.
- **Breaking:** `Baikai.Stream.Event.TerminalPayload` and
  `Baikai.Response.Response` gained an `errorInfo` field; build
  `TerminalPayload` via `doneTerminal` / `errorTerminal`.

### Fixed

- Restored JSON decoding for `BaikaiError` values with omitted optional
  metadata fields.

## [baikai-claude 0.2.0.0] - 2026-06-21

### Added

- The Anthropic API and `claude -p` CLI providers now classify failures
  into the typed `BaikaiError` categories: HTTP errors (via the caught
  `servant-client` `ClientError`) map status/`Retry-After`/body onto
  `AuthError` / `RateLimited` / `ContextOverflow` / `InvalidRequest` /
  `TransientError`, and mid-stream Anthropic `error` events are
  classified by their error type. The result is surfaced on
  `Response.errorInfo`.

## [baikai-openai 0.2.0.0] - 2026-06-21

### Added

- The OpenAI/OpenAI-compatible API and `codex exec` CLI providers now
  classify failures into the typed `BaikaiError` categories the same way
  as `baikai-claude` (HTTP `ClientError` for status-based errors,
  streamed error text for mid-stream errors), surfaced on
  `Response.errorInfo`.

## [baikai-trace-otel 0.2.0.0] - 2026-06-21

### Changed

- Updated the `baikai` dependency bound to `^>=0.2.0` for compatibility with
  the `baikai 0.2.0.0` breaking API release.

## [baikai-effectful 0.2.0.0] - 2026-06-21

### Changed

- Updated the `baikai` dependency bound to `^>=0.2.0` for compatibility with
  the `baikai 0.2.0.0` breaking API release.

## [baikai 0.1.1.0] - 2026-06-12

### Added

- Added provider-agnostic `ResponseFormat` support on `Options`, including
  plain JSON-object mode and named JSON-schema mode.
- Added `Baikai.Embedding`, an OpenAI `/v1/embeddings` client for text
  embeddings.

## [baikai-claude 0.1.1.0] - 2026-06-12

### Added

- Mapped baikai `ResponseFormat` options onto Anthropic `output_config` for
  Claude API requests.
- Exported `mapRequest` for request-mapping tests and downstream inspection.

## [baikai-openai 0.1.1.0] - 2026-06-12

### Added

- Mapped baikai `ResponseFormat` options onto OpenAI Chat Completions
  `response_format`.
- Exported `mapRequest` for request-mapping tests and downstream inspection.

## [baikai-effectful 0.1.0.0] - 2026-06-12

### Added

- Initial release: effectful binding for baikai with the `Baikai` dynamic
  effect, `complete`, `streamCollect`, `streamEach`, and registry-backed
  interpreters.

## [baikai 0.1.0.0] - 2026-06-04

### Added

- Initial release: unified Haskell interface for working with multiple AI
  providers. Core modules including `Baikai`, `Baikai.Prelude`, `Baikai.Api`,
  `Baikai.Provider`, `Baikai.Provider.Registry`, `Baikai.Response`,
  `Baikai.Stream`, `Baikai.Tool`, `Baikai.Trace`, and the cost/usage modules.
- Depends on released `streamly` (`>=0.11 && <0.13`) and `streamly-core`
  (`>=0.3 && <0.5`) from Hackage, so all dependencies resolve from Hackage.

## [baikai-claude 0.1.0.0] - 2026-06-04

### Added

- Initial release: Anthropic Claude providers for the baikai abstraction,
  wrapping the `claude` package for both the Anthropic API and the `claude -p`
  CLI (`Baikai.Provider.Claude.Api`, `.Cli`, `.Interactive`).

## [baikai-openai 0.1.0.0] - 2026-06-04

### Added

- Initial release: OpenAI providers for the baikai abstraction, wrapping the
  `openai` package for OpenAI's Chat Completions API
  (`Baikai.Provider.OpenAI.Api`, `.Cli`, `.Interactive`).

## [baikai-trace-otel 0.1.0.0] - 2026-06-04

### Added

- Initial release: OpenTelemetry `TraceSink` adapter for baikai
  (`Baikai.Trace.Sink.OpenTelemetry`), emitting one OTel span per provider call
  with GenAI semantic-convention attributes plus baikai cost and latency.