《Cursor文檔》-Cursor Python SDK

cursor-sdk 包可讓您從自己的 Python 代碼中調用 Cursor 的智能體。在 Cursor IDE、CLI 和網頁端運行的同一智能體,也可通過 Python 進行腳本調用,並支持同步和異步客戶端、類型化數據類,以及對流和頁面的常規迭代。請在 Cursor 中運行 /sdk 技能以快速入門。

如需使用 REST API,請參閱 Cloud Agents API。如需其他語言支持,請參閱 SDK Bridge

概述

SDK 通過統一接口封裝本地和雲端運行時。無論智能體在哪裏運行,您都編寫相同的代碼。

運行時 功能 適用場景
本地 讓智能體處理磁盤上的本地文件。 針對工作樹運行開發腳本和 CI 檢查。
雲端 (由 Cursor 託管) 在隔離的 VM 中運行,且已克隆您的倉庫。VM 由 Cursor 託管。 調用方沒有倉庫、需要並行運行多個智能體,或運行需要在調用方斷開連接後繼續時。

Agent.create() 傳入 localcloud 以設置運行時。

身份驗證

創建智能體前,請設置 CURSOR_API_KEY 或傳入 api_key

SDK 支持本地和雲端運行時使用用戶 API 密鑰和服務賬戶 API 密鑰。暫不支持團隊 Admin API 密鑰。

export CURSOR_API_KEY="your-key"

用量和計費

SDK 運行遵循與 IDE 和雲端代理運行相同的定價、請求池和隱私模式規則。費用會顯示在團隊的用量儀表盤中,並標記爲 SDK。

如需在代碼中讀取單次運行的 token 數量,請參閱 Token 用量。如需獲取智能體運行的已計費用量和美元費用,請參閱 agent.get_usage()

核心概念

概念 描述
Agent 持久化句柄,包含對話狀態、工作區配置、模型選擇和設置,可在多個提示詞之間保留。
Run 一次提示詞提交,擁有獨立的流、狀態、結果、對話和取消操作。
SDKMessage 運行期間產生的強類型流消息。在本地和雲端運行時中具有相同結構。
CursorClient 用於控制生命週期、配置自定義 HTTP 選項,或在同一進程中使用多個工作區的顯式客戶端。Client 是其別名。
AsyncClient 異步鏡像客戶端。所有異步操作都必須使用它。

安裝

pip install cursor-sdk

需要 Python 3.10 或更高版本。

快速入門

import os

from cursor_sdk import Agent, LocalAgentOptions

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

流事件介紹如何提取助手文本、處理工具調用以及讀取運行狀態。若要一次性完成提示詞的創建、運行和結束,請參閱 Agent.prompt()

雲端快速入門

Python SDK 原生支持 Cursor 雲端代理。你可以列出已連接的倉庫,針對其中一個啓動智能體,等待運行完成,然後評審最終結果。

from cursor_sdk import Agent, CloudAgentOptions, CloudRepository

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

由 SDK 啓動的雲端代理已從默認智能體列表中篩除。要在 Cursor 網頁端或 Cursor 代理窗口中查看它們,請點擊 篩選 > 來源 > SDK

異步用法

異步客戶端提供與同步客戶端相同的接口,推薦用於服務器、機器人和併發智能體編排。AsyncAgentAsyncClientAsyncRunAsyncCursor 均可從 cursor_sdkcursor_sdk.asyncio 導入。

import asyncio
import os

from cursor_sdk import AsyncClient, LocalAgentOptions

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

asyncio.run(main())

沒有全局異步默認客戶端。請顯式實例化 AsyncClient,或將 AsyncClient.launch_bridge(...) 作爲異步上下文管理器使用,以確保每個事件循環都有各自的客戶端。請勿在同一代碼路徑中混用同步和異步客戶端。

直接調用 AsyncAgent 類方法時需要提供 client=。請使用
await client.agents.create(...)
await AsyncAgent.create(..., client=client)

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

創建智能體

Agent.create() 會驗證選項,並立即返回一個句柄。傳入 localcloud 以選擇運行時環境。

from cursor_sdk import Agent, CloudAgentOptions, CloudRepository, LocalAgentOptions

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

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

agent.agent_id 會立即賦值。本地智能體的 ID 爲 agent-<uuid>;雲端代理的 ID 爲 bc-<uuid>agent.model 是帶類型的 ModelSelection,因此可直接使用 agent.model.idagent.model.params

由 SDK 啓動的雲端代理不會顯示在默認智能體列表中。要在 Cursor 網頁端 或 Cursor 代理窗口中
查看它們,請點擊 篩選 > 來源 > SDK

無代碼倉庫雲端代理

雲端代理可在不含代碼倉庫的空 VM 上運行。傳入 cloud 並將 repos 列表設爲空,或完全省略 repos。省略 cloud 則會選擇本地運行時。

from cursor_sdk import Agent, CloudAgentOptions

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

必須爲您的賬戶或團隊啓用無倉庫智能體。倉庫範圍的 API 密鑰無法創建此類智能體;請改用不受限制的服務賬戶密鑰或用戶 API 密鑰。

會話環境變量

對於雲端代理,如果一次運行需要短期憑據或其他僅供該智能體使用的值,請傳遞 env_vars

import os

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

這些值會在靜態存儲時加密,注入雲端代理的 shell,並在刪除智能體時一併刪除。env_vars 不能與調用方提供的 agent_id 一起使用;請省略 agent_id,並從 agent.agent_id 讀取服務器簽發的 ID。變量名不能以 CURSOR_ 開頭。

對於僅應在單次運行期間存在的值,請改爲通過 agent.send() 傳遞。參見單次運行的環境變量

智能體元數據

創建雲端代理時,可爲其添加自定義標識符。元數據可將智能體與系統中的用戶、租戶、工作流或工單關聯,並可通過 client.agents.get()client.agents.list()SDKAgentInfo.metadata 中讀取。這些標籤並非 VM 內的智能體元數據 API;該 API 會從 VM 內部提供當前運行的 ID、所有者、輪次和工作區。

from cursor_sdk import Agent, CloudAgentOptions, CloudRepository

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

