《Cursor文档》-Cursor Python SDK

cursor-sdk 包可让您从自己的 Python 代码中调用 Cursor 的智能体。在 Cursor IDE、CLI 和网页端运行的同一智能体,也可通过 Python 进行脚本调用,并支持同步和异步客户端、类型化数据类,以及对流和页面的常规迭代。请在 Cursor 中运行 /sdk 技能以快速入门。

如需使用 REST API,请参阅 Cloud Agents API。如需其他语言支持,请参阅 SDK Bridge

概述

SDK 通过统一接口封装本地和云端运行时。无论智能体在哪里运行,您都编写相同的代码。

运行时 功能 适用场景
本地 让智能体处理磁盘上的本地文件。 针对工作树运行开发脚本和 CI 检查。
云端 (由 Cursor 托管) 在隔离的 VM 中运行,且已克隆您的仓库。VM 由 Cursor 托管。 调用方没有仓库、需要并行运行多个智能体,或运行需要在调用方断开连接后继续时。

Agent.create() 传入 localcloud 以设置运行时。

身份验证

创建智能体前,请设置 CURSOR_API_KEY 或传入 api_key

SDK 支持本地和云端运行时使用用户 API 密钥和服务账户 API 密钥。暂不支持团队 Admin API 密钥。

export CURSOR_API_KEY="your-key"

用量和计费

SDK 运行遵循与 IDE 和云端代理运行相同的定价、请求池和隐私模式规则。费用会显示在团队的用量仪表盘中,并标记为 SDK。

如需在代码中读取单次运行的 token 数量,请参阅 Token 用量。如需获取智能体运行的已计费用量和美元费用,请参阅 agent.get_usage()

核心概念

概念 描述
Agent 持久化句柄,包含对话状态、工作区配置、模型选择和设置,可在多个提示词之间保留。
Run 一次提示词提交,拥有独立的流、状态、结果、对话和取消操作。
SDKMessage 运行期间产生的强类型流消息。在本地和云端运行时中具有相同结构。
CursorClient 用于控制生命周期、配置自定义 HTTP 选项,或在同一进程中使用多个工作区的显式客户端。Client 是其别名。
AsyncClient 异步镜像客户端。所有异步操作都必须使用它。

安装

pip install cursor-sdk

需要 Python 3.10 或更高版本。

快速入门

import os

from cursor_sdk import Agent, LocalAgentOptions

with Agent.create(
    model="composer-2.5",
    api_key="crsr_key",
    local=LocalAgentOptions(cwd=os.getcwd()),
) as agent:
    print(agent.send("Summarize what this repository does").text())

流事件介绍如何提取助手文本、处理工具调用以及读取运行状态。若要一次性完成提示词的创建、运行和结束,请参阅 Agent.prompt()

云端快速入门

Python SDK 原生支持 Cursor 云端代理。你可以列出已连接的仓库,针对其中一个启动智能体,等待运行完成,然后评审最终结果。

from cursor_sdk import Agent, CloudAgentOptions, CloudRepository

with Agent.create(
    model="composer-2.5",
    api_key="crsr_key",
    cloud=CloudAgentOptions(
        repos=[CloudRepository(url="https://github.com/your-org/your-repo", starting_ref="main")],
        auto_create_pr=True,
    ),
) as agent:
    print(agent.send("Add structured logging to the auth middleware").text())

由 SDK 启动的云端代理已从默认智能体列表中筛除。要在 Cursor 网页端或 Cursor 代理窗口中查看它们,请点击 筛选 > 来源 > SDK

异步用法

异步客户端提供与同步客户端相同的接口,推荐用于服务器、机器人和并发智能体编排。AsyncAgentAsyncClientAsyncRunAsyncCursor 均可从 cursor_sdkcursor_sdk.asyncio 导入。

import asyncio
import os

from cursor_sdk import AsyncClient, LocalAgentOptions

async def main():
    async with await AsyncClient.launch_bridge(workspace=os.getcwd()) as client:
        async with await client.agents.create(
            model="composer-2.5",
            api_key="crsr_key",
            local=LocalAgentOptions(cwd=os.getcwd()),
        ) as agent:
            run = await agent.send("Summarize what this repository does")
            print(await run.text())

asyncio.run(main())

没有全局异步默认客户端。请显式实例化 AsyncClient,或将 AsyncClient.launch_bridge(...) 作为异步上下文管理器使用,以确保每个事件循环都有各自的客户端。请勿在同一代码路径中混用同步和异步客户端。

直接调用 AsyncAgent 类方法时需要提供 client=。请使用
await client.agents.create(...)
await AsyncAgent.create(..., client=client)

同步 异步
CursorClient / Client AsyncClient / AsyncCursorClient
Agent AsyncAgent
Run AsyncRun
Cursor AsyncCursor
ListResult AsyncListResult
DefaultHttpxClient DefaultAsyncHttpxClient

创建智能体

Agent.create() 会验证选项,并立即返回一个句柄。传入 localcloud 以选择运行时环境。

from cursor_sdk import Agent, CloudAgentOptions, CloudRepository, LocalAgentOptions

agent = Agent.create(
    model="composer-2.5",
    local=LocalAgentOptions(cwd="."),
)

cloud_agent = Agent.create(
    model="composer-2.5",
    cloud=CloudAgentOptions(
        repos=[CloudRepository(url="https://github.com/your-org/your-repo", starting_ref="main")],
        auto_create_pr=True,
    ),
)

agent.agent_id 会立即赋值。本地智能体的 ID 为 agent-<uuid>;云端代理的 ID 为 bc-<uuid>agent.model 是带类型的 ModelSelection,因此可直接使用 agent.model.idagent.model.params

由 SDK 启动的云端代理不会显示在默认智能体列表中。要在 Cursor 网页端 或 Cursor 代理窗口中
查看它们,请点击 筛选 > 来源 > SDK

无代码仓库云端代理

云端代理可在不含代码仓库的空 VM 上运行。传入 cloud 并将 repos 列表设为空,或完全省略 repos。省略 cloud 则会选择本地运行时。

from cursor_sdk import Agent, CloudAgentOptions

with Agent.create(cloud=CloudAgentOptions(repos=[])) as agent:
    run = agent.send("Research the top 3 Python testing frameworks and summarize.")
    print(run.wait().result)

必须为您的账户或团队启用无仓库智能体。仓库范围的 API 密钥无法创建此类智能体;请改用不受限制的服务账户密钥或用户 API 密钥。

会话环境变量

对于云端代理,如果一次运行需要短期凭据或其他仅供该智能体使用的值,请传递 env_vars

import os

agent = Agent.create(
    model="composer-2.5",
    cloud=CloudAgentOptions(
        repos=[CloudRepository(url="https://github.com/your-org/your-repo")],
        env_vars={
            "STAGING_API_TOKEN": os.environ["STAGING_API_TOKEN"],
        },
    ),
)

这些值会在静态存储时加密,注入云端代理的 shell,并在删除智能体时一并删除。env_vars 不能与调用方提供的 agent_id 一起使用;请省略 agent_id,并从 agent.agent_id 读取服务器签发的 ID。变量名不能以 CURSOR_ 开头。

对于仅应在单次运行期间存在的值,请改为通过 agent.send() 传递。参见单次运行的环境变量

智能体元数据

创建云端代理时,可为其添加自定义标识符。元数据可将智能体与系统中的用户、租户、工作流或工单关联,并可通过 client.agents.get()client.agents.list()SDKAgentInfo.metadata 中读取。这些标签并非 VM 内的智能体元数据 API;该 API 会从 VM 内部提供当前运行的 ID、所有者、轮次和工作区。

from cursor_sdk import Agent, CloudAgentOptions, CloudRepository

with Agent.create(
    model="composer-2.5",
    cloud=CloudAgentOptions(
        repos=[CloudRepository(url="https://github.com/your-org/your-repo")],
        metadata={
            "end_user_id": "user-123",
            "ticket_id": "ENG-456",
        },
    ),
) as agent:
    print(agent.agent_id)

创建云端代理时可添加元数据。最多可附加 50 个键值对。键不能为空,且不得超过 255 个字符。值必须为不超过 4096 字节的字符串。允许使用空字符串值,空映射会被视为未设置元数据。

如果 API 密钥所属的账户未启用元数据功能,使用非空映射创建智能体将返回 403 feature_unavailable

模型参数

使用 ModelSelection.params 传递特定模型的选项,例如推理 effort 或 Cursor Router 的 optimize_for。参数 ID 和取值因模型而异。使用 Cursor.models.list() 查看您的账户支持哪些参数和预设变体。

from cursor_sdk import Agent, LocalAgentOptions, ModelParameterValue, ModelSelection

agent = Agent.create(
    model=ModelSelection(
        id="composer-2.5",
        params=[ModelParameterValue(id="fast", value="true")],
    ),
    local=LocalAgentOptions(cwd="."),
)

