Skip to main content

Command Palette

Search for a command to run...

SDK

Cursor Python SDK

Paket cursor-sdk memungkinkan Anda memanggil agent Cursor dari kode Python sendiri. Agent yang sama yang berjalan di Cursor IDE, CLI, dan aplikasi web dapat digunakan melalui skrip Python dengan klien sinkron dan asinkron, dataclass berjenis, serta iterasi biasa untuk stream dan page. Jalankan skill /sdk di Cursor untuk memulai.

Untuk REST API, lihat Cloud Agents API. Untuk bahasa lain, lihat SDK Bridge.

Gambaran Umum

SDK menyediakan satu antarmuka untuk runtime lokal dan cloud. Anda menulis kode yang sama, terlepas dari tempat agent berjalan.

RuntimeFungsiKapan digunakan
LokalMenjalankan agent pada file lokal di disk.Skrip pengembangan dan pemeriksaan CI pada working tree.
Cloud (dihosting oleh Cursor)Berjalan di VM terisolasi dengan repo Anda yang telah di-clone. Cursor menjalankan VM tersebut.Saat pemanggil tidak memiliki repo, Anda ingin menjalankan banyak agent secara paralel, atau menjalankan harus tetap berjalan setelah pemanggil terputus.

Atur runtime dengan meneruskan local atau cloud ke Agent.create().

Autentikasi

Atur CURSOR_API_KEY atau berikan api_key sebelum membuat agent.

SDK mendukung kunci API pengguna dan kunci API akun layanan untuk menjalankan agent secara lokal maupun di cloud. Kunci API Admin Tim belum didukung.

export CURSOR_API_KEY="your-key"

Penggunaan dan penagihan

Menjalankan SDK mengikuti aturan penetapan harga, kuota permintaan, dan Mode Privasi yang sama seperti menjalankan dari IDE dan agen cloud. Pengeluaran tim Anda ditampilkan di Dashboard penggunaan pada tag SDK.

Untuk membaca jumlah token per menjalankan dalam kode, lihat Penggunaan token. Untuk mengambil penggunaan yang ditagihkan dan biaya dalam dolar untuk menjalankan agent, lihat agent.get_usage().

Konsep inti

KonsepDeskripsi
AgentHandle persisten yang menyimpan status percakapan, konfigurasi workspace, pemilihan model, dan pengaturan. Tetap tersedia di beberapa prompt.
RunSatu kali pengiriman prompt. Memiliki stream, status, hasil, percakapan, dan pembatalannya sendiri.
SDKMessagePesan stream bertipe yang dihasilkan selama menjalankan. Strukturnya sama di runtime lokal dan cloud.
CursorClientKlien eksplisit untuk kontrol lifecycle, opsi HTTP kustom, atau beberapa workspace dalam satu proses. Client adalah alias.
AsyncClientKlien yang mencerminkan versi async. Diperlukan untuk semua operasi async.

Instalasi

pip install cursor-sdk

Memerlukan Python 3.10 atau yang lebih baru.

Mulai cepat

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

Peristiwa stream menjelaskan cara mengekstrak teks asisten, menangani pemanggilan tool, dan membaca status menjalankan. Untuk prompt sekali jalan (buat, jalankan, selesai), lihat Agent.prompt().

Mulai cepat agen cloud

SDK Python mendukung agen cloud Cursor secara bawaan. Anda dapat mencantumkan repo yang terhubung, memulai agent pada salah satunya, menunggu menjalankan selesai, lalu meninjau hasil akhirnya.

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

Agen cloud yang dimulai melalui SDK tidak ditampilkan dalam daftar agent default. Untuk melihatnya di Cursor Web atau Jendela Agents Cursor, klik Filter > Sumber > SDK.

Penggunaan async

Klien async mencerminkan antarmuka sync dan disarankan untuk server, bot, serta orkestrasi agent secara bersamaan. AsyncAgent, AsyncClient, AsyncRun, dan AsyncCursor diekspor dari cursor_sdk dan cursor_sdk.asyncio.

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

Tidak ada klien default async global. Buat instance AsyncClient secara eksplisit atau gunakan AsyncClient.launch_bridge(...) sebagai context manager async agar setiap event loop memiliki kliennya sendiri. Jangan gunakan klien sync dan async dalam path kode yang sama.

Metode kelas AsyncAgent yang dipanggil langsung memerlukan client=. Gunakan await client.agents.create(...) atau await AsyncAgent.create(..., client=client).

SyncAsync
CursorClient / ClientAsyncClient / AsyncCursorClient
AgentAsyncAgent
RunAsyncRun
CursorAsyncCursor
ListResultAsyncListResult
DefaultHttpxClientDefaultAsyncHttpxClient

Membuat agent

Agent.create() memvalidasi opsi dan langsung mengembalikan handle. Berikan local atau cloud untuk memilih runtime.

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

agent.agent_id langsung terisi. Agent lokal memiliki ID agent-<uuid>; agen cloud memiliki ID bc-<uuid>. agent.model adalah ModelSelection yang bertipe, sehingga agent.model.id dan agent.model.params dapat langsung digunakan.

Variabel lingkungan sesi

Untuk agen cloud, teruskan env_vars jika suatu menjalankan memerlukan kredensial jangka pendek atau nilai lain yang hanya berlaku untuk agen tersebut.

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

Nilai ini dienkripsi saat disimpan, disuntikkan ke shell agen cloud, dan dihapus bersama agen. env_vars tidak dapat digunakan dengan agent_id yang diberikan pemanggil; jangan sertakan agent_id dan baca ID yang diterbitkan server dari agent.agent_id. Nama variabel tidak boleh diawali dengan CURSOR_.

Untuk nilai yang hanya perlu ada selama satu kali menjalankan, teruskan nilai tersebut ke agent.send(). Lihat per-menjalankan.

Metadata agen

Lampirkan pengenal Anda sendiri ke agen cloud saat membuatnya. Metadata dapat menghubungkan agen dengan pengguna, tenant, alur kerja, atau tiket dalam sistem Anda, dan dapat dibaca kembali melalui SDKAgentInfo.metadata dari client.agents.get() dan client.agents.list().

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

Metadata tersedia untuk agen cloud saat dibuat. Anda dapat menambahkan hingga 50 pasangan key-nilai. Key tidak boleh kosong dan panjangnya tidak boleh melebihi 255 karakter. Nilai harus berupa string berukuran maksimal 4096 byte. Nilai string kosong diizinkan, dan mapping kosong dianggap tidak memiliki metadata.

Parameter model

Gunakan ModelSelection.params untuk meneruskan opsi khusus model, seperti reasoning effort atau optimize_for milik Cursor Router. ID dan nilai parameter berbeda-beda menurut model. Gunakan Cursor.models.list() untuk mengetahui parameter yang didukung dan varian preset yang tersedia untuk akun Anda.

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

Gunakan Cursor.models.list() untuk mengetahui ID parameter dan varian prasetel model tertentu. Lihat Cursor Router untuk kontrak pemilihan auto-smart.

Cursor Router

Cursor Router memilih model untuk setiap permintaan Auto. Dalam SDK, Router adalah model auto-smart dengan parameter optimize_for. Fitur ini tersedia di Teams dan Enterprise. Admin Enterprise harus mengaktifkan Router untuk tim sebelum auto-smart muncul di katalog.