創建雲端代理時可添加元數據。最多可附加 50 個鍵值對。鍵不能爲空,且不得超過 255 個字符。值必須爲不超過 4096 字節的字符串。允許使用空字符串值,空映射會被視爲未設置元數據。

如果 API 密鑰所屬的賬戶未啓用元數據功能,使用非空映射創建智能體將返回 403 feature_unavailable

模型參數

使用 ModelSelection.params 傳遞特定模型的選項,例如推理 effort 或 Cursor Router 的 optimize_for。參數 ID 和取值因模型而異。使用 Cursor.models.list() 查看您的賬戶支持哪些參數和預設變體。

from cursor_sdk import Agent, LocalAgentOptions, ModelParameterValue, ModelSelection

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

使用 Cursor.models.list() 查看指定模型的參數 ID 和預設變體。有關 auto-smart 的選擇合約,請參閱 Cursor Router

Cursor Router

Cursor Router 會爲每個 Auto 請求選擇模型。在 SDK 中,Router 是帶有 optimize_for 參數的 auto-smart 模型。它適用於 Teams 和企業版。企業版管理員必須先爲團隊啓用 Router,auto-smart 纔會出現在目錄中。

Cursor SDK 是智能體 SDK,而非獨立的模型推理或聊天補全 API。Router 會爲能夠理解工作區、調用工具、運行命令和編輯文件的 Cursor 智能體運行選擇模型。Cursor 目前尚未提供用於任意模型調用的底層 Router 端點文檔。

選擇成本、平衡或智能

傳入 auto-smart,並顯式設置 optimize_for

產品標籤 SDK 值
成本 cost
平衡 balanced
智能 intelligence

產品文案中請使用 平衡balanced 僅用作 SDK 傳輸值。

import os

from cursor_sdk import Agent, LocalAgentOptions, ModelParameterValue, ModelSelection

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

    print(result.status)

始終傳入 optimize_for。請勿省略該參數,也不要傳入舊版 default 值;支持通過目錄進行發現這一合約。

在模型目錄中查找 Router

Cursor.models.list() 會返回當前 API 密鑰所屬賬戶和團隊可用的模型、參數定義及預設變體。Router 可用時,Cursor Router 會顯示爲 auto-smart。團隊管理員可以禁用 Router,或限制成員可選擇的優化模式。

硬編碼選擇前,請以目錄爲準:

from cursor_sdk import Cursor, ModelParameterValue, ModelSelection

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

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

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

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

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

按運行切換模式

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

from cursor_sdk import ModelParameterValue, ModelSelection, SendOptions

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

單次運行的模型覆蓋會持續生效。後續發送時如未指定覆蓋,將繼續使用新的模型選擇。請參閱單次運行的模型覆蓋

模型 ID:auto-smartautodefault

選擇 含義
搭配 optimize_for 使用的 auto-smart Cursor Router。需要成本、平衡或智能模式時使用。
ModelSelection(id="auto") 當目錄中沒有指定模型時,由服務器選擇的 Auto 回退方案。需要明確指定 Router 模式時,優先使用 auto-smart
省略 optimize_for 或傳入 default 不受支持的 Router 合約。請始終查詢允許的值,並傳入 costbalancedintelligence

計費與路由模型池

  • 所有 Auto 模式均按每個請求所路由模型的標價計費。

  • 每次請求所用的底層模型可能不同。如需進行可復現的比較,請使用固定的模型 ID。

  • 企業版模型允許列表會影響路由模型池。屏蔽必要模型可能會導致 Router 被禁用。

有關當前費率和路由模型池,請參閱 Cursor RouterAuto 模式

Router 缺失的疑難排查

如果找不到 auto-smart 或優化模式被拒絕:

  1. 調用 Cursor.models.list()
  2. 確認結果中包含 auto-smart
  3. 確認 optimize_for 包含所需的值 (costbalancedintelligence) 。
  4. 確認與 API 密鑰關聯的團隊已啓用 Router。
  5. 如果您屬於多個團隊,請確認該密鑰在預期的團隊上下文中使用。
  6. 如果 Router 不可用或無法選擇有效的底層模型,請檢查團隊的模型訪問策略。

原始字典

對於應用代碼,建議優先使用帶類型的 dataclass,因爲 IDE 自動補全和類型檢查的支持更好。SDK 也接受適用於簡短腳本或外部提供的 JSON 的普通字典。蛇形命名法的鍵會被規範化。

from cursor_sdk import Agent

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

智能體

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

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

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

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

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

    def archive(self, options: Mapping[str, Any] | None = None) -> None: ...
    def unarchive(self, options: Mapping[str, Any] | None = None) -> None: ...
    def delete(self, options: Mapping[str, Any] | None = None) -> None: ...
成員 描述
agent_id 穩定的智能體標識符。本地爲 agent-<uuid>,雲端爲 bc-<uuid>
model 當前的類型化模型選擇。使用模型覆蓋成功發送後會更新。
send 使用給定提示詞啓動新的運行。返回 Run 句柄。
reload 在不釋放智能體的情況下重新讀取文件系統配置 (鉤子、項目 MCP、子智能體) 。
close 關閉智能體並釋放資源。
list_messages 列出智能體的消息歷史記錄。
list_artifacts 列出智能體生成的文件 (僅限雲端;本地返回空) 。
download_artifact 按路徑下載文件 (僅限雲端;本地會引發異常) 。
get_usage 獲取智能體的計費 token 用量和美元費用。
archive / unarchive / delete 管理雲端代理的生命週期。

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

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

使用同步 Agent.*Cursor.* 輔助函數時,如果未傳入 client=,SDK 會啓動或複用模塊級默認客戶端。該客戶端會在進程退出時自動關閉,也可以手動顯式關閉:

from cursor_sdk import close_default_client

close_default_client()

Agent.prompt()

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

一次性便捷方法:創建智能體,發送單條提示詞,等待運行完成後釋放資源。

from cursor_sdk import Agent, AgentOptions, LocalAgentOptions

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

異步等效寫法 (假設你已創建 AsyncClient 實例) :

from cursor_sdk import AgentOptions, AsyncAgent, LocalAgentOptions

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

CursorClient

需要顯式控制生命週期、使用自定義 bridge endpoint 或自定義 HTTP 選項,或需在同一進程中使用多個工作區時,請使用 CursorClientClient 仍可用作別名。