使用 Cursor.models.list() 查看指定模型的参数 ID 和预设变体。有关 auto-smart 的选择合约,请参阅 Cursor Router

Cursor Router

Cursor Router 会为每个 Auto 请求选择模型。在 SDK 中,Router 是带有 optimize_for 参数的 auto-smart 模型。它适用于 Teams 和企业版。企业版管理员必须先为团队启用 Router,auto-smart 才会出现在目录中。

Cursor SDK 是智能体 SDK,而非独立的模型推理或聊天补全 API。Router 会为能够理解工作区、调用工具、运行命令和编辑文件的 Cursor 智能体运行选择模型。Cursor 目前尚未提供用于任意模型调用的底层 Router 端点文档。

选择成本、平衡或智能

传入 auto-smart,并显式设置 optimize_for

产品标签 SDK 值
成本 cost
平衡 balanced
智能 intelligence

产品文案中请使用 平衡balanced 仅用作 SDK 传输值。

import os

from cursor_sdk import Agent, LocalAgentOptions, ModelParameterValue, ModelSelection

with Agent.create(
    model=ModelSelection(
        id="auto-smart",
        params=[ModelParameterValue(id="optimize_for", value="balanced")],
    ),
    local=LocalAgentOptions(cwd=os.getcwd()),
) as agent:
    run = agent.send("Find and fix the failing authentication test")
    result = run.wait()

    print(result.status)

始终传入 optimize_for。请勿省略该参数,也不要传入旧版 default 值;支持通过目录进行发现这一合约。

在模型目录中查找 Router

Cursor.models.list() 会返回当前 API 密钥所属账户和团队可用的模型、参数定义及预设变体。Router 可用时,Cursor Router 会显示为 auto-smart。团队管理员可以禁用 Router,或限制成员可选择的优化模式。

硬编码选择前,请以目录为准:

from cursor_sdk import Cursor, ModelParameterValue, ModelSelection

models = Cursor.models.list()
router = next((model for model in models if model.id == "auto-smart"), None)
optimize_for = next(
    (
        parameter
        for parameter in (router.parameters if router else [])
        if parameter.id == "optimize_for"
    ),
    None,
)

if router is None or optimize_for is None:
    raise RuntimeError(
        "Cursor Router is not available for this API key. "
        "Verify that Router is enabled for the key's team."
    )

requested_mode = "balanced"
allowed_values = {entry.value for entry in optimize_for.values}

if requested_mode not in allowed_values:
    raise RuntimeError(
        f'Router mode "{requested_mode}" is not enabled for this team.'
    )

model = ModelSelection(
    id=router.id,
    params=[ModelParameterValue(id=optimize_for.id, value=requested_mode)],
)

按运行切换模式

agent.send() 中指定模型,以更改某次运行的 Router 模式:

from cursor_sdk import ModelParameterValue, ModelSelection, SendOptions

run = agent.send(
    "Handle this complex migration",
    SendOptions(
        model=ModelSelection(
            id="auto-smart",
            params=[ModelParameterValue(id="optimize_for", value="intelligence")],
        ),
    ),
)

单次运行的模型覆盖会持续生效。后续发送时如未指定覆盖,将继续使用新的模型选择。请参阅单次运行的模型覆盖

模型 ID:auto-smartautodefault

选择 含义
搭配 optimize_for 使用的 auto-smart Cursor Router。需要成本、平衡或智能模式时使用。
ModelSelection(id="auto") 当目录中没有指定模型时,由服务器选择的 Auto 回退方案。需要明确指定 Router 模式时,优先使用 auto-smart
省略 optimize_for 或传入 default 不受支持的 Router 合约。请始终查询允许的值,并传入 costbalancedintelligence

计费与路由模型池

  • 所有 Auto 模式均按每个请求所路由模型的标价计费。

  • 每次请求所用的底层模型可能不同。如需进行可复现的比较,请使用固定的模型 ID。

  • 企业版模型允许列表会影响路由模型池。屏蔽必要模型可能会导致 Router 被禁用。

有关当前费率和路由模型池,请参阅 Cursor RouterAuto 模式

Router 缺失的疑难排查

如果找不到 auto-smart 或优化模式被拒绝:

  1. 调用 Cursor.models.list()
  2. 确认结果中包含 auto-smart
  3. 确认 optimize_for 包含所需的值 (costbalancedintelligence) 。
  4. 确认与 API 密钥关联的团队已启用 Router。
  5. 如果您属于多个团队,请确认该密钥在预期的团队上下文中使用。
  6. 如果 Router 不可用或无法选择有效的底层模型,请检查团队的模型访问策略。

原始字典

对于应用代码,建议优先使用带类型的 dataclass,因为 IDE 自动补全和类型检查的支持更好。SDK 也接受适用于简短脚本或外部提供的 JSON 的普通字典。蛇形命名法的键会被规范化。

from cursor_sdk import Agent

with Agent.create(
    {
        "api_key": "crsr_key",
        "model": {"id": "composer-2.5"},
        "local": {"cwd": "."},
    }
) as agent:
    ...

智能体

Agent.create()Agent.resume()client.agents.create()client.agents.resume() 返回的句柄。

class Agent:
    agent_id: str
    model: ModelSelection | None
    client: CursorClient

    def send(
        self,
        message: str | Mapping[str, Any] | UserMessage,
        options: SendOptions | Mapping[str, Any] | None = None,
        *,
        idempotency_key: str | None = None,
    ) -> Run: ...

    def reload(self) -> None: ...
    def close(self) -> None: ...

    def list_messages(
        self, options: Mapping[str, Any] | None = None
    ) -> list[AgentMessage]: ...
    def list_artifacts(self) -> list[SDKArtifact]: ...
    def download_artifact(self, path: str) -> bytes: ...
    def get_usage(self, *, run_id: str | None = None) -> AgentUsage: ...

    def archive(self, options: Mapping[str, Any] | None = None) -> None: ...
    def unarchive(self, options: Mapping[str, Any] | None = None) -> None: ...
    def delete(self, options: Mapping[str, Any] | None = None) -> None: ...
成员 描述
agent_id 稳定的智能体标识符。本地为 agent-<uuid>,云端为 bc-<uuid>
model 当前的类型化模型选择。使用模型覆盖成功发送后会更新。
send 使用给定提示词启动新的运行。返回 Run 句柄。
reload 在不释放智能体的情况下重新读取文件系统配置 (钩子、项目 MCP、子智能体) 。
close 关闭智能体并释放资源。
list_messages 列出智能体的消息历史记录。
list_artifacts 列出智能体生成的文件 (仅限云端;本地返回空) 。
download_artifact 按路径下载文件 (仅限云端;本地会引发异常) 。
get_usage 获取智能体的计费 token 用量和美元费用。
archive / unarchive / delete 管理云端代理的生命周期。

使用上下文管理器自动清理:

with Agent.create(model="composer-2.5", local=LocalAgentOptions(cwd=".")) as agent:
    print(agent.send("Explain this repository").text())

使用同步 Agent.*Cursor.* 辅助函数时,如果未传入 client=,SDK 会启动或复用模块级默认客户端。该客户端会在进程退出时自动关闭,也可以手动显式关闭:

from cursor_sdk import close_default_client

close_default_client()

Agent.prompt()

Agent.prompt(
    message: str | Mapping[str, Any] | UserMessage,
    options: AgentOptions | Mapping[str, Any] | None = None,
    *,
    client: CursorClient | None = None,
) -> RunResult

一次性便捷方法:创建智能体,发送单条提示词,等待运行完成后释放资源。

from cursor_sdk import Agent, AgentOptions, LocalAgentOptions

result = Agent.prompt(
    "What does the auth middleware do?",
    AgentOptions(model="composer-2.5", local=LocalAgentOptions(cwd=".")),
)
print(result.result)

异步等效写法 (假设你已创建 AsyncClient 实例) :

from cursor_sdk import AgentOptions, AsyncAgent, LocalAgentOptions

result = await AsyncAgent.prompt(
    "What does the auth middleware do?",
    AgentOptions(model="composer-2.5", local=LocalAgentOptions(cwd=".")),
    client=client,
)

CursorClient

需要显式控制生命周期、使用自定义 bridge endpoint 或自定义 HTTP 选项,或需在同一进程中使用多个工作区时,请使用 CursorClientClient 仍可用作别名。

from cursor_sdk import CursorClient, LocalAgentOptions

with CursorClient.launch_bridge(workspace=".") as client:
    with client.agents.create(
        model="composer-2.5",
        api_key="crsr_key",
        local=LocalAgentOptions(cwd="."),
    ) as agent:
        print(agent.send("Summarize what this repository does").text())

资源

显式客户端提供资源命名空间:

资源 同步方法示例 异步方法示例
agents client.agents.create(...)client.agents.list(...)client.agents.get(...) await client.agents.create(...)await client.agents.list(...)
models client.models.list() await client.models.list()
repositories client.repositories.list() await client.repositories.list()

client.create_agent(...)client.list_agents(...) 等顶层方法仍然可用,但对于应用代码,推荐使用资源命名空间。

自定义 HTTP 客户端

同步和异步客户端均支持使用自定义 httpx 客户端,以配置代理、传输方式及其他高级 HTTP 选项:

from cursor_sdk import CursorClient, DefaultHttpxClient

with CursorClient.launch_bridge(
    workspace=".",
    http_client=DefaultHttpxClient(proxy="http://proxy.example.com"),
) as client:
    ...
from cursor_sdk import AsyncClient, DefaultAsyncHttpxClient

async with await AsyncClient.launch_bridge(
    workspace=".",
    http_client=DefaultAsyncHttpxClient(proxy="http://proxy.example.com"),
) as client:
    ...

DefaultHttpxClientDefaultAsyncHttpxClient 会保留 SDK 默认的超时和重定向行为。普通的 httpx.Clienthttpx.AsyncClient 则使用 httpx 的默认值。

配置超时和重试

两个客户端都提供 with_options(...),该方法会返回一个浅拷贝,与原对象共享连接设置,并覆盖默认值。可使用 timeout 为所有请求设置超时,或分别设置 unary_timeoutstream_timeoutmax_retries 控制客户端的重试次数:

short = client.with_options(timeout=5.0, max_retries=2)
agent = short.agents.create(model="composer-2.5", local=LocalAgentOptions(cwd="."))

异步版本:

short_async = async_client.with_options(timeout=5.0, max_retries=2)
agent = await short_async.agents.create(model="composer-2.5", local=LocalAgentOptions(cwd="."))

发送消息

每次调用 agent.send() 都会返回一个 Run。每次调用 await async_agent.send() 都会返回一个 AsyncRun。智能体会在多次运行之间保留对话上下文;每次运行对应处理一个提示词的工作单元。

print(agent.send("Find the bug in src/auth.py").text())

# 同一个智能体,完整的对话上下文会保留下来。
print(agent.send("Fix it and add a regression test").text())

异步版本:

run = await agent.send("Find the bug in src/auth.py")
print(await run.text())

run = await agent.send("Fix it and add a regression test")
print(await run.text())

要在发送文本时附带图像:

run = agent.send(
    {
        "text": "What's in this screenshot?",
        "images": [{"data": base64_png, "mime_type": "image/png"}],
    }
)

您还可以使用辅助数据类。SDKImage.from_file(path) 会从磁盘读取文件,并自动处理 base64 编码:

from cursor_sdk import SDKImage, UserMessage

run = agent.send(
    UserMessage(
        text="What's in this screenshot?",
        images=[SDKImage.from_file("screenshot.png")],
    )
)

对于已具备编码字节数据或远程 URL 的调用方,也可使用 SDKImage.data_image(base64_data, mime_type)SDKImage.url_image(url)

运行

class Run:
    id: str
    agent_id: str
    status: str  # "running" | "finished" | "error" | "cancelled" | "expired"
    result: str
    model: ModelSelection | None
    duration_ms: int
    git: RunGitInfo | None
    created_at: str | None
    usage: TokenUsage | None  # 累计值;实时句柄的属性

    def stream(self) -> Iterator[SDKMessage]: ...
    def messages(self) -> Iterator[SDKMessage]: ...
    def events(self) -> Iterator[RunStreamEvent]: ...
    def iter_text(self) -> Iterator[str]: ...
    def text(self) -> str: ...
    def wait(self) -> RunResult: ...
    def cancel(self) -> None: ...
    def conversation(self) -> list[ConversationTurn]: ...
    def conversation_json(self) -> str: ...
    def observe(self, *, after_offset: str | None = None) -> Iterator[RunStreamEvent]: ...

    def supports(self, operation: str) -> bool: ...
    def unsupported_reason(self, operation: str) -> str | None: ...
    def on_did_change_status(
        self, listener: Callable[[str], None]
    ) -> Callable[[], None]: ...

run.stream()run.messages() 的别名。直接迭代 run 会生成 RunStreamEvent envelopes,与 run.events() 相同。

AsyncRun 具有相同的状态字段,包括 usage。执行 I/O 操作的方法均为 async:async for message in run.stream()async for message in run.messages()async for event in run.events()async for text in run.iter_text()await run.text()await run.wait()await run.cancel()await run.conversation()await run.conversation_json()async for event in run.observe()

流式输出

run = agent.send("Find the bug in src/auth.py")

for message in run.messages():
    if message.type == "assistant":
        for block in message.message.content:
            if block.type == "text":
                print(block.text, end="")
    elif message.type == "thinking":
        print(message.text, end="")
    elif message.type == "tool_call":
        print(f"[tool] {message.name}: {message.status}")
    elif message.type == "status":
        print(f"[status] {message.status}")
    elif message.type == "usage":
        print(f"[usage] turn total={message.usage.total_tokens}")

运行流只能消费一次。run.messages()run.events()run.iter_text() 都会从同一个底层流中读取并推进流。流结束后,运行会保存终端结果 (run.resultrun.statusrun.usagerun.git 等) 。调用 run.wait() 可读取所有剩余事件,并返回带类型信息的 RunResult

不使用流式传输时的等待

result = run.wait()

print(result.status)       # "finished" | "error" | "cancelled" | "expired"
print(result.result)       # 最终助手文本(如有)
print(result.model)        # 此次运行所用的已解析 ModelSelection
print(result.duration_ms)
print(result.usage)        # 累计 TokenUsage;不可用时为 None
print(result.git)          # 云端 RunGitInfo

异步版本:

result = await run.wait()

Token 用量

运行时提供 Token 用量时,运行会报告该信息。可在实时句柄的 run.usage 中读取累计总量 (流式传输期间或在 wait() 之后) ,也可在 run.wait() 返回的 RunResultresult.usage 中读取。两者都包含汇总自所有报告用量轮次的 TokenUsage;如果没有任何轮次报告用量,两者均为 None——例如,未完成任何轮次就被取消的运行、不提供用量信息的运行时,或尚未对账用量的已分离云端快照。

@dataclass(frozen=True)
class TokenUsage:
    input_tokens: int
    output_tokens: int
    cache_read_tokens: int
    cache_write_tokens: int
    total_tokens: int
    reasoning_tokens: int | None = None
字段 描述
input_tokens 发送给模型的提示词 token。
output_tokens 模型生成的 token。
cache_read_tokens 从提示词缓存中读取的 token。
cache_write_tokens 写入提示词缓存的 token。
total_tokens input_tokens + output_tokens + cache_read_tokens + cache_write_tokens。不包括 reasoning_tokens
reasoning_tokens 推理 token,是 output_tokens 的一部分。模型或运行时时未报告该值时为 None
result = run.wait()

if result.usage is not None:
    print(f"total: {result.usage.total_tokens}")
    print(f"in: {result.usage.input_tokens}, out: {result.usage.output_tokens}")
    print(
        f"cache read/write: {result.usage.cache_read_tokens}/{result.usage.cache_write_tokens}"
    )
else:
    print("no usage reported for this run")

reasoning_tokens 已计入 output_tokens,因此 total_tokens 不再包含它,以避免重复计算。

如需获取流式传输过程中每轮的数值,请处理 usage 流事件 (SDKUsageMessage)。它会在每个报告用量的轮次结束时触发一次,并携带该轮的 TokenUsagerun.usageresult.usage 在整个运行期间持续累计。流式轮次结束后,句柄会优先使用这些累计总量;否则,若 bridge 提供相关数据,则使用 wait() 返回的用量,或 get_run / list_runs 快照中的用量。

for message in run.messages():
    if message.type == "usage":
        print(f"turn used {message.usage.total_tokens} tokens")

# 或在等待完成后 / 无需自行读取消息:
result = run.wait()
print(run.usage, result.usage)

异步对应写法:async for message in run.messages()await run.wait()run.usageAsyncRun 中仍为同步属性。

TokenUsagecursor_sdk 导出 (高级调用方还可使用 to_token_usage / sum_token_usage) 。在线传输的 JSON 使用驼峰命名法 (inputTokens,…) ;Python dataclass 使用 snake_case。

token 数量由 runtime 报告,不代表费用。要获取智能体运行的已计费用量和美元费用,请调用 agent.get_usage()

读取文本输出

iter_text() 在流式输出过程中生成助手文本。text() 返回最终文本;如果运行尚未结束,则会阻塞并等待 wait()

for chunk in run.iter_text():
    print(chunk, end="")

final_text = run.text()

异步版本:

async for chunk in run.iter_text():
    print(chunk, end="")

