Skip to content

Documentation navigation

Versioning & Stability

What the SDK version and event-contract version mean, which surfaces are stable, and how deprecations are communicated.

#Versioning & Stability

mAIvn ships two version numbers, and they answer two different questions. One tells you which release of the SDK you have installed. The other tells event consumers (your backend, your frontend, your webhooks) which shape of streaming events to expect. This page explains both, what counts as stable versus experimental, and how we tell you when something is changing.

#What this is

When you build on top of any SDK, two things can move underneath you: the code you import and the data that flows out of it. mAIvn versions each of these separately so that a change to one never silently surprises consumers of the other.

  • The SDK version (maivn.__version__) is the release of the maivn package on your machine. Check its release notes and test upgrades; a version number alone does not establish compatibility.
  • The event contract version (APP_EVENT_CONTRACT_VERSION) describes the shape of the normalized events your application receives when it streams an agent's execution. It travels stamped onto every event, so a consumer can read it off the wire and decide how to handle the payload.

In plain terms: the SDK version is for you, the developer upgrading a dependency. The contract version is for the systems that read your agent's output, especially a frontend you do not redeploy in lockstep with your backend. The rest of this page makes both precise, with runnable examples.

#The SDK version (__version__) and what semver means for you

The installed release is available as a string on the top-level package and is part of the public surface:

Python
import maivn

print(maivn.__version__)

It is also exposed through the CLI for quick diagnostics, useful in a bug report or a CI log:

Shell
maivn version
# Prints the installed SDK version.

The SDK currently uses a 0.x version. Under semantic versioning, major version zero denotes initial development and does not promise a stable API. Pin the version you tested, review changes before upgrading, and run your integration tests against the new package.

For example, a PEP 621 pyproject.toml dependency goes in a list:

TOML
[project]
# Illustrative pin: select the release qualified for your application.
dependencies = ["maivn==0.1.0"]

A requirements.txt uses maivn==0.1.0 on its own line. Neither format uses a standalone maivn = "..." assignment. Keep package pins and deployed service compatibility under review together.

#The AppEvent contract version (APP_EVENT_CONTRACT_VERSION) and why it matters for event consumers

When you stream an agent's execution, the raw transport events are normalized into a stable, app-facing shape called AppEvent (see the Events reference and the Frontend Events guide). Every normalized event carries the contract version it was produced under:

Python
from maivn.events import APP_EVENT_CONTRACT_VERSION

print(APP_EVENT_CONTRACT_VERSION)  # "v1"

The same constant is also importable from the events module, which is where most event-handling code lives:

Python
from maivn.events import APP_EVENT_CONTRACT_VERSION

Every AppEvent is stamped with it. You can read it off any event you receive:

Python
from maivn import Agent
from maivn.events import RawSSEEvent, normalize_stream
from maivn.messages import HumanMessage

agent = Agent(name="assistant", api_key="your-api-key")

raw_events = (
    RawSSEEvent(name=event.name, payload=event.payload)
    for event in agent.stream([HumanMessage(content="Hello!")])
)
for event in normalize_stream(raw_events):
    assert event.contract_version == "v1"
    send_to_frontend(event.model_dump())

Why this is separate from the SDK version. The SDK version changes when you upgrade a dependency. The contract version changes only when the shape of the events changes, and those two events rarely happen at the same time. The classic case is a frontend you ship independently of your backend: a browser app may run for weeks against a backend you have since upgraded. By keying on the contract version rather than the package version, that frontend can recognize which event shape it is being handed and adapt, without ever knowing which maivn release produced it.

How the contract evolves without breaking you. The contract is designed to grow additively:

  • The nested descriptors on AppEvent (tool, assistant, assignment, enrichment, interrupt, output, error_info, and the rest) are declared with Pydantic's extra="allow". New fields can appear on a descriptor without invalidating consumers that validate the payload. Unknown fields are accepted, not rejected.
  • Normalized payloads intentionally preserve the older flat fields alongside the newer nested descriptors, so a consumer written against an earlier shape can keep reading the fields it already knows while it migrates.
  • Unknown or custom event names pass through normalization unchanged, which is the supported path for domain-specific event extensions (set event_kind to "custom" and include both contract_version and event_name).

