Metadata-Version: 2.5
Name: mutagent-sdk
Version: 0.4.0
Summary: Python SDK for the MutagenT Server API Documentation
License: Apache-2.0
License-File: LICENSE
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: typing-extensions>=4.0.0
Provides-Extra: dev
Requires-Dist: mypy>=1.9.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest-httpx>=0.30.0; extra == 'dev'
Requires-Dist: pytest>=7.0.0; extra == 'dev'
Requires-Dist: ruff>=0.4.0; extra == 'dev'
Description-Content-Type: text/markdown

```
╔══════════════════════════════════════════════════════════════════════════════╗
║                                                                              ║
║    ███╗   ███╗██╗   ██╗████████╗ █████╗  ██████╗ ███████╗███╗   ██╗████████╗ ║
║    ████╗ ████║██║   ██║╚══██╔══╝██╔══██╗██╔════╝ ██╔════╝████╗  ██║╚══██╔══╝ ║
║    ██╔████╔██║██║   ██║   ██║   ███████║██║  ███╗█████╗  ██╔██╗ ██║   ██║    ║
║    ██║╚██╔╝██║██║   ██║   ██║   ██╔══██║██║   ██║██╔══╝  ██║╚██╗██║   ██║    ║
║    ██║ ╚═╝ ██║╚██████╔╝   ██║   ██║  ██║╚██████╔╝███████╗██║ ╚████║   ██║    ║
║    ╚═╝     ╚═╝ ╚═════╝    ╚═╝   ╚═╝  ╚═╝ ╚═════╝ ╚══════╝╚═╝  ╚═══╝   ╚═╝    ║
║                                                                              ║
║              ██████╗ ██╗   ██╗████████╗██╗  ██╗ ██████╗ ███╗   ██╗           ║
║              ██╔══██╗╚██╗ ██╔╝╚══██╔══╝██║  ██║██╔═══██╗████╗  ██║           ║
║              ██████╔╝ ╚████╔╝    ██║   ███████║██║   ██║██╔██╗ ██║           ║
║              ██╔═══╝   ╚██╔╝     ██║   ██╔══██║██║   ██║██║╚██╗██║           ║
║              ██║        ██║      ██║   ██║  ██║╚██████╔╝██║ ╚████║           ║
║              ╚═╝        ╚═╝      ╚═╝   ╚═╝  ╚═╝ ╚═════╝ ╚═╝  ╚═══╝           ║
║                                                                              ║
║                    Python SDK for AI-Native Development.                     ║
║                                                                              ║
╚══════════════════════════════════════════════════════════════════════════════╝
```

<p align="center">
  <a href="https://pypi.org/project/mutagent-sdk/"><img src="https://img.shields.io/pypi/v/mutagent-sdk?style=for-the-badge&color=3776AB&logo=pypi&logoColor=white" alt="PyPI"></a>
  <a href="https://www.python.org/downloads/"><img src="https://img.shields.io/badge/Python-3.10+-3776AB?style=for-the-badge&logo=python&logoColor=white" alt="Python 3.10+"></a>
  <a href="https://www.python-httpx.org/"><img src="https://img.shields.io/badge/httpx-0.27+-yellow?style=for-the-badge" alt="httpx"></a>
  <a href="https://docs.pydantic.dev/"><img src="https://img.shields.io/badge/Pydantic-2.0+-e92063?style=for-the-badge&logo=pydantic&logoColor=white" alt="Pydantic v2"></a>
  <a href="#license"><img src="https://img.shields.io/badge/License-Apache_2.0-blue?style=for-the-badge" alt="Apache 2.0"></a>
</p>

<p align="center">
  <em>The Python client for the MutagenT platform API.</em>
</p>

---

## 🎯 What is MutagenT Python SDK?

The **MutagenT Python SDK** is a client for the MutagenT platform API, generated from the platform's
OpenAPI document. It provides:

- 🔒 **Models**: a Pydantic v2 model for each request and response body in the API spec. Methods
  return the decoded JSON (`dict` or `list`), not model instances.