final_text = await run.text()

取消一次运行

run.cancel()

异步版本:

await run.cancel()

run.cancel() 会请求取消仍在执行的运行。状态将变为 "cancelled",实时流会停止,进行中的工具调用会停止,run.wait() 将以 status: "cancelled" 完成。部分输出 (截至目前已写入的助手文本) 会保留在 Run 对象中。

取消已结束的运行 ("finished""error""cancelled""expired") 会引发 UnsupportedRunOperationError。如不确定,可通过 run.status 进行判断:

if run.status == "running":
    run.cancel()

读取运行状态

print(run.id)
print(run.status)  # "running" | "finished" | "error" | "cancelled" | "expired"

stop = run.on_did_change_status(lambda status: print(f"status changed to {status}"))
stop()  # 移除监听器

turns = run.conversation()

run.conversation() 返回类型化的 list[ConversationTurn]。无需订阅实时流,即可用它渲染或持久化结构化历史记录。run.conversation_json() 返回原始 JSON string。

对于异步运行,请使用 await run.conversation()await run.conversation_json()

单次运行模型覆盖

传给 agent.send()model 会覆盖智能体在该次运行中的模型选择,并持续生效:后续未指定覆盖项的发送会继续使用新模型。若要切换回原模型,请传递另一个 model 覆盖项,或通过 agent.model 读取当前选择。

from cursor_sdk import ModelParameterValue, ModelSelection, SendOptions

run = agent.send(
    "Plan the refactor",
    SendOptions(
        model=ModelSelection(
            id="composer-2.5",
            params=[ModelParameterValue(id="fast", value="true")],
        ),
    ),
)

run.modelresult.model 反映本次运行所选用的模型,运行开始后不可更改。

单次运行的环境变量

云端代理也可接收仅用于单次运行的环境变量。在 SendOptions 中传入 cloud.env_vars,这些值仅会注入该次运行的智能体 shell 中——运行结束后,它们会从 VM 中移除,后续运行无法访问。这适合用于在不同轮次间轮换的凭据,例如在请求智能体使用前刚刚签发的短期部署令牌。

from cursor_sdk import CloudSendOptions, SendOptions

run = agent.send(
    "Deploy the preview environment",
    SendOptions(
        cloud=CloudSendOptions(env_vars={"DEPLOY_TOKEN": mint_short_lived_token()}),
    ),
)

如果单次运行范围的变量与 CloudAgentOptionsenv_vars 中的智能体范围变量同名,则该次运行以单次运行的值为准;下次运行时则恢复使用智能体范围的值。

单次运行变量在首次发送时也可使用。SDK 会在创建智能体时一并传入这些变量,并将其限定于初始运行,因此不会持久化到智能体中。与智能体范围变量一样,它们在静态存储时会加密,且名称不能以 CURSOR_ 开头。

单次运行的环境变量仅适用于云端代理,且不适用于针对公共仓库运行的智能体。对于本地智能体,智能体进程会继承你的环境,因此请在调用 send() 前为该进程设置变量。

对话模式

传入 mode="plan"mode="agent",可控制运行是先探索并制定方案,还是直接实施更改。有关 Plan 模式在产品中的作用,请参阅Plan 模式

在传递给 Agent.create()AgentOptions 中设置 mode,以确定首次运行的模式。后续调用 agent.send() 时,省略 mode 可保持对话的当前模式;传入 mode 则仅切换该次运行的模式。

from cursor_sdk import Agent, AgentOptions, CloudAgentOptions, CloudRepository, SendOptions

with Agent.create(
    AgentOptions(
        model="composer-2.5",
        mode="plan",
        cloud=CloudAgentOptions(
            repos=[CloudRepository(url="https://github.com/your-org/your-repo")],
        ),
    )
) as agent:
    agent.send("Design the auth refactor").wait()
    agent.send(
        "Looks good, start building",
        SendOptions(mode="agent"),
    ).wait()

流式传输原始增量

SendOptions 中传入 on_deltaon_step 回调,以获取更底层的更新。同步回调会直接内联调用。异步回调可以是同步函数或异步函数;在处理下一个事件之前,会等待可等待的返回值完成。

from cursor_sdk import SendOptions

def on_delta(update):
    if update.type in ("text-delta", "thinking-delta"):
        print(update.text, end="")

run = agent.send(
    "Refactor the utils module",
    SendOptions(on_delta=on_delta, on_step=lambda step: print(f"[step] {step.type}")),
)
run.wait()

具体的 update 和 step 子类定义在 cursor_sdk.events 中:

from cursor_sdk.events import TextDeltaUpdate, ToolCallStartedUpdate

if isinstance(update, TextDeltaUpdate):
    print(update.text)

为保持向后兼容,仍可从 cursor_sdk 导入它们,但新代码应从 cursor_sdk.events 导入。

SendOptions

属性 类型 描述
model str \| ModelSelection \| Mapping[str, Any] 单次发送的模型覆盖设置。若省略,则使用 agent.model。发送成功后持续生效。
mode "agent" \| "plan" 单次发送的对话模式覆盖设置。若在后续消息中省略,则保留对话当前的模式。
mcp_servers Mapping[str, McpServerConfig] 内联 MCP 服务器定义。完全替换此次运行创建时的服务器。
cloud.env_vars Mapping[str, str] 仅适用于云端代理。为此次运行注入单次运行的环境变量,运行结束后移除。仅在此次运行中按名称覆盖智能体范围的 env_vars
local.force bool 仅适用于本地智能体。默认值为 None (未设置) 。设为 True 可在开始处理此消息前终止卡住的活动运行。云端会在服务端返回 409 agent_busy,因此无需提供等效设置。
idempotency_key str 可选的、由客户端为此次发送生成的幂等键。
on_step Callable[[ConversationStep], Any] 每个对话步骤 (文本、思考或工具批次) 完成后调用的回调。
on_delta Callable[[InteractionUpdate], Any] 每个原始 InteractionUpdate 的回调。

接下来的三个分区详细介绍 SDKMessageInteractionUpdateConversationTurn。首次阅读时可快速浏览或跳过;恢复智能体将继续后续内容。

流事件

run.messages() 会生成带类型的 SDK 消息数据类。可根据 message.type 区分消息类型。运行时提供时,所有消息都会包含 agent_idrun_id

SDKMessage = (
    SDKSystemMessage
    | SDKUserMessageEvent
    | SDKAssistantMessage
    | SDKThinkingMessage
    | SDKToolUseMessage
    | SDKStatusMessage
    | SDKTaskMessage
    | SDKRequestMessage
    | SDKUsageMessage
    | Mapping[str, Any]
)
type 数据类 关键字段
"system" SDKSystemMessage subtypemodeltools
"user" SDKUserMessageEvent message.content
"assistant" SDKAssistantMessage 包含 TextBlockToolUseBlock 值的 message.content
"thinking" SDKThinkingMessage textthinking_duration_ms
"tool_call" SDKToolUseMessage call_idnamestatusargsresulttruncated
"status" SDKStatusMessage statusmessage
"task" SDKTaskMessage statustext
"request" SDKRequestMessage request_id
"usage" SDKUsageMessage usage (TokenUsage)

大多数工具调用会发出两次 SDKToolUseMessage:首次发出时,status="running"args 已填充;完成后会再次发出,此时 status="completed" (或 "error") 且 result 已填充。truncated 标志指示 SDK 是否因负载过大而截断了 argsresult

每个报告 token 用量的轮次结束时,都会发出一次 SDKUsageMessage,其中包含该轮的 TokenUsage。跨轮次的累计用量保存在 run.usageresult.usage 中。请参阅 Token 用量

@dataclass(frozen=True)
class SDKUsageMessage:
    type: Literal["usage"]
    agent_id: str
    run_id: str
    usage: TokenUsage

流结束后,结果数据 (最终文本、模型、时长、累计 token 用量、Git 元数据) 会保存在 Run 对象中。使用 run.wait() 读取这些数据;如果运行时报告了 result.usage,也可通过它读取。

工具调用 schema 不稳定。 tool_call 事件中的 argsresult 负载反映各工具的内部结构,可能会随工具演进而变化。工具名称也可能被重命名或替换。请将 argsresult 视为无类型数据,并进行防御性解析。事件信封 (typecall_idnamestatus) 是稳定的。

run.events() 会生成更底层的 RunStreamEvent 信封。当需要偏移量、终端结果信封或原始交互更新时,请使用它:

for event in run.events():
    print(event.kind, event.offset)

交互更新

InteractionUpdate 是传递给 agent.send()on_delta 回调的原始增量类型。与 SDKMessage 事件相比,更新粒度更细:文本按 token 逐个流式传输,工具调用则会随着 args 的累积报告部分状态。