Cursor SDK adalah SDK agent, bukan API inferensi model atau chat completion yang berdiri sendiri. Router memilih model untuk eksekusi agent Cursor yang dapat menalar dalam workspace, memanggil alat, menjalankan perintah, dan mengedit file. Saat ini, Cursor tidak mendokumentasikan endpoint Router raw untuk panggilan model arbitrer.

Pilih Cost, Balance, atau Intelligence

Teruskan auto-smart dan atur optimize_for secara eksplisit:

Label produkNilai SDK
Costcost
Balancebalanced
Intelligenceintelligence

Gunakan Balance dalam teks produk. Gunakan balanced hanya sebagai nilai wire SDK.

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

Selalu sertakan optimize_for. Jangan menghilangkannya atau mengirim nilai default lama; discovery melalui katalog adalah kontrak yang didukung.

Menemukan Router di katalog model

Cursor.models.list() mengembalikan model, definisi parameter, dan varian preset yang tersedia untuk akun dan tim saat ini yang terkait dengan kunci API. Cursor Router ditampilkan sebagai auto-smart jika Router tersedia. Administrator tim dapat menonaktifkan Router atau membatasi mode optimasi yang dapat dipilih anggota.

Gunakan katalog sebagai sumber acuan sebelum menetapkan pilihan secara hard-code:

from cursor_sdk import Cursor, ModelParameterValue, ModelSelectionmodels = Cursor.models.list()router = next((model for model in models if model.id == "auto-smart"), None)optimize_for = next(    (        parameter        for parameter in (router.parameters if router else [])        if parameter.id == "optimize_for"    ),    None,)if router is None or optimize_for is None:    raise RuntimeError(        "Cursor Router is not available for this API key. "        "Verify that Router is enabled for the key's team."    )requested_mode = "balanced"allowed_values = {entry.value for entry in optimize_for.values}if requested_mode not in allowed_values:    raise RuntimeError(        f'Router mode "{requested_mode}" is not enabled for this team.'    )model = ModelSelection(    id=router.id,    params=[ModelParameterValue(id=optimize_for.id, value=requested_mode)],)

Beralih mode untuk setiap menjalankan

Override model pada agent.send() untuk mengubah mode Router untuk sebuah menjalankan:

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

Override model per menjalankan bersifat permanen. Pengiriman selanjutnya tanpa override akan tetap menggunakan pilihan baru. Lihat Override model per menjalankan.

ID model: auto-smart, auto, dan default

PilihanArti
auto-smart dengan optimize_forCursor Router. Gunakan ini jika Anda menginginkan Cost, Balance, atau Intelligence.
ModelSelection(id="auto")Fallback Auto yang dipilih server saat model tertentu tidak tersedia di katalog. Utamakan auto-smart jika Anda memerlukan mode Router yang eksplisit.
Tidak menyertakan optimize_for atau mengirim defaultBukan kontrak Router yang didukung. Selalu temukan nilai yang diizinkan, lalu teruskan cost, balanced, atau intelligence.

Penagihan dan kumpulan perutean

  • Cost mengikuti perilaku Auto klasik dan penetapan harga Auto gabungan.
  • Balance dan Intelligence menggunakan Cursor Router dan ditagihkan sesuai tarif model yang dirutekan berdasarkan paket atau kontrak Anda.
  • Model yang digunakan dapat berubah di antara permintaan. Pilih ID model tetap jika Anda memerlukan perbandingan yang dapat direproduksi.
  • Daftar model yang diizinkan untuk perusahaan membentuk kumpulan perutean. Memblokir model yang diperlukan dapat menonaktifkan Router.

Untuk tarif saat ini dan kumpulan perutean, lihat Cursor Router dan Models & Pricing.

Pemecahan masalah Router yang tidak tersedia

Jika auto-smart tidak tersedia atau mode pengoptimalan ditolak:

  1. Panggil Cursor.models.list().
  2. Pastikan auto-smart ada dalam hasil.
  3. Pastikan optimize_for mencakup nilai yang diinginkan (cost, balanced, atau intelligence).
  4. Pastikan Router diaktifkan untuk tim yang terkait dengan kunci API.
  5. Jika Anda tergabung dalam beberapa tim, pastikan key digunakan dalam konteks tim yang dimaksud.
  6. Periksa kebijakan model-access tim jika Router tidak tersedia atau tidak dapat memilih underlying model yang valid.

Kamus mentah

Dataclass bertipe lebih disarankan untuk kode aplikasi karena pelengkapan otomatis IDE dan type checking bekerja lebih baik. SDK juga menerima kamus biasa untuk skrip singkat atau JSON yang disediakan dari sumber eksternal. Key snake-case dinormalisasi.

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

Agent

Objek handle yang dikembalikan oleh Agent.create(), Agent.resume(), client.agents.create(), dan 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: ...
AnggotaDeskripsi
agent_idIdentifier agent yang stabil. agent-<uuid> untuk lokal, bc-<uuid> untuk cloud.
modelPemilihan model bertipe saat ini. Diperbarui setelah pengiriman berhasil dengan override model.
sendMemulai menjalankan baru dengan prompt yang diberikan. Mengembalikan handle Run.
reloadMemuat ulang config sistem berkas (hooks, MCP proyek, subagents) tanpa menutupnya.
closeMenutup agent dan melepaskan sumber daya.
list_messagesMencantumkan riwayat message agent.
list_artifactsMencantumkan file yang dihasilkan agent (khusus cloud; lokal mengembalikan daftar kosong).
download_artifactMengunduh file berdasarkan path (khusus cloud; lokal memunculkan error).
get_usageMengambil penggunaan token yang ditagihkan dan biaya dalam dolar untuk agent.
archive / unarchive / deleteMengelola lifecycle agen cloud.

Gunakan context manager untuk cleanup otomatis:

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

Saat Anda menggunakan helper sinkron Agent.* atau Cursor.* tanpa meneruskan client=, SDK akan memulai atau menggunakan kembali klien default tingkat modul. Klien ini akan ditutup secara otomatis saat proses berakhir, tetapi Anda juga dapat menutupnya secara eksplisit:

from cursor_sdk import close_default_clientclose_default_client()

Agent.prompt()

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

Kemudahan one-shot: membuat agent, mengirim satu prompt, menunggu menjalankan selesai, lalu melepasnya.

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

Versi async (dengan asumsi Anda sudah membuka AsyncClient):

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

CursorClient

Gunakan CursorClient jika Anda memerlukan kontrol lifecycle secara eksplisit, bridge endpoint kustom, opsi HTTP kustom, atau beberapa workspace dalam satu process. Client tetap tersedia sebagai alias.

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

Sumber Daya

Klien eksplisit menyediakan namespace sumber daya:

Sumber DayaContoh metode sinkronContoh metode asinkron
agentsclient.agents.create(...), client.agents.list(...), client.agents.get(...)await client.agents.create(...), await client.agents.list(...)
modelsclient.models.list()await client.models.list()
repositoriesclient.repositories.list()await client.repositories.list()

Metode tingkat atas seperti client.create_agent(...) dan client.list_agents(...) tetap tersedia, tetapi namespace sumber daya adalah bentuk yang direkomendasikan untuk kode aplikasi.

Klien HTTP kustom

Klien sync dan async mendukung klien httpx kustom untuk proksi, transport, dan konfigurasi HTTP lanjutan lainnya:

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

DefaultHttpxClient dan DefaultAsyncHttpxClient mempertahankan batas waktu dan perilaku pengalihan default SDK. Sementara itu, httpx.Client dan httpx.AsyncClient biasa menggunakan default httpx.

Mengonfigurasi batas waktu dan percobaan ulang

