Skip to main content

Command Palette

Search for a command to run...

SDK

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 osfrom cursor_sdk import Agent, LocalAgentOptionswith 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, CloudRepositorywith 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 asyncioimport osfrom cursor_sdk import AsyncClient, LocalAgentOptionsasync 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 / ClientAsyncClient / AsyncCursorClient
AgentAsyncAgent
RunAsyncRun
CursorAsyncCursor
ListResultAsyncListResult
DefaultHttpxClientDefaultAsyncHttpxClient

创建智能体

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

from cursor_sdk import Agent, CloudAgentOptions, CloudRepository, LocalAgentOptionsagent = 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

无代码仓库云端代理

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

from cursor_sdk import Agent, CloudAgentOptionswith 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 osagent = 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, CloudRepositorywith 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 字节的字符串。允许使用空字符串值,空映射会被视为未设置元数据。

模型参数

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

from cursor_sdk import Agent, LocalAgentOptions, ModelParameterValue, ModelSelectionagent = 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 osfrom cursor_sdk import Agent, LocalAgentOptions, ModelParameterValue, ModelSelectionwith 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, ModelSelectionmodels = 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, SendOptionsrun = 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-smartCursor Router。需要成本、平衡或智能模式时使用。
ModelSelection(id="auto")当目录中没有指定模型时,由服务器选择的 Auto 回退方案。需要明确指定 Router 模式时,优先使用 auto-smart
省略 optimize_for 或传入 default不受支持的 Router 合约。请始终查询允许的值,并传入 costbalancedintelligence

计费与路由模型池

  • Cost 沿用经典 Auto 行为和捆绑式 Auto 定价。
  • BalanceIntelligence 使用 Cursor Router,并按您的方案或合约中路由模型的费率计费。
  • 每次请求所用的底层模型可能不同。如需进行可复现的比较,请使用固定的模型 ID。
  • 企业版模型允许列表会影响路由模型池。屏蔽必要模型可能会导致 Router 被禁用。

有关当前费率和路由模型池,请参阅 Cursor Router模型与价格

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 Agentwith 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_clientclose_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, LocalAgentOptionsresult = 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, LocalAgentOptionsresult = 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, LocalAgentOptionswith 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())

资源

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

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

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

自定义 HTTP 客户端

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

from cursor_sdk import CursorClient, DefaultHttpxClientwith CursorClient.launch_bridge(    workspace=".",    http_client=DefaultHttpxClient(proxy="http://proxy.example.com"),) as client:    ...
from cursor_sdk import AsyncClient, DefaultAsyncHttpxClientasync 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, UserMessagerun = 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)        # 此次运行所用的已解析 ModelSelectionprint(result.duration_ms)print(result.usage)        # 累计 TokenUsage;不可用时为 Noneprint(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_tokensinput_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, SendOptionsrun = 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, SendOptionsrun = 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, SendOptionswith 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 SendOptionsdef 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, ToolCallStartedUpdateif isinstance(update, TextDeltaUpdate):    print(update.text)

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

SendOptions

属性类型描述
modelstr | ModelSelection | Mapping[str, Any]单次发送的模型覆盖设置。若省略,则使用 agent.model。发送成功后持续生效。
mode"agent" | "plan"单次发送的对话模式覆盖设置。若在后续消息中省略,则保留对话当前的模式。
mcp_serversMapping[str, McpServerConfig]内联 MCP 服务器定义。完全替换此次运行创建时的服务器。
cloud.env_varsMapping[str, str]仅适用于云端代理。为此次运行注入单次运行的环境变量,运行结束后移除。仅在此次运行中按名称覆盖智能体范围的 env_vars
local.forcebool仅适用于本地智能体。默认值为 None (未设置) 。设为 True 可在开始处理此消息前终止卡住的活动运行。云端会在服务端返回 409 agent_busy,因此无需提供等效设置。
idempotency_keystr可选的、由客户端为此次发送生成的幂等键。
on_stepCallable[[ConversationStep], Any]每个对话步骤 (文本、思考或工具批次) 完成后调用的回调。
on_deltaCallable[[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"SDKSystemMessagesubtypemodeltools
"user"SDKUserMessageEventmessage.content
"assistant"SDKAssistantMessage包含 TextBlockToolUseBlock 值的 message.content
"thinking"SDKThinkingMessagetextthinking_duration_ms
"tool_call"SDKToolUseMessagecall_idnamestatusargsresulttruncated
"status"SDKStatusMessagestatusmessage
"task"SDKTaskMessagestatustext
"request"SDKRequestMessagerequest_id
"usage"SDKUsageMessageusage (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 = NoneConversationStep = (    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 CursorClientwith 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 CursorClientwith 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 Cursorme = 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 AsyncCursorme = 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, LocalAgentOptionsagent = 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, LocalAgentOptionsdef 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 Pathartifacts = 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, LocalAgentOptionswith 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, LocalAgentOptionsasync 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_clientclose_default_client()

配置参考

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

AgentOptions

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

LocalAgentOptions

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

CloudAgentOptions

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

AgentDefinition

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

CustomTool

@dataclassclass CustomTool:    execute: Callable[[Mapping[str, Any], CustomToolContext], Any]    description: str | None = None    input_schema: Mapping[str, Any] | None = Noneclass 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
错误触发条件
AuthenticationErrorAPI 密钥无效或未登录。
PermissionDeniedError已通过身份验证的调用方无权执行所请求的操作。
RateLimitError请求过多或超出用量限额。
ConfigurationError模型无效、缺少必需配置,或请求参数有误。
AgentBusyError智能体已有处于 CREATINGRUNNING 状态的运行时发送后续请求 (HTTP 409,代码 agent_busy) 。
BadRequestError请求格式不正确。
IntegrationNotConnectedError为未连接 SCM 提供商的仓库创建云端代理。
NetworkError服务不可用或网络故障。
APITimeoutError请求超时。
InternalServerErrorCursor 服务返回了服务器错误。
NotFoundError未找到所请求的资源。
AgentNotFoundError智能体不存在,或在当前工作目录下不可见。
UnsupportedRunOperationError当前运行状态不支持该运行操作。

使用退避策略重试

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

import timefrom cursor_sdk import Agent, AgentOptions, CursorAgentError, LocalAgentOptions, RateLimitErrorfor 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, AgentBusyErroragent = 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) ,不支持编程式回调。