InteractionUpdate = (
    TextDeltaUpdate
    | ThinkingDeltaUpdate
    | ThinkingCompletedUpdate
    | ToolCallStartedUpdate
    | ToolCallCompletedUpdate
    | PartialToolCallUpdate
    | TokenDeltaUpdate
    | StepStartedUpdate
    | StepCompletedUpdate
    | TurnEndedUpdate
    | UserMessageAppendedUpdate
    | SummaryUpdate
    | SummaryStartedUpdate
    | SummaryCompletedUpdate
    | ShellOutputDeltaUpdate
    | UnknownInteractionUpdate
    | Mapping[str, Any]
)

模型在提交工具调用前流式传入参数时,会发出 PartialToolCallUpdate。适用于 SDKToolUseMessage.args 的稳定性免责声明同样适用于此处。

对话类型

通过 run.conversation() 返回的运行中每轮对话的结构化视图。每个条目都是一个包装器,包含轮次 type 判别字段以及 turn 中的类型化负载。

@dataclass(frozen=True)
class ConversationTurn:
    type: str  # "agentConversationTurn" | "shellConversationTurn"
    turn: AgentConversationTurn | ShellConversationTurn | Mapping[str, Any]

@dataclass(frozen=True)
class AgentConversationTurn:
    user_message: Mapping[str, Any] | None = None
    steps: Sequence[ConversationStep] = ()

@dataclass(frozen=True)
class ShellConversationTurn:
    shell_command: ShellCommand | None = None
    shell_output: ShellOutput | None = None

ConversationStep = (
    AssistantConversationStep
    | ToolCallConversationStep
    | ThinkingConversationStep
    | Mapping[str, Any]
)

根据 turn.type 区分类型,并通过 turn.turn 读取负载:

for turn in run.conversation():
    if turn.type == "agentConversationTurn":
        for step in turn.turn.steps:
            print(step.type)
    elif turn.type == "shellConversationTurn":
        print(turn.turn.shell_command, turn.turn.shell_output)

on_step 回调中的 run.conversation() 会针对每个 ConversationStep 触发,而非每个轮次。工具调用对话步骤携带 Mapping[str, Any] 负载。工具调用负载的具体内容应视为无类型数据;请参阅流事件下的稳定性说明

恢复智能体

Agent.resume(
    agent_id: str,
    options: AgentOptions | Mapping[str, Any] | None = None,
    *,
    client: CursorClient | None = None,
) -> Agent

使用 Agent.resume()client.agents.resume(),通过 ID 重新连接到现有智能体。常见用法包括:重新连接到之前启动的长时间运行云端代理,或在本地进程重启后继续对话。系统会根据 ID 前缀自动检测运行环境 (bc- 表示云端,其他前缀表示本地) 。

agent = Agent.resume("bc-abc123")
run = agent.send("Also update the changelog")
run.wait()

异步版本:

agent = await client.agents.resume("bc-abc123")
run = await agent.send("Also update the changelog")
await run.wait()

除非再次传入 model,否则恢复时 agent.model 将为 None。内联 MCP 服务器不会在恢复后保留;它们通常包含机密信息,仅存于内存中。恢复时请再次传入,或者为需要保留的服务器使用基于文件的 MCP 配置 (.cursor/mcp.jsonlocal.setting_sources) 。

本地持久化

本地智能体通过 bridge 持久化保存对话状态和运行元数据,因此后续交互和 Agent.resume() 在进程重启后仍可继续使用。默认情况下,bridge 会将这些数据存储在磁盘上各工作区对应的状态根目录下。云端代理在服务器端持久化保存数据,因此无论从何处恢复云端代理,都会返回同一段对话。

本地持久化以工作区为单位。当 bridge 作为长期运行的 sidecar 或子进程运行时,请为其指定与智能体相同的工作区,以便本地 list、get 和 resume 调用能找到正确的智能体。在客户端中设置一次工作区,并将 cwd 传递给本地 list 和 get 调用:

from cursor_sdk import CursorClient

with CursorClient.launch_bridge(workspace="/path/to/repo") as client:
    agents = client.agents.list(runtime="local", cwd="/path/to/repo")
    info = client.agents.get(agents.items[0].agent_id, cwd="/path/to/repo")

查看智能体和运行

使用 CursorClient 调用列表、获取和分页 API。

from cursor_sdk import CursorClient

with CursorClient.launch_bridge(workspace=".") as client:
    agents = client.agents.list(runtime="local", cwd=".")

    for agent_info in agents.auto_paging_iter():
        print(agent_info.agent_id)

    info = client.agents.get(agents.items[0].agent_id)
    runs = client.agents.list_runs(info.agent_id)
    run = client.agents.get_run(runs.items[0].id)

异步对应形式:

agents = await client.agents.list(runtime="local", cwd=".")

async for agent_info in agents.auto_paging_iter():
    print(agent_info.agent_id)

info = await client.agents.get(agents.items[0].agent_id)
runs = await client.agents.list_runs(info.agent_id)
run = await client.agents.get_run(runs.items[0].id)

在智能体句柄上使用 agent.list_messages() 读取消息历史记录。只有 ID 时,可使用 Agent.messages.list(agent_id),这是带类型属性的同一调用的便捷形式。

使用 Agent.get_run(run_id)client.agents.get_run(run_id) 获取运行,
无需智能体句柄。使用
Agent.cancel_run(run_id, agent_id=...)
client.agents.cancel_run(run_id, agent_id=...) 将其取消。异步客户端方法可
await,且使用相同的参数。

AgentMessage 与流式 SDKMessage 不同:

@dataclass(frozen=True)
class AgentMessage:
    type: str
    uuid: str
    agent_id: str
    message: Any = None

列表端点返回 ListResult[T]。可直接使用 .items.next_cursor,通过 for item in page 遍历当前页,或通过 .auto_paging_iter() 遍历所有页。异步列表端点返回 AsyncListResult[T]async for item in page 遍历当前页,而 async for item in page.auto_paging_iter() 遍历结果集中的所有页。

SDKAgentInfo

Agent.list()Agent.get()client.agents.list()client.agents.get() 返回的元数据结构。

@dataclass(frozen=True)
class SDKAgentInfo:
    agent_id: str
    name: str
    summary: str
    last_modified: str | None = None
    status: str | None = None  # "running" | "finished" | "error"
    created_at: str | None = None
    archived: bool = False
    runtime: Literal["local", "cloud"] | None = None
    cwd: str = ""
    env: CloudEnvironment | None = None
    repos: Sequence[str] = ()
    metadata: Mapping[str, str] = {}  # 来自 CloudAgentOptions.metadata;本地智能体为空

云端代理生命周期

云端代理会一直保留在团队工作区中,直到被归档或删除。client.agents.list(runtime="cloud") 默认不显示已归档的智能体;传入 include_archived=True 可查看它们。按 pr_url 筛选,可找到创建特定 PR 的智能体。

# 通过 ID 操作,无需智能体句柄:
Agent.archive(agent_id)
Agent.unarchive(agent_id)
Agent.delete(agent_id)

# 通过显式指定的客户端:
client.agents.archive(agent_id)
client.agents.unarchive(agent_id)
client.agents.delete(agent_id)

# 通过现有智能体句柄:
agent.archive()
agent.unarchive()
agent.delete()

archive 会软删除智能体,但会话记录仍可读取。unarchive 会将其恢复。delete 会永久删除;后续读取会返回 NotFoundError

异步生命周期方法名称相同,且可使用 await 调用。

agent.get_usage()

获取智能体各次运行的已计费 token 用量和美元费用。云端代理会返回按运行划分的明细;本地智能体会返回按轮次划分的明细。传入 run_id 可将结果限定为单个条目:云端代理使用 run-<uuid> 格式的运行 ID;本地智能体使用之前 get_usage().runs[].run_id 中的 ID。

usage = agent.get_usage()

print(f"tokens: {usage.usage.total_tokens}")
if usage.cost is not None:
    print(f"charged: ${usage.cost.charged_cents / 100:.2f}")
for run in usage.runs:
    print(run.run_id, run.usage.total_tokens)
@dataclass(frozen=True)
class AgentUsage:
    usage: TokenUsage              # 所有 `runs` 的汇总
    runs: Sequence[RunUsage] = ()
    cost: UsageCost | None = None  # 所有 `runs` 的汇总

@dataclass(frozen=True)
class RunUsage:
    run_id: str
    usage: TokenUsage
    cost: UsageCost | None = None

@dataclass(frozen=True)
class UsageCost:
    raw_cost_cents: float  # 未享受折扣的模型 token 成本;按请求计费的用量为 0
    charged_cents: float   # 实际收取的金额,已计入折扣和 Cursor Token 费率

费用已包含折扣,运行结束后可能需要片刻才能结算;在此之前,costNone。对于方案内包含、BYOK 和额度授予的用量,charged_cents0.0