Kedua klien menyediakan with_options(...), yang mengembalikan salinan dangkal dengan pengaturan koneksi yang sama dan menimpa nilai default. Gunakan timeout untuk semua permintaan, atau atur unary_timeout dan stream_timeout secara terpisah. max_retries mengontrol percobaan ulang klien:

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

Padanan async:

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="."))

Mengirim pesan

Setiap agent.send() mengembalikan Run. Setiap await async_agent.send() mengembalikan AsyncRun. Agent mempertahankan konteks percakapan antar-menjalankan; menjalankan merupakan unit kerja untuk satu prompt.

print(agent.send("Find the bug in src/auth.py").text())# Agent yang sama, seluruh konteks percakapan dipertahankan.print(agent.send("Fix it and add a regression test").text())

Versi async:

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())

Untuk mengirim gambar beserta teks:

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

Anda juga dapat menggunakan dataclass bantuan. SDKImage.from_file(path) membaca dari disk dan menangani encoding base64 untuk Anda:

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

SDKImage.data_image(base64_data, mime_type) dan SDKImage.url_image(url) juga tersedia bagi pemanggil yang sudah memiliki byte terenkode atau URL jarak jauh.

Jalankan

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  # kumulatif; properti pada handle yang aktif    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() adalah alias dari run.messages(). Mengiterasi run secara langsung menghasilkan envelope RunStreamEvent, seperti halnya run.events().

AsyncRun memiliki field status yang sama, termasuk usage. Metode yang melakukan I/O bersifat 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(), dan async for event in run.observe().

Streaming

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}")

Stream menjalankan hanya dapat digunakan sekali. run.messages(), run.events(), dan run.iter_text() semuanya menggunakan stream dasar yang sama dan meneruskannya. Setelah stream selesai, menjalankan menyimpan hasil akhir (run.result, run.status, run.usage, run.git, ...). Panggil run.wait() untuk menguras peristiwa yang tersisa dan mengembalikan RunResult bertipe.

result = run.wait()print(result.status)       # "finished" | "error" | "cancelled" | "expired"print(result.result)       # teks akhir dari asisten, jika adaprint(result.model)        # ModelSelection yang digunakan untuk run iniprint(result.duration_ms)print(result.usage)        # TokenUsage kumulatif, atau None jika tidak tersediaprint(result.git)          # RunGitInfo di Cloud

Versi async:

result = await run.wait()

Penggunaan token

Menjalankan melaporkan penggunaan token jika runtime menyediakannya. Baca total kumulatif dari run.usage pada handle aktif (selama streaming atau setelah wait()), atau dari result.usage pada RunResult yang dikembalikan oleh run.wait(). Keduanya berisi TokenUsage yang dijumlahkan dari setiap turn yang melaporkan penggunaan, dan keduanya bernilai None jika tidak ada turn yang melakukannya—misalnya, menjalankan yang dibatalkan dan tidak pernah menyelesaikan turn, runtime yang tidak mengekspos penggunaan, atau snapshot Cloud yang terpisah dan belum merekonsiliasi penggunaan.

@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
FieldDeskripsi
input_tokensToken prompt yang dikirim ke model.
output_tokensToken yang dihasilkan oleh model.
cache_read_tokensToken yang diambil dari cache prompt.
cache_write_tokensToken yang ditulis ke cache prompt.
total_tokensinput_tokens + output_tokens + cache_read_tokens + cache_write_tokens. Tidak mencakup reasoning_tokens.
reasoning_tokensToken penalaran, bagian dari output_tokens. None jika model atau runtime tidak melaporkannya.
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 sudah dihitung dalam output_tokens, sehingga total_tokens tidak menyertakannya untuk menghindari penghitungan ganda.

Untuk angka per giliran saat dialirkan, tangani peristiwa stream usage (SDKUsageMessage). Peristiwa ini dipicu sekali di akhir setiap giliran yang melaporkan penggunaan dan memuat TokenUsage untuk giliran tersebut. run.usage dan result.usage tetap bersifat kumulatif sepanjang menjalankan. Setelah giliran stream, handle mengutamakan total yang telah dijumlahkan tersebut; jika tidak, handle menggunakan data penggunaan dari wait() atau snapshot get_run / list_runs saat bridge menyediakannya.

for message in run.messages():    if message.type == "usage":        print(f"turn used {message.usage.total_tokens} tokens")# Atau setelah wait() / tanpa memproses pesan sendiri:result = run.wait()print(run.usage, result.usage)

Versi async: async for message in run.messages() dan await run.wait(). run.usage tetap merupakan properti sync pada AsyncRun.

TokenUsage diekspor dari cursor_sdk (serta to_token_usage / sum_token_usage untuk caller tingkat lanjut). JSON pada wire menggunakan camelCase (inputTokens, …); dataclass Python menggunakan snake_case.

Jumlah token adalah yang dilaporkan runtime; jumlah tersebut tidak menunjukkan biaya. Untuk penggunaan yang ditagihkan dan biaya dalam dolar dari menjalankan agent, panggil agent.get_usage().

Membaca output teks

iter_text() menghasilkan teks asisten secara streaming. text() mengembalikan teks terminal akhir dan akan memblokir di wait() jika run masih berjalan.

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

Versi async:

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

Membatalkan menjalankan

run.cancel()

Padanan async:

await run.cancel()

run.cancel() meminta pembatalan menjalankan yang aktif. Status berubah menjadi "cancelled", live stream berhenti, pemanggilan tool yang sedang berjalan dihentikan, dan run.wait() selesai dengan status: "cancelled". Output parsial (teks asisten yang telah ditulis sejauh ini) tetap tersimpan pada objek Run.

Membatalkan menjalankan yang sudah berstatus terminal ("finished", "error", "cancelled", "expired") akan memunculkan UnsupportedRunOperationError. Jika ragu, periksa run.status terlebih dahulu:

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

Membaca status menjalankan

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()  # hapus listenerturns = run.conversation()

run.conversation() mengembalikan list[ConversationTurn] bertipe. Gunakan untuk merender atau menyimpan riwayat terstruktur tanpa berlangganan ke live stream. run.conversation_json() mengembalikan string JSON mentah.

Untuk menjalankan async, gunakan await run.conversation() dan await run.conversation_json().

Override model per menjalankan

model yang diteruskan ke agent.send() menggantikan pilihan model agent untuk menjalankan tersebut, lalu tetap digunakan: pengiriman berikutnya tanpa override akan terus menggunakan model baru. Untuk beralih kembali, teruskan override model lain atau baca pilihan saat ini dari agent.model.

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

run.model dan result.model mencerminkan pilihan yang digunakan oleh menjalankan ini dan tidak dapat diubah setelah menjalankan dimulai.

Variabel lingkungan per-menjalankan

Agen cloud juga dapat menerima variabel lingkungan untuk satu kali menjalankan. Teruskan cloud.env_vars dalam SendOptions, lalu nilainya akan dimasukkan ke shell agen hanya untuk menjalankan tersebut — setelah menjalankan selesai, nilai tersebut dihapus dari VM dan tidak tersedia pada menjalankan berikutnya. Ini cocok untuk kredensial yang berganti antarturn, seperti token deploy berumur singkat yang Anda terbitkan tepat sebelum meminta agen menggunakannya.

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

Jika variabel khusus menjalankan memiliki nama yang sama dengan variabel khusus agent dari env_vars di CloudAgentOptions, nilai khusus menjalankan akan diprioritaskan untuk menjalankan tersebut, lalu nilai khusus agent digunakan kembali pada menjalankan berikutnya.