from cursor_sdk import CursorClient, LocalAgentOptions

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

資源

顯式客戶端提供資源命名空間:

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

client.create_agent(...)client.list_agents(...) 等頂層方法仍然可用,但對於應用代碼,推薦使用資源命名空間。

自定義 HTTP 客戶端

同步和異步客戶端均支持使用自定義 httpx 客戶端,以配置代理、傳輸方式及其他高級 HTTP 選項:

from cursor_sdk import CursorClient, DefaultHttpxClient

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

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

DefaultHttpxClientDefaultAsyncHttpxClient 會保留 SDK 默認的超時和重定向行爲。普通的 httpx.Clienthttpx.AsyncClient 則使用 httpx 的默認值。

配置超時和重試

兩個客戶端都提供 with_options(...),該方法會返回一個淺拷貝,與原對象共享連接設置,並覆蓋默認值。可使用 timeout 爲所有請求設置超時,或分別設置 unary_timeoutstream_timeoutmax_retries 控制客戶端的重試次數:

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

異步版本:

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

發送消息

每次調用 agent.send() 都會返回一個 Run。每次調用 await async_agent.send() 都會返回一個 AsyncRun。智能體會在多次運行之間保留對話上下文;每次運行對應處理一個提示詞的工作單元。

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

# 同一個智能體,完整的對話上下文會保留下來。
print(agent.send("Fix it and add a regression test").text())

異步版本:

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

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

要在發送文本時附帶圖像:

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

您還可以使用輔助數據類。SDKImage.from_file(path) 會從磁盤讀取文件,並自動處理 base64 編碼:

from cursor_sdk import SDKImage, UserMessage

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

對於已具備編碼字節數據或遠程 URL 的調用方,也可使用 SDKImage.data_image(base64_data, mime_type)SDKImage.url_image(url)

運行

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

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

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

run.stream()run.messages() 的別名。直接迭代 run 會生成 RunStreamEvent envelopes,與 run.events() 相同。

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

流式輸出

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

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

運行流只能消費一次。run.messages()run.events()run.iter_text() 都會從同一個底層流中讀取並推進流。流結束後,運行會保存終端結果 (run.resultrun.statusrun.usagerun.git 等) 。調用 run.wait() 可讀取所有剩餘事件,並返回帶類型信息的 RunResult

不使用流式傳輸時的等待

result = run.wait()

print(result.status)       # "finished" | "error" | "cancelled" | "expired"
print(result.result)       # 最終助手文本(如有)
print(result.model)        # 此次運行所用的已解析 ModelSelection
print(result.duration_ms)
print(result.usage)        # 累計 TokenUsage;不可用時爲 None
print(result.git)          # 雲端 RunGitInfo

異步版本:

result = await run.wait()

Token 用量

運行時提供 Token 用量時,運行會報告該信息。可在即時句柄的 run.usage 中讀取累計總量 (流式傳輸期間或在 wait() 之後) ,也可在 run.wait() 返回的 RunResultresult.usage 中讀取。兩者都包含彙總自所有報告用量輪次的 TokenUsage;如果沒有任何輪次報告用量,兩者均爲 None——例如,未完成任何輪次就被取消的運行、不提供用量信息的運行時,或尚未對賬用量的已分離雲端快照。

@dataclass(frozen=True)
class TokenUsage:
    input_tokens: int
    output_tokens: int
    cache_read_tokens: int
    cache_write_tokens: int
    total_tokens: int
    reasoning_tokens: int | None = None
字段 描述
input_tokens 發送給模型的提示詞 token。
output_tokens 模型生成的 token。
cache_read_tokens 從提示詞緩存中讀取的 token。
cache_write_tokens 寫入提示詞緩存的 token。
total_tokens input_tokens + output_tokens + cache_read_tokens + cache_write_tokens。不包括 reasoning_tokens
reasoning_tokens 推理 token,是 output_tokens 的一部分。模型或運行時時未報告該值時爲 None
result = run.wait()

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

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

如需獲取流式傳輸過程中每輪的數值,請處理 usage 流事件 (SDKUsageMessage)。它會在每個報告用量的輪次結束時觸發一次,並攜帶該輪的 TokenUsagerun.usageresult.usage 在整個運行期間持續累計。流式輪次結束後,句柄會優先使用這些累計總量;否則,若 bridge 提供相關數據,則使用 wait() 返回的用量,或 get_run / list_runs 快照中的用量。

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

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

異步對應寫法:async for message in run.messages()await run.wait()run.usageAsyncRun 中仍爲同步屬性。

TokenUsagecursor_sdk 導出 (高級調用方還可使用 to_token_usage / sum_token_usage) 。在線傳輸的 JSON 使用駝峯命名法 (inputTokens,…) ;Python dataclass 使用 snake_case。

token 數量由 runtime 報告,不代表費用。要獲取智能體運行的已計費用量和美元費用,請調用 agent.get_usage()

讀取文本輸出

iter_text() 在流式輸出過程中生成助手文本。text() 返回最終文本;如果運行尚未結束,則會阻塞並等待 wait()

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

final_text = run.text()

異步版本:

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

final_text = await run.text()

取消一次運行

run.cancel()

異步版本:

await run.cancel()

run.cancel() 會請求取消仍在執行的運行。狀態將變爲 "cancelled",即時流會停止,進行中的工具調用會停止,run.wait() 將以 status: "cancelled" 完成。部分輸出 (截至目前已寫入的助手文本) 會保留在 Run 對象中。

取消已結束的運行 ("finished""error""cancelled""expired") 會引發 UnsupportedRunOperationError。如不確定,可通過 run.status 進行判斷:

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

讀取運行狀態

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

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

turns = run.conversation()

run.conversation() 返回類型化的 list[ConversationTurn]。無需訂閱即時流,即可用它渲染或持久化結構化歷史記錄。run.conversation_json() 返回原始 JSON string。

對於異步運行,請使用 await run.conversation()await run.conversation_json()

單次運行模型覆蓋

傳給 agent.send()model 會覆蓋智能體在該次運行中的模型選擇,並持續生效:後續未指定覆蓋項的發送會繼續使用新模型。若要切換回原模型,請傳遞另一個 model 覆蓋項,或通過 agent.model 讀取當前選擇。

