github JuliusBrussee/caveman sdk-python-v1.2.0
caveman-sdk 1.2.0

one hour ago
  • Breaking (license): relicensed from MIT to Apache-2.0, along with the rest of
    the repository in Caveman 3.0.0. Releases before this one keep the MIT license.
  • Callers that only waited on another call's shared capabilities fetch no longer
    record its failure in the breaker: one refused connect at cold start is one
    failure, not one per waiter. An interrupted half-open probe records nothing
    and frees the probe slot. New CircuitBreaker.release().
  • observe()/observe_background() normalize the receipt scope, as TypeScript
    does, and drop a receipt with an invalid scope. Async observe() has its own
    receipt worker (one worker, sixteen queued), so receipts never take optimize's
    slots.
  • A runtime token is stripped of surrounding whitespace (a mounted secret file's
    trailing newline); a token with any other character outside printable ASCII
    is invalid_configuration instead of a runtime_unavailable on every call.
  • An https:// or socks proxy URL is invalid_configuration; ready() and
    preflight() name the unsupported scheme. MiddlewareError takes an optional
    detail.
  • endpoint is the runtime origin (scheme://host[:port]), as in TypeScript,
    and "" when the endpoint was refused; it never echoes userinfo.
  • delete_session() validates the response like TypeScript: schema_version
    must be 1, originals_deleted is true only for a literal true, and
    deleted appears only with four safe non-negative integer counts.
  • The recovery binding passes only handle/offset/limit/query to
    retrieve(); non-object arguments or a missing handle raise
    MiddlewareError("invalid_request"), which adapters turn into a tool error.
  • Coroutine sinks (on_report, on_decision, on_diagnostic) run on the
    caller's event loop instead of leaking a "never awaited" warning; their
    failures never reach the call.
  • The version_unverified warn-once line reads Caveman middleware is running on an unverified framework version, because that call proceeds.
  • The transport bounds the whole exchange (connect, proxy tunnel, TLS, headers
    and body) by the deadline, and never reuses connections the server closed
    while idle.
  • aclose() never blocks on a stuck worker.
  • The first capabilities fetch is single-flight. An unusable capabilities view
    is refreshed once. Server-advertised deadlines are capped.
  • JSON is parsed strictly (no NaN; integer-valued floats become ints), and
    endpoint parsing is stricter.
  • Warn-once rules, the decision event's runtime_build, and adapter_error
    for an unserializable manifest now match TypeScript.
  • New unsupported_provider and unsupported_request reason codes.
  • Exporter: cost is also emitted as caveman.usage.cost_usd.
  • The warn-once line now reads Caveman middleware passed content through unchanged: adapter=… reason=…, the same as TypeScript. Log filters that
    match the old Caveman middleware decision: prefix need updating.
  • Strict ready()/preflight() now report the first decline().
  • decline() accepts any catalog reason and an optional adapter id, which the
    warn-once line names. It never raises in strict mode.
  • Python floor lowered from 3.13 to 3.11.
  • caveman_cloud.middleware implements middleware protocol 1.1 and is stable:
    it follows semver, because caveman-middleware 1.0 depends on it. Requests carry Caveman-Middleware-Features,
    Caveman-Middleware-Client, and, when a tracer is configured, traceparent/tracestate for the SDK's own span
    (never the application's ambient context, as in TypeScript).
  • Capabilities are parsed tolerantly and cached for 300 s with single-flight
    refresh. A new policy revision or transform version no longer rejects a plan.
  • Only exact_ccr replacements that carry the recovery marker and handle and are
    shorter in UTF-8 bytes are applied. recovery: "none" is never applied, which
    closes a text-injection path.
  • New circuit breaker: opens after 5 consecutive or 10 of 20 failures, stays
    open 30 s, then allows one probe. Deadlines count; local and 4xx errors don't.
    Ill-formed Unicode is reported as unsupported_shape. Retry-After is honored.
  • The default deadline comes from capabilities (500 ms before the first fetch).
    Retrieve has its own 5 s deadline and its own pool.
  • Async calls respect their deadline even while queued. Pools are rebuilt after
    fork(). aclose() resolves in-flight calls as closed instead of raising
    CancelledError.
  • Transport: keep-alive reuse; DNS, connect and TLS inside the deadline;
    HTTPS_PROXY/HTTP_PROXY/NO_PROXY; ssl_context; a pluggable transport;
    endpoint path prefixes; allow_insecure_transport; max_concurrency.
  • Per-candidate budgets replace the whole-call bypass at 256 candidates or 4096
    manifest items.
  • Endpoint problems no longer raise at construction. recovery() returns None
    for an invalid scope. Scopes are normalized, so emails and spaces are hashed.
    delete_session() returns the result.
  • New: warn-once logging on caveman.middleware, on_decision events
    (including no_candidate), opt-in OTel tracer/meter, and as_sync(),
    ensure_sync(), ensure_async().
  • The credential is kept out of vars(), repr() and pickling.
  • OTelExporter.record_span(cache_creation_tokens=) emits
    gen_ai.usage.cache_creation.input_tokens. gen_ai.usage.cost_usd is
    deprecated; it stays through 1.x.
  • Release process: each release gets a GitHub Release with these notes and a
    CycloneDX SBOM of its dependency graph.

Verify this release

  • Registry provenance (trusted publishing from this workflow): https://pypi.org/project/caveman-sdk/1.2.0/#files
  • CycloneDX SBOM of the published dependency graph: attached .cdx.json
  • Built from annotated, GitHub-verified tag sdk-python-v1.2.0 on main

Don't miss a new caveman release

NewReleases is sending notifications on new releases.