Variabel per-menjalankan juga berfungsi pada pengiriman pertama. SDK meneruskannya saat membuat agent, dengan cakupan pada menjalankan awal, sehingga tidak disimpan secara persisten pada agent. Seperti variabel khusus agent, variabel ini dienkripsi saat disimpan dan namanya tidak boleh diawali dengan CURSOR_.

Variabel lingkungan per-menjalankan hanya tersedia untuk agen cloud dan tidak tersedia bagi agent yang berjalan pada repo publik. Untuk agent lokal, proses agent mewarisi lingkungan Anda sendiri, jadi atur variabel pada proses sebelum memanggil send().

Mode percakapan

Teruskan mode="plan" atau mode="agent" untuk menentukan apakah suatu menjalankan mengeksplorasi dan merencanakan terlebih dahulu atau langsung menerapkan perubahan. Lihat Mode Plan untuk mengetahui fungsi mode plan dalam produk.

Atur mode di AgentOptions yang diteruskan ke Agent.create() untuk menetapkan mode menjalankan pertama. Pada panggilan agent.send() tindak lanjut, hilangkan mode untuk mempertahankan mode percakapan saat ini, atau teruskan mode untuk beralih hanya pada menjalankan tersebut.

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

Streaming delta mentah

Teruskan callback on_delta dan on_step dalam SendOptions untuk menerima pembaruan tingkat rendah. Callback sinkron dipanggil secara inline. Callback async dapat berupa sinkron atau async; nilai kembalian yang dapat di-await akan di-await sebelum peristiwa berikutnya diproses.

from cursor_sdk import SendOptionsdef on_delta(update):    if update.type in ("text-delta", "thinking-delta"):        print(update.text, end="")run = agent.send(    "Refactor the utils module",    SendOptions(on_delta=on_delta, on_step=lambda step: print(f"[step] {step.type}")),)run.wait()

Subkelas update dan step yang konkret terdapat di cursor_sdk.events:

from cursor_sdk.events import TextDeltaUpdate, ToolCallStartedUpdateif isinstance(update, TextDeltaUpdate):    print(update.text)

Keduanya tetap dapat diimpor dari cursor_sdk demi kompatibilitas mundur, tetapi kode baru sebaiknya mengimpor dari cursor_sdk.events.

SendOptions

PropertiJenisDeskripsi
modelstr | ModelSelection | Mapping[str, Any]Override model untuk setiap pengiriman. Jika dihilangkan, menggunakan agent.model. Tetap berlaku setelah pengiriman berhasil.
mode"agent" | "plan"Override mode percakapan untuk setiap pengiriman. Jika dihilangkan pada tindak lanjut, mode percakapan saat ini tetap digunakan.
mcp_serversMapping[str, McpServerConfig]Definisi server MCP inline. Sepenuhnya menggantikan server yang ditentukan saat pembuatan untuk menjalankan ini.
cloud.env_varsMapping[str, str]Hanya untuk agen cloud. Variabel lingkungan per-menjalankan yang diinjeksi untuk menjalankan ini dan dihapus setelah selesai. Mengoverride env_vars dalam cakupan agent berdasarkan nama, hanya untuk menjalankan ini.
local.forceboolHanya untuk agent lokal. Default-nya None (tidak diatur). Atur ke True untuk mengakhiri active menjalankan yang macet sebelum memulai pesan ini. Cloud mengembalikan 409 agent_busy di sisi server, sehingga tidak memerlukan padanan.
idempotency_keystrKey idempotensi opsional yang dibuat oleh klien untuk pengiriman ini.
on_stepCallable[[ConversationStep], Any]Callback setelah setiap langkah percakapan selesai (teks, thinking, atau batch tool).
on_deltaCallable[[InteractionUpdate], Any]Callback untuk setiap InteractionUpdate mentah.

Tiga bagian berikutnya berisi referensi terperinci untuk SDKMessage, InteractionUpdate, dan ConversationTurn. Baca sekilas atau lewati saat pertama kali membaca; Melanjutkan agent melanjutkan pembahasan.

Peristiwa stream

run.messages() menghasilkan dataclass pesan SDK bertipe. Bedakan berdasarkan message.type. Semua pesan mencakup agent_id dan run_id jika disediakan oleh runtime.

SDKMessage = (    SDKSystemMessage    | SDKUserMessageEvent    | SDKAssistantMessage    | SDKThinkingMessage    | SDKToolUseMessage    | SDKStatusMessage    | SDKTaskMessage    | SDKRequestMessage    | SDKUsageMessage    | Mapping[str, Any])
typeDataclassField utama
"system"SDKSystemMessagesubtype, model, tools
"user"SDKUserMessageEventmessage.content
"assistant"SDKAssistantMessagemessage.content dengan nilai TextBlock dan ToolUseBlock
"thinking"SDKThinkingMessagetext, thinking_duration_ms
"tool_call"SDKToolUseMessagecall_id, name, status, args, result, truncated
"status"SDKStatusMessagestatus, message
"task"SDKTaskMessagestatus, text
"request"SDKRequestMessagerequest_id
"usage"SDKUsageMessageusage (TokenUsage)

SDKToolUseMessage dipancarkan dua kali untuk sebagian besar pemanggilan tool: pertama dengan status="running" dan args terisi, lalu saat selesai dengan status="completed" (atau "error") dan result terisi. truncated menandakan apakah SDK memotong args atau result karena payload terlalu besar.

SDKUsageMessage dipancarkan sekali di akhir setiap giliran yang melaporkan penggunaan token, dan memuat TokenUsage untuk giliran tersebut. Total kumulatif untuk semua giliran tetap berada di run.usage dan result.usage. Lihat Penggunaan token.

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

Data hasil (teks akhir, model, durasi, penggunaan token kumulatif, metadata git) tersedia pada objek Run setelah stream selesai. Gunakan run.wait() untuk membacanya, termasuk result.usage jika runtime melaporkannya.

Skema pemanggilan tool tidak stabil. Payload args dan result pada peristiwa tool_call mencerminkan struktur internal setiap tool dan dapat berubah seiring perkembangan tool. Nama tool juga dapat diubah atau diganti. Perlakukan args dan result sebagai data tanpa tipe, lalu parsing secara defensif. Envelope peristiwa (type, call_id, name, status) bersifat stabil.

run.events() menghasilkan envelope RunStreamEvent tingkat rendah. Gunakan saat Anda memerlukan offset, envelope hasil terminal, atau pembaruan interaksi mentah:

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

Pembaruan interaksi

InteractionUpdate adalah jenis delta mentah yang diteruskan ke callback on_delta pada agent.send(). Pembaruan ini lebih terperinci daripada peristiwa SDKMessage: teks di-stream token demi token, dan pemanggilan tool melaporkan status parsial seiring args terakumulasi.

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

PartialToolCallUpdate dipancarkan saat model melakukan streaming argumen ke pemanggilan tool sebelum melakukan commit. Penafian stabilitas yang berlaku untuk SDKToolUseMessage.args juga berlaku di sini.

Jenis percakapan

Tampilan terstruktur per giliran dari sebuah menjalankan yang dikembalikan oleh run.conversation(). Setiap item merupakan wrapper yang memuat pembeda type giliran beserta payload bertipe dalam turn.