from cursor_sdk import ModelParameterValue, ModelSelection, SendOptions

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

run.modelresult.model 反映本次運行所選用的模型,運行開始後不可更改。

單次運行的環境變量

雲端代理也可接收僅用於單次運行的環境變量。在 SendOptions 中傳入 cloud.env_vars,這些值僅會注入該次運行的智能體 shell 中——運行結束後,它們會從 VM 中移除,後續運行無法訪問。這適合用於在不同輪次間輪換的憑據,例如在請求智能體使用前剛剛簽發的短期部署令牌。

from cursor_sdk import CloudSendOptions, SendOptions

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

如果單次運行範圍的變量與 CloudAgentOptionsenv_vars 中的智能體範圍變量同名,則該次運行以單次運行的值爲準;下次運行時則恢復使用智能體範圍的值。

單次運行變量在首次發送時也可使用。SDK 會在創建智能體時一併傳入這些變量,並將其限定於初始運行,因此不會持久化到智能體中。與智能體範圍變量一樣,它們在靜態存儲時會加密,且名稱不能以 CURSOR_ 開頭。

單次運行的環境變量僅適用於雲端代理,且不適用於針對公共倉庫運行的智能體。對於本地智能體,智能體進程會繼承你的環境,因此請在調用 send() 前爲該進程設置變量。

對話模式

傳入 mode="plan"mode="agent",可控制運行是先探索並制定方案,還是直接實施更改。有關 Plan 模式在產品中的作用,請參閱Plan 模式

在傳遞給 Agent.create()AgentOptions 中設置 mode,以確定首次運行的模式。後續調用 agent.send() 時,省略 mode 可保持對話的當前模式;傳入 mode 則僅切換該次運行的模式。

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

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

流式傳輸原始增量

SendOptions 中傳入 on_deltaon_step 回調,以獲取更底層的更新。同步回調會直接內聯調用。異步回調可以是同步函數或異步函數;在處理下一個事件之前,會等待可等待的返回值完成。

from cursor_sdk import SendOptions

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

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

具體的 update 和 step 子類定義在 cursor_sdk.events 中:

from cursor_sdk.events import TextDeltaUpdate, ToolCallStartedUpdate

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

爲保持向後兼容,仍可從 cursor_sdk 導入它們,但新代碼應從 cursor_sdk.events 導入。

SendOptions

屬性 類型 描述
model str \| ModelSelection \| Mapping[str, Any] 單次發送的模型覆蓋設置。若省略,則使用 agent.model。發送成功後持續生效。
mode "agent" \| "plan" 單次發送的對話模式覆蓋設置。若在後續消息中省略,則保留對話當前的模式。
mcp_servers Mapping[str, McpServerConfig] 內聯 MCP 服務器定義。完全替換此次運行創建時的服務器。
cloud.env_vars Mapping[str, str] 僅適用於雲端代理。爲此次運行注入單次運行的環境變量,運行結束後移除。僅在此次運行中按名稱覆蓋智能體範圍的 env_vars
local.force bool 僅適用於本地智能體。默認值爲 None (未設置) 。設爲 True 可在開始處理此消息前終止卡住的活動運行。雲端會在服務端返回 409 agent_busy,因此無需提供等效設置。
idempotency_key str 可選的、由客戶端爲此次發送生成的冪等鍵。
on_step Callable[[ConversationStep], Any] 每個對話步驟 (文本、思考或工具批次) 完成後調用的回調。
on_delta Callable[[InteractionUpdate], Any] 每個原始 InteractionUpdate 的回調。

接下來的三個分區詳細介紹 SDKMessageInteractionUpdateConversationTurn。首次閱讀時可快速瀏覽或跳過;恢復智能體將繼續後續內容。

流事件

run.messages() 會生成帶類型的 SDK 消息數據類。可根據 message.type 區分消息類型。運行時提供時,所有消息都會包含 agent_idrun_id

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

大多數工具調用會發出兩次 SDKToolUseMessage:首次發出時,status="running"args 已填充;完成後會再次發出,此時 status="completed" (或 "error") 且 result 已填充。truncated 標誌指示 SDK 是否因負載過大而截斷了 argsresult

每個報告 token 用量的輪次結束時,都會發出一次 SDKUsageMessage,其中包含該輪的 TokenUsage。跨輪次的累計用量保存在 run.usageresult.usage 中。請參閱 Token 用量

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

流結束後,結果數據 (最終文本、模型、時長、累計 token 用量、Git 元數據) 會保存在 Run 對象中。使用 run.wait() 讀取這些數據;如果運行時報告了 result.usage,也可通過它讀取。

工具調用 schema 不穩定。 tool_call 事件中的 argsresult 負載反映各工具的內部結構,可能會隨工具演進而變化。工具名稱也可能被重命名或替換。請將 argsresult 視爲無類型數據,並進行防禦性解析。事件信封 (typecall_idnamestatus) 是穩定的。

run.events() 會生成更底層的 RunStreamEvent 信封。當需要偏移量、終端結果信封或原始交互更新時,請使用它:

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

交互更新

InteractionUpdate 是傳遞給 agent.send()on_delta 回調的原始增量類型。與 SDKMessage 事件相比,更新粒度更細:文本按 token 逐個流式傳輸,工具調用則會隨着 args 的累積報告部分狀態。

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

模型在提交工具調用前流式傳入參數時,會發出 PartialToolCallUpdate。適用於 SDKToolUseMessage.args 的穩定性免責聲明同樣適用於此處。

對話類型

通過 run.conversation() 返回的運行中每輪對話的結構化視圖。每個條目都是一個包裝器,包含輪次 type 判別字段以及 turn 中的類型化負載。

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

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

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

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

根據 turn.type 區分類型,並通過 turn.turn 讀取負載:

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

on_step 回調中的 run.conversation() 會針對每個 ConversationStep 觸發,而非每個輪次。工具調用對話步驟攜帶 Mapping[str, Any] 負載。工具調用負載的具體內容應視爲無類型數據;請參閱流事件下的穩定性說明

恢復智能體

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