- ⚡ **Sync + Async**: `Mutagent` (sync) and `AsyncMutagent` (async) expose the same groups and methods
- 🐍 **Python 3.10+**: three runtime dependencies: `httpx`, `pydantic`, `typing-extensions`
- 🔐 **HTTPS by default**: a plain-HTTP server URL is refused for a non-local host unless you pass
  `allow_insecure_http=True`
- 🧩 **Spec-generated**: every group is emitted from the platform's OpenAPI document

### Core Capabilities

| Feature | Description |
|---------|-------------|
| **Agents** | Create, list, update, and delete agents; fetch one by id or by slug |
| **Organizations & Workspaces** | Administer organizations and workspaces, check slugs, set a default workspace |
| **Members & Invitations** | Add, re-role, and remove members; send, resend, and revoke invitations |
| **LLM Providers** | Register provider credentials, browse the model catalog, test a connection |
| **Account & Sessions** | Read and update your profile, change your password, list and revoke login sessions |
| **Managed Agents** | Deploy managed agent packages into slots, activate a revision, retire a slot |
| **Traces** | Ingest trace batches; list traces, spans and log records |
| **Cloud Sandboxes** | Sandbox providers and presets, sandbox lifecycle, commands, the sandbox token exchange |
| **Environments** | Workspace Environments: named sets of variables and secrets |
| **Helix Sessions** | Launch Helix sessions and send input, signal, checkpoint and restore them |

---

## 🔁 0.4.0 breaking changes

0.4.0 is the first published release to carry these changes. Code written against any earlier
release needs the following.

The comparisons below name 0.1.1, the release they were written against. Two versions sit between
it and this one: **0.3.0** has been on PyPI since 2 September and is a later build of the same
pre-rename client, so every rename listed here applies when upgrading from it; **0.2.0** was
prepared but never reached PyPI, because the repository's version had been set below the 0.3.0
already published there.

**Client groups**

- `sandbox` holds sandbox providers, presets, the sandbox lifecycle, commands, the token exchange
  (`create_sandbox_token`) and the session routes addressed by sandbox id.
- New group `helix_sessions`: `launch_helix_session`, `list_helix_sessions`,
  `send_helix_session_input`, `close_helix_session_input`, `signal_helix_session`,
  `checkpoint_helix_session`, `list_helix_session_checkpoints`, `restore_helix_session`,
  `stream_helix_session`, `get_helix_models`, `set_helix_default_models`. The ones that existed in
  0.1.1 were methods of `sandbox`.
- New group `environments`. In 0.1.1 its operations were methods of `sandbox`.
- `helix_agent_deployments` is renamed `managed_agents`. Its method names are unchanged.
- `provider_configs` is renamed `llm_providers`. Its methods are renamed too; see the table below.
- `user_profile` keeps its name. Two of its methods are renamed; see the table below.

**Operation names**

39 operations are renamed. In the first 27 rows the 0.1.1 name was derived from the route. The last
12 rows rename operations that already had their own names.

