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 os
from cursor_sdk import Agent, LocalAgentOptions
with Agent.create(
model="composer-2.5",
api_key="crsr_key",
local=LocalAgentOptions(cwd=os.getcwd()),
) as agent:
print(agent.send("Summarize what this repository does").text())
流事件介紹如何提取助手文本、處理工具調用以及讀取運行狀態。若要一次性完成提示詞的創建、運行和結束,請參閱 Agent.prompt()。
雲端快速入門¶
Python SDK 原生支持 Cursor 雲端代理。你可以列出已連接的倉庫,針對其中一個啓動智能體,等待運行完成,然後評審最終結果。
from cursor_sdk import Agent, CloudAgentOptions, CloudRepository
with Agent.create(
model="composer-2.5",
api_key="crsr_key",
cloud=CloudAgentOptions(
repos=[CloudRepository(url="https://github.com/your-org/your-repo", starting_ref="main")],
auto_create_pr=True,
),
) as agent:
print(agent.send("Add structured logging to the auth middleware").text())
由 SDK 啓動的雲端代理已從默認智能體列表中篩除。要在 Cursor 網頁端或 Cursor 代理窗口中查看它們,請點擊 篩選 > 來源 > SDK。
異步用法¶
異步客戶端提供與同步客戶端相同的接口,推薦用於服務器、機器人和併發智能體編排。AsyncAgent、AsyncClient、AsyncRun 和 AsyncCursor 均可從 cursor_sdk 和 cursor_sdk.asyncio 導入。
import asyncio
import os
from cursor_sdk import AsyncClient, LocalAgentOptions
async def main():
async with await AsyncClient.launch_bridge(workspace=os.getcwd()) as client:
async with await client.agents.create(
model="composer-2.5",
api_key="crsr_key",
local=LocalAgentOptions(cwd=os.getcwd()),
) as agent:
run = await agent.send("Summarize what this repository does")
print(await run.text())
asyncio.run(main())
沒有全局異步默認客戶端。請顯式實例化 AsyncClient,或將 AsyncClient.launch_bridge(...) 作爲異步上下文管理器使用,以確保每個事件循環都有各自的客戶端。請勿在同一代碼路徑中混用同步和異步客戶端。
直接調用 AsyncAgent 類方法時需要提供 client=。請使用
await client.agents.create(...) 或
await AsyncAgent.create(..., client=client)。
| 同步 | 異步 |
|---|---|
CursorClient / Client |
AsyncClient / AsyncCursorClient |
Agent |
AsyncAgent |
Run |
AsyncRun |
Cursor |
AsyncCursor |
ListResult |
AsyncListResult |
DefaultHttpxClient |
DefaultAsyncHttpxClient |
創建智能體¶
Agent.create() 會驗證選項,並立即返回一個句柄。傳入 local 或 cloud 以選擇運行時環境。
from cursor_sdk import Agent, CloudAgentOptions, CloudRepository, LocalAgentOptions
agent = Agent.create(
model="composer-2.5",
local=LocalAgentOptions(cwd="."),
)
cloud_agent = Agent.create(
model="composer-2.5",
cloud=CloudAgentOptions(
repos=[CloudRepository(url="https://github.com/your-org/your-repo", starting_ref="main")],
auto_create_pr=True,
),
)
agent.agent_id 會立即賦值。本地智能體的 ID 爲 agent-<uuid>;雲端代理的 ID 爲 bc-<uuid>。agent.model 是帶類型的 ModelSelection,因此可直接使用 agent.model.id 和 agent.model.params。
由 SDK 啓動的雲端代理不會顯示在默認智能體列表中。要在 Cursor 網頁端 或 Cursor 代理窗口中
查看它們,請點擊 篩選 > 來源 > SDK。
無代碼倉庫雲端代理¶
雲端代理可在不含代碼倉庫的空 VM 上運行。傳入 cloud 並將 repos 列表設爲空,或完全省略 repos。省略 cloud 則會選擇本地運行時。
from cursor_sdk import Agent, CloudAgentOptions
with Agent.create(cloud=CloudAgentOptions(repos=[])) as agent:
run = agent.send("Research the top 3 Python testing frameworks and summarize.")
print(run.wait().result)
必須爲您的賬戶或團隊啓用無倉庫智能體。倉庫範圍的 API 密鑰無法創建此類智能體;請改用不受限制的服務賬戶密鑰或用戶 API 密鑰。
會話環境變量¶
對於雲端代理,如果一次運行需要短期憑據或其他僅供該智能體使用的值,請傳遞 env_vars。
import os
agent = Agent.create(
model="composer-2.5",
cloud=CloudAgentOptions(
repos=[CloudRepository(url="https://github.com/your-org/your-repo")],
env_vars={
"STAGING_API_TOKEN": os.environ["STAGING_API_TOKEN"],
},
),
)
這些值會在靜態存儲時加密,注入雲端代理的 shell,並在刪除智能體時一併刪除。env_vars 不能與調用方提供的 agent_id 一起使用;請省略 agent_id,並從 agent.agent_id 讀取服務器簽發的 ID。變量名不能以 CURSOR_ 開頭。
對於僅應在單次運行期間存在的值,請改爲通過 agent.send() 傳遞。參見單次運行的環境變量。
智能體元數據¶
創建雲端代理時,可爲其添加自定義標識符。元數據可將智能體與系統中的用戶、租戶、工作流或工單關聯,並可通過 client.agents.get() 和 client.agents.list() 在 SDKAgentInfo.metadata 中讀取。這些標籤並非 VM 內的智能體元數據 API;該 API 會從 VM 內部提供當前運行的 ID、所有者、輪次和工作區。
from cursor_sdk import Agent, CloudAgentOptions, CloudRepository
with Agent.create(
model="composer-2.5",
cloud=CloudAgentOptions(
repos=[CloudRepository(url="https://github.com/your-org/your-repo")],
metadata={
"end_user_id": "user-123",
"ticket_id": "ENG-456",
},
),
) as agent:
print(agent.agent_id)
創建雲端代理時可添加元數據。最多可附加 50 個鍵值對。鍵不能爲空,且不得超過 255 個字符。值必須爲不超過 4096 字節的字符串。允許使用空字符串值,空映射會被視爲未設置元數據。
如果 API 密鑰所屬的賬戶未啓用元數據功能,使用非空映射創建智能體將返回 403 feature_unavailable。
模型參數¶
使用 ModelSelection.params 傳遞特定模型的選項,例如推理 effort 或 Cursor Router 的 optimize_for。參數 ID 和取值因模型而異。使用 Cursor.models.list() 查看您的賬戶支持哪些參數和預設變體。
from cursor_sdk import Agent, LocalAgentOptions, ModelParameterValue, ModelSelection
agent = Agent.create(
model=ModelSelection(
id="composer-2.5",
params=[ModelParameterValue(id="fast", value="true")],
),
local=LocalAgentOptions(cwd="."),
)
使用 Cursor.models.list() 查看指定模型的參數 ID 和預設變體。有關 auto-smart 的選擇合約,請參閱 Cursor Router。
Cursor Router¶
Cursor Router 會爲每個 Auto 請求選擇模型。在 SDK 中,Router 是帶有 optimize_for 參數的 auto-smart 模型。它適用於 Teams 和企業版。企業版管理員必須先爲團隊啓用 Router,auto-smart 纔會出現在目錄中。
Cursor SDK 是智能體 SDK,而非獨立的模型推理或聊天補全 API。Router 會爲能夠理解工作區、調用工具、運行命令和編輯文件的 Cursor 智能體運行選擇模型。Cursor 目前尚未提供用於任意模型調用的底層 Router 端點文檔。
選擇成本、平衡或智能¶
傳入 auto-smart,並顯式設置 optimize_for:
| 產品標籤 | SDK 值 |
|---|---|
| 成本 | cost |
| 平衡 | balanced |
| 智能 | intelligence |
產品文案中請使用 平衡。balanced 僅用作 SDK 傳輸值。
import os
from cursor_sdk import Agent, LocalAgentOptions, ModelParameterValue, ModelSelection
with Agent.create(
model=ModelSelection(
id="auto-smart",
params=[ModelParameterValue(id="optimize_for", value="balanced")],
),
local=LocalAgentOptions(cwd=os.getcwd()),
) as agent:
run = agent.send("Find and fix the failing authentication test")
result = run.wait()
print(result.status)
始終傳入 optimize_for。請勿省略該參數,也不要傳入舊版 default 值;支持通過目錄進行發現這一合約。
在模型目錄中查找 Router¶
Cursor.models.list() 會返回當前 API 密鑰所屬賬戶和團隊可用的模型、參數定義及預設變體。Router 可用時,Cursor Router 會顯示爲 auto-smart。團隊管理員可以禁用 Router,或限制成員可選擇的優化模式。
硬編碼選擇前,請以目錄爲準:
from cursor_sdk import Cursor, ModelParameterValue, ModelSelection
models = Cursor.models.list()
router = next((model for model in models if model.id == "auto-smart"), None)
optimize_for = next(
(
parameter
for parameter in (router.parameters if router else [])
if parameter.id == "optimize_for"
),
None,
)
if router is None or optimize_for is None:
raise RuntimeError(
"Cursor Router is not available for this API key. "
"Verify that Router is enabled for the key's team."
)
requested_mode = "balanced"
allowed_values = {entry.value for entry in optimize_for.values}
if requested_mode not in allowed_values:
raise RuntimeError(
f'Router mode "{requested_mode}" is not enabled for this team.'
)
model = ModelSelection(
id=router.id,
params=[ModelParameterValue(id=optimize_for.id, value=requested_mode)],
)
按運行切換模式¶
在 agent.send() 中指定模型,以更改某次運行的 Router 模式:
from cursor_sdk import ModelParameterValue, ModelSelection, SendOptions
run = agent.send(
"Handle this complex migration",
SendOptions(
model=ModelSelection(
id="auto-smart",
params=[ModelParameterValue(id="optimize_for", value="intelligence")],
),
),
)
單次運行的模型覆蓋會持續生效。後續發送時如未指定覆蓋,將繼續使用新的模型選擇。請參閱單次運行的模型覆蓋。
模型 ID:auto-smart、auto 和 default¶
| 選擇 | 含義 |
|---|---|
搭配 optimize_for 使用的 auto-smart |
Cursor Router。需要成本、平衡或智能模式時使用。 |
ModelSelection(id="auto") |
當目錄中沒有指定模型時,由服務器選擇的 Auto 回退方案。需要明確指定 Router 模式時,優先使用 auto-smart。 |
省略 optimize_for 或傳入 default |
不受支持的 Router 合約。請始終查詢允許的值,並傳入 cost、balanced 或 intelligence。 |
計費與路由模型池¶
-
所有 Auto 模式均按每個請求所路由模型的標價計費。
-
每次請求所用的底層模型可能不同。如需進行可復現的比較,請使用固定的模型 ID。
- 企業版模型允許列表會影響路由模型池。屏蔽必要模型可能會導致 Router 被禁用。
有關當前費率和路由模型池,請參閱 Cursor Router 和 Auto 模式。
Router 缺失的疑難排查¶
如果找不到 auto-smart 或優化模式被拒絕:
- 調用
Cursor.models.list()。 - 確認結果中包含
auto-smart。 - 確認
optimize_for包含所需的值 (cost、balanced或intelligence) 。 - 確認與 API 密鑰關聯的團隊已啓用 Router。
- 如果您屬於多個團隊,請確認該密鑰在預期的團隊上下文中使用。
- 如果 Router 不可用或無法選擇有效的底層模型,請檢查團隊的模型訪問策略。
原始字典¶
對於應用代碼,建議優先使用帶類型的 dataclass,因爲 IDE 自動補全和類型檢查的支持更好。SDK 也接受適用於簡短腳本或外部提供的 JSON 的普通字典。蛇形命名法的鍵會被規範化。
from cursor_sdk import Agent
with Agent.create(
{
"api_key": "crsr_key",
"model": {"id": "composer-2.5"},
"local": {"cwd": "."},
}
) as agent:
...
智能體¶
Agent.create()、Agent.resume()、client.agents.create() 和 client.agents.resume() 返回的句柄。
class Agent:
agent_id: str
model: ModelSelection | None
client: CursorClient
def send(
self,
message: str | Mapping[str, Any] | UserMessage,
options: SendOptions | Mapping[str, Any] | None = None,
*,
idempotency_key: str | None = None,
) -> Run: ...
def reload(self) -> None: ...
def close(self) -> None: ...
def list_messages(
self, options: Mapping[str, Any] | None = None
) -> list[AgentMessage]: ...
def list_artifacts(self) -> list[SDKArtifact]: ...
def download_artifact(self, path: str) -> bytes: ...
def get_usage(self, *, run_id: str | None = None) -> AgentUsage: ...
def archive(self, options: Mapping[str, Any] | None = None) -> None: ...
def unarchive(self, options: Mapping[str, Any] | None = None) -> None: ...
def delete(self, options: Mapping[str, Any] | None = None) -> None: ...
| 成員 | 描述 |
|---|---|
agent_id |
穩定的智能體標識符。本地爲 agent-<uuid>,雲端爲 bc-<uuid>。 |
model |
當前的類型化模型選擇。使用模型覆蓋成功發送後會更新。 |
send |
使用給定提示詞啓動新的運行。返回 Run 句柄。 |
reload |
在不釋放智能體的情況下重新讀取文件系統配置 (鉤子、項目 MCP、子智能體) 。 |
close |
關閉智能體並釋放資源。 |
list_messages |
列出智能體的消息歷史記錄。 |
list_artifacts |
列出智能體生成的文件 (僅限雲端;本地返回空) 。 |
download_artifact |
按路徑下載文件 (僅限雲端;本地會引發異常) 。 |
get_usage |
獲取智能體的計費 token 用量和美元費用。 |
archive / unarchive / delete |
管理雲端代理的生命週期。 |
使用上下文管理器自動清理:
with Agent.create(model="composer-2.5", local=LocalAgentOptions(cwd=".")) as agent:
print(agent.send("Explain this repository").text())
使用同步 Agent.* 或 Cursor.* 輔助函數時,如果未傳入 client=,SDK 會啓動或複用模塊級默認客戶端。該客戶端會在進程退出時自動關閉,也可以手動顯式關閉:
from cursor_sdk import close_default_client
close_default_client()
Agent.prompt()¶
Agent.prompt(
message: str | Mapping[str, Any] | UserMessage,
options: AgentOptions | Mapping[str, Any] | None = None,
*,
client: CursorClient | None = None,
) -> RunResult
一次性便捷方法:創建智能體,發送單條提示詞,等待運行完成後釋放資源。
from cursor_sdk import Agent, AgentOptions, LocalAgentOptions
result = Agent.prompt(
"What does the auth middleware do?",
AgentOptions(model="composer-2.5", local=LocalAgentOptions(cwd=".")),
)
print(result.result)
異步等效寫法 (假設你已創建 AsyncClient 實例) :
from cursor_sdk import AgentOptions, AsyncAgent, LocalAgentOptions
result = await AsyncAgent.prompt(
"What does the auth middleware do?",
AgentOptions(model="composer-2.5", local=LocalAgentOptions(cwd=".")),
client=client,
)
CursorClient¶
需要顯式控制生命週期、使用自定義 bridge endpoint 或自定義 HTTP 選項,或需在同一進程中使用多個工作區時,請使用 CursorClient。Client 仍可用作別名。
from cursor_sdk import CursorClient, LocalAgentOptions
with CursorClient.launch_bridge(workspace=".") as client:
with client.agents.create(
model="composer-2.5",
api_key="crsr_key",
local=LocalAgentOptions(cwd="."),
) as agent:
print(agent.send("Summarize what this repository does").text())
資源¶
顯式客戶端提供資源命名空間:
| 資源 | 同步方法示例 | 異步方法示例 |
|---|---|---|
agents |
client.agents.create(...)、client.agents.list(...)、client.agents.get(...) |
await client.agents.create(...)、await client.agents.list(...) |
models |
client.models.list() |
await client.models.list() |
repositories |
client.repositories.list() |
await client.repositories.list() |
client.create_agent(...) 和 client.list_agents(...) 等頂層方法仍然可用,但對於應用代碼,推薦使用資源命名空間。
自定義 HTTP 客戶端¶
同步和異步客戶端均支持使用自定義 httpx 客戶端,以配置代理、傳輸方式及其他高級 HTTP 選項:
from cursor_sdk import CursorClient, DefaultHttpxClient
with CursorClient.launch_bridge(
workspace=".",
http_client=DefaultHttpxClient(proxy="http://proxy.example.com"),
) as client:
...
from cursor_sdk import AsyncClient, DefaultAsyncHttpxClient
async with await AsyncClient.launch_bridge(
workspace=".",
http_client=DefaultAsyncHttpxClient(proxy="http://proxy.example.com"),
) as client:
...
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, UserMessage
run = agent.send(
UserMessage(
text="What's in this screenshot?",
images=[SDKImage.from_file("screenshot.png")],
)
)
對於已具備編碼字節數據或遠程 URL 的調用方,也可使用 SDKImage.data_image(base64_data, mime_type) 和 SDKImage.url_image(url)。
運行¶
class Run:
id: str
agent_id: str
status: str # "running" | "finished" | "error" | "cancelled" | "expired"
result: str
model: ModelSelection | None
duration_ms: int
git: RunGitInfo | None
created_at: str | None
usage: TokenUsage | None # 累計值;即時句柄的屬性
def stream(self) -> Iterator[SDKMessage]: ...
def messages(self) -> Iterator[SDKMessage]: ...
def events(self) -> Iterator[RunStreamEvent]: ...
def iter_text(self) -> Iterator[str]: ...
def text(self) -> str: ...
def wait(self) -> RunResult: ...
def cancel(self) -> None: ...
def conversation(self) -> list[ConversationTurn]: ...
def conversation_json(self) -> str: ...
def observe(self, *, after_offset: str | None = None) -> Iterator[RunStreamEvent]: ...
def supports(self, operation: str) -> bool: ...
def unsupported_reason(self, operation: str) -> str | None: ...
def on_did_change_status(
self, listener: Callable[[str], None]
) -> Callable[[], None]: ...
run.stream() 是 run.messages() 的別名。直接迭代 run 會生成 RunStreamEvent envelopes,與 run.events() 相同。
AsyncRun 具有相同的狀態字段,包括 usage。執行 I/O 操作的方法均爲 async:async for message in run.stream()、async for message in run.messages()、async for event in run.events()、async for text in run.iter_text()、await run.text()、await run.wait()、await run.cancel()、await run.conversation()、await run.conversation_json() 和 async for event in run.observe()。
流式輸出¶
run = agent.send("Find the bug in src/auth.py")
for message in run.messages():
if message.type == "assistant":
for block in message.message.content:
if block.type == "text":
print(block.text, end="")
elif message.type == "thinking":
print(message.text, end="")
elif message.type == "tool_call":
print(f"[tool] {message.name}: {message.status}")
elif message.type == "status":
print(f"[status] {message.status}")
elif message.type == "usage":
print(f"[usage] turn total={message.usage.total_tokens}")
運行流只能消費一次。run.messages()、run.events() 和 run.iter_text() 都會從同一個底層流中讀取並推進流。流結束後,運行會保存終端結果 (run.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) # 此次運行所用的已解析 ModelSelection
print(result.duration_ms)
print(result.usage) # 累計 TokenUsage;不可用時爲 None
print(result.git) # 雲端 RunGitInfo
異步版本:
result = await run.wait()
Token 用量¶
運行時提供 Token 用量時,運行會報告該信息。可在即時句柄的 run.usage 中讀取累計總量 (流式傳輸期間或在 wait() 之後) ,也可在 run.wait() 返回的 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, SendOptions
run = 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, SendOptions
run = 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, SendOptions
with Agent.create(
AgentOptions(
model="composer-2.5",
mode="plan",
cloud=CloudAgentOptions(
repos=[CloudRepository(url="https://github.com/your-org/your-repo")],
),
)
) as agent:
agent.send("Design the auth refactor").wait()
agent.send(
"Looks good, start building",
SendOptions(mode="agent"),
).wait()
流式傳輸原始增量¶
在 SendOptions 中傳入 on_delta 和 on_step 回調,以獲取更底層的更新。同步回調會直接內聯調用。異步回調可以是同步函數或異步函數;在處理下一個事件之前,會等待可等待的返回值完成。
from cursor_sdk import SendOptions
def on_delta(update):
if update.type in ("text-delta", "thinking-delta"):
print(update.text, end="")
run = agent.send(
"Refactor the utils module",
SendOptions(on_delta=on_delta, on_step=lambda step: print(f"[step] {step.type}")),
)
run.wait()
具體的 update 和 step 子類定義在 cursor_sdk.events 中:
from cursor_sdk.events import TextDeltaUpdate, ToolCallStartedUpdate
if isinstance(update, TextDeltaUpdate):
print(update.text)
爲保持向後兼容,仍可從 cursor_sdk 導入它們,但新代碼應從 cursor_sdk.events 導入。
SendOptions¶
| 屬性 | 類型 | 描述 |
|---|---|---|
model |
str \| ModelSelection \| Mapping[str, Any] |
單次發送的模型覆蓋設置。若省略,則使用 agent.model。發送成功後持續生效。 |
mode |
"agent" \| "plan" |
單次發送的對話模式覆蓋設置。若在後續消息中省略,則保留對話當前的模式。 |
mcp_servers |
Mapping[str, McpServerConfig] |
內聯 MCP 服務器定義。完全替換此次運行創建時的服務器。 |
cloud.env_vars |
Mapping[str, str] |
僅適用於雲端代理。爲此次運行注入單次運行的環境變量,運行結束後移除。僅在此次運行中按名稱覆蓋智能體範圍的 env_vars。 |
local.force |
bool |
僅適用於本地智能體。默認值爲 None (未設置) 。設爲 True 可在開始處理此消息前終止卡住的活動運行。雲端會在服務端返回 409 agent_busy,因此無需提供等效設置。 |
idempotency_key |
str |
可選的、由客戶端爲此次發送生成的冪等鍵。 |
on_step |
Callable[[ConversationStep], Any] |
每個對話步驟 (文本、思考或工具批次) 完成後調用的回調。 |
on_delta |
Callable[[InteractionUpdate], Any] |
每個原始 InteractionUpdate 的回調。 |
接下來的三個分區詳細介紹 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 = None
ConversationStep = (
AssistantConversationStep
| ToolCallConversationStep
| ThinkingConversationStep
| Mapping[str, Any]
)
根據 turn.type 區分類型,並通過 turn.turn 讀取負載:
for turn in run.conversation():
if turn.type == "agentConversationTurn":
for step in turn.turn.steps:
print(step.type)
elif turn.type == "shellConversationTurn":
print(turn.turn.shell_command, turn.turn.shell_output)
on_step 回調中的 run.conversation() 會針對每個 ConversationStep 觸發,而非每個輪次。工具調用對話步驟攜帶 Mapping[str, Any] 負載。工具調用負載的具體內容應視爲無類型數據;請參閱流事件下的穩定性說明。
恢復智能體¶
Agent.resume(
agent_id: str,
options: AgentOptions | Mapping[str, Any] | None = None,
*,
client: CursorClient | None = None,
) -> Agent
使用 Agent.resume() 或 client.agents.resume(),通過 ID 重新連接到現有智能體。常見用法包括:重新連接到之前啓動的長時間運行雲端代理,或在本地進程重啓後繼續對話。系統會根據 ID 前綴自動檢測運行環境 (bc- 表示雲端,其他前綴表示本地) 。
agent = Agent.resume("bc-abc123")
run = agent.send("Also update the changelog")
run.wait()
異步版本:
agent = await client.agents.resume("bc-abc123")
run = await agent.send("Also update the changelog")
await run.wait()
除非再次傳入 model,否則恢復時 agent.model 將爲 None。內聯 MCP 服務器不會在恢復後保留;它們通常包含機密信息,僅存於內存中。恢復時請再次傳入,或者爲需要保留的服務器使用基於文件的 MCP 配置 (.cursor/mcp.json 和 local.setting_sources) 。
本地持久化¶
本地智能體通過 bridge 持久化保存對話狀態和運行元數據,因此後續交互和 Agent.resume() 在進程重啓後仍可繼續使用。默認情況下,bridge 會將這些數據存儲在磁盤上各工作區對應的狀態根目錄下。雲端代理在服務器端持久化保存數據,因此無論從何處恢復雲端代理,都會返回同一段對話。
本地持久化以工作區爲單位。當 bridge 作爲長期運行的 sidecar 或子進程運行時,請爲其指定與智能體相同的工作區,以便本地 list、get 和 resume 調用能找到正確的智能體。在客戶端中設置一次工作區,並將 cwd 傳遞給本地 list 和 get 調用:
from cursor_sdk import CursorClient
with CursorClient.launch_bridge(workspace="/path/to/repo") as client:
agents = client.agents.list(runtime="local", cwd="/path/to/repo")
info = client.agents.get(agents.items[0].agent_id, cwd="/path/to/repo")
查看智能體和運行¶
使用 CursorClient 調用列表、獲取和分頁 API。
from cursor_sdk import CursorClient
with CursorClient.launch_bridge(workspace=".") as client:
agents = client.agents.list(runtime="local", cwd=".")
for agent_info in agents.auto_paging_iter():
print(agent_info.agent_id)
info = client.agents.get(agents.items[0].agent_id)
runs = client.agents.list_runs(info.agent_id)
run = client.agents.get_run(runs.items[0].id)
異步對應形式:
agents = await client.agents.list(runtime="local", cwd=".")
async for agent_info in agents.auto_paging_iter():
print(agent_info.agent_id)
info = await client.agents.get(agents.items[0].agent_id)
runs = await client.agents.list_runs(info.agent_id)
run = await client.agents.get_run(runs.items[0].id)
在智能體句柄上使用 agent.list_messages() 讀取消息歷史記錄。只有 ID 時,可使用 Agent.messages.list(agent_id),這是帶類型屬性的同一調用的便捷形式。
使用 Agent.get_run(run_id) 或 client.agents.get_run(run_id) 獲取運行,
無需智能體句柄。使用
Agent.cancel_run(run_id, agent_id=...) 或
client.agents.cancel_run(run_id, agent_id=...) 將其取消。異步客戶端方法可
await,且使用相同的參數。
AgentMessage 與流式 SDKMessage 不同:
@dataclass(frozen=True)
class AgentMessage:
type: str
uuid: str
agent_id: str
message: Any = None
列表端點返回 ListResult[T]。可直接使用 .items 和 .next_cursor,通過 for item in page 遍歷當前頁,或通過 .auto_paging_iter() 遍歷所有頁。異步列表端點返回 AsyncListResult[T];async for item in page 遍歷當前頁,而 async for item in page.auto_paging_iter() 遍歷結果集中的所有頁。
SDKAgentInfo¶
Agent.list()、Agent.get()、client.agents.list() 和 client.agents.get() 返回的元數據結構。
@dataclass(frozen=True)
class SDKAgentInfo:
agent_id: str
name: str
summary: str
last_modified: str | None = None
status: str | None = None # "running" | "finished" | "error"
created_at: str | None = None
archived: bool = False
runtime: Literal["local", "cloud"] | None = None
cwd: str = ""
env: CloudEnvironment | None = None
repos: Sequence[str] = ()
metadata: Mapping[str, str] = {} # 來自 CloudAgentOptions.metadata;本地智能體爲空
雲端代理生命週期¶
雲端代理會一直保留在團隊工作區中,直到被歸檔或刪除。client.agents.list(runtime="cloud") 默認不顯示已歸檔的智能體;傳入 include_archived=True 可查看它們。按 pr_url 篩選,可找到創建特定 PR 的智能體。
# 通過 ID 操作,無需智能體句柄:
Agent.archive(agent_id)
Agent.unarchive(agent_id)
Agent.delete(agent_id)
# 通過顯式指定的客戶端:
client.agents.archive(agent_id)
client.agents.unarchive(agent_id)
client.agents.delete(agent_id)
# 通過現有智能體句柄:
agent.archive()
agent.unarchive()
agent.delete()
archive 會軟刪除智能體,但會話記錄仍可讀取。unarchive 會將其恢復。delete 會永久刪除;後續讀取會返回 NotFoundError。
異步生命週期方法名稱相同,且可使用 await 調用。
agent.get_usage()¶
獲取智能體各次運行的已計費 token 用量和美元費用。雲端代理會返回按運行劃分的明細;本地智能體會返回按輪次劃分的明細。傳入 run_id 可將結果限定爲單個條目:雲端代理使用 run-<uuid> 格式的運行 ID;本地智能體使用之前 get_usage().runs[].run_id 中的 ID。
usage = agent.get_usage()
print(f"tokens: {usage.usage.total_tokens}")
if usage.cost is not None:
print(f"charged: ${usage.cost.charged_cents / 100:.2f}")
for run in usage.runs:
print(run.run_id, run.usage.total_tokens)
@dataclass(frozen=True)
class AgentUsage:
usage: TokenUsage # 所有 `runs` 的彙總
runs: Sequence[RunUsage] = ()
cost: UsageCost | None = None # 所有 `runs` 的彙總
@dataclass(frozen=True)
class RunUsage:
run_id: str
usage: TokenUsage
cost: UsageCost | None = None
@dataclass(frozen=True)
class UsageCost:
raw_cost_cents: float # 未享受折扣的模型 token 成本;按請求計費的用量爲 0
charged_cents: float # 實際收取的金額,已計入折扣和 Cursor Token 費率
費用已包含折扣,運行結束後可能需要片刻才能結算;在此之前,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 Cursor
me = Cursor.me()
models = Cursor.models.list()
repositories = Cursor.repositories.list()
使用顯式客戶端的等效版本:
me = client.me()
models = client.models.list()
repositories = client.repositories.list()
異步對應形式:
from cursor_sdk import AsyncCursor
me = await AsyncCursor.me(client=client)
models = await AsyncCursor.models.list(client=client)
repositories = await AsyncCursor.repositories.list(client=client)
Cursor.me() 會返回一個 SDKUser,其中包含 api_key_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, LocalAgentOptions
agent = Agent.create(
AgentOptions(
model="composer-2.5",
local=LocalAgentOptions(cwd="."),
agents={
"code-reviewer": AgentDefinition(
description="Expert code reviewer for quality and security.",
prompt="Review code for bugs, security issues, and proven approaches.",
model="inherit",
),
"test-writer": AgentDefinition(
description="Writes tests for code changes.",
prompt="Write comprehensive tests for the given code.",
),
},
)
)
已提交到倉庫 .cursor/agents/*.md 中的子智能體 (帶有 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, LocalAgentOptions
def get_deployment_status(args, context: CustomToolContext):
service = args["service"]
return f"Service {service} is healthy."
with Agent.create(
model="composer-2.5",
local=LocalAgentOptions(
cwd=".",
custom_tools={
"get_deployment_status": CustomTool(
description="Look up the current deployment status for a service.",
input_schema={
"type": "object",
"properties": {
"service": {"type": "string", "description": "Service name"},
},
"required": ["service"],
},
execute=get_deployment_status,
),
},
),
) as agent:
agent.send("Is the checkout service healthy?").wait()
execute 接收解析後的參數,以及可用時帶有 tool_call_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 Path
artifacts = agent.list_artifacts()
for artifact in artifacts:
print(artifact.path, artifact.size_bytes)
# 將單個產物下載到本地磁盤。
content = agent.download_artifact(artifacts[0].path)
Path("review.md").write_bytes(content)
異步智能體支持 await agent.list_artifacts() 和 await agent.download_artifact(path)。
產物支持取決於運行時。Local SDK 智能體調用 list_artifacts() 時會返回空列表,調用 download_artifact() 時會引發異常。
資源管理¶
使用完畢後,請始終關閉智能體。最簡潔的同步用法是使用上下文管理器:
from cursor_sdk import Agent, LocalAgentOptions
with Agent.create(model="composer-2.5", local=LocalAgentOptions(cwd=".")) as agent:
agent.send("Summarize the repository").wait()
如需手動釋放資源:
agent.close()
異步智能體和客戶端支持異步上下文管理器,並可使用 await 進行清理:
from cursor_sdk import AsyncClient, LocalAgentOptions
async with await AsyncClient.launch_bridge(workspace=".") as client:
async with await client.agents.create(
model="composer-2.5",
local=LocalAgentOptions(cwd="."),
) as agent:
run = await agent.send("Summarize the repository")
await run.wait()
要顯式釋放資源:
await agent.close()
await client.aclose()
模塊級同步默認客戶端會在進程退出時自動關閉。長時間運行的進程可顯式將其關閉並重置:
from cursor_sdk import close_default_client
close_default_client()
配置參考¶
Python SDK 支持輔助數據類和原始字典。數據類使用 Python snake_case 字段,推薦在應用代碼中使用。
AgentOptions¶
| 屬性 | 類型 | 默認值 | 描述 |
|---|---|---|---|
model |
str \| ModelSelection \| Mapping[str, Any] |
本地必填;雲端默認使用服務器解析的默認值 | 要使用的模型。請參閱 ModelSelection。 |
api_key |
str |
CURSOR_API_KEY 環境變量 |
用戶 API 密鑰或服務賬戶密鑰。暫不支持團隊管理員密鑰。 |
name |
str |
自動生成 | 在 client.agents.list() / client.agents.get() 中顯示的易讀智能體名稱。 |
local |
LocalAgentOptions \| Mapping[str, Any] |
None |
本地智能體配置。傳入以創建本地智能體。 |
cloud |
CloudAgentOptions \| Mapping[str, Any] |
None |
雲端代理配置。傳入以創建雲端代理。 |
mcp_servers |
Mapping[str, McpServerConfig] |
None |
內聯 MCP 服務器定義。 |
agents |
Mapping[str, AgentDefinition \| Mapping[str, Any]] |
None |
子智能體定義。 |
tools |
Sequence[str] |
默認工具集 | 僅向模型提供列出的內置工具。[] 表示不提供內置工具;模型只能返回文本。僅限本地智能體。 |
disallowed_tools |
Sequence[str] |
None |
移除列出的內置工具;其他工具仍可用。與 tools 同時使用時,以拒絕列表爲準。僅限本地智能體。 |
agent_id |
str |
自動生成 | 持久化智能體 ID。傳入後可在多次調用間保持 ID 穩定。 |
idempotency_key |
str |
雲端自動生成 | 可選的客戶端生成冪等鍵。僅限雲端。 |
mode |
"agent" \| "plan" |
None |
智能體首次運行時的初始對話模式。省略時,服務器將以 Agent 模式啓動。請參閱對話模式。 |
LocalAgentOptions¶
| 屬性 | 類型 | 默認值 | 描述 |
|---|---|---|---|
cwd |
str \| os.PathLike |
None |
主工作目錄。不接受多項列表;多根目錄請使用 dirs。 |
dirs |
Sequence[str \| os.PathLike] |
None |
多根目錄配置的額外工作區文件夾。與 cwd 合併後,將從每個路徑加載規則、技能和工作區上下文。 |
setting_sources |
Sequence[SettingSource] |
None |
可用的設置層:”project”、”user”、”team”、”mdm”、”plugins” 或 “all”。 |
sandbox_options |
SandboxOptions \| Mapping[str, Any] |
None |
本地沙箱選項。 |
store |
LocalAgentStoreConfig \| Mapping[str, Any] |
None |
傳遞給 bridge 的本地存儲配置。 |
auto_review |
bool |
None |
如果連接的後端支持,則通過 Auto-review 模式處理本地工具調用。 |
custom_tools |
Mapping[str, CustomTool \| Mapping[str, Any]] |
None |
向本地智能體提供的自定義工具。 |
CloudAgentOptions¶
| 屬性 | 類型 | 默認值 | 描述 |
|---|---|---|---|
env |
CloudEnvironment \| Mapping[str, Any] |
None |
執行環境。省略時,服務器使用由 Cursor 託管的雲端 VM。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¶
@dataclass
class CustomTool:
execute: Callable[[Mapping[str, Any], CustomToolContext], Any]
description: str | None = None
input_schema: Mapping[str, Any] | None = None
class CustomToolContext:
tool_call_id: str | None = None
ModelSelection¶
@dataclass(frozen=True)
class ModelSelection:
id: str
params: Sequence[ModelParameterValue] = ()
@dataclass(frozen=True)
class ModelParameterValue:
id: str
value: str
id 是模型標識符 (例如 "composer-2.5" 或 "auto-smart") 。params 包含模型專屬參數,例如推理 effort 或 Router 的 optimize_for。使用 Cursor.models.list() 可查看您賬戶可用的有效 ID、參數定義和預設變體。有關 Router 的選擇合約,請參閱 Cursor Router。
McpServerConfig¶
from cursor_sdk.types import McpServerConfig
@dataclass(frozen=True)
class HttpMcpServerConfig:
url: str
type: Literal["http", "sse"] | str = "http"
headers: Mapping[str, str] | None = None
auth: McpAuth | Mapping[str, Any] | None = None
@dataclass(frozen=True)
class SseMcpServerConfig(HttpMcpServerConfig):
type: Literal["sse"] = "sse"
@dataclass(frozen=True)
class StdioMcpServerConfig:
command: str
args: Sequence[str] | None = None
env: Mapping[str, str] | None = None
cwd: str | os.PathLike | None = None # 僅限本地;雲端不支持此字段
@dataclass(frozen=True)
class McpAuth:
client_id: str
client_secret: str | None = None
scopes: Sequence[str] = ()
對於在雲端運行的 HTTP 服務器,headers 和 auth 由 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 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 time
from cursor_sdk import Agent, AgentOptions, CursorAgentError, LocalAgentOptions, RateLimitError
for attempt in range(3):
try:
result = Agent.prompt(
"Audit the auth middleware for missing input validation",
AgentOptions(model="composer-2.5", local=LocalAgentOptions(cwd=".")),
)
break
except RateLimitError as err:
time.sleep(float(err.retry_after) if err.retry_after else 2**attempt)
except CursorAgentError as err:
if not err.is_retryable:
raise
time.sleep(2**attempt)
服務器返回 request_id 時,每個 CursorAgentError 都會包含該 ID。報錯時請記錄它,以便支持團隊排查故障。
IntegrationNotConnectedError¶
class IntegrationNotConnectedError(ConfigurationError):
provider: str # 例如:"github"、"gitlab"、"azuredevops"
help_url: str # 用於重新連接的儀表盤鏈接
使用 help_url 將用戶引導至正確的重新連接流程。無需發佈新版 SDK 即可添加新的提供商。
AgentBusyError¶
雲端代理同一時間只允許一個活躍運行。當同一智能體的另一個運行仍處於 CREATING 或 RUNNING 狀態時,調用 agent.send() (或以其他方式創建運行) 會引發 AgentBusyError。
is_retryable 爲 False。立即重試仍會失敗,直到活躍運行進入終止狀態或被取消。其他 409 響應 (如 agent_archived) 則會引發 ConfigurationError。
等待活躍運行完成,使用 run.cancel() 取消它,或在再次發送前輪詢 Agent.list_runs():
from cursor_sdk import Agent, AgentBusyError
agent = Agent.resume("bc-00000000-0000-0000-0000-000000000001")
try:
agent.send("Also add tests for the auth middleware.")
except AgentBusyError:
runs = Agent.list_runs(agent.agent_id, {"runtime": "cloud", "limit": 1})
active = runs.items[0] if runs.items else None
if active is not None and active.status == "running":
active.cancel()
agent.send("Also add tests for the auth middleware.")
本地智能體不會拋出 AgentBusyError。在 send() 中傳入 local={"force": True},可在啓動新的本地運行前終止卡住的運行。
UnsupportedRunOperationError¶
class UnsupportedRunOperationError(ConfigurationError):
operation: str
噹噹前運行不允許執行某個 Run 操作時引發。最常見的情況是對已處於終止狀態的運行調用 run.cancel()。
run.supports(operation) 和 run.unsupported_reason(operation) 用於報告 SDK 層面是否支持某個操作名稱 ("stream"、"wait"、"cancel"、"conversation") ,不會檢查運行的狀態。請讀取 run.status,以避免調用對狀態敏感的操作。
疑難排查¶
設置 CURSOR_SDK_LOG=debug (或 info) ,爲 SDK 自身的日誌記錄器添加 stderr 處理程序。SDK 僅配置自己的 cursor_sdk 日誌記錄器,因此不會影響宿主應用的日誌配置。
CURSOR_SDK_LOG=debug python my_script.py
隨包附帶的 bridge 可執行文件會以 cursor-sdk-bridge 的名稱安裝到 PATH 中。直接運行它,確認 wheel 中包含的構建版本:
cursor-sdk-bridge --help
已知限制¶
- 工具調用的負載 schema 有意不採用強類型定義。
- 內聯 MCP 服務器不會在
Agent.resume()後保留。如有需要,請在恢復時再次傳入。 - 自定義工具 (
local.custom_tools) 和工具集限制 (tools、disallowed_tools) 僅適用於本地智能體。這些限制不會保留在智能體中;請在恢復時再次傳入。 - 本地智能體尚不支持 Artifact 下載。
local.setting_sources(以及它所控制的基於文件的 MCP 和子智能體路徑) 不適用於雲端代理。雲端始終加載project、team和plugins。- 鉤子僅支持基於文件的方式 (
.cursor/hooks.json) ,不支持編程式回調。