@dataclass(frozen=True)class ConversationTurn:    type: str  # "agentConversationTurn" | "shellConversationTurn"    turn: AgentConversationTurn | ShellConversationTurn | Mapping[str, Any]@dataclass(frozen=True)class AgentConversationTurn:    user_message: Mapping[str, Any] | None = None    steps: Sequence[ConversationStep] = ()@dataclass(frozen=True)class ShellConversationTurn:    shell_command: ShellCommand | None = None    shell_output: ShellOutput | None = NoneConversationStep = (    AssistantConversationStep    | ToolCallConversationStep    | ThinkingConversationStep    | Mapping[str, Any])

Bedakan berdasarkan turn.type dan baca payload melalui 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)

run.conversation() dari callback on_step dipanggil untuk setiap ConversationStep, bukan setiap giliran. Langkah percakapan panggilan tool memuat payload Mapping[str, Any]. Perlakukan detail payload panggilan tool sebagai data tanpa tipe; lihat catatan stabilitas di bagian Peristiwa stream.

Melanjutkan agent

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

Gunakan Agent.resume() atau client.agents.resume() untuk menyambungkan kembali ke agent yang sudah ada berdasarkan ID. Alur umum: menyambungkan kembali ke agen cloud berjangka panjang yang sebelumnya telah dijalankan, atau melanjutkan percakapan setelah proses lokal dimulai ulang. Runtime terdeteksi otomatis dari awalan ID (bc- adalah cloud, selain itu lokal).

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

Padanan async:

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

agent.model akan bernilai None saat dilanjutkan, kecuali Anda meneruskan model lagi. Server MCP inline tidak dipertahankan saat dilanjutkan; server ini sering memuat secret dan hanya tersimpan di memori. Teruskan server tersebut lagi saat dilanjutkan, atau gunakan konfigurasi MCP berbasis file (.cursor/mcp.json dan local.setting_sources) untuk server yang perlu dipertahankan.

Persistensi lokal

Agent lokal menyimpan status percakapan dan metadata menjalankan melalui bridge, sehingga tindak lanjut dan Agent.resume() tetap tersedia setelah proses dimulai ulang. Secara default, bridge menyimpannya di state root per workspace pada disk. Agen cloud menyimpan data di sisi server, sehingga melanjutkan agen cloud dari mana saja akan mengembalikan percakapan yang sama.

Persistensi lokal dibatasi per workspace. Saat bridge berjalan sebagai sidecar atau subproses berjangka panjang, gunakan workspace yang sama dengan agent agar panggilan list, get, dan resume lokal menemukan agent yang tepat. Atur sekali pada client, lalu teruskan cwd ke panggilan list dan get lokal:

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

Memeriksa agent dan menjalankan

Gunakan CursorClient untuk API daftar, ambil, dan pagination.

from cursor_sdk import CursorClientwith CursorClient.launch_bridge(workspace=".") as client:    agents = client.agents.list(runtime="local", cwd=".")    for agent_info in agents.auto_paging_iter():        print(agent_info.agent_id)    info = client.agents.get(agents.items[0].agent_id)    runs = client.agents.list_runs(info.agent_id)    run = client.agents.get_run(runs.items[0].id)

Padanan async:

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)

Gunakan agent.list_messages() pada handle agent untuk membaca riwayat pesan. Agent.messages.list(agent_id) adalah cara praktis dengan atribut bertipe untuk pemanggilan yang sama jika Anda hanya memiliki ID.

Gunakan Agent.get_run(run_id) atau client.agents.get_run(run_id) untuk mengambil menjalankan tanpa handle agent. Batalkan dengan Agent.cancel_run(run_id, agent_id=...) atau client.agents.cancel_run(run_id, agent_id=...). Metode client async dapat di-await dan menggunakan argumen yang sama.

AgentMessage berbeda dari SDKMessage yang dialirkan:

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

Endpoint daftar mengembalikan ListResult[T]. Gunakan .items dan .next_cursor secara langsung, iterasi halaman saat ini dengan for item in page, atau iterasi semua halaman dengan .auto_paging_iter(). Endpoint daftar asinkron mengembalikan AsyncListResult[T]; async for item in page mengiterasi halaman saat ini, sedangkan async for item in page.auto_paging_iter() mengiterasi setiap halaman dalam kumpulan hasil.

SDKAgentInfo

Struktur metadata yang dikembalikan oleh Agent.list(), Agent.get(), client.agents.list(), dan 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] = {}  # dari CloudAgentOptions.metadata; kosong untuk agent lokal

Siklus hidup agen cloud

Agen cloud tetap berada di workspace tim Anda sampai diarsipkan atau dihapus. client.agents.list(runtime="cloud") default menyembunyikan agen yang diarsipkan; gunakan include_archived=True untuk melihatnya. Filter berdasarkan pr_url untuk menemukan agen yang membuka pull request tertentu.

# Berdasarkan ID, tidak memerlukan handle agent:Agent.archive(agent_id)Agent.unarchive(agent_id)Agent.delete(agent_id)# Melalui client eksplisit:client.agents.archive(agent_id)client.agents.unarchive(agent_id)client.agents.delete(agent_id)# Pada handle agent yang sudah ada:agent.archive()agent.unarchive()agent.delete()

archive mengarsipkan agent agar transkrip tetap dapat dibaca. unarchive memulihkannya. delete bersifat permanen; pembacaan selanjutnya akan menghasilkan NotFoundError.

Metode siklus hidup asinkron menggunakan nama yang sama dan dapat di-await.

agent.get_usage()

Ambil penggunaan token yang ditagihkan dan biaya dalam dolar untuk eksekusi agent. Agen cloud mengembalikan perincian per-eksekusi; agent lokal mengembalikan perincian per-giliran. Teruskan run_id untuk membatasi hasil ke satu entri: untuk agen cloud, ID eksekusi run-<uuid>; untuk agent lokal, ID dari get_usage().runs[].run_id sebelumnya.

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              # dijumlahkan dari semua `runs`    runs: Sequence[RunUsage] = ()    cost: UsageCost | None = None  # dijumlahkan dari semua `runs`@dataclass(frozen=True)class RunUsage:    run_id: str    usage: TokenUsage    cost: UsageCost | None = None@dataclass(frozen=True)class UsageCost:    raw_cost_cents: float  # biaya token model sebelum diskon; 0 untuk penggunaan dengan harga per permintaan    charged_cents: float   # jumlah yang dikenakan, termasuk diskon dan Tarif Token Cursor

Biaya mencakup diskon dan mungkin memerlukan beberapa saat untuk diproses setelah menjalankan berakhir; cost bernilai None hingga prosesnya selesai. charged_cents bernilai 0.0 untuk penggunaan yang termasuk dalam paket, BYOK (Bring Your Own Key), dan hibah kredit.

Ini berbeda dari tampilan Penggunaan token: run.usage adalah jumlah token aktual untuk satu menjalankan, sedangkan get_usage() adalah catatan tagihan untuk seluruh menjalankan agent's. Pada agent async, hasil await agent.get_usage() akan sama. AgentUsage, RunUsage, dan UsageCost diekspor dari cursor_sdk.

Namespace Cursor

Pembacaan tingkat akun dan katalog. Metode sync menerima api_key opsional; jika tidak disediakan, akan menggunakan CURSOR_API_KEY.

from cursor_sdk import Cursorme = Cursor.me()models = Cursor.models.list()repositories = Cursor.repositories.list()

Versi klien eksplisit:

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

Padanan async:

from cursor_sdk import AsyncCursorme = await AsyncCursor.me(client=client)models = await AsyncCursor.models.list(client=client)repositories = await AsyncCursor.repositories.list(client=client)

