> ## Documentation Index
> Fetch the complete documentation index at: https://agent.minimaxi.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Python SDK

> 用 minimax-code-sdk 在 Python 中程序化驱动本机 MiniMax Code。

Python SDK 提供和 [TypeScript SDK](https://agent.minimaxi.com/docs/cli/sdk.md) 同样的能力：在 Python 代码里创建 Thread、跑 Turn、流式读取事件、续接 Session。

每一轮 Turn 对应一个本机 `mcode exec --output-format=stream-json` 进程，通过 `--session` 续接同一个 Session。当前是 `0.x`，API 在 `1.0` 前可能随次要版本调整。

相关页面：[TypeScript SDK](https://agent.minimaxi.com/docs/cli/sdk.md)、[Headless 与 CI](https://agent.minimaxi.com/docs/cli/automation.md)。包页面：[PyPI `minimax-code-sdk`](https://pypi.org/project/minimax-code-sdk/)。

## 环境要求

| 组件 | 要求 |
| - | - |
| Python | `>=3.10` |
| MiniMax Code CLI（`mcode`） | `>=0.6.3` |
| 事件 `schemaVersion` | `1` |

SDK 不负责安装 CLI，需要单独安装。运行前需要已登录，或在数据目录里配置可用的 API Key Provider。

## 安装

```bash theme={null}
pip install minimax-code-sdk        # 或：uv add minimax-code-sdk
npm install -g @minimax-ai/code     # mcode CLI
```

导入名是 `minimax_code`。

## 快速开始

```python theme={null}
import asyncio
from minimax_code import MCode, ThreadOptions


async def main() -> None:
    client = MCode()
    thread = client.start_thread(ThreadOptions(cwd=".", permission="smart"))

    turn = await thread.run("Summarize this repository in one sentence.")
    print(thread.id, turn.final_response, turn.usage)

    # 同一个 Session，下一轮
    turn = await thread.run("Now list its top-level directories.")
    print(turn.final_response)


asyncio.run(main())
```

`run()` 只在状态为 `succeeded` 时返回 `Turn`，包含 `final_response`、归一化后的 `items`、`usage`、`model`、`session_id`、`turn_id`、`duration_ms` 和完整的 CLI `result`。其他结果一律抛异常。

### 同步 API

代码不是 async 的话，用 `SyncMCode`。方法相同，只是不用 `await`：

```python theme={null}
from minimax_code import SyncMCode

with SyncMCode() as client:
    thread = client.start_thread()
    print(thread.run("hello").final_response)
    for event in thread.run_streamed("again"):
        print(event["type"])
```

`SyncMCode` 自带事件循环，所以不能在已有事件循环的环境里用，比如 Jupyter notebook 或 `async def` 函数内部。在这些环境里跑 Turn 会抛出一个 `RuntimeError`，提示改用 async API。这时请用 `MCode` 加 `await`。

## CLI 查找顺序

1. `MCodeOptions(bin=...)`；
2. 环境变量 `MCODE_BIN`；
3. `PATH` 上的 `mcode`。

SDK 不会通过 shell 启动 CLI。找不到 CLI 时抛 `MCodeNotFoundError`。每个客户端在第一次运行前执行一次 `mcode --version`，CLI 低于 `0.6.3` 时抛 `MCodeVersionError`。

Windows 上，官方安装器或 npm / pnpm 生成的 `mcode.cmd` 启动器会被解析到它实际运行的 JS 入口和 Node 运行时。无法识别的 `.cmd` 会被拒绝，这时把 JS 入口作为 `bin` 传入。

## 选项

选项都是 dataclass，分别传给客户端、Thread 和每一轮 Turn。

### `MCode(MCodeOptions(...))`

| 字段 | 说明 |
| - | - |
| `bin` | 显式指定 `mcode` 路径或命令名 |
| `data_dir` | 数据目录，以 `MINIMAX_DATA_DIR` 传给 CLI |
| `env` | 子进程环境变量。设置后会**替换** `os.environ`；`repr()` 里不显示值 |
| `config_path` | 运行时配置文件，以 `--config` 传入 |

只想追加变量、不替换整个环境时，合并 `os.environ`：

```python theme={null}
import os
from minimax_code import MCode, MCodeOptions

client = MCode(MCodeOptions(env={**os.environ, "FOO": "bar"}))
```

### `start_thread` / `resume_thread(ThreadOptions(...))`

| 字段 | CLI 参数 |
| - | - |
| `cwd` | `--cwd`；默认是当前工作目录，在创建 Thread 时解析 |
| `model` / `effort` | `--model`（`provider/model`）/ `--effort` |
| `permission` | `--permission`：`smart` / `full` / `off` |
| `mode` | `--mode`：`standard` / `lightweight`；只对新 Thread 有效 |
| `prompt_mode` | `--prompt-mode`：`tui` / `coding` / `work` |
| `system_prompt` | 替换系统提示词（SDK 写入临时文件） |
| `append_system_prompt` | 追加到系统提示词（SDK 写入临时文件） |

非法取值会在启动 CLI 前抛 `MCodeInvocationError`，`resume_thread` 传 `mode="lightweight"` 也一样。没有 `ask` 权限：每轮 Turn 是独立进程，不支持交互式权限确认。

### `thread.run` / `thread.run_streamed(prompt, RunOptions(...))`

| 字段 | 说明 |
| - | - |
| `files` | 附件（`--file`，可多个） |
| `timeout_ms` | 单轮超时，由 CLI 执行 |
| `max_steps` | `--max-steps` |

```python theme={null}
from minimax_code import RunOptions

turn = await thread.run(
    "Diagnose and fix the failing CI job",
    RunOptions(files=["./ci.log"], timeout_ms=10 * 60_000, max_steps=50),
)
```

一个 Thread 同一时间只跑一轮 Turn。并发调用会抛 `ThreadBusyError`，不会排队。

## Thread 与续接

`thread.id` 就是 Session id，第一轮 Turn 发出第一个事件后就能拿到。把它存下来，之后用 `resume_thread` 续接：

```python theme={null}
thread = client.start_thread(ThreadOptions(cwd="/path/to/project"))
await thread.run("...")

later = client.resume_thread(thread.id, ThreadOptions(cwd="/path/to/project"))
print((await later.run("What did I ask first?")).final_response)
```

Session 归属于创建它的工作区，所以 `resume_thread()` 要传同一个 `cwd`。不传 `cwd` 时用调用时的当前工作目录。Thread 在创建时固定 `cwd`，之后 `os.chdir()` 不影响它。从另一个工作区续接会抛 `MCodeRunError`，重试也没用。

## 流式输出

`run_streamed()` 返回 `StreamedTurn`，用 `async for` 遍历。`agent_message` 的文本增量既可能出现在 `item.started`，也可能出现在 `item.updated`，所以要从所有带 item 的事件里读 `contentDelta`：

```python theme={null}
streamed = await thread.run_streamed("Fix the failing test.")
async for event in streamed:
    item = event.get("item")
    if item and item["type"] == "agent_message":
        print(item.get("contentDelta", ""), end="")
    elif event["type"] == "turn.failed":
        print("failed:", event.get("error"))
```

事件就是 CLI 的 stream-json 事件，以普通 dict 原样透传，未知类型也会透传：`exec.started`、`session.started` / `session.resumed`、`turn.started`、`item.started` / `item.updated` / `item.completed`、`turn.completed`、`turn.failed`、`exec.completed`。唯一的例外：同一个 item 的 `item.updated` 快照（不带 `contentDelta`）和上一份完全相同时会被跳过。文本增量不会被跳过。

`turn.failed` 是普通事件，只有进程或协议故障时遍历才会抛异常。

`Turn.items` 是归一化后的 dataclass：`AgentMessageItem`、`ReasoningItem`、`ToolCallItem`。Turn 结束时还没收到 `item.completed` 的 item 会标记 `incomplete=True`。

## 错误

所有错误都继承自 `MCodeError`，带有 `exit_code`、`stderr`（CLI stderr 末尾，仅用于诊断）、`session_id`、`result` 和 `items`。

| 错误 | 常见原因 |
| - | - |
| `MCodeInvocationError` | SDK 在启动 CLI 前拒绝的选项，或 CLI 退出码 `2` |
| `MCodeRunError` | Turn 以 `failed`、`timeout` 或 `limit_exceeded` 结束；额外带 `status` 和 `category` |
| `MCodeAbortError` | Turn 被取消（退出码 `130` 或结果为 cancelled） |
| `MCodeProtocolError` | stdout 不是 JSON、缺少 `exec.completed`、管道断开等 |
| `MCodeNotFoundError` | 找不到 CLI |
| `MCodeVersionError` | CLI 低于 `0.6.3`，或事件 `schemaVersion` 不受支持 |
| `ThreadBusyError` | 同一 Thread 上并发跑 Turn |

`MCodeRunError.status` 是 `failed`、`timeout` 或 `limit_exceeded`；`category` 是 `config`、`runtime`、`internal` 或 `None`。`MCODE_EXEC_EXIT_CODES` 按名字列出 CLI 退出码。

```python theme={null}
from minimax_code import MCodeAbortError, MCodeError, MCodeRunError

try:
    turn = await thread.run("Run the migration")
except MCodeRunError as error:
    print(error.status, error.category, error.exit_code, error.session_id)
except MCodeAbortError:
    print("cancelled")
except MCodeError as error:
    print(type(error).__name__, error)
```

SDK 不会自动重试。错误带 `session_id` 时，可以用 `resume_thread(error.session_id, ...)` 接着跑。错误对象可以 pickle，比如从 `ProcessPoolExecutor` 的 worker 里返回。

## 取消与超时

* `streamed.cancel()` 发送 `SIGTERM`，也就是 CLI 的取消信号，之后流会以 CLI 的收尾事件结束；
* 提前离开 `async for`（`break` 或抛异常），或者取消正在跑 `thread.run()` 的 task，都会停掉 CLI：先 `SIGTERM`，超过 CLI 60 秒的关闭预算还没退出就 `SIGKILL`。同一 Thread 的下一轮会等这次关闭完成，不会抛 `ThreadBusyError`；
* `async with streamed:` 或 `await streamed.aclose()` 可以确定性地停掉 CLI；
* `timeout_ms` 由 CLI 执行。超过 `timeout_ms` 90 秒后 CLI 还在跑，SDK 会杀掉它并抛 `status="timeout"` 的 `MCodeRunError`；
* Windows 上取消会立即停掉 CLI。

```python theme={null}
streamed = await thread.run_streamed("Refactor the module")
async with streamed:
    async for event in streamed:
        if event["type"] == "item.completed":
            break  # 离开代码块时停掉 CLI
```

## 暂不支持

* 交互式权限确认（`permission="ask"`）和进程内自定义工具；
* `output_schema`（结构化输出约束）、审批回调、运行中转向、fork。

需要直接调用 CLI 或处理结构化输出时，请使用 [Headless 与 CI](https://agent.minimaxi.com/docs/cli/automation.md)。