使用 Agent.resume()client.agents.resume(),通過 ID 重新連接到現有智能體。常見用法包括:重新連接到之前啓動的長時間運行雲端代理,或在本地進程重啓後繼續對話。系統會根據 ID 前綴自動檢測運行環境 (bc- 表示雲端,其他前綴表示本地) 。

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

異步版本:

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

除非再次傳入 model,否則恢復時 agent.model 將爲 None。內聯 MCP 服務器不會在恢復後保留;它們通常包含機密信息,僅存於內存中。恢復時請再次傳入,或者爲需要保留的服務器使用基於文件的 MCP 配置 (.cursor/mcp.jsonlocal.setting_sources) 。

本地持久化

本地智能體通過 bridge 持久化保存對話狀態和運行元數據,因此後續交互和 Agent.resume() 在進程重啓後仍可繼續使用。默認情況下,bridge 會將這些數據存儲在磁盤上各工作區對應的狀態根目錄下。雲端代理在服務器端持久化保存數據,因此無論從何處恢復雲端代理,都會返回同一段對話。

本地持久化以工作區爲單位。當 bridge 作爲長期運行的 sidecar 或子進程運行時,請爲其指定與智能體相同的工作區,以便本地 list、get 和 resume 調用能找到正確的智能體。在客戶端中設置一次工作區,並將 cwd 傳遞給本地 list 和 get 調用:

from cursor_sdk import CursorClient

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

查看智能體和運行

使用 CursorClient 調用列表、獲取和分頁 API。

from cursor_sdk import CursorClient

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

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

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

異步對應形式:

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

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

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

在智能體句柄上使用 agent.list_messages() 讀取消息歷史記錄。只有 ID 時,可使用 Agent.messages.list(agent_id),這是帶類型屬性的同一調用的便捷形式。

使用 Agent.get_run(run_id)client.agents.get_run(run_id) 獲取運行,
無需智能體句柄。使用
Agent.cancel_run(run_id, agent_id=...)
client.agents.cancel_run(run_id, agent_id=...) 將其取消。異步客戶端方法可
await,且使用相同的參數。

AgentMessage 與流式 SDKMessage 不同:

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

列表端點返回 ListResult[T]。可直接使用 .items.next_cursor,通過 for item in page 遍歷當前頁,或通過 .auto_paging_iter() 遍歷所有頁。異步列表端點返回 AsyncListResult[T]async for item in page 遍歷當前頁,而 async for item in page.auto_paging_iter() 遍歷結果集中的所有頁。

SDKAgentInfo

Agent.list()Agent.get()client.agents.list()client.agents.get() 返回的元數據結構。

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

雲端代理生命週期

雲端代理會一直保留在團隊工作區中,直到被歸檔或刪除。client.agents.list(runtime="cloud") 默認不顯示已歸檔的智能體;傳入 include_archived=True 可查看它們。按 pr_url 篩選,可找到創建特定 PR 的智能體。

# 通過 ID 操作,無需智能體句柄:
Agent.archive(agent_id)
Agent.unarchive(agent_id)
Agent.delete(agent_id)

# 通過顯式指定的客戶端:
client.agents.archive(agent_id)
client.agents.unarchive(agent_id)
client.agents.delete(agent_id)

# 通過現有智能體句柄:
agent.archive()
agent.unarchive()
agent.delete()

archive 會軟刪除智能體,但會話記錄仍可讀取。unarchive 會將其恢復。delete 會永久刪除;後續讀取會返回 NotFoundError

異步生命週期方法名稱相同,且可使用 await 調用。

agent.get_usage()

獲取智能體各次運行的已計費 token 用量和美元費用。雲端代理會返回按運行劃分的明細;本地智能體會返回按輪次劃分的明細。傳入 run_id 可將結果限定爲單個條目:雲端代理使用 run-<uuid> 格式的運行 ID;本地智能體使用之前 get_usage().runs[].run_id 中的 ID。

usage = agent.get_usage()

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

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

@dataclass(frozen=True)
class UsageCost:
    raw_cost_cents: float  # 未享受折扣的模型 token 成本;按請求計費的用量爲 0
    charged_cents: float   # 實際收取的金額,已計入折扣和 Cursor Token 費率

費用已包含折扣,運行結束後可能需要片刻才能結算;在此之前,costNone。對於方案內包含、BYOK 和額度授予的用量,charged_cents0.0

這與Token 用量不同:run.usage 是單次運行的即時 token 計數,而 get_usage() 是該智能體所有運行的計費記錄。對於異步智能體,await agent.get_usage() 的結果相同。AgentUsageRunUsageUsageCost 均從 cursor_sdk 導出。

Cursor 命名空間

用於賬戶級和目錄讀取。同步方法可接受 api_key,否則會使用 CURSOR_API_KEY

from cursor_sdk import Cursor

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

使用顯式客戶端的等效版本:

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

異步對應形式:

from cursor_sdk import AsyncCursor

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

Cursor.me() 會返回一個 SDKUser,其中包含 api_key_namecreated_at 以及
可選的 user_iduser_emailuser_first_nameuser_last_name
字段。

在調用 Agent.create()agent.send() 前,使用 Cursor.models.list() 獲取有效的模型 ID 及各模型參數。參數因模型而異。常見示例包括 reasoning effort,以及 auto-smart 的 Cursor Router optimize_for 參數。

可用目錄因賬戶和團隊而異。只有 API 密鑰所屬團隊可使用 Router 時,Cursor Router 纔會以 auto-smart 的形式出現。請參閱 Cursor Router

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

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

每個 SDKModel 的預設 variants 均已包含有效的 params,因此可以直接複製到 ModelSelection 中。

如果未指定目標模型,但希望使用 Cost、Balance 或 Intelligence,請優先顯式選擇 Router (auto-smart + optimize_for) 。只有在希望由服務器自動選擇 Auto、且不選擇 Router 模式時,纔回退到 ModelSelection(id="auto")。使用 Cursor Router 時,始終顯式傳入 optimize_for

Cursor.repositories.list() 會返回調用方賬戶或團隊中可供雲端代理使用的 SCM 倉庫 (GitHub、GitLab、Bitbucket、Azure DevOps,具體取決於已連接的服務) 。每個條目都提供一個 url。使用這些 URL 填充 CloudAgentOptions.repos