| 0.1.1 | 0.4.0 |
|-------|-------|
| `sandbox.get_api_sandbox_providers` | `sandbox.list_sandbox_providers` |
| `sandbox.post_api_sandbox_preflight` | `sandbox.preflight_sandbox` |
| `sandbox.get_api_sandbox_presets` | `sandbox.list_sandbox_presets` |
| `sandbox.post_api_sandbox_run` | `sandbox.run_sandbox_command` |
| `sandbox.post_api_sandbox` | `sandbox.create_sandbox` |
| `sandbox.get_api_sandbox` | `sandbox.list_sandboxes` |
| `sandbox.get_api_sandbox_by_id` | `sandbox.get_sandbox` |
| `sandbox.delete_api_sandbox_by_id` | `sandbox.delete_sandbox` |
| `sandbox.get_api_sandbox_by_id_stream` | `sandbox.stream_sandbox` |
| `sandbox.post_api_sandbox_by_id_exec` | `sandbox.exec_sandbox_command` |
| `sandbox.post_api_sandbox_telemetry_v1_traces` | `sandbox.ingest_sandbox_traces` |
| `sandbox.get_api_sandbox_by_id_traces` | `sandbox.list_sandbox_spans` |
| `sandbox.post_api_sandbox_by_id_session` | `sandbox.start_sandbox_helix_session` |
| `sandbox.get_api_sandbox_helix_defaults` | `helix_sessions.get_helix_models` |
| `sandbox.put_api_sandbox_helix_defaults` | `helix_sessions.set_helix_default_models` |
| `sandbox.get_api_sandbox_by_id_sessions` | `sandbox.list_sandbox_helix_sessions` |
| `sandbox.post_api_sandbox_by_id_input` | `sandbox.send_sandbox_helix_session_input` |
| `sandbox.post_api_sandbox_by_id_signal` | `sandbox.signal_sandbox_helix_session` |
| `sandbox.post_api_sandbox_by_id_checkpoint` | `sandbox.checkpoint_sandbox_helix_session` |
| `sandbox.get_api_sandbox_by_id_checkpoints` | `sandbox.list_sandbox_checkpoints` |
| `sandbox.post_api_sandbox_by_id_restore` | `sandbox.restore_sandbox` |
| `sandbox.post_api_sandbox_token` | `sandbox.create_sandbox_token` |
| `sandbox.get_api_sandbox_environments` | `environments.list_environments` |
| `sandbox.get_api_sandbox_environments_by_name` | `environments.get_environment` |
| `sandbox.put_api_sandbox_environments_by_name` | `environments.replace_environment` |
| `sandbox.patch_api_sandbox_environments_by_name` | `environments.update_environment` |
| `sandbox.delete_api_sandbox_environments_by_name` | `environments.delete_environment` |
| `user_profile.list_sessions` | `user_profile.list_user_sessions` |
| `user_profile.delete_session` | `user_profile.revoke_user_session` |
| `sandbox.list_helix_workspace_sessions` | `helix_sessions.list_helix_sessions` |
| `sandbox.input_helix_session` | `helix_sessions.send_helix_session_input` |
| `provider_configs.list_providers` | `llm_providers.list_provider_configs` |
| `provider_configs.create_provider` | `llm_providers.create_provider_config` |
| `provider_configs.get_provider` | `llm_providers.get_provider_config` |
| `provider_configs.update_provider` | `llm_providers.update_provider_config` |
| `provider_configs.delete_provider` | `llm_providers.delete_provider_config` |
| `provider_configs.get_models_catalog` | `llm_providers.get_model_catalog` |
| `provider_configs.list_provider_models` | `llm_providers.list_provider_config_models` |
| `provider_configs.test_provider` | `llm_providers.test_provider_config` |

**Model and enum names**

Model and enum names in `mutagent.models` come from the schema names in the API document, for example
`Mode`, `HelixArm`, `HelixSignal`, `HelixLaunchRequest`, `LlmProviderType` and `ErrorResponse`. Names
the generator invented in 0.1.1, such as `Schemadefaul7`, `ModeArmModel` and `NameSlugDescription5`,
no longer exist.

String enums, such as `Mode`, `HelixArm`, `HelixSignal`, `QueryFlag` and `WorkspaceDriftPolicy`, are
`Enum` classes that subclass `str`, so a member compares equal to its value
(`Mode.HEADLESS == "headless"`).

**Session mode values**

A Helix session mode is `"headless"` or `"interactive"` (`Mode.HEADLESS`, `Mode.INTERACTIVE`). The
0.1.1 values `"oneshot"` and `"rpc"` are gone.

**Default server**

When you pass no `server_url` and `MUTAGENT_SERVER_URL` is unset, the client calls
`https://api.mutagent.io`. In 0.1.1 it called `http://localhost:3003`.

**Stream methods**

`sandbox.stream_sandbox` and `helix_sessions.stream_helix_session` changed. In the sync client they
return `None`; 0.1.1 returned the decoded JSON body. In the async client they are async generators that
request `Accept: text/event-stream`. The Known limitations section below describes how they behave in
0.4.0.

---

## 📦 Installation

```bash
pip install mutagent-sdk
```

> The PyPI distribution is `mutagent-sdk`; the import path is `mutagent`.

```python
from mutagent import Mutagent, AsyncMutagent
```

---

## 🚀 Quick Start

### Sync client

```python
from mutagent import Mutagent

client = Mutagent(api_key="YOUR_API_KEY")

agents = client.agents.list_agents(limit=10)
print(f"Found {len(agents['data'])} agents")
```