这与Token 用量不同:run.usage 是单次运行的实时 token 计数,而 get_usage() 是该智能体所有运行的计费记录。对于异步智能体,await agent.get_usage() 的结果相同。AgentUsageRunUsageUsageCost 均从 cursor_sdk 导出。

Cursor 命名空间

用于账户级和目录读取。同步方法可接受 api_key,否则会使用 CURSOR_API_KEY

from cursor_sdk import Cursor

me = Cursor.me()
models = Cursor.models.list()
repositories = Cursor.repositories.list()

使用显式客户端的等效版本:

me = client.me()
models = client.models.list()
repositories = client.repositories.list()

异步对应形式:

from cursor_sdk import AsyncCursor

me = await AsyncCursor.me(client=client)
models = await AsyncCursor.models.list(client=client)
repositories = await AsyncCursor.repositories.list(client=client)

Cursor.me() 会返回一个 SDKUser,其中包含 api_key_namecreated_at 以及
可选的 user_iduser_emailuser_first_nameuser_last_name
字段。

在调用 Agent.create()agent.send() 前,使用 Cursor.models.list() 获取有效的模型 ID 及各模型参数。参数因模型而异。常见示例包括 reasoning effort,以及 auto-smart 的 Cursor Router optimize_for 参数。

可用目录因账户和团队而异。只有 API 密钥所属团队可使用 Router 时,Cursor Router 才会以 auto-smart 的形式出现。请参阅 Cursor Router

models = Cursor.models.list()
composer = next((model for model in models if model.id == "composer-2.5"), None)

print(composer.parameters if composer else [])
# [
#   ModelParameterDefinition(
#       id="fast",
#       display_name="Fast",
#       values=(
#           ModelParameterDefinitionValue(value="false"),
#           ModelParameterDefinitionValue(value="true", display_name="Fast"),
#       ),
#   ),
# ]

每个 SDKModel 的预设 variants 均已包含有效的 params,因此可以直接复制到 ModelSelection 中。

如果未指定目标模型,但希望使用 Cost、Balance 或 Intelligence,请优先显式选择 Router (auto-smart + optimize_for) 。只有在希望由服务器自动选择 Auto、且不选择 Router 模式时,才回退到 ModelSelection(id="auto")。使用 Cursor Router 时,始终显式传入 optimize_for

Cursor.repositories.list() 会返回调用方账户或团队中可供云端代理使用的 SCM 仓库 (GitHub、GitLab、Bitbucket、Azure DevOps,具体取决于已连接的服务) 。每个条目都提供一个 url。使用这些 URL 填充 CloudAgentOptions.repos

MCP 服务器

智能体可根据运行时,从内联定义、项目/用户设置、插件和仪表盘托管的配置中获取 MCP 服务器。

from cursor_sdk import (
    Agent,
    AgentOptions,
    HttpMcpServerConfig,
    LocalAgentOptions,
    McpAuth,
    StdioMcpServerConfig,
)

agent = Agent.create(
    AgentOptions(
        model="composer-2.5",
        local=LocalAgentOptions(cwd="."),
        mcp_servers={
            "docs": HttpMcpServerConfig(
                url="https://example.com/mcp",
                auth=McpAuth(client_id="client-id", scopes=["read", "write"]),
            ),
            "filesystem": StdioMcpServerConfig(
                command="npx",
                args=["-y", "@modelcontextprotocol/server-filesystem", "."],
            ),
        },
    )
)

为便于快速编写脚本,也支持使用扁平字典 ({"type": "http", "url": ...}{"type": "stdio", "command": ...}) 。

会加载哪些内容

本地智能体最多可从五个来源加载服务器;如果名称冲突,优先使用最先匹配的来源:

  1. agent.send() 中的 mcp_servers。会完全替换该次运行在创建时配置的服务器 (不会合并) 。
  2. Agent.create() 中的 mcp_servers。未提供单次发送的覆盖配置时使用。
  3. 插件服务器,前提是 local.setting_sources 包含 "plugins"
  4. 项目服务器,来自 .cursor/mcp.json,前提是 local.setting_sources 包含 "project"
  5. 用户服务器,来自 ~/.cursor/mcp.json,前提是 local.setting_sources 包含 "user"

未设置 local.setting_sources 时,只会加载内联服务器。如果本地 MCP 服务器需要通过 OAuth 登录,SDK 可以复用 Cursor app 中保存的登录信息,但无法打开浏览器让你登录。

云端代理从以下来源加载服务器:

  1. agent.send() 中的 mcp_servers。会完全替换该次运行在创建时配置的服务器 (不会合并) 。
  2. Agent.create() 中的 mcp_servers。未提供单次发送的覆盖配置时使用。
  3. 来自 cursor.com/agents 的个人和团队 MCP 服务器。

如果内联服务器不包含 authheaders,且你之前已在 cursor.com/agents 上授权该服务器 URL,那么使用个人 API token 认证的运行会自动复用这些 OAuth token。服务账户 API 密钥无法回退到用户认证,因为它们不与任何用户关联。

local.setting_sources 不适用于云端代理。

云端

云端代理也支持以内联方式使用已认证的 MCP 配置。云端 MCP 支持 HTTP 和 stdio 传输方式。静态 API 密钥或 Bearer token 请使用 HTTP headers。对于受 OAuth 保护的服务器,请使用 HTTP auth。如果服务器在云端 VM 中运行,并从环境变量读取凭据,请使用 stdio env

from cursor_sdk import (
    Agent,
    AgentOptions,
    CloudAgentOptions,
    CloudRepository,
    HttpMcpServerConfig,
    StdioMcpServerConfig,
)

agent = Agent.create(
    AgentOptions(
        model="composer-2.5",
        cloud=CloudAgentOptions(
            repos=[CloudRepository(url="https://github.com/your-org/your-repo")],
        ),
        mcp_servers={
            "linear": HttpMcpServerConfig(
                url="https://mcp.linear.app/mcp",
                headers={"Authorization": "Bearer linear_pat_xxx"},
            ),
            "github": StdioMcpServerConfig(
                command="npx",
                args=["-y", "@modelcontextprotocol/server-github"],
                env={"GITHUB_TOKEN": "ghp_xxx"},
            ),
        },
    )
)
  • HTTP headersauth 由 Cursor’s 后端处理。敏感字段会被脱敏,不会传入 VM。
  • 由于服务器在 VM 中运行,Stdio env 值会传入 VM。请将其视为其他运行时机密信息。
  • 在 cursor.com/agents 上为 MCP 服务器配置的 OAuth 即使针对团队级服务器,仍按用户分别设置。

完整配置格式请参阅 MCP,云端特有行为请参阅 云端代理能力

子智能体

定义可由主智能体通过 Agent 工具创建的具名子智能体。将其以内联方式传入:

from cursor_sdk import Agent, AgentDefinition, AgentOptions, LocalAgentOptions

agent = Agent.create(
    AgentOptions(
        model="composer-2.5",
        local=LocalAgentOptions(cwd="."),
        agents={
            "code-reviewer": AgentDefinition(
                description="Expert code reviewer for quality and security.",
                prompt="Review code for bugs, security issues, and proven approaches.",
                model="inherit",
            ),
            "test-writer": AgentDefinition(
                description="Writes tests for code changes.",
                prompt="Write comprehensive tests for the given code.",
            ),
        },
    )
)

