Skip to main content

Votrix Managed Agents (VMA) Python SDK

votrix is the Python client for the native Votrix Managed Agents API. AsyncVotrix covers the broader native resource surface; Votrix provides a synchronous GA wrapper for API-key administration, model-provider discovery, Vaults, and provider BYOK credentials. Neither client exposes internal environment-variable names.

The package requires Python 3.10 or newer.

Installation

The SDK has not been published to PyPI yet. Install it from this repository during development:

python -m pip install -e ./sdks/python

After the first release, the published installation command will be:

python -m pip install votrix-managed-agents

From inside sdks/python, install development dependencies with python -m pip install -e ".[dev]".

This distribution installs only the votrix client package. It does not install the Votrix Managed Agents server, its app package, or the server's legacy compatibility namespace, so it can be installed alongside the service source tree without a package-name collision.

Client setup

Pass the API key and service URL explicitly:

from votrix import AsyncVotrix

client = AsyncVotrix(
    api_key="vma_live_...",
    base_url="https://vma.example.com",
)

Alternatively, set both environment variables and construct the client with no credentials in application code:

export VMA_API_KEY="vma_live_..."
export VMA_BASE_URL="https://vma.example.com"
from votrix import AsyncVotrix

client = AsyncVotrix()

base_url or VMA_BASE_URL is always required. VOTRIX_VMA_API_KEY and VOTRIX_VMA_BASE_URL are supported as namespaced aliases. The default authentication scheme sends x-api-key. For a deployment that accepts bearer authentication, select it explicitly:

Production keys start with vma_live_; staging, development, local, and test keys start with vma_test_.

client = AsyncVotrix(
    api_key="vma_live_...",
    base_url="https://vma.example.com",
    auth_scheme="bearer",
)

Use the client as an async context manager so its connection pool is closed deterministically:

import asyncio

from votrix import AsyncVotrix


async def main() -> None:
    async with AsyncVotrix() as client:
        providers = await client.model_providers.list()
        for provider in providers.data:
            print(provider.id, provider.display_name)


asyncio.run(main())

If a context manager does not fit the application's lifetime, call await client.close() during shutdown.

Managed Agents resources

The public-beta client exposes API keys, agents, environments, sessions, files, skills, Memory Stores, Vaults, model Credentials, model providers, and raw usage as typed async resources:

async with AsyncVotrix() as client:
    agent = await client.agents.create(
        name="support-agent",
        model={"id": "deepseek/deepseek-v4-pro", "provider": "openrouter"},
        system="Help the end user clearly and concisely.",
    )

    environment = await client.environments.create(
        name="production-runtime",
        config={"type": "cloud"},
    )

    session = await client.sessions.create(
        agent=agent.id,
        environment_id=environment.id,
        vault_ids=["vault_end_user", "vault_organization"],
    )

    usage = await client.usage.list(session_id=session.id, metric="model_tokens")

Native callers may pass SessionFundingRequest(type="platform_credits") to sessions.create; the other values are byok and organization_default. Omission preserves the CMA-compatible request shape and uses the Organization default. Funding selection is fixed for the lifetime of the Session.

Session creation and event submission automatically send a fresh Idempotency-Key, which makes the SDK's retry policy safe. Pass idempotency_key= when the key must survive a caller-level retry or process restart.

Request and response objects accept the Votrix extensions for their resource while retaining the shared Claude Managed Agents field names where the APIs overlap.

Memory Stores are available through memory_stores, with nested memories and memory_versions resources. Generic Vault Credentials remain deliberately absent; provider BYOK uses the typed vaults.model_credentials surface below.

Memory Stores

Create a store, manage path-addressed memories, and inspect or redact immutable versions through the native async client:

store = await client.memory_stores.create(name="Account context")
memory = await client.memory_stores.memories.create(
    store.id,
    path="/accounts/acme.md",
    content="ACME prefers email.",
    view="full",
)

memory = await client.memory_stores.memories.update(
    memory.id,
    memory_store_id=store.id,
    content="ACME prefers chat.",
    precondition={
        "type": "content_sha256",
        "content_sha256": memory.content_sha256,
    },
    view="full",
)

versions = await client.memory_stores.memory_versions.list(
    store.id,
    memory_id=memory.id,
    view="full",
)

first_version = await client.memory_stores.memories.versions.retrieve(
    1,
    memory_store_id=store.id,
    memory_id=memory.id,
)

Use memories.retrieve_by_path(path, memory_store_id=...) (or its by_path alias) for direct path lookup. A depth-limited memory list may contain MemoryListItem(type="memory_prefix", ...) directory rollups. Redaction is available at memory_stores.memory_versions.redact(...); the API rejects redaction of a live memory's current head version.

API-key lifecycle

Both clients expose scoped Organization-key administration:

created = await client.api_keys.create(
    name="production-worker",
    scopes=["api", "worker"],
)
save_once(created.secret.get_secret_value())

rotated = await client.api_keys.rotate(created.id, reason="scheduled rollover")
save_once(rotated.secret.get_secret_value())

await client.api_keys.revoke(rotated.id, reason="retired")

The plaintext key is represented as Pydantic SecretStr and is present only in create() and rotate() results. List, retrieve, and revoke use the safe ApiKey metadata model, which ignores any unexpected secret field returned by a misconfigured intermediary. API-key lifecycle methods are also available on the synchronous Votrix client without await.

Model-provider credentials

Discover provider IDs from the service instead of hard-coding provider secret names:

providers = await client.model_providers.list()
openrouter = next(item for item in providers.data if item.id == "openrouter")