> `server_url` defaults to `MUTAGENT_SERVER_URL`, and to `https://api.mutagent.io` when that is unset.
> Pass `server_url="http://localhost:3003"` to call a local server.

Set `MUTAGENT_API_KEY` in your environment and omit the argument:

```bash
export MUTAGENT_API_KEY="mg_live_xxxxxxxx"
```

```python
from mutagent import Mutagent

client = Mutagent()  # reads MUTAGENT_API_KEY
```

### Async client

```python
import asyncio
from mutagent import AsyncMutagent

async def main():
    async with AsyncMutagent(api_key="YOUR_API_KEY") as client:
        # Who am I?
        profile = await client.user_profile.get_profile()
        print(profile)

        # Which workspaces can I see?
        workspaces = await client.workspaces.list_workspaces()
        print(workspaces)

asyncio.run(main())
```

### Request bodies

A method that sends a body takes a model instance or a plain `dict`. A `dict` is sent as written, so
its keys must be the API's camelCase wire names; the `...TypedDict` types in `mutagent.models` use those
names as keys. A model instance is sent with `model_dump(by_alias=True, exclude_none=True)`, so it also
goes out with camelCase keys, and its fields accept either the snake_case name or the camelCase alias
(`SandboxTokenRequest(workspace_id=...)` or `SandboxTokenRequest(workspaceId=...)`). 44 request and
response models cannot be instantiated (see Known limitations below). A `dict` body:

```python
from mutagent import Mutagent

client = Mutagent()

agent = client.agents.create_agent({
    "name": "Support Agent",
    "slug": "support-agent",
    "systemPrompt": "You answer customer support questions.",
})
print(agent["id"])
```

### Errors

A non-2xx response raises `SDKError`, which carries `status_code`, `body` and the `httpx.Response` as
`response`.

```python
from mutagent import Mutagent, SDKError

client = Mutagent()

try:
    client.agents.get_agent(404)
except SDKError as e:
    print(f"HTTP {e.status_code}: {e.body}")
```

---

## 📚 Groups

The client exposes one group per API tag. Every method has a sync form on `Mutagent` and an async form
on `AsyncMutagent`:

| Group | Methods |
|-------|---------|
| `client.user_profile` | `get_profile`, `update_profile`, `delete_account`, `change_password`, `list_user_sessions`, `revoke_user_session` |
| `client.organizations` | `list_organizations`, `create_organization`, `get_organization`, `update_organization`, `delete_organization`, `get_organization_by_slug`, `check_organization_slug`, `get_organization_member_count` |
| `client.organization_members` | `list_organization_members`, `add_organization_member`, `update_organization_member`, `remove_organization_member` |
| `client.workspaces` | `list_workspaces`, `create_workspace`, `get_workspace`, `update_workspace`, `delete_workspace`, `set_default_workspace` |
| `client.workspace_members` | `list_workspace_members`, `add_workspace_member`, `update_workspace_member`, `remove_workspace_member` |
| `client.invitations` | `list_invitations`, `create_invitation`, `get_invitation`, `delete_invitation`, `resend_invitation` |
| `client.agents` | `list_agents`, `create_agent`, `get_agent`, `update_agent`, `delete_agent`, `get_agent_by_slug` |
| `client.llm_providers` | `list_provider_configs`, `create_provider_config`, `list_available_models`, `get_provider_config`, `update_provider_config`, `delete_provider_config`, `get_model_catalog`, `list_provider_config_models`, `test_provider_config` |
| `client.managed_agents` | `get_helix_agent_capabilities`, `list_helix_agents`, `get_helix_agent`, `deploy_helix_agent`, `activate_helix_agent`, `retire_helix_agent`, `get_helix_agent_operation` |
| `client.traces` | `ingest_trace_batch`, `list_traces`, `list_logs`, `get_trace`, `list_trace_spans` |
| `client.sandbox` | `list_sandbox_providers`, `preflight_sandbox`, `list_sandbox_presets`, `run_sandbox_command`, `list_sandboxes`, `create_sandbox`, `get_sandbox`, `delete_sandbox`, `stream_sandbox`, `exec_sandbox_command`, `ingest_sandbox_traces`, `list_sandbox_spans`, `start_sandbox_helix_session`, `list_sandbox_helix_sessions`, `send_sandbox_helix_session_input`, `signal_sandbox_helix_session`, `checkpoint_sandbox_helix_session`, `list_sandbox_checkpoints`, `restore_sandbox`, `create_sandbox_token` |
| `client.environments` | `list_environments`, `get_environment`, `replace_environment`, `update_environment`, `delete_environment` |
| `client.helix_sessions` | `list_helix_sessions`, `launch_helix_session`, `send_helix_session_input`, `close_helix_session_input`, `signal_helix_session`, `checkpoint_helix_session`, `list_helix_session_checkpoints`, `restore_helix_session`, `stream_helix_session`, `get_helix_models`, `set_helix_default_models` |