A new value of APP_EVENT_CONTRACT_VERSION (for example, a future "v2") is reserved for changes that are not purely additive: a rename or a removal that older consumers cannot absorb. Because the version rides on every event, you can support more than one frontend at a time by branching on it:

Python
def handle(event):
    if event.contract_version == "v1":
        render_v1(event)
    else:
        # A version you do not recognize: degrade gracefully rather than crash.
        log.warning("Unrecognized event contract version: %s", event.contract_version)
        render_best_effort(event)
Tip Preserve contract_version end to end. When you forward event.model_dump() from your backend to your frontend, the field comes along for free. Keep it on the wire so the frontend can make the same decision the backend could.

This contract is the same one your own application routes expose when you mount the event stream. For example, mount_events(app) adds GET /maivn/events/{session_id} to your FastAPI app, and the events it serves carry the same contract_version your frontend can branch on:

Python
from fastapi import FastAPI
from maivn.events.fastapi import mount_events

app = FastAPI()
mount_events(app)  # -> GET /maivn/events/{session_id}

#Which surfaces are stable vs experimental

The public boundary is defined by the __all__ exports of maivn, maivn.events, and maivn.messages. The owned wire contracts they expose come from the installed maivn-contracts dependency.

Stable — import and rely on these:

  • The core classes: Agent, Swarm, Client, ClientBuilder, BaseScope, MCPServer, MCPAutoSetup, ToolOverride.
  • The decorators: tool_output, toolify, toolset, depends_on_tool, depends_on_agent, depends_on_private_data, depends_on_interrupt, depends_on_await_for, depends_on_reevaluate, and requires_producer_reference.
  • Public models exported through maivn, including InvokeResponse, privacy/configuration models, permissions, memory models, and provider metadata. Per-run token_usage is a dictionary property on InvokeResponse, not a public model.
  • The maivn.events surface: AppEvent, RawSSEEvent, EventBridge, normalize_stream, the build_*_payload helpers, and APP_EVENT_CONTRACT_VERSION.
  • Configuration, logging, scheduling, and interrupt helpers exported at the top level.
  • Public SDK exceptions exported from maivn, led by MaivnSDKError and MaivnHTTPError.
Note The authoritative list of the public surface is the package's __all__. If a name appears there (and on the per-class pages under api/), it is part of the supported interface. If it does not, treat it as internal.

Internal — do not import or depend on these:

Anything under the maivn._internal package is private. The single-underscore name is the signal: these are implementation details that can change, move, or disappear in any release, including patch releases, with no notice and no deprecation cycle. This holds even though some internal symbols are re-exported under their public import path. Rely on the public path, never the _internal one.

Catch public SDK-owned failures through MaivnSDKError, and handle typed HTTP responses through MaivnHTTPError:

Python
from maivn import Agent, MaivnHTTPError, MaivnSDKError
from maivn.messages import HumanMessage

agent = Agent(name="assistant", api_key="your-api-key")

try:
    response = agent.invoke([HumanMessage(content="Hello!")])
except MaivnHTTPError as exc:
    log.error("mAIvn API failed (%s): %s", exc.status_code, exc.reason)
    raise
except MaivnSDKError as exc:
    log.error("mAIvn SDK failed: %s", exc)
    raise

Importing a concrete type from maivn._internal is unsupported. That path can change at any release. See Errors and Exceptions for the current public hierarchy.

#How deprecations are communicated

Read the release notes and migration guidance for the specific SDK version you intend to install. Do not assume that a compatibility alias or an internal helper will remain available because it imported successfully in an older build.

To expose Python deprecation warnings during development:

Shell
python -W default::DeprecationWarning your_app.py

Warnings help where the relevant path emits one; their absence does not prove that an upgrade is compatible. Test public API usage and normalized event payloads before updating a production dependency.

#Next steps

  • Overview — what mAIvn is, the one mental model, and your first agent.
  • Core Concepts — the building blocks the public surface is made of.
  • SDK Reference — the per-class home of the public surface; the __all__ of every page.
  • Events — the full AppEvent contract, normalization helpers, and payload builders.
  • Frontend Events guide — how to stream the contract to a browser and key UI state off contract_version.
  • Errors & Exceptions — the public SDK exception hierarchy and transport behavior.
  • Troubleshooting — the concrete errors you may see and how to fix each one.
  • Shared Data Models — result and privacy model shapes, including InvokeResponse and its normalized token-usage dictionary.