Cursor.me() mengembalikan SDKUser dengan field api_key_name, created_at, serta opsional user_id, user_email, user_first_name, dan user_last_name.

Gunakan Cursor.models.list() untuk mengetahui ID model yang valid dan parameter khusus model sebelum memanggil Agent.create() atau agent.send(). Parameter bersifat spesifik untuk setiap model. Contoh umum meliputi reasoning effort dan optimize_for Cursor Router pada auto-smart.

Katalog bersifat spesifik untuk akun dan tim. Cursor Router hanya muncul sebagai auto-smart jika Router tersedia untuk tim kunci API. Lihat 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"),#       ),#   ),# ]

Varian preset pada setiap SDKModel sudah berisi params yang valid, sehingga dapat disalin ke ModelSelection.

Utamakan pemilihan Router secara eksplisit (auto-smart + optimize_for) saat model target tidak tersedia dan Anda menginginkan Cost, Balance, atau Intelligence. Gunakan ModelSelection(id="auto") sebagai cadangan hanya jika Anda menginginkan Auto yang dipilih server tanpa memilih mode Router. Untuk Cursor Router, selalu teruskan optimize_for secara eksplisit.

Cursor.repositories.list() mengembalikan repo SCM (GitHub, GitLab, Bitbucket, Azure DevOps, bergantung pada yang terhubung) yang tersedia untuk agen cloud pada akun atau tim pemanggil. Setiap item menyediakan url. Gunakan URL ini untuk mengisi CloudAgentOptions.repos.

Server MCP

Agent dapat menggunakan server MCP dari definisi inline, pengaturan proyek/pengguna, plugin, dan konfigurasi yang dikelola melalui Dashboard, bergantung pada runtime.

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", "."],            ),        },    ))

Dictionary sederhana ({"type": "http", "url": ...} dan {"type": "stdio", "command": ...}) juga didukung untuk memudahkan pembuatan skrip cepat.

Yang dimuat

Agent lokal memuat server dari hingga lima sumber. Jika ada nama yang sama, sumber pertama yang cocok akan diprioritaskan:

  1. mcp_servers di agent.send(). Sepenuhnya menggantikan server yang ditentukan saat pembuatan untuk menjalankan tersebut (tidak digabungkan).
  2. mcp_servers di Agent.create(). Digunakan jika tidak ada override per-pengiriman.
  3. Server plugin, jika local.setting_sources mencakup "plugins".
  4. Server proyek dari .cursor/mcp.json, jika local.setting_sources mencakup "project".
  5. Server pengguna dari ~/.cursor/mcp.json, jika local.setting_sources mencakup "user".

Tanpa local.setting_sources, hanya server inline yang dimuat. Jika server MCP lokal memerlukan login OAuth, SDK dapat menggunakan kembali login yang tersimpan dari aplikasi Cursor, tetapi tidak dapat membuka browser untuk melakukan login.

Agen cloud memuat server dari:

  1. mcp_servers di agent.send(). Sepenuhnya menggantikan server yang ditentukan saat pembuatan untuk menjalankan tersebut (tidak digabungkan).
  2. mcp_servers di Agent.create(). Digunakan jika tidak ada override per-pengiriman.
  3. Server MCP pengguna dan tim Anda dari cursor.com/agents.

Jika server inline tidak mencakup auth atau headers dan Anda sebelumnya telah mengotorisasi URL server tersebut di cursor.com/agents, menjalankan yang diautentikasi dengan token API pribadi akan otomatis menggunakan kembali token OAuth tersebut. Kunci API akun layanan tidak dapat menggunakan autentikasi pengguna sebagai cadangan karena tidak terkait dengan pengguna.

local.setting_sources tidak berlaku untuk agen cloud.

Cloud

Agen cloud juga menerima konfigurasi MCP terautentikasi secara inline. MCP Cloud mendukung transport HTTP dan stdio. Gunakan headers HTTP untuk kunci API statis atau token Bearer. Gunakan auth HTTP untuk server yang dilindungi OAuth. Gunakan env stdio saat server berjalan di dalam VM cloud dan membaca kredensial dari variabel lingkungan.

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 dan auth ditangani oleh backend Cursor. Field sensitif disamarkan dan tidak masuk ke VM.
  • Nilai env Stdio diteruskan ke VM karena server berjalan di sana. Perlakukan nilai tersebut seperti secret runtime lainnya.
  • OAuth untuk server MCP yang dikonfigurasi di cursor.com/agents tetap berlaku per pengguna, bahkan untuk server tingkat tim.

Lihat MCP untuk format konfigurasi lengkap dan kemampuan Cloud Agent untuk perilaku khusus cloud.

Subagent

Tentukan subagent bernama yang dapat dijalankan oleh agent utama melalui tool Agent. Sertakan secara inline:

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