vault = await client.vaults.create(display_name="End-user credentials")
credential = await client.vaults.model_credentials.create(
    vault.id,
    provider=openrouter.id,
    api_key=end_user_api_key,
    display_name="Personal OpenRouter key",
)

# Rotation keeps the same credential binding and still hides internal names.
credential = await client.vaults.model_credentials.rotate(
    vault.id,
    credential.id,
    api_key=rotated_end_user_api_key,
)

credentials = await client.vaults.model_credentials.list(vault.id)
credential = await client.vaults.model_credentials.retrieve(
    credential.id,
    vault_id=vault.id,
)

# Archive permanently purges the stored provider key.
credential = await client.vaults.model_credentials.archive(
    credential.id,
    vault_id=vault.id,
)

The caller supplies only a stable provider ID and the write-only API key. The service maps that provider to its internal credential representation; callers do not send or need to know a secret_name such as OPENROUTER_API_KEY.

create() and rotate() accept a plaintext api_key as a write-only request field. List, retrieve, rotate, and archive responses never contain that value, auth, or secret_name. Archive and delete purge the encrypted secret before changing lifecycle state, so an archived Credential cannot be rotated or used again. Use delete(credential.id, vault_id=vault.id) when no tombstoned Credential metadata is needed.

The same BYOK lifecycle is available synchronously:

from votrix import Votrix

with Votrix(
    api_key="vma_live_...",
    base_url="https://vma.example.com",
) as client:
    provider = client.model_providers.retrieve("openrouter")
    vault = client.vaults.create(display_name="End-user credentials")
    credential = client.vaults.model_credentials.create(
        vault.id,
        provider=provider.id,
        api_key=end_user_api_key,
    )
    credentials = client.vaults.model_credentials.list(vault.id)
    credential = client.vaults.model_credentials.retrieve(
        credential.id,
        vault_id=vault.id,
    )

The synchronous client intentionally exposes provisioning surfaces only: API keys, model providers, Vaults, and model Credentials. Use AsyncVotrix for Agents, Sessions, Files, and Skills.

Pagination

List methods return an awaitable paginator. Await it to inspect one page and advance manually:

page = await client.agents.list(limit=25)
for agent in page.data:
    print(agent.id)

next_page = await page.get_next_page()

Or iterate over the paginator to traverse all pages lazily:

async for agent in client.agents.list(limit=100):
    print(agent.id)

Session event streams

Session streams use server-sent events. Open them with the returned async context manager so the HTTP response is always closed:

async with await client.sessions.events.stream(session.id) as stream:
    async for event in stream:
        print(event.type, event.seq)

The stream object deliberately requires the async with await ...stream(...) form before iteration. If the connection ends unexpectedly, it reconnects up to the client's max_retries, sends the last received SSE ID as Last-Event-ID, and suppresses replayed event IDs. Set max_reconnects on stream() to override that limit for one stream. Cancelling the consuming task or leaving the context closes the active HTTP response.

File downloads

Downloads return a binary response wrapper. Use read() to obtain the bytes:

download = await client.files.download(file_id)
contents = await download.read()

print(download.filename, download.content_type, len(contents))

for chunk in download.iter_bytes(64 * 1024):
    process(chunk)

await download.write_to_file("./result.bin")

read() buffers the response for compatibility. For large files, consume a fresh download incrementally instead:

download = await client.files.download(file_id, stream=True)
async for chunk in download.aiter_bytes(64 * 1024):
    process(chunk)

stream=False is the backwards-compatible default, so existing synchronous iter_bytes() calls still operate on buffered content. With stream=True, write_to_file() also writes incrementally when the response has not already been buffered. The SDK never interprets or writes downloaded bytes unless write_to_file() is called explicitly. Consuming a streaming response closes it; if one is abandoned before consumption, call await download.aclose() or use it as an async context manager.

Development

pytest
pyright
python -m build

The package ships inline annotations and a py.typed marker. Stable resource methods and response fields are typed; intentionally forward-compatible API metadata and extension fields may remain Any.

Download files

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

Source Distribution

votrix_managed_agents-0.1.0.tar.gz (43.6 kB view details)

Uploaded Source

Built Distribution

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

votrix_managed_agents-0.1.0-py3-none-any.whl (31.2 kB view details)

Uploaded Python 3

File details

Details for the file votrix_managed_agents-0.1.0.tar.gz.

File metadata

  • Download URL: votrix_managed_agents-0.1.0.tar.gz
  • Upload date:
  • Size: 43.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for votrix_managed_agents-0.1.0.tar.gz
Algorithm Hash digest
SHA256 bfbf579d8ad1a95f51a313c1df0ba71772d8bf8bf0775cb1d68bfe2b4b3dfec8
MD5 94a9c522a238e676c5274cff782db19a
BLAKE2b-256 7831ee945d0d018395a89cbb7aee53826f3fd158a433a1816bb3734c0c2055fa

See more details on using hashes here.

Provenance

The following attestation bundles were made for votrix_managed_agents-0.1.0.tar.gz:

Publisher: python-sdk-publish.yml on votrixai/votrix-managed-agents

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file votrix_managed_agents-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for votrix_managed_agents-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7a6745c2eb8eac4ab47a6b5f4883e4c144c76b0976bbf334074784b0226a1be2
MD5 3d7a967eecdc5cfe84dfc3bf5b75f2b2
BLAKE2b-256 6bb80f0e3b26ae20cfcfbc4df09fcb32186568427b46809aaf51042aac6897a6

See more details on using hashes here.

Provenance

The following attestation bundles were made for votrix_managed_agents-0.1.0-py3-none-any.whl:

Publisher: python-sdk-publish.yml on votrixai/votrix-managed-agents

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

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