Per-method reference lives in [`docs/sdks/`](./docs/sdks/).

### Examples

```python
from mutagent import Mutagent

client = Mutagent()

# Organizations, members and invitations
members = client.organization_members.list_organization_members("<org-id>")
invitation = client.invitations.create_invitation(
    "<org-id>", {"email": "dev@example.com", "role": "editor"}
)

# Workspaces
workspaces = client.workspaces.list_workspaces()
client.workspaces.set_default_workspace("<workspace-id>")

# LLM providers
provider = client.llm_providers.create_provider_config(
    {"name": "Anthropic", "provider": "anthropic", "apiKey": "<provider-key>"}
)
print(client.llm_providers.test_provider_config(provider["id"]))

# Managed agents and traces
managed = client.managed_agents.list_helix_agents(limit=20)
traces = client.traces.list_traces(limit=10)
```

---

## ☁️ Cloud Sandboxes, Environments and Helix Sessions

The `sandbox`, `environments` and `helix_sessions` groups call routes that accept only a short-lived
sandbox token sent as `Authorization: Bearer`. The one exception is `sandbox.create_sandbox_token`,
which exchanges your API key for that token. Pass the token to a second client as `bearer_token`
(`Mutagent(bearer_token=...)` or `AsyncMutagent(bearer_token=...)`).

Pass one credential per client. An explicit `bearer_token` wins over `MUTAGENT_API_KEY` from the environment;
passing both `api_key` and `bearer_token` raises `ValueError`. Use the API key for platform operations and the
sandbox token as `bearer_token` for sandbox, Environment and Helix session operations.

```python
from mutagent import Mutagent
from mutagent.models import HelixSignal, Mode

platform = Mutagent(api_key="YOUR_API_KEY")
token = platform.sandbox.create_sandbox_token({"workspaceId": "<workspace-id>"})
print(token["expiresIn"])

client = Mutagent(bearer_token=token["token"])

session = client.helix_sessions.launch_helix_session(body={"mode": Mode.INTERACTIVE})
client.helix_sessions.send_helix_session_input(
    session["reference"],
    {"line": '{"type": "prompt", "id": "p1", "message": "List the files"}'},
)
client.helix_sessions.signal_helix_session(session["reference"], {"signal": HelixSignal.SIGINT})
```

| Operation | Method | Route |
|-----------|--------|-------|
| List sandbox providers | `sandbox.list_sandbox_providers` | `GET /api/sandbox/providers` |
| Preflight a sandbox definition | `sandbox.preflight_sandbox` | `POST /api/sandbox/preflight` |
| List sandbox presets | `sandbox.list_sandbox_presets` | `GET /api/sandbox/presets` |
| Run one command in a new sandbox | `sandbox.run_sandbox_command` | `POST /api/sandbox/run` |
| Spawn a sandbox | `sandbox.create_sandbox` | `POST /api/sandbox` |
| List sandboxes | `sandbox.list_sandboxes` | `GET /api/sandbox` |
| Get sandbox status | `sandbox.get_sandbox` | `GET /api/sandbox/{id}` |
| Tear down a sandbox | `sandbox.delete_sandbox` | `DELETE /api/sandbox/{id}` |
| Run a command in a sandbox | `sandbox.exec_sandbox_command` | `POST /api/sandbox/{id}/exec` |
| Watch a sandbox's output | `sandbox.stream_sandbox` | `GET /api/sandbox/{id}/stream` |
| Read a sandbox's captured spans | `sandbox.list_sandbox_spans` | `GET /api/sandbox/{id}/traces` |
| Ingest OTLP spans from inside a sandbox | `sandbox.ingest_sandbox_traces` | `POST /api/sandbox/telemetry/v1/traces` |
| Exchange an API key for a sandbox operator token | `sandbox.create_sandbox_token` | `POST /api/sandbox/token` |
| List workspace Environments | `environments.list_environments` | `GET /api/sandbox/environments` |
| Launch a Helix session | `helix_sessions.launch_helix_session` | `POST /api/sandbox/helix/sessions` |
| Send a JSON command to a session | `helix_sessions.send_helix_session_input` | `POST /api/sandbox/helix/sessions/{reference}/input` |
| Stream a session's output | `helix_sessions.stream_helix_session` | `GET /api/sandbox/helix/sessions/{reference}/stream` |