Subagent yang di-commit ke repo di .cursor/agents/*.md (dengan frontmatter name, description, dan model opsional) juga akan terdeteksi. Definisi inline menggantikan definisi berbasis file dengan nama yang sama.

Subagent bertingkat

Subagent dapat memunculkan subagentnya sendiri hingga batas kedalaman tertentu. Saat subagent menggunakan tool Agent, subagent tersebut mengakses executor subagent yang sama dengan parent, sehingga parent dapat mendelegasikan tugas ke subagent yang kemudian mendelegasikannya lebih lanjut. Setiap tingkat melihat kumpulan subagent bernama yang sama. Agent tingkat teratas dan subagent langsungnya dapat meluncurkan subagent, tetapi subagent yang diluncurkan oleh subagent lain tidak dapat meluncurkan subagent lebih lanjut.

Membatasi kumpulan alat

tools menetapkan daftar alat bawaan yang diizinkan untuk model; disallowed_tools menghapus alat tertentu dan mempertahankan yang lainnya, termasuk alat yang ditambahkan ke platform setelah versi SDK Anda dirilis. Keduanya saat ini hanya tersedia untuk agent lokal dan tidak disimpan pada agent: teruskan kembali saat melanjutkan untuk mempertahankan pembatasan.

from cursor_sdk import Agent, AgentOptions, LocalAgentOptions# Agent baca saja: hanya tool ini yang tersedia.reader = Agent.create(    AgentOptions(        model="composer-2.5",        tools=["read", "grep", "glob", "ls"],        local=LocalAgentOptions(cwd="."),    ))# Semua tool kecuali shell.no_shell = Agent.create(    AgentOptions(        model="composer-2.5",        disallowed_tools=["shell"],        local=LocalAgentOptions(cwd="."),    ))
  • Jika tools dihilangkan, kumpulan alat standar untuk model yang dipilih akan digunakan; tools=[] tidak menyediakan alat bawaan, sehingga model hanya dapat merespons dengan teks.
  • Kedua field menerima nama publik ("read", "edit", "task", "webSearch", ...) serta grup kapabilitas "shell" dan "mcp". Nama yang tidak dikenal akan memunculkan BadRequestError saat pembuatan.
  • Larangan diprioritaskan: sebuah tool harus ada di tools (jika diatur) dan tidak ada di disallowed_tools agar tersedia.
  • Melarang "mcp" juga menghapus alat kustom. Melarang "task" mencegah subagent; jika tidak, subagent tetap memiliki kumpulan alat terkurasi masing-masing.

Alat kustom

Alat kustom memungkinkan Anda menyediakan fungsi Python untuk agent lokal tanpa perlu menyiapkan server MCP terpisah. Teruskan fungsi tersebut melalui LocalAgentOptions.custom_tools.

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

execute menerima argumen yang telah diuraikan serta CustomToolContext dengan tool_call_id jika tersedia. Fungsi ini dapat mengembalikan string, nilai yang kompatibel dengan JSON, atau mapping dengan daftar content. Custom tools hanya tersedia untuk agent lokal.

Hooks

Hooks hanya berbasis file. Tidak ada callback hook secara terprogram. Hooks adalah batas kebijakan proyek, bukan pengaturan per proses.

  • Lokal: Tambahkan .cursor/hooks.json ke repo yang diteruskan sebagai local.cwd, atau tambahkan ~/.cursor/hooks.json untuk hooks tingkat pengguna.
  • Cloud: Commit .cursor/hooks.json beserta skripnya ke repo yang diteruskan dalam cloud.repos. Agen cloud yang dibuat oleh SDK secara otomatis memuat project hooks. Pada paket Enterprise, agen tersebut juga menjalankan Team hooks dan hooks yang dikelola perusahaan.

Lihat Hooks untuk format konfigurasi dan dukungan hooks Agen Cloud untuk perilaku cloud.

Artefak

Cantumkan dan unduh file dari workspace agent.

@dataclass(frozen=True)class SDKArtifact:    path: str    size_bytes: int = 0    updated_at: str = ""
from pathlib import Pathartifacts = agent.list_artifacts()for artifact in artifacts:    print(artifact.path, artifact.size_bytes)# Unduh satu artefak ke disk.content = agent.download_artifact(artifacts[0].path)Path("review.md").write_bytes(content)

Agent async menyediakan await agent.list_artifacts() dan await agent.download_artifact(path).

Dukungan artifact bergantung pada runtime. Agent SDK Local mengembalikan daftar kosong dari list_artifacts() dan menghasilkan error saat memanggil download_artifact().

Manajemen sumber daya

Selalu tutup agent setelah selesai digunakan. Pola sinkronisasi yang paling rapi adalah context manager:

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

Untuk melepas resource secara eksplisit:

agent.close()

Agent dan klien asinkron mendukung context manager asinkron serta cleanup dengan await:

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

Untuk melepas resource secara eksplisit:

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

Klien default sinkron tingkat modul akan ditutup secara otomatis saat proses berakhir. Proses yang berjalan lama dapat menutup dan mengatur ulangnya secara eksplisit:

from cursor_sdk import close_default_clientclose_default_client()

Referensi konfigurasi

SDK Python mendukung dataclass bantuan dan dictionary mentah. Dataclass menggunakan field Python berformat snake_case dan lebih disarankan untuk kode aplikasi.

AgentOptions

PropertiJenisDefaultDeskripsi
modelstr | ModelSelection | Mapping[str, Any]Wajib untuk lokal; cloud menggunakan default yang ditentukan server jika tidak tersediaModel yang digunakan. Lihat ModelSelection.
api_keystrenv CURSOR_API_KEYKunci API pengguna atau key akun layanan. Key Admin Tim belum didukung.
namestrDibuat otomatisNama agent yang mudah dibaca dan ditampilkan dalam client.agents.list() / client.agents.get().
localLocalAgentOptions | Mapping[str, Any]NoneKonfigurasi agent lokal. Teruskan untuk membuat agent lokal.
cloudCloudAgentOptions | Mapping[str, Any]NoneKonfigurasi agen cloud. Teruskan untuk membuat agen cloud.
mcp_serversMapping[str, McpServerConfig]NoneDefinisi server MCP inline.
agentsMapping[str, AgentDefinition | Mapping[str, Any]]NoneDefinisi subagent.
toolsSequence[str]Kumpulan alat defaultHanya alat bawaan yang tercantum yang tersedia untuk model. [] berarti tidak ada alat bawaan; model hanya dapat merespons dengan teks. Khusus agent lokal.
disallowed_toolsSequence[str]NoneMenghapus alat bawaan yang tercantum; alat lainnya tetap tersedia. disallowed_tools diprioritaskan saat digabungkan dengan tools. Khusus agent lokal.
agent_idstrDibuat otomatisID agent persisten. Teruskan untuk mempertahankan ID yang stabil di seluruh invocation.
idempotency_keystrDibuat otomatis untuk cloudKey idempotensi opsional yang dibuat oleh klien. Khusus cloud.
mode"agent" | "plan"NoneMode percakapan awal untuk proses pertama agent. Jika dihilangkan, server memulai dalam mode agent. Lihat Mode percakapan.

LocalAgentOptions

PropertiJenisDefaultDeskripsi
cwdstr | os.PathLikeNoneDirektori kerja utama. Daftar dengan beberapa entri tidak didukung; gunakan dirs untuk beberapa root.
dirsSequence[str | os.PathLike]NoneFolder workspace tambahan untuk konfigurasi multi-root. Digabungkan dengan cwd agar aturan, skill, dan konteks workspace dimuat dari setiap path.
setting_sourcesSequence[SettingSource]NoneLapisan pengaturan yang tersedia: "project", "user", "team", "mdm", "plugins", atau "all".
sandbox_optionsSandboxOptions | Mapping[str, Any]NoneOpsi sandbox lokal.
storeLocalAgentStoreConfig | Mapping[str, Any]NoneKonfigurasi store lokal yang diteruskan ke bridge.
auto_reviewboolNoneArahkan pemanggilan tool lokal melalui Auto-review jika backend yang terhubung mendukungnya.
custom_toolsMapping[str, CustomTool | Mapping[str, Any]]NoneTool kustom yang tersedia untuk agent lokal.

CloudAgentOptions

PropertiJenisdefaultDeskripsi
envCloudEnvironment | Mapping[str, Any]NoneLingkungan eksekusi. Jika tidak diisi, server menggunakan VM cloud yang di-host Cursor. pool dan machine menargetkan worker yang di-host sendiri dan Anda jalankan.
reposSequence[CloudRepository | Mapping[str, Any]]NoneRepositori yang akan di-clone ke VM. Jangan isi repos maupun env untuk agen tanpa repo dengan workspace kosong. Berikan pr_url pada repo untuk menautkan agen ke PR yang sudah ada.
work_on_current_branchboolNonePush commit ke branch yang ada, bukan membuat branch baru. Server memperlakukan nilai yang tidak diisi sebagai False.
auto_create_prboolNoneBuka PR saat run selesai. Server memperlakukan nilai yang tidak diisi sebagai False.
open_as_cursor_github_appboolTrue untuk kunci akun layanan, False untuk kunci penggunaBuka PR sebagai Cursor GitHub App, bukan sebagai pemilik kunci API. Nilai yang telah ditetapkan dikembalikan saat create, get, dan list.
skip_reviewer_requestboolNoneJangan minta pengguna pemanggil sebagai reviewer pada PR. Server memperlakukan nilai yang tidak diisi sebagai False.
env_varsMapping[str, str]NoneVariabel lingkungan untuk agen cloud dalam cakupan sesi.
metadataMapping[str, str]NoneTag string milik pemanggil yang disimpan secara persisten pada agen cloud. Lihat Metadata agen.

AgentDefinition

PropertiJenisDefaultDeskripsi
descriptionstrwajibKapan subagent ini digunakan. Ditampilkan kepada agent induk agar mengetahui kapan perlu memunculkannya.
promptstrwajibPrompt sistem untuk subagent.
modelstr | ModelSelection | Mapping[str, Any] | "inherit"NoneOverride model. None dan "inherit" sama-sama menggunakan pilihan agent induk.
mcp_serversSequence[str | AgentDefinitionMcpServer | Mapping[str, Any]]NoneServer MCP yang tersedia untuk subagent ini. Nama merujuk ke server dalam mcp_servers agent induk.

CustomTool

@dataclassclass CustomTool:    execute: Callable[[Mapping[str, Any], CustomToolContext], Any]    description: str | None = None    input_schema: Mapping[str, Any] | None = Noneclass CustomToolContext:    tool_call_id: str | None = None

ModelSelection

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

id adalah pengenal model (misalnya, "composer-2.5" atau "auto-smart"). params memuat parameter khusus model, seperti tingkat upaya penalaran atau optimize_for Router. Gunakan Cursor.models.list() untuk mengetahui ID yang valid, definisi parameter, dan varian preset yang tersedia untuk akun Anda. Lihat Cursor Router untuk kontrak pemilihan 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  # hanya lokal; cloud menolak field ini@dataclass(frozen=True)class McpAuth:    client_id: str    client_secret: str | None = None    scopes: Sequence[str] = ()

Untuk server HTTP yang berjalan di cloud, headers dan auth ditangani oleh backend Cursor. Field sensitif disamarkan sebelum terlihat oleh VM. Untuk server stdio di cloud, nilai env diteruskan ke VM (perlakukan sebagai secret runtime lainnya).

UserMessage

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

Bentuk terstruktur dari argumen pesan agent.send(). Gunakan untuk mengirim gambar beserta teks.

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: ...

Berikan url jarak jauh atau data base64 beserta mime_type. from_data() menerima byte atau string base64. from_file() membaca file dari disk dan mengodekannya ke base64.

SettingSource

SettingSource tersedia di cursor_sdk.types.

from cursor_sdk.types import SettingSource

Mengontrol lapisan pengaturan di disk yang dimuat oleh agent lokal. Agen cloud selalu memuat project, team, dan plugins, serta mengabaikan field ini.

NilaiSumber
"project".cursor/ di workspace
"user"~/.cursor/
"team"Pengaturan tim yang disinkronkan dari Dashboard
"mdm"Pengaturan perusahaan yang dikelola MDM
"plugins"Pengaturan yang disediakan plugin
"all"Singkatan untuk semua opsi di atas

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]: ...

Dikembalikan oleh client.agents.list(), client.agents.list_runs(), dan Agent.list(). next_cursor kosong jika tidak ada halaman berikutnya. Endpoint daftar asinkron mengembalikan AsyncListResult[T] beserta padanan yang dapat di-await.

Error

Semua error SDK merupakan turunan dari CursorAgentError. CursorSDKError adalah alias root yang kompatibel dengan versi sebelumnya bagi pemanggil lama. Gunakan is_retryable dan retry_after untuk menentukan logika percobaan ulang.

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
ErrorKapan
AuthenticationErrorKunci API tidak valid atau belum login.
PermissionDeniedErrorPemanggil yang telah diautentikasi tidak memiliki izin untuk operasi yang diminta.
RateLimitErrorTerlalu banyak permintaan atau batas penggunaan terlampaui.
ConfigurationErrorModel tidak valid, konfigurasi wajib tidak ada, atau parameter permintaan tidak tepat.
AgentBusyErrorMengirim tindak lanjut saat agent sudah memiliki run berstatus CREATING atau RUNNING (HTTP 409, kode agent_busy).
BadRequestErrorPermintaan tidak valid.
IntegrationNotConnectedErrorMembuat agen cloud untuk repo dengan provider SCM yang belum terhubung.
NetworkErrorLayanan tidak tersedia atau terjadi kegagalan jaringan.
APITimeoutErrorPermintaan melebihi batas waktu.
InternalServerErrorLayanan Cursor mengembalikan error server.
NotFoundErrorSumber daya yang diminta tidak ditemukan.
AgentNotFoundErrorAgent tidak ada atau tidak terlihat di direktori kerja saat ini.
UnsupportedRunOperationErrorRun operation tidak didukung untuk status run saat ini.

Percobaan ulang dengan backoff

is_retryable dan retry_after menentukan logika percobaan ulang di sisi pemanggil. retry_after berupa string bergaya HTTP (dalam detik atau tanggal HTTP) yang diberikan oleh server saat ditetapkan.

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

Setiap CursorAgentError mencakup request_id jika server mengembalikannya. Selalu catat ID tersebut saat menampilkan error agar tim dukungan dapat melacak kegagalan tersebut.

IntegrationNotConnectedError

class IntegrationNotConnectedError(ConfigurationError):    provider: str   # misalnya "github", "gitlab", "azuredevops"    help_url: str   # tautan Dashboard untuk menyambung ulang

Gunakan help_url untuk mengarahkan pengguna ke alur penyambungan kembali yang tepat. Provider baru dapat ditambahkan tanpa merilis SDK.

AgentBusyError

Agen cloud hanya mengizinkan satu run aktif dalam satu waktu. AgentBusyError muncul saat Anda memanggil agent.send() (atau membuat run dengan cara lain) ketika run lain pada agen yang sama masih berstatus CREATING atau RUNNING.

is_retryable bernilai False. Percobaan ulang langsung akan terus gagal hingga run aktif mencapai status terminal atau Anda membatalkannya. Respons 409 lainnya, seperti agent_archived, akan memunculkan ConfigurationError.

Tunggu hingga run aktif selesai, batalkan dengan run.cancel(), atau cek secara berkala Agent.list_runs() sebelum mengirim lagi:

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

Agent lokal tidak memunculkan AgentBusyError. Teruskan local={"force": True} ke send() untuk menghentikan local run yang macet sebelum memulai yang baru.

UnsupportedRunOperationError

class UnsupportedRunOperationError(ConfigurationError):    operation: str

Dimunculkan ketika operasi Run tidak diizinkan pada run saat ini. Kasus yang paling umum adalah memanggil run.cancel() pada run yang sudah berada dalam status terminal.

run.supports(operation) dan run.unsupported_reason(operation) melaporkan kapabilitas tingkat SDK untuk nama operasi ("stream", "wait", "cancel", "conversation") dan tidak memeriksa status run. Baca run.status untuk memastikan pemanggilan yang bergantung pada status aman dilakukan.

Pemecahan masalah

Atur CURSOR_SDK_LOG=debug (atau info) untuk menambahkan handler stderr ke logger internal SDK. SDK hanya mengonfigurasi logger cursor_sdk miliknya, sehingga tidak akan mengganggu konfigurasi logging aplikasi host.

CURSOR_SDK_LOG=debug python my_script.py

Biner bridge bawaan diinstal sebagai cursor-sdk-bridge di PATH bersama package. Jalankan langsung untuk memastikan build yang disertakan dalam wheel Anda:

cursor-sdk-bridge --help

Keterbatasan yang diketahui

  • Schema payload pemanggilan tool memang tidak diketik secara ketat.
  • Server MCP inline tidak dipertahankan setelah Agent.resume(). Teruskan kembali saat melanjutkan jika diperlukan.
  • Tool kustom (local.custom_tools) dan pembatasan kumpulan alat (tools, disallowed_tools) hanya tersedia untuk agent lokal. Pembatasan ini tidak dipertahankan pada agent; teruskan kembali saat melanjutkan.
  • Pengunduhan artifact belum diimplementasikan untuk agent lokal.
  • local.setting_sources (beserta path MCP dan subagent berbasis file yang diaturnya) tidak berlaku untuk agen cloud. Cloud selalu memuat project, team, dan plugins.
  • Hook hanya berbasis file (.cursor/hooks.json). Tidak ada callback programatis.