MCP 服務器

智能體可根據運行時,從內聯定義、項目/用戶設置、插件和儀表盤託管的配置中獲取 MCP 服務器。

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

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

爲便於快速編寫腳本,也支持使用扁平字典 ({"type": "http", "url": ...}{"type": "stdio", "command": ...}) 。

會加載哪些內容

本地智能體最多可從五個來源加載服務器;如果名稱衝突,優先使用最先匹配的來源:

  1. agent.send() 中的 mcp_servers。會完全替換該次運行在創建時配置的服務器 (不會合並) 。
  2. Agent.create() 中的 mcp_servers。未提供單次發送的覆蓋配置時使用。
  3. 插件服務器,前提是 local.setting_sources 包含 "plugins"
  4. 項目服務器,來自 .cursor/mcp.json,前提是 local.setting_sources 包含 "project"
  5. 用戶服務器,來自 ~/.cursor/mcp.json,前提是 local.setting_sources 包含 "user"

未設置 local.setting_sources 時,只會加載內聯服務器。如果本地 MCP 服務器需要通過 OAuth 登錄,SDK 可以複用 Cursor app 中保存的登錄信息,但無法打開瀏覽器讓你登錄。

雲端代理從以下來源加載服務器:

  1. agent.send() 中的 mcp_servers。會完全替換該次運行在創建時配置的服務器 (不會合並) 。
  2. Agent.create() 中的 mcp_servers。未提供單次發送的覆蓋配置時使用。
  3. 來自 cursor.com/agents 的個人和團隊 MCP 服務器。

如果內聯服務器不包含 authheaders,且你之前已在 cursor.com/agents 上授權該服務器 URL,那麼使用個人 API token 認證的運行會自動複用這些 OAuth token。服務賬戶 API 密鑰無法回退到用戶認證,因爲它們不與任何用戶關聯。

local.setting_sources 不適用於雲端代理。

雲端

雲端代理也支持以內聯方式使用已認證的 MCP 配置。雲端 MCP 支持 HTTP 和 stdio 傳輸方式。靜態 API 密鑰或 Bearer token 請使用 HTTP headers。對於受 OAuth 保護的服務器,請使用 HTTP auth。如果服務器在雲端 VM 中運行,並從環境變量讀取憑據,請使用 stdio env

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

agent = Agent.create(
    AgentOptions(
        model="composer-2.5",
        cloud=CloudAgentOptions(
            repos=[CloudRepository(url="https://github.com/your-org/your-repo")],
        ),
        mcp_servers={
            "linear": HttpMcpServerConfig(
                url="https://mcp.linear.app/mcp",
                headers={"Authorization": "Bearer linear_pat_xxx"},
            ),
            "github": StdioMcpServerConfig(
                command="npx",
                args=["-y", "@modelcontextprotocol/server-github"],
                env={"GITHUB_TOKEN": "ghp_xxx"},
            ),
        },
    )
)
  • HTTP headersauth 由 Cursor’s 後端處理。敏感字段會被脫敏,不會傳入 VM。
  • 由於服務器在 VM 中運行,Stdio env 值會傳入 VM。請將其視爲其他運行時機密信息。
  • 在 cursor.com/agents 上爲 MCP 服務器配置的 OAuth 即使針對團隊級服務器,仍按用戶分別設置。

完整配置格式請參閱 MCP,雲端特有行爲請參閱 雲端代理能力

子智能體

定義可由主智能體通過 Agent 工具創建的具名子智能體。將其以內聯方式傳入:

from cursor_sdk import Agent, AgentDefinition, AgentOptions, LocalAgentOptions

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

