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() 传入 local 或 cloud 以设置运行时。
身份验证
创建智能体前,请设置 CURSOR_API_KEY 或传入 api_key。
SDK 支持本地和云端运行时使用用户 API 密钥和服务账户 API 密钥。暂不支持团队 Admin API 密钥。
- 用户 API 密钥:Cursor Dashboard -> API Keys
- 服务账户 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。
异步用法
异步客户端提供与同步客户端相同的接口,推荐用于服务器、机器人和并发智能体编排。AsyncAgent、AsyncClient、AsyncRun 和 AsyncCursor 均可从 cursor_sdk 和 cursor_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 / Client | AsyncClient / AsyncCursorClient |
Agent | AsyncAgent |
Run | AsyncRun |
Cursor | AsyncCursor |
ListResult | AsyncListResult |
DefaultHttpxClient | DefaultAsyncHttpxClient |
创建智能体
Agent.create() 会验证选项,并立即返回一个句柄。传入 local 或 cloud 以选择运行时环境。
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.id 和 agent.model.params。
由 SDK 启动的云端代理不会显示在默认智能体列表中。要在 Cursor 网页端 或 Cursor 代理窗口中 查看它们,请点击 筛选 > 来源 > SDK。
无代码仓库云端代理
云端代理可在不含代码仓库的空 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 字节的字符串。允许使用空字符串值,空映射会被视为未设置元数据。
如果 API 密钥所属的账户未启用元数据功能,使用非空映射创建智能体将返回 403 feature_unavailable。
模型参数
使用 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-smart、auto 和 default
| 选择 | 含义 |
|---|---|
搭配 optimize_for 使用的 auto-smart | Cursor Router。需要成本、平衡或智能模式时使用。 |
ModelSelection(id="auto") | 当目录中没有指定模型时,由服务器选择的 Auto 回退方案。需要明确指定 Router 模式时,优先使用 auto-smart。 |
省略 optimize_for 或传入 default | 不受支持的 Router 合约。请始终查询允许的值,并传入 cost、balanced 或 intelligence。 |
计费与路由模型池
- Cost 沿用经典 Auto 行为和捆绑式 Auto 定价。
- Balance 和 Intelligence 使用 Cursor Router,并按您的方案或合约中路由模型的费率计费。
- 每次请求所用的底层模型可能不同。如需进行可复现的比较,请使用固定的模型 ID。
- 企业版模型允许列表会影响路由模型池。屏蔽必要模型可能会导致 Router 被禁用。
有关当前费率和路由模型池,请参阅 Cursor Router 和 模型与价格。
Router 缺失的疑难排查
如果找不到 auto-smart 或优化模式被拒绝:
- 调用
Cursor.models.list()。 - 确认结果中包含
auto-smart。 - 确认
optimize_for包含所需的值 (cost、balanced或intelligence) 。 - 确认与 API 密钥关联的团队已启用 Router。
- 如果您属于多个团队,请确认该密钥在预期的团队上下文中使用。
- 如果 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 选项,或需在同一进程中使用多个工作区时,请使用 CursorClient。Client 仍可用作别名。
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())资源
显式客户端提供资源命名空间:
| 资源 | 同步方法示例 | 异步方法示例 |
|---|---|---|
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, 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: ...DefaultHttpxClient 和 DefaultAsyncHttpxClient 会保留 SDK 默认的超时和重定向行为。普通的 httpx.Client 和 httpx.AsyncClient 则使用 httpx 的默认值。
配置超时和重试
两个客户端都提供 with_options(...),该方法会返回一个浅拷贝,与原对象共享连接设置,并覆盖默认值。可使用 timeout 为所有请求设置超时,或分别设置 unary_timeout 和 stream_timeout。max_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.result、run.status、run.usage、run.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() 返回的 RunResult 的 result.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)。它会在每个报告用量的轮次结束时触发一次,并携带该轮的 TokenUsage。run.usage 和 result.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.usage 在 AsyncRun 中仍为同步属性。
TokenUsage 从 cursor_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.model 和 result.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()}), ),)如果单次运行范围的变量与 CloudAgentOptions 的 env_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_delta 和 on_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
| 属性 | 类型 | 描述 |
|---|---|---|
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 的回调。 |
接下来的三个分区详细介绍 SDKMessage、InteractionUpdate 和 ConversationTurn。首次阅读时可快速浏览或跳过;恢复智能体将继续后续内容。
流事件
run.messages() 会生成带类型的 SDK 消息数据类。可根据 message.type 区分消息类型。运行时提供时,所有消息都会包含 agent_id 和 run_id。
SDKMessage = ( SDKSystemMessage | SDKUserMessageEvent | SDKAssistantMessage | SDKThinkingMessage | SDKToolUseMessage | SDKStatusMessage | SDKTaskMessage | SDKRequestMessage | SDKUsageMessage | Mapping[str, Any])type | 数据类 | 关键字段 |
|---|---|---|
"system" | SDKSystemMessage | subtype、model、tools |
"user" | SDKUserMessageEvent | message.content |
"assistant" | SDKAssistantMessage | 包含 TextBlock 和 ToolUseBlock 值的 message.content |
"thinking" | SDKThinkingMessage | text、thinking_duration_ms |
"tool_call" | SDKToolUseMessage | call_id、name、status、args、result、truncated |
"status" | SDKStatusMessage | status、message |
"task" | SDKTaskMessage | status、text |
"request" | SDKRequestMessage | request_id |
"usage" | SDKUsageMessage | usage (TokenUsage) |
大多数工具调用会发出两次 SDKToolUseMessage:首次发出时,status="running" 且 args 已填充;完成后会再次发出,此时 status="completed" (或 "error") 且 result 已填充。truncated 标志指示 SDK 是否因负载过大而截断了 args 或 result。
每个报告 token 用量的轮次结束时,都会发出一次 SDKUsageMessage,其中包含该轮的 TokenUsage。跨轮次的累计用量保存在 run.usage 和 result.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事件中的args和result负载反映各工具的内部结构,可能会随工具演进而变化。工具名称也可能被重命名或替换。请将args和result视为无类型数据,并进行防御性解析。事件信封 (type、call_id、name、status) 是稳定的。
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.json 和 local.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 费率费用已包含折扣,运行结束后可能需要片刻才能结算;在此之前,cost 为 None。对于方案内包含、BYOK 和额度授予的用量,charged_cents 为 0.0。
这与Token 用量不同:run.usage 是单次运行的实时 token 计数,而 get_usage() 是该智能体所有运行的计费记录。对于异步智能体,await agent.get_usage() 的结果相同。AgentUsage、RunUsage 和 UsageCost 均从 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_name、created_at 以及
可选的 user_id、user_email、user_first_name 和 user_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": ...}) 。
会加载哪些内容
本地智能体最多可从五个来源加载服务器;如果名称冲突,优先使用最先匹配的来源:
agent.send()中的mcp_servers。会完全替换该次运行在创建时配置的服务器 (不会合并) 。Agent.create()中的mcp_servers。未提供单次发送的覆盖配置时使用。- 插件服务器,前提是
local.setting_sources包含"plugins"。 - 项目服务器,来自
.cursor/mcp.json,前提是local.setting_sources包含"project"。 - 用户服务器,来自
~/.cursor/mcp.json,前提是local.setting_sources包含"user"。
未设置 local.setting_sources 时,只会加载内联服务器。如果本地 MCP 服务器需要通过 OAuth 登录,SDK 可以复用 Cursor app 中保存的登录信息,但无法打开浏览器让你登录。
云端代理从以下来源加载服务器:
agent.send()中的mcp_servers。会完全替换该次运行在创建时配置的服务器 (不会合并) 。Agent.create()中的mcp_servers。未提供单次发送的覆盖配置时使用。- 来自 cursor.com/agents 的个人和团队 MCP 服务器。
如果内联服务器不包含 auth 或 headers,且你之前已在 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
headers和auth由 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 中的子智能体 (带有 name、description 和可选 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_id 的 CustomToolContext。它可以返回 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
| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
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。pool 和 machine 指向您运行的自托管 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
@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 = NoneModelSelection
@dataclass(frozen=True)class ModelSelection: id: str params: Sequence[ModelParameterValue] = ()@dataclass(frozen=True)class ModelParameterValue: id: str value: strid 是模型标识符 (例如 "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 服务器,headers 和 auth 由 Cursor 后端处理。敏感字段会在 VM 读取前被脱敏。对于在云端运行的 stdio 服务器,env 值会传入 VM (请将其视为运行时机密信息) 。
用户消息
@dataclass(frozen=True)class UserMessage: text: str images: Sequence[SDKImage | Mapping[str, Any]] | None = Noneagent.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 data。from_data() 接受字节数据或 base64 字符串。from_file() 从磁盘读取文件并将其编码为 base64。
SettingSource
可通过 cursor_sdk.types 获取 SettingSource。
from cursor_sdk.types import SettingSource控制本地智能体加载哪些存储在磁盘上的设置层。云端代理始终加载 project、team 和 plugins,并忽略此字段。
| 值 | 来源 |
|---|---|
"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 错误都继承自 CursorAgentError。CursorSDKError 是为兼容较早调用方保留的根异常别名。使用 is_retryable 和 retry_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 | 智能体已有处于 CREATING 或 RUNNING 状态的运行时发送后续请求 (HTTP 409,代码 agent_busy) 。 |
BadRequestError | 请求格式不正确。 |
IntegrationNotConnectedError | 为未连接 SCM 提供商的仓库创建云端代理。 |
NetworkError | 服务不可用或网络故障。 |
APITimeoutError | 请求超时。 |
InternalServerError | Cursor 服务返回了服务器错误。 |
NotFoundError | 未找到所请求的资源。 |
AgentNotFoundError | 智能体不存在,或在当前工作目录下不可见。 |
UnsupportedRunOperationError | 当前运行状态不支持该运行操作。 |
使用退避策略重试
is_retryable 和 retry_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
云端代理同一时间只允许一个活跃运行。当同一智能体的另一个运行仍处于 CREATING 或 RUNNING 状态时,调用 agent.send() (或以其他方式创建运行) 会引发 AgentBusyError。
is_retryable 为 False。立即重试仍会失败,直到活跃运行进入终止状态或被取消。其他 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) 和工具集限制 (tools、disallowed_tools) 仅适用于本地智能体。这些限制不会保留在智能体中;请在恢复时再次传入。 - 本地智能体尚不支持 Artifact 下载。
local.setting_sources(以及它所控制的基于文件的 MCP 和子智能体路径) 不适用于云端代理。云端始终加载project、team和plugins。- 钩子仅支持基于文件的方式 (
.cursor/hooks.json) ,不支持编程式回调。