The Groups table above lists every method in these groups.

---

## ⚠️ Known limitations

- 44 of 132 request and response models cannot be instantiated because the generator references
  nested types it does not emit (for example `HelixLaunchRequest`, whose `env` record type is
  missing). Pass those request bodies as dicts, e.g.
  `client.helix_sessions.launch_helix_session(body={"mode": Mode.INTERACTIVE})`.
  The affected models are `Agent`, `AgentList`, `AgentRevision`, `AgentRevisionPage`,
  `AgentSlotChange`, `CreateAgentRequest`, `CreateOrganizationRequest`, `CreateProviderConfigRequest`,
  `CreateWorkspaceRequest`, `DeployAgentResult`, `DeploymentOperation`, `EnvironmentPatchRequest`,
  `EnvironmentReplaceRequest`, `HelixLaunchRequest`, `HelixLaunchedSession`, `HelixRestoreRequest`,
  `HelixSessionRestoreResult`, `LogRecord`, `LogRecordList`, `ManagedAgentDetail`, `ModelsList`,
  `NoProviderConfiguredError`, `ProviderConfig`, `ProviderConfigsList`, `SandboxDefinition`,
  `SandboxPreflightRequest`, `SandboxRestoreResult`, `SandboxSessionStartRequest`,
  `SandboxSpawnRequest`, `Span`, `SpanList`, `Trace`, `TraceBatchRequest`, `TraceBatchSpan`,
  `TraceBatchTrace`, `TraceList`, `UpdateAgentRequest`, `UpdateOrganizationRequest`,
  `UpdateProviderConfigRequest`, `UpdateWorkspaceRequest`, `Workspace`, `WorkspaceModelListing`,
  `WorkspaceWithRole` and `WorkspacesList`. The fix is planned in a follow-up release, 0.4.1.
- Methods are annotated with model return types, but return the response JSON as a `dict` at runtime.
  Use dict access (`session["reference"]`). Typed return values are also planned for 0.4.1.

Streaming in 0.4.0: the sync `stream_sandbox` and `stream_helix_session` send
`Accept: application/json`, read the whole response, and return `None`; the event data is discarded.
The async versions raise `TypeError` before a request is sent.

---

## 🧪 Testing

The package has a `dev` extras group with the test and lint tools:

```bash
pip install "mutagent-sdk[dev]"
# Includes: pytest, pytest-asyncio, pytest-httpx, ruff, mypy
```

From a checkout of this package, run the test suite:

```bash
pytest tests/
```

Tests live in `tests/` at the package root.

---

## 🏗️ Generated by mutagent-xgen

This package is generated by [mutagent-xgen](../mutagent-xgen/) — MutagenT's proprietary
in-house SDK generator. The generator ensures the Python client stays in sync with the API
specification.

To regenerate after API changes:

```bash
# Fetch latest spec from running server
bash scripts/dump-spec.sh

# Regenerate SDK
mutagent-xgen run
```

> **Note:** `README.md` is emitted **once** and is never rewritten by a regeneration, so the
> hand-written content here is safe.

---

## 📜 License

This SDK is released under the [Apache License 2.0](./LICENSE).

Copyright 2026 MutagenT. All rights reserved.

---

<p align="center">
  <sub>Built with care by the MutagenT Team &bull; <a href="https://mutagent.io">mutagent.io</a></sub>
</p>