已提交到倉庫 .cursor/agents/*.md 中的子智能體 (帶有 namedescription 和可選 model frontmatter) 也會被讀取。同名的內聯定義會覆蓋基於文件的定義。

嵌套子智能體

子智能體可在嵌套層數限制內創建自己的子智能體。子智能體使用 Agent 工具時,會調用與其父級相同的子智能體執行器,因此父級可以將任務委託給能夠繼續委託的子智能體。每一層都能看到同一組具名子智能體。頂層智能體及其直屬子智能體可以啓動子智能體,但由子智能體啓動的子智能體不能再啓動更多子智能體。

限制工具集

tools 用於將提供給模型的內置工具設爲允許列表;disallowed_tools 用於移除指定工具並保留其餘工具,包括在您的 SDK 版本發佈後添加到平臺的工具。目前兩者僅適用於本地智能體,且都不會保存在智能體中:恢復時請再次傳入,以繼續保留限制。

from cursor_sdk import Agent, AgentOptions, LocalAgentOptions

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

# 除 shell 外的所有工具。
no_shell = Agent.create(
    AgentOptions(
        model="composer-2.5",
        disallowed_tools=["shell"],
        local=LocalAgentOptions(cwd="."),
    )
)
  • 省略 tools 時,將爲所選模型提供標準工具集;tools=[] 則不提供內置工具,因此模型只能返回文本。
  • 兩個字段均接受公開名稱 ("read""edit""task""webSearch"、……) 以及能力組 "shell""mcp"。未知名稱會在創建時引發 BadRequestError
  • 禁用優先:工具必須包含在 tools 中 (如已設置) ,且不在 disallowed_tools 中,纔會被提供。
  • 禁用 "mcp" 也會移除自定義工具。禁用 "task" 會阻止子智能體;否則子智能體將保留各自精選的工具集。

自定義工具

自定義工具可讓你將 Python 函數提供給本地智能體使用,無需單獨搭建 MCP 服務器。通過 LocalAgentOptions.custom_tools 傳入。

from cursor_sdk import Agent, CustomTool, CustomToolContext, LocalAgentOptions

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

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

execute 接收解析後的參數,以及可用時帶有 tool_call_idCustomToolContext。它可以返回 string、JSON 兼容的值,或包含 content 列表的 mapping。自定義工具僅支持本地智能體。

鉤子

鉤子僅支持基於文件的配置,不支持編程式鉤子回調。鉤子是項目策略的邊界,而非單次運行的可調選項。

  • **本地:**將 .cursor/hooks.json 添加到 local.cwd 指定的倉庫中,或添加 ~/.cursor/hooks.json 以配置用戶級鉤子。
  • **雲端:**將 .cursor/hooks.json 及其腳本提交到 cloud.repos 指定的倉庫。由 SDK 創建的雲端代理會自動加載項目鉤子。在企業版方案中,它們還會運行團隊鉤子和由企業統一管理的鉤子。

有關配置格式,請參閱 鉤子;有關雲端行爲,請參閱 雲端代理鉤子支持

產物

列出並下載智能體工作區中的文件。

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

artifacts = agent.list_artifacts()

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

# 將單個產物下載到本地磁盤。
content = agent.download_artifact(artifacts[0].path)
Path("review.md").write_bytes(content)

異步智能體支持 await agent.list_artifacts()await agent.download_artifact(path)

產物支持取決於運行時。Local SDK 智能體調用 list_artifacts() 時會返回空列表,調用 download_artifact() 時會引發異常。

資源管理

使用完畢後,請始終關閉智能體。最簡潔的同步用法是使用上下文管理器:

from cursor_sdk import Agent, LocalAgentOptions

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

如需手動釋放資源:

agent.close()

異步智能體和客戶端支持異步上下文管理器,並可使用 await 進行清理:

from cursor_sdk import AsyncClient, LocalAgentOptions

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

要顯式釋放資源:

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

模塊級同步默認客戶端會在進程退出時自動關閉。長時間運行的進程可顯式將其關閉並重置:

from cursor_sdk import close_default_client

close_default_client()

配置參考

Python SDK 支持輔助數據類和原始字典。數據類使用 Python snake_case 字段,推薦在應用代碼中使用。

AgentOptions

屬性 類型 默認值 描述
model str \| ModelSelection \| Mapping[str, Any] 本地必填;雲端默認使用服務器解析的默認值 要使用的模型。請參閱 ModelSelection
api_key str CURSOR_API_KEY 環境變量 用戶 API 密鑰或服務賬戶密鑰。暫不支持團隊管理員密鑰。
name str 自動生成 client.agents.list() / client.agents.get() 中顯示的易讀智能體名稱。
local LocalAgentOptions \| Mapping[str, Any] None 本地智能體配置。傳入以創建本地智能體。
cloud CloudAgentOptions \| Mapping[str, Any] None 雲端代理配置。傳入以創建雲端代理。
mcp_servers Mapping[str, McpServerConfig] None 內聯 MCP 服務器定義。
agents Mapping[str, AgentDefinition \| Mapping[str, Any]] None 子智能體定義。
tools Sequence[str] 默認工具集 僅向模型提供列出的內置工具。[] 表示不提供內置工具;模型只能返回文本。僅限本地智能體。
disallowed_tools Sequence[str] None 移除列出的內置工具;其他工具仍可用。與 tools 同時使用時,以拒絕列表爲準。僅限本地智能體。
agent_id str 自動生成 持久化智能體 ID。傳入後可在多次調用間保持 ID 穩定。
idempotency_key str 雲端自動生成 可選的客戶端生成冪等鍵。僅限雲端。
mode "agent" \| "plan" None 智能體首次運行時的初始對話模式。省略時,服務器將以 Agent 模式啓動。請參閱對話模式

LocalAgentOptions

屬性 類型 默認值 描述
cwd str \| os.PathLike None 主工作目錄。不接受多項列表;多根目錄請使用 dirs
dirs Sequence[str \| os.PathLike] None 多根目錄配置的額外工作區文件夾。與 cwd 合併後,將從每個路徑加載規則、技能和工作區上下文。
setting_sources Sequence[SettingSource] None 可用的設置層:”project”、”user”、”team”、”mdm”、”plugins” 或 “all”。
sandbox_options SandboxOptions \| Mapping[str, Any] None 本地沙箱選項。
store LocalAgentStoreConfig \| Mapping[str, Any] None 傳遞給 bridge 的本地存儲配置。
auto_review bool None 如果連接的後端支持,則通過 Auto-review 模式處理本地工具調用。
custom_tools Mapping[str, CustomTool \| Mapping[str, Any]] None 向本地智能體提供的自定義工具

CloudAgentOptions

屬性 類型 默認值 描述
env CloudEnvironment \| Mapping[str, Any] None 執行環境。省略時,服務器使用由 Cursor 託管的雲端 VM。poolmachine 指向您運行的自託管 workers。
repos Sequence[CloudRepository \| Mapping[str, Any]] None 要克隆到 VM 的倉庫。省略或傳入 [],可創建工作區爲空的無倉庫智能體。在倉庫中傳入 pr_url,可將智能體關聯到現有 PR。
work_on_current_branch bool None 將提交推送到現有分支,而非新分支。服務器會將省略的值視爲 False
auto_create_pr bool None 運行完成時創建 PR。服務器會將省略的值視爲 False
open_as_cursor_github_app bool 服務賬戶密鑰爲 True,用戶密鑰爲 False 以 Cursor GitHub App 身份而非 API 密鑰所有者的身份創建 PR。解析後的值會在創建、獲取和列出操作中返回。
skip_reviewer_request bool None 不將調用用戶請求爲 PR 審閱人。服務器會將省略的值視爲 False
env_vars Mapping[str, str] None 雲端代理的會話級環境變量。
metadata Mapping[str, str] None 由調用方擁有並持久保存於雲端代理上的 string 標籤。請參閱智能體元數據

AgentDefinition

屬性 類型 默認值 描述
description str 必填 此子智能體的適用場景。會顯示給父智能體,以便其知道何時生成子智能體。
prompt str 必填 子智能體的系統提示詞。
model str \| ModelSelection \| Mapping[str, Any] \| "inherit" None 模型覆蓋。None"inherit" 均使用父智能體的模型選擇。
mcp_servers Sequence[str \| AgentDefinitionMcpServer \| Mapping[str, Any]] None 此子智能體可用的 MCP 服務器。名稱引用父智能體 mcp_servers 中的服務器。

CustomTool

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

class CustomToolContext:
    tool_call_id: str | None = None

ModelSelection

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

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

id 是模型標識符 (例如 "composer-2.5""auto-smart") 。params 包含模型專屬參數,例如推理 effort 或 Router 的 optimize_for。使用 Cursor.models.list() 可查看您賬戶可用的有效 ID、參數定義和預設變體。有關 Router 的選擇合約,請參閱 Cursor Router

McpServerConfig

from cursor_sdk.types import McpServerConfig

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

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

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

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

對於在雲端運行的 HTTP 服務器,headersauth 由 Cursor 後端處理。敏感字段會在 VM 讀取前被脫敏。對於在雲端運行的 stdio 服務器,env 值會傳入 VM (請將其視爲運行時機密信息) 。

用戶消息

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

agent.send() 的消息參數的結構化形式。可用於隨文本一同發送圖像。

SDKImage

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

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

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

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

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

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

傳入遠程 url,或傳入包含 mime_type 的 base64 datafrom_data() 接受字節數據或 base64 字符串。from_file() 從磁盤讀取文件並將其編碼爲 base64。

SettingSource

可通過 cursor_sdk.types 獲取 SettingSource

from cursor_sdk.types import SettingSource

控制本地智能體加載哪些存儲在磁盤上的設置層。雲端代理始終加載 projectteamplugins,並忽略此字段。

來源
"project" 工作區中的 .cursor/
"user" ~/.cursor/
"team" 從儀表盤同步的團隊設置
"mdm" 由 MDM 管理的企業版設置
"plugins" 插件提供的設置
"all" 以上所有項的簡寫

ListResult

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

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

client.agents.list()client.agents.list_runs()Agent.list() 返回。當沒有更多頁面時,next_cursor 爲空。異步列表端點返回 AsyncListResult[T],並提供可 await 的對應方法。

錯誤

所有 SDK 錯誤都繼承自 CursorAgentErrorCursorSDKError 是爲兼容較早調用方保留的根異常別名。使用 is_retryableretry_after 實現重試邏輯。

class CursorAgentError(Exception):
    message: str
    code: str | None
    status: int | None
    status_code: int | None
    details: list[Mapping[str, Any]]
    is_retryable: bool
    cause: BaseException | None
    proto_error_code: str | None
    request_id: str | None
    headers: Mapping[str, str]
    retry_after: str | None
錯誤 觸發條件
AuthenticationError API 密鑰無效或未登錄。
PermissionDeniedError 已通過身份驗證的調用方無權執行所請求的操作。
RateLimitError 請求過多或超出用量限額。
ConfigurationError 模型無效、缺少必需配置,或請求參數有誤。
AgentBusyError 智能體已有處於 CREATINGRUNNING 狀態的運行時發送後續請求 (HTTP 409,代碼 agent_busy) 。
BadRequestError 請求格式不正確。
IntegrationNotConnectedError 爲未連接 SCM 提供商的倉庫創建雲端代理。
NetworkError 服務不可用或網絡故障。
APITimeoutError 請求超時。
InternalServerError Cursor 服務返回了服務器錯誤。
NotFoundError 未找到所請求的資源。
AgentNotFoundError 智能體不存在,或在當前工作目錄下不可見。
UnsupportedRunOperationError 當前運行狀態不支持該運行操作。

使用退避策略重試

is_retryableretry_after 用於控制調用方的重試邏輯。retry_after 是由服務器設置時提供的 HTTP 風格 string (以秒數或 HTTP 日期表示) 。

import time

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

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

服務器返回 request_id 時,每個 CursorAgentError 都會包含該 ID。報錯時請記錄它,以便支持團隊排查故障。

IntegrationNotConnectedError

class IntegrationNotConnectedError(ConfigurationError):
    provider: str   # 例如:"github"、"gitlab"、"azuredevops"
    help_url: str   # 用於重新連接的儀表盤鏈接

使用 help_url 將用戶引導至正確的重新連接流程。無需發佈新版 SDK 即可添加新的提供商。

AgentBusyError

雲端代理同一時間只允許一個活躍運行。當同一智能體的另一個運行仍處於 CREATINGRUNNING 狀態時,調用 agent.send() (或以其他方式創建運行) 會引發 AgentBusyError

is_retryableFalse。立即重試仍會失敗,直到活躍運行進入終止狀態或被取消。其他 409 響應 (如 agent_archived) 則會引發 ConfigurationError

等待活躍運行完成,使用 run.cancel() 取消它,或在再次發送前輪詢 Agent.list_runs()

from cursor_sdk import Agent, AgentBusyError

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

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

本地智能體不會拋出 AgentBusyError。在 send() 中傳入 local={"force": True},可在啓動新的本地運行前終止卡住的運行。

UnsupportedRunOperationError

class UnsupportedRunOperationError(ConfigurationError):
    operation: str

噹噹前運行不允許執行某個 Run 操作時引發。最常見的情況是對已處於終止狀態的運行調用 run.cancel()

run.supports(operation)run.unsupported_reason(operation) 用於報告 SDK 層面是否支持某個操作名稱 ("stream""wait""cancel""conversation") ,不會檢查運行的狀態。請讀取 run.status,以避免調用對狀態敏感的操作。

疑難排查

設置 CURSOR_SDK_LOG=debug (或 info) ,爲 SDK 自身的日誌記錄器添加 stderr 處理程序。SDK 僅配置自己的 cursor_sdk 日誌記錄器,因此不會影響宿主應用的日誌配置。

CURSOR_SDK_LOG=debug python my_script.py

隨包附帶的 bridge 可執行文件會以 cursor-sdk-bridge 的名稱安裝到 PATH 中。直接運行它,確認 wheel 中包含的構建版本:

cursor-sdk-bridge --help

已知限制

  • 工具調用的負載 schema 有意不採用強類型定義。
  • 內聯 MCP 服務器不會在 Agent.resume() 後保留。如有需要,請在恢復時再次傳入。
  • 自定義工具 (local.custom_tools) 和工具集限制 (toolsdisallowed_tools) 僅適用於本地智能體。這些限制不會保留在智能體中;請在恢復時再次傳入。
  • 本地智能體尚不支持 Artifact 下載。
  • local.setting_sources (以及它所控制的基於文件的 MCP 和子智能體路徑) 不適用於雲端代理。雲端始終加載 projectteamplugins
  • 鉤子僅支持基於文件的方式 (.cursor/hooks.json) ,不支持編程式回調。
羽毛球分组比赛记分
小程序二维码

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

小夜