Skip to main content

warp-commerce-types

Formal commerce types for Python — the twin of @warp-lang/commerce-types.

Typed money, validated state transitions, and the six commerce invariants of the Warp Commerce Model — as Pydantic v2 models. Both this package and the TypeScript package are generated from / read the same canonical schema (../../schema), so the two languages agree by construction:

  • the data shapes come from schema/structure/*.schema.json;
  • the legal state-machine edges come from schema/behavior/transitions.json;
  • the invariant definitions come from schema/behavior/invariants.json.
pip install warp-commerce-types

Available on PyPI as of v1.0.0. If you're building from a pre-release checkout (before v1.0.0 is live on PyPI), the line above won't resolve yet — install from source instead:

# from a checkout of the warp-lang repo:
pip install ./packages/commerce-types-py
# …or editable, with dev deps, for working on the package:
pip install -e "./packages/commerce-types-py[dev]"

What you get

from warp_commerce_types import (
    Money, new_commitment, transition_commitment, audit_commerce, allocate,
)

# Currency-safe money. You cannot add MAD to EUR — and minor units are correct
# per currency (TND is 3-decimal: 1.5 TND == 1500 millimes, not 150).
from warp_commerce_types import add, convert
add(Money(amount=100, currency="MAD"), Money(amount=50, currency="MAD"))
# add(Money(amount=1, currency="MAD"), Money(amount=1, currency="EUR"))  -> CurrencyMismatchError

# Exact splits that always reconcile (largest-remainder, minor-unit aware):
allocate(Money(amount=100, currency="MAD"), [1, 1, 1])
# -> 33.34 + 33.33 + 33.33 == 100.00 exactly

# State machines validate every move against the canonical transition table.
c = new_commitment("buyer", "seller")
r = transition_commitment(c, {"type": "Proposed"}, actor="buyer")
assert r.ok and r.value.state.type == "Proposed"
bad = transition_commitment(c, {"type": "Fulfilled"}, actor="buyer")
assert not bad.ok and "Invariant 2" in bad.error   # Draft -> Fulfilled is illegal

# The six invariants, as runtime checkers that return actionable violations.
violations = audit_commerce(commitments=[c], fulfillments=[], parties=[])

The agent toolkit

The same agent toolkit that ships in the TypeScript package is now available in Python, behaviour-equivalent (the conformance cross-check proves the bindings agree on the model these compose). It is a thin composition over the primitives above — it does not re-derive invariant or transition logic.

from warp_commerce_types import (
    guard_action, guard_object, valid_transitions, create_session,
    unify, to_stripe_action, World, ProposedAction, UnifySource,
)

# Guardrail — validate a proposed action BEFORE it executes.
verdict = guard_action(world, ProposedAction(commitment=cid, to={"type": "Accepted"}, actor="agent"))
# verdict.ok -> True/False; on rejection, verdict.violations = [{rule, message, fix}]

# Planning oracle — on rejection, the legal moves from the current state.
valid_transitions({"type": "Fulfilled"})   # ['Disputed', 'Refunded']  (a pure read of the table)
verdict.alternatives                         # [{to, label, bounded?}] — LEGAL transitions, not guaranteed-safe

# Session coherence — catch cross-step violations a single check misses.
session = create_session(world)
session.propose(refund_80); session.propose(refund_80)
session.propose(refund_80)  # BLOCKED [I-1]: cumulative 240 > committed 200, with the remaining-refundable bound

# Interop CIR — unify caller-corresponded platform objects; emit validated descriptors.
unify([UnifySource("shopify", order), UnifySource("stripe", charge)])  # mismatch -> I-1 (not auto-reconciled)
to_stripe_action(refund_action).descriptor   # {"kind": "stripe.refund", ...} — a descriptor, NOT an executed call
  • guard_action / guard_object — compose transition_commitment (I-2) + audit_commerce (the six invariants); never raise on rejection, never coerce.
  • valid_transitions — the legal target states from a state, a pure read of the transition table. These are legal transitions, not guaranteed-safe actions; the absence of a bounded note promises nothing.
  • create_session — accumulates a world + a refund ledger; catches a cumulative over-refund (three 80s against a 200 order) the point-in-time check cannot see. The cumulative check probes the same check_i1_value_conservation. It also provides idempotency / replay-safety (a same-key — or same-fingerprint — retry is a no-op returning replay=True, never a double-apply; per-session, in-memory) and optimistic-conflict detection (pass expected_version from commitment_version; a stale plan is rejected as a conflict, rule="version-conflict", so you re-read and re-plan — optimistic, not a lock). Both are available in all four bindings.
  • create_multi_agent_session — a thin wrapper over create_session that makes it first-class that several named agents act on one shared world: it keeps a who-did-what log + actors_summary(), and on a rejection it names the actor whose action tipped the shared world into violation (result.actor + result.attribution). This is not new invariant logic — the underlying session is already actor-agnostic, so the cumulative / conflict / replay checks already span actors; the wrapper only adds attribution. Scope (honest): it attributes the single action that triggered the violation, not collusion or multi-party intent.
  • multi-object coherencecreate_session now also caps the sum of refunds across a commitment tree (a parent + its children, keyed by the tree root) against the parent's committed amount, additive to the per-commitment cap. Refunds spread over different children — each individually valid, each child reconciling to the parent via I-6 — cannot cumulatively exceed the parent. It composes the existing check_i6_tree_consistency (structure) + the same check_i1_value_conservation cumulative probe (lifted to the parent). Standalone commitments are never tree members, so single-commitment behaviour is unchanged.
  • plan_compensation / validate_compensation / compensate / compensate_session (saga) — model the unwinding of a multi-step flow as a validated sequence of compensating actions and check the compensation is coherent (a reversal that would over-refund is rejected with the bounded guidance). Default mapping: a Fulfilled step reverses to Refunded for the committed amount; a committed-but-undelivered step (Accepted / Active / Modified / PartiallyFulfilled) reverses to Cancelled. Overrides (compensate_with) are still bounded by the transition table. It composes valid_transitions + create_session; it does not execute or orchestrate rollbacks on external systems — a plan is a sequence of validated descriptors.
  • unify — merges objects the caller asserts correspond (a mechanism, not auto-reconciliation); a value mismatch is surfaced as I-1. The outbound emitters return platform-shaped descriptors only — no network, no credentials, no execution. (Python ships inbound mappers for Shopify and Stripe; unify itself is platform-agnostic.)

Runnable twins of the TypeScript examples live in examples/: agent_guardrail.py, planning_oracle.py, agent_session.py, multi_agent.py, multi_object.py, saga.py, cross_platform.py.

Per-binding notes for the multi-agent / multi-object / saga ports

These three features are ports of the TypeScript session-layer features, composing the Python binding's existing primitives (no schema change, no reimplemented invariant or transition logic). Two honest per-binding notes:

  • Multi-agent attribution wording differs from TS. The Python attribution string conveys the same facts as the TS twin (the tipping actor, the prior actors as accumulated context, and whether the cause was a conflict or an invariant violation), but is the Python binding's own phrasing — not a byte-for-byte copy of the TS sentence. Tests assert the facts, not the exact sentence. The structured fields (actor, violations, conflict, alternatives, …) are identical to TS.
  • Multi-object has no shape gap. Python exposes a standalone check_i6_tree_consistency(parent, children) (the same shape as TS), so the per-tree cap composes it directly — no auditing of a root+children subset was needed.

Binding coverage: the agent toolkit is available in all four bindings — TypeScript, Python, Rust, and Go — behaviour-equivalent on the shared scenarios. The Rust and Go runtimes are conformance-focused (deserialize + audit), so their toolkits document two honest binding limits: the audit returns invariant ids (so guard messages are standard per-invariant text, not per-violation prose), and those bindings ship no platform inbound mappers (unify is platform-agnostic, so callers map platform objects themselves). The VERDICTS match across all four.

The model

Five primitives — Party, Value, Intent, Commitment, Fulfillment — plus the v0.3 commerce vocabulary (terms, auctions, resolution, metering, evidence, …), all generated as Pydantic models with discriminated unions keyed on "type" / "kind".

Concern Module
Currency-safe Money, minor-unit math, allocate, MoneyBreakdown warp_commerce_types.money
Primitive constructors (new_commitment, party_id, …) warp_commerce_types.primitives
transition_* / is_valid_*_transition, history synthesis warp_commerce_types.transitions
check_i1..i6, audit_commerce, check_loyalty_liability warp_commerce_types.invariants
Generated data models warp_commerce_types (re-exported)
Platform adapters warp_commerce_types.platforms.shopify, …stripe

The six invariants

  1. Value Conservation — value is transferred, not created; no mixed currencies without explicit conversion. (Fourth clause: loyalty-point liability — check_loyalty_liability.)
  2. State Monotonicity — only legal transitions; terminal states never reverse.
  3. Capacity Verification — a buyer must be verified (can_buy) before Accepted.
  4. Temporal Integrity — commitments form before fulfillments execute; append-only history; timestamps never move backward.
  5. Identity Permanence — identifiers are globally unique, never reused.
  6. Commitment Tree Consistency — a parent's value equals the sum of its children, within minor-unit tolerance (build exact children with allocate).

MoneyBreakdown

A total decomposed into labelled components. Construction enforces the money_breakdown_sum rule from schema/behavior/invariants.json: components sum to the total (minor-unit tolerance), all share one currency, and discount components are negative.

from warp_commerce_types import MoneyBreakdown
MoneyBreakdown.model_validate({
    "components": [
        {"kind": "subtotal", "amount": {"amount": 90, "currency": "MAD"}},
        {"kind": "discount", "amount": {"amount": -10, "currency": "MAD"}},
        {"kind": "tax",      "amount": {"amount": 20, "currency": "MAD"}},
    ],
    "total": {"amount": 100, "currency": "MAD"},
})  # ok — components sum to 100

Regenerating from the schema

The models and the bundled behavior data are generated. Edit the schema, never the generated _models.py:

python scripts/generate_from_schema.py   # reads ../../schema, writes src/.../_models.py

Development

pip install -e ".[dev]"
pytest        # mirrors the TS bug-fix, transition, and invariant suites
mypy          # configured in pyproject.toml
python -m build

MIT licensed. Part of the Warp project.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

warp_commerce_types-1.3.0.tar.gz (71.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

warp_commerce_types-1.3.0-py3-none-any.whl (63.4 kB view details)

Uploaded Python 3

File details

Details for the file warp_commerce_types-1.3.0.tar.gz.

File metadata

  • Download URL: warp_commerce_types-1.3.0.tar.gz
  • Upload date:
  • Size: 71.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for warp_commerce_types-1.3.0.tar.gz
Algorithm Hash digest
SHA256 11a26bb85074a3947bdf0c180a7b932eec18c0a7d2464c409916d3b42c981f63
MD5 160eee98014c076d96681fa7ff390ae8
BLAKE2b-256 3b3455eea1ac0ae22c6614968e6e62e0d619bef16eaee44541345f478a01c60d

See more details on using hashes here.

File details

Details for the file warp_commerce_types-1.3.0-py3-none-any.whl.

File metadata

File hashes

Hashes for warp_commerce_types-1.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 28ab709757fd22c1ada478a8de3229c92d434a95d17405df2248911a76808cd7
MD5 4d574126ee25272456797bfad65e3e57
BLAKE2b-256 1c2c7b929fa4deb4c8adc5fedb2eb116999a3d053f4f5eec019745020dc5a098

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page