已提交到仓库 .cursor/agents/*.md 中的子智能体 (带有 namedescription 和可选 model frontmatter) 也会被读取。同名的内联定义会覆盖基于文件的定义。

嵌套子智能体

子智能体可在嵌套层数限制内创建自己的子智能体。子智能体使用 Agent 工具时,会调用与其父级相同的子智能体执行器,因此父级可以将任务委托给能够继续委托的子智能体。每一层都能看到同一组具名子智能体。顶层智能体及其直属子智能体可以启动子智能体,但由子智能体启动的子智能体不能再启动更多子智能体。

限制工具集

tools 用于将提供给模型的内置工具设为允许列表;disallowed_tools 用于移除指定工具并保留其余工具,包括在您的 SDK 版本发布后添加到平台的工具。目前两者仅适用于本地智能体,且都不会保存在智能体中:恢复时请再次传入,以继续保留限制。

from cursor_sdk import Agent, AgentOptions, LocalAgentOptions

# 只读智能体:仅提供以下工具。
reader = Agent.create(
    AgentOptions(
        model="composer-2.5",
        tools=["read", "grep", "glob", "ls"],
        local=LocalAgentOptions(cwd="."),
    )
)

# 除 shell 外的所有工具。
no_shell = Agent.create(
    AgentOptions(
        model="composer-2.5",
        disallowed_tools=["shell"],
        local=LocalAgentOptions(cwd="."),
    )
)
  • 省略 tools 时,将为所选模型提供标准工具集;tools=[] 则不提供内置工具,因此模型只能返回文本。
  • 两个字段均接受公开名称 ("read""edit""task""webSearch"、……) 以及能力组 "shell""mcp"。未知名称会在创建时引发 BadRequestError
  • 禁用优先:工具必须包含在 tools 中 (如已设置) ,且不在 disallowed_tools 中,才会被提供。
  • 禁用 "mcp" 也会移除自定义工具。禁用 "task" 会阻止子智能体;否则子智能体将保留各自精选的工具集。

自定义工具

自定义工具可让你将 Python 函数提供给本地智能体使用,无需单独搭建 MCP 服务器。通过 LocalAgentOptions.custom_tools 传入。

from cursor_sdk import Agent, CustomTool, CustomToolContext, LocalAgentOptions

def get_deployment_status(args, context: CustomToolContext):
    service = args["service"]
    return f"Service {service} is healthy."

with Agent.create(
    model="composer-2.5",
    local=LocalAgentOptions(
        cwd=".",
        custom_tools={
            "get_deployment_status": CustomTool(
                description="Look up the current deployment status for a service.",
                input_schema={
                    "type": "object",
                    "properties": {
                        "service": {"type": "string", "description": "Service name"},
                    },
                    "required": ["service"],
                },
                execute=get_deployment_status,
            ),
        },
    ),
) as agent:
    agent.send("Is the checkout service healthy?").wait()

execute 接收解析后的参数,以及可用时带有 tool_call_idCustomToolContext。它可以返回 string、JSON 兼容的值,或包含 content 列表的 mapping。自定义工具仅支持本地智能体。

钩子

钩子仅支持基于文件的配置,不支持编程式钩子回调。钩子是项目策略的边界,而非单次运行的可调选项。

  • **本地:**将 .cursor/hooks.json 添加到 local.cwd 指定的仓库中,或添加 ~/.cursor/hooks.json 以配置用户级钩子。
  • **云端:**将 .cursor/hooks.json 及其脚本提交到 cloud.repos 指定的仓库。由 SDK 创建的云端代理会自动加载项目钩子。在企业版方案中,它们还会运行团队钩子和由企业统一管理的钩子。

有关配置格式,请参阅 钩子;有关云端行为,请参阅 云端代理钩子支持

产物

列出并下载智能体工作区中的文件。

@dataclass(frozen=True)
class SDKArtifact:
    path: str
    size_bytes: int = 0
    updated_at: str = ""
from pathlib import Path

artifacts = agent.list_artifacts()

for artifact in artifacts:
    print(artifact.path, artifact.size_bytes)

# 将单个产物下载到本地磁盘。
content = agent.download_artifact(artifacts[0].path)
Path("review.md").write_bytes(content)

异步智能体支持 await agent.list_artifacts()await agent.download_artifact(path)

产物支持取决于运行时。Local SDK 智能体调用 list_artifacts() 时会返回空列表,调用 download_artifact() 时会引发异常。

资源管理

使用完毕后,请始终关闭智能体。最简洁的同步用法是使用上下文管理器:

from cursor_sdk import Agent, LocalAgentOptions

with Agent.create(model="composer-2.5", local=LocalAgentOptions(cwd=".")) as agent:
    agent.send("Summarize the repository").wait()

如需手动释放资源:

agent.close()

异步智能体和客户端支持异步上下文管理器,并可使用 await 进行清理:

from cursor_sdk import AsyncClient, LocalAgentOptions

async with await AsyncClient.launch_bridge(workspace=".") as client:
    async with await client.agents.create(
        model="composer-2.5",
        local=LocalAgentOptions(cwd="."),
    ) as agent:
        run = await agent.send("Summarize the repository")
        await run.wait()

要显式释放资源:

await agent.close()
await client.aclose()

模块级同步默认客户端会在进程退出时自动关闭。长时间运行的进程可显式将其关闭并重置:

from cursor_sdk import close_default_client

close_default_client()

配置参考

Python SDK 支持辅助数据类和原始字典。数据类使用 Python snake_case 字段,推荐在应用代码中使用。

AgentOptions

属性 类型 默认值 描述
model str \| ModelSelection \| Mapping[str, Any] 本地必填;云端默认使用服务器解析的默认值 要使用的模型。请参阅 ModelSelection
api_key str CURSOR_API_KEY 环境变量 用户 API 密钥或服务账户密钥。暂不支持团队管理员密钥。
name str 自动生成 client.agents.list() / client.agents.get() 中显示的易读智能体名称。
local LocalAgentOptions \| Mapping[str, Any] None 本地智能体配置。传入以创建本地智能体。
cloud CloudAgentOptions \| Mapping[str, Any] None 云端代理配置。传入以创建云端代理。
mcp_servers Mapping[str, McpServerConfig] None 内联 MCP 服务器定义。
agents Mapping[str, AgentDefinition \| Mapping[str, Any]] None 子智能体定义。
tools Sequence[str] 默认工具集 仅向模型提供列出的内置工具。[] 表示不提供内置工具;模型只能返回文本。仅限本地智能体。
disallowed_tools Sequence[str] None 移除列出的内置工具;其他工具仍可用。与 tools 同时使用时,以拒绝列表为准。仅限本地智能体。
agent_id str 自动生成 持久化智能体 ID。传入后可在多次调用间保持 ID 稳定。
idempotency_key str 云端自动生成 可选的客户端生成幂等键。仅限云端。
mode "agent" \| "plan" None 智能体首次运行时的初始对话模式。省略时,服务器将以 Agent 模式启动。请参阅对话模式

LocalAgentOptions

属性 类型 默认值 描述
cwd str \| os.PathLike None 主工作目录。不接受多项列表;多根目录请使用 dirs
dirs Sequence[str \| os.PathLike] None 多根目录配置的额外工作区文件夹。与 cwd 合并后,将从每个路径加载规则、技能和工作区上下文。
setting_sources Sequence[SettingSource] None 可用的设置层:”project”、”user”、”team”、”mdm”、”plugins” 或 “all”。
sandbox_options SandboxOptions \| Mapping[str, Any] None 本地沙箱选项。
store LocalAgentStoreConfig \| Mapping[str, Any] None 传递给 bridge 的本地存储配置。
auto_review bool None 如果连接的后端支持,则通过 Auto-review 模式处理本地工具调用。
custom_tools Mapping[str, CustomTool \| Mapping[str, Any]] None 向本地智能体提供的自定义工具

CloudAgentOptions

属性 类型 默认值 描述
env CloudEnvironment \| Mapping[str, Any] None 执行环境。省略时,服务器使用由 Cursor 托管的云端 VM。poolmachine 指向您运行的自托管 workers。
repos Sequence[CloudRepository \| Mapping[str, Any]] None 要克隆到 VM 的仓库。省略或传入 [],可创建工作区为空的无仓库智能体。在仓库中传入 pr_url,可将智能体关联到现有 PR。
work_on_current_branch bool None 将提交推送到现有分支,而非新分支。服务器会将省略的值视为 False
auto_create_pr bool None 运行完成时创建 PR。服务器会将省略的值视为 False
open_as_cursor_github_app bool 服务账户密钥为 True,用户密钥为 False 以 Cursor GitHub App 身份而非 API 密钥所有者的身份创建 PR。解析后的值会在创建、获取和列出操作中返回。
skip_reviewer_request bool None 不将调用用户请求为 PR 审阅人。服务器会将省略的值视为 False
env_vars Mapping[str, str] None 云端代理的会话级环境变量。
metadata Mapping[str, str] None 由调用方拥有并持久保存于云端代理上的 string 标签。请参阅智能体元数据

AgentDefinition

属性 类型 默认值 描述
description str 必填 此子智能体的适用场景。会显示给父智能体,以便其知道何时生成子智能体。
prompt str 必填 子智能体的系统提示词。
model str \| ModelSelection \| Mapping[str, Any] \| "inherit" None 模型覆盖。None"inherit" 均使用父智能体的模型选择。
mcp_servers Sequence[str \| AgentDefinitionMcpServer \| Mapping[str, Any]] None 此子智能体可用的 MCP 服务器。名称引用父智能体 mcp_servers 中的服务器。

CustomTool

@dataclass
class CustomTool:
    execute: Callable[[Mapping[str, Any], CustomToolContext], Any]
    description: str | None = None
    input_schema: Mapping[str, Any] | None = None

class CustomToolContext:
    tool_call_id: str | None = None

ModelSelection

@dataclass(frozen=True)
class ModelSelection:
    id: str
    params: Sequence[ModelParameterValue] = ()

@dataclass(frozen=True)
class ModelParameterValue:
    id: str
    value: str

id 是模型标识符 (例如 "composer-2.5""auto-smart") 。params 包含模型专属参数,例如推理 effort 或 Router 的 optimize_for。使用 Cursor.models.list() 可查看您账户可用的有效 ID、参数定义和预设变体。有关 Router 的选择合约,请参阅 Cursor Router

McpServerConfig

from cursor_sdk.types import McpServerConfig

@dataclass(frozen=True)
class HttpMcpServerConfig:
    url: str
    type: Literal["http", "sse"] | str = "http"
    headers: Mapping[str, str] | None = None
    auth: McpAuth | Mapping[str, Any] | None = None

@dataclass(frozen=True)
class SseMcpServerConfig(HttpMcpServerConfig):
    type: Literal["sse"] = "sse"

@dataclass(frozen=True)
class StdioMcpServerConfig:
    command: str
    args: Sequence[str] | None = None
    env: Mapping[str, str] | None = None
    cwd: str | os.PathLike | None = None  # 仅限本地;云端不支持此字段

@dataclass(frozen=True)
class McpAuth:
    client_id: str
    client_secret: str | None = None
    scopes: Sequence[str] = ()

对于在云端运行的 HTTP 服务器,headersauth 由 Cursor 后端处理。敏感字段会在 VM 读取前被脱敏。对于在云端运行的 stdio 服务器,env 值会传入 VM (请将其视为运行时机密信息) 。

用户消息

@dataclass(frozen=True)
class UserMessage:
    text: str
    images: Sequence[SDKImage | Mapping[str, Any]] | None = None

agent.send() 的消息参数的结构化形式。可用于随文本一同发送图像。

SDKImage

@dataclass(frozen=True)
class SDKImage:
    url: str | None = None
    data: str | None = None
    mime_type: str | None = None
    dimension: SDKImageDimension | Mapping[str, Any] | None = None

    @classmethod
    def from_url(cls, url: str, dimension=None) -> SDKImage: ...

    @classmethod
    def from_data(cls, data: bytes | str, mime_type: str, dimension=None) -> SDKImage: ...

    @classmethod
    def url_image(cls, url: str, dimension=None) -> SDKImage: ...

    @classmethod
    def data_image(cls, data: str, mime_type: str, dimension=None) -> SDKImage: ...

    @classmethod
    def from_file(cls, path, *, mime_type=None, dimension=None) -> SDKImage: ...

传入远程 url,或传入包含 mime_type 的 base64 datafrom_data() 接受字节数据或 base64 字符串。from_file() 从磁盘读取文件并将其编码为 base64。

SettingSource

可通过 cursor_sdk.types 获取 SettingSource

from cursor_sdk.types import SettingSource

控制本地智能体加载哪些存储在磁盘上的设置层。云端代理始终加载 projectteamplugins,并忽略此字段。

来源
"project" 工作区中的 .cursor/
"user" ~/.cursor/
"team" 从仪表盘同步的团队设置
"mdm" 由 MDM 管理的企业版设置
"plugins" 插件提供的设置
"all" 以上所有项的简写

ListResult

@dataclass(frozen=True)
class ListResult(Generic[T]):
    items: list[T]
    next_cursor: str = ""

    def to_dict(self) -> dict[str, Any]: ...
    def has_next_page(self) -> bool: ...
    def next_page_info(self) -> dict[str, str]: ...
    def get_next_page(self) -> ListResult[T]: ...
    def auto_paging_iter(self) -> Iterator[T]: ...

client.agents.list()client.agents.list_runs()Agent.list() 返回。当没有更多页面时,next_cursor 为空。异步列表端点返回 AsyncListResult[T],并提供可 await 的对应方法。

错误

所有 SDK 错误都继承自 CursorAgentErrorCursorSDKError 是为兼容较早调用方保留的根异常别名。使用 is_retryableretry_after 实现重试逻辑。

class CursorAgentError(Exception):
    message: str
    code: str | None
    status: int | None
    status_code: int | None
    details: list[Mapping[str, Any]]
    is_retryable: bool
    cause: BaseException | None
    proto_error_code: str | None
    request_id: str | None
    headers: Mapping[str, str]
    retry_after: str | None
错误 触发条件
AuthenticationError API 密钥无效或未登录。
PermissionDeniedError 已通过身份验证的调用方无权执行所请求的操作。
RateLimitError 请求过多或超出用量限额。
ConfigurationError 模型无效、缺少必需配置,或请求参数有误。
AgentBusyError 智能体已有处于 CREATINGRUNNING 状态的运行时发送后续请求 (HTTP 409,代码 agent_busy) 。
BadRequestError 请求格式不正确。
IntegrationNotConnectedError 为未连接 SCM 提供商的仓库创建云端代理。
NetworkError 服务不可用或网络故障。
APITimeoutError 请求超时。
InternalServerError Cursor 服务返回了服务器错误。
NotFoundError 未找到所请求的资源。
AgentNotFoundError 智能体不存在,或在当前工作目录下不可见。
UnsupportedRunOperationError 当前运行状态不支持该运行操作。

使用退避策略重试

is_retryableretry_after 用于控制调用方的重试逻辑。retry_after 是由服务器设置时提供的 HTTP 风格 string (以秒数或 HTTP 日期表示) 。

import time

from cursor_sdk import Agent, AgentOptions, CursorAgentError, LocalAgentOptions, RateLimitError

for attempt in range(3):
    try:
        result = Agent.prompt(
            "Audit the auth middleware for missing input validation",
            AgentOptions(model="composer-2.5", local=LocalAgentOptions(cwd=".")),
        )
        break
    except RateLimitError as err:
        time.sleep(float(err.retry_after) if err.retry_after else 2**attempt)
    except CursorAgentError as err:
        if not err.is_retryable:
            raise
        time.sleep(2**attempt)

服务器返回 request_id 时,每个 CursorAgentError 都会包含该 ID。报错时请记录它,以便支持团队排查故障。

IntegrationNotConnectedError

class IntegrationNotConnectedError(ConfigurationError):
    provider: str   # 例如:"github"、"gitlab"、"azuredevops"
    help_url: str   # 用于重新连接的仪表盘链接

使用 help_url 将用户引导至正确的重新连接流程。无需发布新版 SDK 即可添加新的提供商。

AgentBusyError

云端代理同一时间只允许一个活跃运行。当同一智能体的另一个运行仍处于 CREATINGRUNNING 状态时,调用 agent.send() (或以其他方式创建运行) 会引发 AgentBusyError

is_retryableFalse。立即重试仍会失败,直到活跃运行进入终止状态或被取消。其他 409 响应 (如 agent_archived) 则会引发 ConfigurationError

等待活跃运行完成,使用 run.cancel() 取消它,或在再次发送前轮询 Agent.list_runs()

from cursor_sdk import Agent, AgentBusyError

agent = Agent.resume("bc-00000000-0000-0000-0000-000000000001")

try:
    agent.send("Also add tests for the auth middleware.")
except AgentBusyError:
    runs = Agent.list_runs(agent.agent_id, {"runtime": "cloud", "limit": 1})
    active = runs.items[0] if runs.items else None
    if active is not None and active.status == "running":
        active.cancel()
    agent.send("Also add tests for the auth middleware.")

本地智能体不会抛出 AgentBusyError。在 send() 中传入 local={"force": True},可在启动新的本地运行前终止卡住的运行。

UnsupportedRunOperationError

class UnsupportedRunOperationError(ConfigurationError):
    operation: str

当当前运行不允许执行某个 Run 操作时引发。最常见的情况是对已处于终止状态的运行调用 run.cancel()

run.supports(operation)run.unsupported_reason(operation) 用于报告 SDK 层面是否支持某个操作名称 ("stream""wait""cancel""conversation") ,不会检查运行的状态。请读取 run.status,以避免调用对状态敏感的操作。

疑难排查

设置 CURSOR_SDK_LOG=debug (或 info) ,为 SDK 自身的日志记录器添加 stderr 处理程序。SDK 仅配置自己的 cursor_sdk 日志记录器,因此不会影响宿主应用的日志配置。

CURSOR_SDK_LOG=debug python my_script.py

随包附带的 bridge 可执行文件会以 cursor-sdk-bridge 的名称安装到 PATH 中。直接运行它,确认 wheel 中包含的构建版本:

cursor-sdk-bridge --help

已知限制

  • 工具调用的负载 schema 有意不采用强类型定义。
  • 内联 MCP 服务器不会在 Agent.resume() 后保留。如有需要,请在恢复时再次传入。
  • 自定义工具 (local.custom_tools) 和工具集限制 (toolsdisallowed_tools) 仅适用于本地智能体。这些限制不会保留在智能体中;请在恢复时再次传入。
  • 本地智能体尚不支持 Artifact 下载。
  • local.setting_sources (以及它所控制的基于文件的 MCP 和子智能体路径) 不适用于云端代理。云端始终加载 projectteamplugins
  • 钩子仅支持基于文件的方式 (.cursor/hooks.json) ,不支持编程式回调。
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