@cursor/sdk 包讓你可以從自己的代碼中調用 Cursor 的智能體。現在,原本運行在 Cursor IDE、CLI 和網頁端 app 中的同一智能體,也可以通過 TypeScript 腳本調用。在 Cursor 中運行 /sdk 技能即可快速入門。
Cookbook¶
Cursor
Cookbook 提供端到端示例:包括 SDK
快速開始、app-builder 原型工具、面向雲端
代理的 看板,以及 編程智能體
CLI。這些示例可作爲構建 CI 自動修復機器人、缺陷分診 worker、代碼評審流程、嵌入產品的智能體和編排器的良好起點。
概覽¶
SDK 通過統一接口封裝本地和雲端運行時。無論智能體在何處運行,編寫的代碼都相同。
| 運行時 | 功能 | 適用場景 |
|---|---|---|
| 本地 | 在 Node 進程中以內聯方式運行智能體循環。文件直接從磁盤讀取。 | 針對工作樹運行的開發腳本和 CI 檢查。 |
| 雲端 (由 Cursor 託管) | 在已克隆倉庫的隔離 VM 中運行。VM 由 Cursor 運行。 | 調用方沒有倉庫、需要並行運行多個智能體,或需要在調用方斷開連接後繼續運行時。 |
本地指本地智能體循環,而非本地模型¶
“本地”描述的是智能體循環和文件系統訪問的運行位置,而不是
模型的運行位置。兩種模式下,所有推理均通過 Cursor 託管的模型進行。
本地模式會將文件保留在你的機器上;雲端模式則在
Cursor 環境中運行。無論哪種情況,模型本身均由託管服務提供。
運行時由傳遞給 Agent.create() 的鍵 (local 或 cloud) 決定。兩種運行時都使用相同的 CURSOR_API_KEY。
如需瞭解 REST API,請參閱 Cloud Agents API。如需瞭解其他語言,請參閱 SDK Bridge。
身份驗證¶
創建智能體前,請設置 CURSOR_API_KEY (或傳入 apiKey) 。對於尚未預配密鑰的交互式主機,Cursor.auth.login() 會通過瀏覽器登錄簽發並存儲密鑰。
SDK 支持將用戶 API 密鑰和服務賬戶 API 密鑰用於本地和雲端運行。暫不支持團隊 Admin API 密鑰。
- Cursor Dashboard → API Keys 中的用戶 API 密鑰
- 團隊設置中的服務賬戶 API 密鑰。請參閱服務賬戶
export CURSOR_API_KEY="your-key"
用量與計費¶
SDK 運行與 IDE 和 Cloud Agents 運行適用相同的定價、請求池和隱私模式規則。費用會顯示在團隊的用量儀表盤中,並帶有 SDK 標籤。
服務賬戶 API 密鑰的費用將計入擁有該服務賬戶的團隊。用戶 API 密鑰的費用將計入對應用戶的方案。
如需在代碼中讀取每次運行的 token 數量,請參閱 Token 用量。如需獲取某個智能體運行的已計費用量和美元費用,請參閱 Agent.getUsage()。
核心概念¶
| 概念 | 描述 |
|---|---|
| 智能體 | 持久化容器,包含對話狀態、工作區配置和設置,可跨多個提示詞持續存在。 |
| 運行 | 一次提示詞提交,擁有獨立的流、狀態、結果和取消操作。 |
| SDKMessage | 運行期間發出的標準化流事件,在所有運行時中具有相同結構。 |
安裝¶
npm install @cursor/sdk
包名以 @ 開頭。npm 上不存在不帶 @ 的 cursor/sdk。
運行時支持¶
SDK 要求 Node.js 22.13 或更高版本。它提供按平臺劃分的 @cursor/sdk-<os>-<arch> 二進制文件,用於沙盒隔離和 ripgrep,因此這是一個以 Node 爲主的包。
導入 @cursor/sdk 時不會立即加載本地智能體棧。本地執行器會在首次本地 acquire 時加載,因此僅使用雲端功能或類型的用戶無需承擔本地導入開銷。進程中的第一個本地智能體會產生一次性導入開銷,之後模塊會保持緩存。
@cursor/sdk 發佈自包含的 .d.ts 文件,因此無需拉取未發佈的工作區包即可解析類型。升級後,請重新運行類型檢查。TurnEndedUpdate 等流類型會解析爲實際類型,而不是 any。
單文件捆綁包和編譯型可執行文件¶
@cursor/sdk/bundled 是 SDK 的自包含單文件構建,提供與 @cursor/sdk 相同的公共 API。當你的應用以單個文件形式發佈時,請使用它:通過 bun build --compile 生成的獨立二進制可執行文件,或由 esbuild 生成的單文件捆綁包。
默認構建會在運行時按需加載部分模塊。單文件捆綁器無法跟蹤這些加載,因此編譯後的應用在首次調用 Agent.create() 時會失敗,並報出類似 Cannot find module './986.js' 的錯誤。打包入口將所有內容放入一個文件中,因此捆綁器會預先嵌入整個 SDK。
| 入口 | 內容 |
|---|---|
@cursor/sdk/bundled |
@cursor/sdk 導出的全部內容。 |
@cursor/sdk/bundled/sqlite |
SqliteLocalAgentStore,與 @cursor/sdk/sqlite 相同。 |
import { Agent } from "@cursor/sdk/bundled";
const agent = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
model: { id: "composer-2.5" },
local: { cwd: process.cwd() },
});
像平常一樣使用 Bun 編譯:
bun build --compile main.ts --outfile my-agent
以下幾點需要注意:
- 打包入口在 Bun 上運行,包括通過
bun build --compile生成的可執行文件。它們也可在 Node 上加載,但 SQLite 存儲在該環境中不可用,因此默認的本地智能體存儲會回退到 JSONL。不以單文件形式發佈的 Node 應用應繼續導入@cursor/sdk。 - **
zod、@bufbuild/protobuf和@connectrpc/*包會從你自行安裝的依賴中解析。**它們隨@cursor/sdk提供,打包工具會嵌入一份共享副本,因此傳遞給自定義工具的 Zod schema 能繼續正常工作。 - **原生二進制文件不能包含在 JavaScript bundle 中。**沙盒隔離和內置 ripgrep 由各平臺對應的
@cursor/sdk-<os>-<arch>包提供。請將node_modules/@cursor/sdk-<os>-<arch>/放在編譯後的可執行文件旁,SDK 會在那裏找到它。否則,搜索會回退到PATH中的rg,啓用sandboxOptions則會拋出ConfigurationError。
打包入口的類型解析方式與 @cursor/sdk 相同。無需更改 TypeScript 配置。
快速開始¶
最快的入門方式:讓本地智能體針對當前工作樹運行,並即時接收事件流。有關雲端設置,請參閱下方的創建智能體。
import { Agent } from "@cursor/sdk";
const agent = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
model: { id: "composer-2.5" },
local: { cwd: process.cwd() },
});
const run = await agent.send("Summarize what this repository does");
for await (const event of run.stream()) {
console.log(event);
}
每個事件都是可區分的 SDKMessage。流式傳輸介紹瞭如何提取助手文本、處理工具調用,以及通過 await using 清理資源。有關一次性提示詞 (創建、運行、釋放資源) ,請參閱 Agent.prompt()。
快速開始會自動批准工具調用¶
默認本地智能體會執行工具調用 (shell、編輯、寫入等) ,無需
請求批准;無界面模式下不會提示人工介入。若要控制工具調用,請配置
鉤子 (如 beforeShellExecution 或
preToolUse) ,或通過 local.sandboxOptions.enabled:
true 運行。
創建智能體¶
function Agent.create(options: AgentOptions): Promise<SDKAgent>;
Agent.create() 會驗證選項,並立即返回句柄。傳入 local 或 cloud 以選擇運行時。
// 本地智能體
const agent = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
model: { id: "composer-2.5" },
local: { cwd: "/path/to/repo" },
});
// 雲端代理
const agent = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
model: { id: "composer-2.5" },
cloud: {
repos: [{ url: "https://github.com/your-org/your-repo", startingRef: "main" }],
autoCreatePR: true,
},
});
agent.agentId 會立即賦值。本地智能體的 ID 爲 agent-<uuid>;雲端代理的 ID 爲 bc-<uuid>。
SDK 啓動的雲端代理不會顯示在默認智能體列表中。要在 Cursor Web 或 Cursor 窗口中
查看它們,請點擊 篩選 > 來源 > SDK。
無代碼倉庫的雲端代理¶
雲端代理可在不含代碼倉庫的空 VM 上運行。傳入 cloud 並將 repos 列表留空,或者完全省略 repos。省略 cloud 則會選擇本地運行時。
const agent = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
cloud: { repos: [] },
});
const run = await agent.send(
"Research the top 3 TypeScript testing frameworks and summarize."
);
console.log((await run.wait()).result);
必須爲您的賬戶或團隊啓用無倉庫智能體。代碼倉庫範圍的 API 密鑰無法創建此類智能體;請改用不受限制的服務賬戶密鑰或用戶 API 密鑰。
會話環境變量¶
對於雲端代理,當運行需要短期憑證或其他僅供該智能體使用的值時,請傳入 cloud.envVars。
const agent = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
cloud: {
repos: [{ url: "https://github.com/your-org/your-repo" }],
envVars: {
STAGING_API_TOKEN: process.env.STAGING_API_TOKEN!,
},
},
});
這些值會在靜態存儲時加密,注入雲端代理的 shell,並在刪除智能體時一併刪除。envVars 不能與調用方提供的 agentId 同時使用;請省略 agentId,並從 agent.agentId 讀取服務器簽發的 ID。變量名不能以 CURSOR_ 開頭。
對於僅需在單次運行期間存在的值,請改用 agent.send() 傳遞。請參閱單次運行的環境變量。
智能體元數據¶
使用 cloud.metadata 爲雲端代理添加自定義 string 標籤。這些標籤會隨智能體持久保存,並可通過 Agent.get() 和 Agent.list() 的 SDKAgentInfo.metadata 返回。這些標籤不同於 VM 內的
智能體元數據 API;該 API 會在 VM 內提供當前
運行的 ID、所有者、輪次和工作區。
const agent = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
cloud: {
repos: [{ url: "https://github.com/your-org/your-repo" }],
metadata: {
end_user_id: "user-123",
ticket_id: "ENG-456",
},
},
});
模型參數¶
使用 model.params 傳遞模型專屬選項,例如 reasoning effort。參數 ID 和取值因模型而異。使用 Cursor.models.list() 查看您的賬戶支持哪些參數和預設變體。
對於舊版按請求計費方案,如果所選模型需要,Cursor 會自動啓用 Max Mode。
Composer 2 會重新路由至 Composer 2.5¶
Composer 2 已停止服務。仍傳遞 composer-2 或
composer-2-fast 的 SDK 請求會在認證時重新路由至 Composer 2.5,因此現有
腳本可繼續運行。如果您依賴 composer-2-fast 變體,請確認
快速模式的行爲仍符合您的預期。
const agent = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
model: {
id: "composer-2.5",
params: [{ id: "fast", value: "true" }],
},
local: { cwd: process.cwd() },
});
Cursor Router¶
Cursor Router 會爲每個 Auto 請求選擇模型。在 SDK 中,Router 是帶有 optimize_for 參數的 auto-smart 模型。它適用於 Teams 和企業版。企業版管理員必須先爲團隊啓用 Router,auto-smart 纔會出現在目錄中。
Cursor SDK 是智能體 SDK,而非獨立的模型推理或聊天補全 API。Router 會爲能理解工作區、調用工具、運行命令和編輯文件的 Cursor 智能體運行選擇模型。Cursor 目前未提供可用於任意模型調用的原始 Router 端點文檔。
選擇 Cost、Balance 或 Intelligence¶
傳入 auto-smart,並顯式設置 optimize_for:
| 產品標籤 | SDK 值 |
|---|---|
| Cost | cost |
| Balance | balanced |
| Intelligence | intelligence |
產品文案中使用 Balance。balanced 僅用作 SDK 傳輸值。
import { Agent } from "@cursor/sdk";
await using agent = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
model: {
id: "auto-smart",
params: [{ id: "optimize_for", value: "balanced" }],
},
local: { cwd: process.cwd() },
});
const run = await agent.send("Find and fix the failing authentication test");
const result = await run.wait();
console.log(result.status);
console.log(result.requestId);
始終傳遞 optimize_for。請勿省略該字段,也不要傳遞舊版 default 值;通過目錄發現是受支持的合約。
在模型目錄中查找 Router¶
Cursor.models.list() 會返回當前 API 密鑰的賬戶和團隊可用的模型、參數定義及預設變體。Router 可用時,Cursor Router 會顯示爲 auto-smart。團隊管理員可以禁用 Router,或限制成員可選擇的優化模式。
在硬編碼選擇之前,應以目錄爲準:
import { Cursor, type ModelSelection } from "@cursor/sdk";
const models = await Cursor.models.list();
const router = models.find((model) => model.id === "auto-smart");
const optimizeFor = router?.parameters?.find(
(parameter) => parameter.id === "optimize_for",
);
if (!router || !optimizeFor) {
throw new Error(
"Cursor Router is not available for this API key. Verify that Router is enabled for the key's team.",
);
}
const requestedMode = "balanced";
const allowedValues = new Set(
optimizeFor.values.map(({ value }) => value),
);
if (!allowedValues.has(requestedMode)) {
throw new Error(
`Router mode "${requestedMode}" is not enabled for this team.`,
);
}
const model: ModelSelection = {
id: router.id,
params: [{ id: optimizeFor.id, value: requestedMode }],
};
按運行切換模式¶
在 agent.send() 中覆蓋模型,以更改某次運行的 Router 模式:
const run = await agent.send("Handle this complex migration", {
model: {
id: "auto-smart",
params: [{ id: "optimize_for", value: "intelligence" }],
},
});
單次運行的模型覆蓋會持續生效。後續發送時若未指定覆蓋,仍會使用新的模型選擇。參閱單次運行模型覆蓋。
模型 ID:auto-smart、auto 和 default¶
| 選擇 | 含義 |
|---|---|
搭配 optimize_for 使用 auto-smart |
Cursor Router。需要 Cost、Balance 或 Intelligence 時使用。 |
{ id: "auto" } |
當目錄中沒有指定模型時,由服務器選擇的 Auto 回退方案。如需顯式指定 Router 模式,優先使用 auto-smart。 |
省略 optimize_for 或傳入 default |
不受支持的 Router 合約。請始終查詢允許的值,並傳入 cost、balanced 或 intelligence。 |
計費與路由用量池¶
- 所有 Auto 模式均按每個請求所路由模型的標價計費。
- 底層模型可能因請求而異。需要進行可復現的比較時,請優先使用固定的模型 ID。
- 企業版模型允許列表決定路由用量池。屏蔽必需模型可能會禁用 Router。
有關當前費率和路由用量池,請參閱 Cursor Router 和 Auto 模式。
Router 缺失的疑難排查¶
如果找不到 auto-smart,或優化模式被拒絕:
- 調用
Cursor.models.list()。 - 確認結果中包含
auto-smart。 - 確認
optimize_for包含所需的值 (cost、balanced或intelligence) 。 - 確認與 API 密鑰關聯的團隊已啓用 Router。
- 如果您屬於多個團隊,請確認該密鑰在預期的團隊上下文中使用。
- 如果 Router 不可用或無法選擇有效的底層模型,請檢查團隊的模型訪問策略。
SDKAgent¶
Agent.create() 和 Agent.resume() 返回的句柄。
interface SDKAgent {
readonly agentId: string;
readonly model: ModelSelection | undefined;
send(message: string | SDKUserMessage, options?: SendOptions): Promise<Run>;
close(): void;
reload(): Promise<void>;
[Symbol.asyncDispose](): Promise<void>;
listArtifacts(): Promise<SDKArtifact[]>;
downloadArtifact(path: string): Promise<Buffer>;
getUsage(options?: GetUsageOptions): Promise<AgentUsage>;
}
| 成員 | 描述 |
|---|---|
agentId |
穩定的智能體標識符。本地爲 agent-<uuid>,雲端爲 bc-<uuid>。 |
model |
當前模型選擇。每次成功調用 send({ model }) 後都會更新。在被設置前爲 undefined (包括調用方未傳入 model 的已恢復智能體) 。 |
send |
使用給定提示詞啓動新的運行。返回 Run 句柄。 |
close |
開始釋放資源,不等待完成。即發即棄。 |
reload |
重新讀取文件系統配置 (鉤子、項目 MCP、子智能體) ,無需釋放資源。 |
[Symbol.asyncDispose] |
異步釋放資源。與 await using 搭配使用以自動清理。 |
listArtifacts |
列出智能體生成的文件 (僅限雲端;本地返回空) 。 |
downloadArtifact |
按路徑下載文件 (僅限雲端;本地會拋出異常) 。 |
getUsage |
獲取智能體的計費 token 用量和美元費用。 |
Agent.prompt()¶
function Agent.prompt(message: string, options?: AgentOptions): Promise<RunResult>;
一次性便捷方法:創建智能體、發送一條提示詞、等待運行完成後釋放資源。
const result = await Agent.prompt("What does the auth middleware do?", {
apiKey: process.env.CURSOR_API_KEY!,
model: { id: "composer-2.5" },
local: { cwd: process.cwd() },
});
發送消息¶
每次調用 agent.send() 都會返回一個 Run。智能體會在多次運行之間保留對話上下文;一次運行對應處理一個提示詞的工作單元。
運行¶
type RunStatus = "running" | "finished" | "error" | "cancelled";
type RunOperation = "stream" | "wait" | "cancel" | "conversation";
interface Run {
readonly id: string;
readonly requestId?: string;
readonly agentId: string;
readonly status: RunStatus;
readonly result?: string;
readonly error?: RunError;
readonly model?: ModelSelection;
readonly durationMs?: number;
readonly usage?: TokenUsage;
readonly git?: RunGitInfo;
readonly createdAt?: number;
stream(): AsyncGenerator<SDKMessage, void>;
wait(): Promise<RunResult>;
cancel(): Promise<void>;
conversation(): Promise<ConversationTurn[]>;
supports(operation: RunOperation): boolean;
unsupportedReason(operation: RunOperation): string | undefined;
onDidChangeStatus(listener: (status: RunStatus) => void): () => void;
}
interface RunGitInfo {
branches: Array<{ repoUrl: string; branch?: string; prUrl?: string }>;
}
interface RunError {
message: string;
code?: string;
}
interface TokenUsage {
inputTokens: number;
outputTokens: number;
cacheReadTokens: number;
cacheWriteTokens: number;
totalTokens: number;
reasoningTokens?: number;
}
interface RunResult {
id: string;
requestId?: string;
status: "finished" | "error" | "cancelled";
result?: string;
error?: RunError;
model?: ModelSelection;
durationMs?: number;
usage?: TokenUsage;
git?: RunGitInfo;
}
流式傳輸¶
const run = await agent.send("Find the bug in src/auth.ts");
for await (const event of run.stream()) {
switch (event.type) {
case "assistant":
for (const block of event.message.content) {
if (block.type === "text") process.stdout.write(block.text);
}
break;
case "thinking":
process.stdout.write(event.text);
break;
case "tool_call":
console.log(`[tool] ${event.name}: ${event.status}`);
break;
case "status":
console.log(`[status] ${event.status}`);
break;
}
}
// 在同一智能體中繼續對話。上一次運行的對話狀態
// 會自動加載。
const run2 = await agent.send("Fix it and add a regression test");
await run2.wait();
要隨文本發送圖像:
const run = await agent.send({
text: "What's in this screenshot?",
images: [{ data: base64Png, mimeType: "image/png" }],
});
不使用流式傳輸時等待¶
const result = await run.wait();
console.log(result.status); // "finished" | "error" | "cancelled"
console.log(result.result); // 最終助手文本(如有)
console.log(result.error); // 運行失敗時爲 { message, code? }
console.log(result.model); // 本次運行使用的已解析 ModelSelection
console.log(result.durationMs);
console.log(result.usage); // 累計 TokenUsage;不可用時爲 undefined
console.log(result.git); // 在 Cloud 上爲 { branches: [{ repoUrl, branch?, prUrl? }] }
最終的助手文本以 string 形式存儲在 result.result 中。無需在 text、message、messages 或 content 字段中查找。如果需要按步驟獲取會話記錄,請調用 run.conversation(),以獲得結構化的 ConversationTurn[] 視圖:
const result = await run.wait();
const finalText = result.result ?? "";
const turns = await run.conversation();
const lastAssistant = turns
.flatMap((t) => (t.type === "agentConversationTurn" ? t.turn.steps : []))
.filter((s) => s.type === "assistantMessage")
.at(-1);
console.log(lastAssistant?.message.text);
取消一次運行¶
await run.cancel();
取消運行。狀態將變爲 "cancelled",即時流將中止,正在進行的工具調用將停止,run.wait() 將以 status: "cancelled" 完成。部分輸出 (截至目前生成的助手文本) 會保留在 Run 對象中。
運行中的本地和雲端運行均支持取消;如果運行已結束,則此操作無效。
讀取運行狀態¶
console.log(run.status); // "running" | "finished" | "error" | "cancelled"
const stop = run.onDidChangeStatus((status) => {
console.log(`status changed to ${status}`);
});
// 調用 `stop()` 移除監聽器。
// 此次運行中累積對話的按輪次結構化視圖
const turns = await run.conversation();
run.conversation() 返回該運行的 ConversationTurn[] (包含步驟的智能體輪次,或包含命令和輸出的 shell 輪次) 。無需訂閱即時流,即可用它渲染或持久化該運行的結構化歷史記錄。
使用量¶
運行時提供使用量時,運行會報告該用量。運行期間可從 run.usage 讀取累計總量,調用 run.wait() 後可從 result.usage 讀取。兩者都包含所有報告用量的輪次彙總而成的 TokenUsage;如果沒有任何輪次報告用量,則兩者均爲 undefined (例如,已取消且從未完成任何輪次的運行,或不提供用量信息的運行時) 。
interface TokenUsage {
inputTokens: number;
outputTokens: number;
cacheReadTokens: number;
cacheWriteTokens: number;
totalTokens: number;
reasoningTokens?: number;
}
| 字段 | 描述 |
|---|---|
inputTokens |
發送給模型的提示詞 token。 |
outputTokens |
模型生成的 token。 |
cacheReadTokens |
從提示詞緩存讀取的 token。 |
cacheWriteTokens |
寫入提示詞緩存的 token。 |
totalTokens |
inputTokens + outputTokens + cacheReadTokens + cacheWriteTokens。不包括 reasoningTokens。 |
reasoningTokens |
推理 token,是 outputTokens 的一部分。模型或運行時未報告時省略。 |
const result = await run.wait();
if (result.usage) {
console.log(`total: ${result.usage.totalTokens}`);
console.log(`in: ${result.usage.inputTokens}, out: ${result.usage.outputTokens}`);
console.log(
`cache read/write: ${result.usage.cacheReadTokens}/${result.usage.cacheWriteTokens}`
);
} else {
console.log("no usage reported for this run");
}
reasoningTokens 已計入 outputTokens,因此 totalTokens 不再重複計入,以避免重複計算。
如需獲取流式傳輸過程中每輪的用量數據,請處理 usage 流事件 (SDKUsageMessage)。它會在每個上報用量的輪次結束時觸發一次,並攜帶該輪的 TokenUsage。run.usage 和 result.usage 在整個運行過程中始終爲累計值。
for await (const event of run.stream()) {
if (event.type === "usage") {
console.log(`turn used ${event.usage.totalTokens} tokens`);
}
}
令牌計數由運行時報告,不代表費用。要獲取智能體運行的已計費用量和美元費用,請調用 agent.getUsage()。
使用 requestId 關聯 Run¶
每次調用 agent.send() 時,平臺都會生成一個 UUID,並通過 requestId 字段在 Run 和 RunResult 中提供。使用它將腳本或 CI Run 與後端日誌、使用分析和支持線程關聯,而不要僅憑 agentId 猜測。
const run = await agent.send("Audit the auth middleware");
console.log(run.requestId); // 例如:"6e0d261c-86a2-4383-89f0-9162c1c10662"
const result = await run.wait();
logger.info({ requestId: result.requestId }, "run finished");
requestId 會隨運行一併持久化,因此可在內存、SQLite 和 JSONL 本地存儲之間往返傳遞;後端返回該值時,也會將其設置到雲端運行中。請將其與錯誤中的 error.requestId 一併記錄,以便同一標識符貫穿成功和失敗路徑。
單次運行模型覆蓋¶
傳遞給 agent.send() 的 model 會覆蓋智能體在該次運行中的模型選擇,之後會持續生效:後續發送時若未指定覆蓋,將繼續使用新模型。若要切換回原來的模型,請傳遞另一個 model 覆蓋,或通過 agent.model 讀取當前選擇。
const run = await agent.send("Plan the refactor", {
model: { id: "composer-2.5", params: [{ id: "fast", value: "true" }] },
});
console.log(agent.model); // 發送成功後更新爲該覆蓋設置
run.model 和 result.model 反映該次運行實際使用的模型選擇,且運行開始後不可更改。
單次運行的環境變量¶
雲端代理還可接收僅用於單次運行的環境變量。在 agent.send() 中傳入 cloud.envVars,這些值會注入智能體在該次運行中使用的 shell。運行結束後,它們會從 VM 中移除,下一次運行無法訪問。對於在輪次之間輪換的憑據,這種方式很合適,例如在讓智能體使用前剛剛簽發的短期部署令牌。
const run = await agent.send("Deploy the preview environment", {
cloud: {
envVars: {
DEPLOY_TOKEN: await mintShortLivedToken(),
},
},
});
如果單次運行的變量與 Agent.create() 的 cloud.envVars 中某個智能體範圍變量同名,該次運行會優先使用單次運行的值;下一次運行時則會恢復使用智能體範圍的值。
單次運行變量同樣適用於首次發送。SDK 會在創建智能體時一併傳遞這些變量,並將其作用範圍限定爲初始運行,因此不會持久保存在智能體中。與智能體範圍變量一樣,它們在靜態存儲時會加密,且名稱不能以 CURSOR_ 開頭。
單次運行的環境變量僅適用於雲端代理,且不適用於針對公開倉庫運行的智能體。對於本地智能體,智能體進程會繼承你自己的環境,因此請在調用 send() 前爲進程設置變量。
對話模式¶
傳入 mode: "plan" 或 mode: "agent",控制運行是先探索並制定方案,還是直接實施更改。有關 Plan 模式在產品中的作用,請參閱 Plan 模式。
在 Agent.create() 中設置 mode,以確定首次運行的模式。在後續的 agent.send() 調用中,省略 mode 可保留對話當前的模式;傳入 mode 則僅切換該次運行的模式。
const agent = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
model: { id: "composer-2.5" },
mode: "plan",
cloud: {
repos: [{ url: "https://github.com/your-org/your-repo" }],
},
});
await (await agent.send("Design the auth refactor")).wait();
await (await agent.send("Looks good, start building", { mode: "agent" })).wait();
流式獲取原始增量¶
run.stream() 會產生規範化的 SDKMessage 事件。若需獲取更底層的更新 (逐 token 文本、流式傳入的工具調用 args、思考增量、嵌套任務更新和步驟邊界) ,請向 send() 傳入 onDelta 和 onStep 回調:
const run = await agent.send("Refactor the utils module", {
onDelta: ({ update }) => {
if (update.type === "text-delta") process.stdout.write(update.text);
if (update.type === "thinking-delta") process.stdout.write(update.text);
},
onStep: ({ step }) => {
console.log(`[step] ${step.type}`);
},
});
在處理下一次更新前,會先等待回調完成,因此你可以施加背壓。InteractionUpdate涵蓋text-delta、thinking-delta、thinking-completed、tool-call-started、tool-call-completed、tool-call-delta、partial-tool-call、token-delta、step-started、step-completed、turn-ended,以及少量摘要和 shell 輸出增量。
單次發送選項¶
| 屬性 | 類型 | 描述 |
|---|---|---|
model |
ModelSelection |
單次發送的模型覆蓋設置。若省略,則使用 agent.model。粘性:發送成功後會更新 agent.model。 |
mode |
"agent" \| "plan" |
單次發送的對話模式覆蓋設置。若在後續消息中省略,則保留對話當前的模式。 |
mcpServers |
Record<string, McpServerConfig> |
內聯 MCP 服務器定義。會完全替換此次運行創建時配置的服務器。 |
onStep |
(args: { step }) => void \| Promise<void> |
每個對話步驟完成後 (文本、思考或工具批次) 調用的回調。 |
onDelta |
(args: { update }) => void \| Promise<void> |
每個原始 InteractionUpdate 的回調。 |
idempotencyKey |
string |
可選的客戶端生成冪等鍵,用於此次發送。 |
cloud.envVars |
Record<string, string> |
僅限雲端代理。爲此次運行注入單次運行的環境變量,運行結束後會移除。僅在此次運行中按名稱覆蓋智能體範圍內的 cloud.envVars。 |
local.force |
boolean |
僅限智能體。默認值爲 false。開始發送此消息前,使卡住的活躍運行過期。雲端會在服務器端返回 409 agent_busy,因此無需對應選項。 |
local.customTools |
Record<string, SDKCustomTool> |
僅限智能體。此次運行的自定義工具。會替換該智能體創建時配置的 local.customTools,僅對此次運行生效。 |
接下來的三個部分詳細介紹 SDKMessage、InteractionUpdate 和 ConversationTurn。首次閱讀時可快速瀏覽或跳過;恢復智能體將繼續正文。
流事件¶
由 run.stream() 產生的事件。可通過 type 區分。所有事件均包含 agent_id 和 run_id。
type SDKMessage =
| SDKSystemMessage
| SDKUserMessageEvent
| SDKAssistantMessage
| SDKThinkingMessage
| SDKToolUseMessage
| SDKStatusMessage
| SDKTaskMessage
| {
type: "request";
agent_id: string;
run_id: string;
request_id: string;
}
| SDKUsageMessage;
type |
描述 | 關鍵字段 |
|---|---|---|
"system" |
初始化元數據。在運行開始時發出一次。 | subtype? ("init"), model?, tools? |
"user" |
此次運行的用戶提示詞回顯。 | message.content: TextBlock[] |
"assistant" |
模型文本輸出。 | message.content: (TextBlock \| ToolUseBlock)[] |
"thinking" |
思考內容。 | text, thinking_duration_ms? |
"tool_call" |
工具調用生命週期。開始時攜帶 args 發出,完成時再次攜帶 result 發出。 |
call_id, name, status, args?, result?, truncated? |
"status" |
雲端運行生命週期狀態變化。 | status, message? |
"task" |
任務級里程碑和摘要。 | status?, text? |
"request" |
等待用戶輸入或批准。 | request_id |
"usage" |
每輪 token 使用量;運行時報告後,會在該輪結束時發出一次。 | usage (TokenUsage) |
流完成後,結果數據 (最終文本、模型、時長、累計 token 使用量、Git 元數據) 會保存在 Run 對象中。使用 run.wait() 讀取。
工具調用 schema 不穩定。
tool_call事件中的args和result負載反映各工具的內部結構,可能會隨工具演進而變化。工具名稱也可能被重命名或替換。請將args和result視爲unknown,並進行防禦性解析。事件信封 (type、call_id、name、status) 是穩定的。
消息類型¶
interface SDKSystemMessage {
type: "system";
subtype?: "init";
agent_id: string;
run_id: string;
model?: ModelSelection;
tools?: string[];
}
interface SDKUserMessageEvent {
type: "user";
agent_id: string;
run_id: string;
message: { role: "user"; content: TextBlock[] };
}
interface SDKAssistantMessage {
type: "assistant";
agent_id: string;
run_id: string;
message: {
role: "assistant";
content: Array<TextBlock | ToolUseBlock>;
};
}
interface SDKThinkingMessage {
type: "thinking";
agent_id: string;
run_id: string;
text: string;
thinking_duration_ms?: number;
}
interface SDKToolUseMessage {
type: "tool_call";
agent_id: string;
run_id: string;
call_id: string;
name: string;
status: "running" | "completed" | "error";
args?: unknown;
result?: unknown;
truncated?: { args?: boolean; result?: boolean };
}
interface SDKStatusMessage {
type: "status";
agent_id: string;
run_id: string;
status: "CREATING" | "RUNNING" | "FINISHED" | "ERROR" | "CANCELLED" | "EXPIRED";
message?: string;
}
interface SDKTaskMessage {
type: "task";
agent_id: string;
run_id: string;
status?: string;
text?: string;
}
interface SDKUsageMessage {
type: "usage";
agent_id: string;
run_id: string;
usage: TokenUsage;
}
interface TextBlock {
type: "text";
text: string;
}
interface ToolUseBlock {
type: "tool_use";
id: string;
name: string;
input: unknown;
}
大多數工具調用會發出兩次 SDKToolUseMessage:首次 status: "running",並填充 args;完成時再次發出,status: "completed" (或 "error") ,並填充 result。truncated 標誌表示 SDK 是否因負載過大而截斷了 args 或 result。
SDKStatusMessage 涵蓋雲端的生命週期狀態轉換。CREATING 表示 VM 配置和倉庫克隆;RUNNING 表示智能體正在工作;其餘均爲終態。
每個報告使用量的輪次結束時,都會發出一次 SDKUsageMessage,其中包含該輪的 TokenUsage。跨輪次的累計總用量保存在 run.usage 和 result.usage 中。參閱 使用量。
交互更新¶
InteractionUpdate 是傳遞給 agent.send() 的 onDelta 回調的原始增量類型。與 SDKMessage 事件相比,更新粒度更細:文本按 token 流式傳輸,工具調用會隨着 args 的累積報告部分狀態,思考內容會即時傳入。
type InteractionUpdate =
| TextDeltaUpdate
| ThinkingDeltaUpdate
| ThinkingCompletedUpdate
| ToolCallStartedUpdate
| ToolCallCompletedUpdate
| ToolCallDeltaUpdate
| PartialToolCallUpdate
| TokenDeltaUpdate
| StepStartedUpdate
| StepCompletedUpdate
| TurnEndedUpdate
| UserMessageAppendedUpdate
| SummaryUpdate
| SummaryStartedUpdate
| SummaryCompletedUpdate
| ShellOutputDeltaUpdate;
更新類型¶
interface TextDeltaUpdate {
type: "text-delta";
text: string;
}
interface ThinkingDeltaUpdate {
type: "thinking-delta";
text: string;
}
interface ThinkingCompletedUpdate {
type: "thinking-completed";
thinkingDurationMs: number;
}
interface ToolCallStartedUpdate {
type: "tool-call-started";
callId: string;
toolCall: ToolCall;
modelCallId: string;
}
interface PartialToolCallUpdate {
type: "partial-tool-call";
callId: string;
toolCall: ToolCall;
modelCallId: string;
}
interface ToolCallCompletedUpdate {
type: "tool-call-completed";
callId: string;
toolCall: ToolCall;
modelCallId: string;
}
interface ToolCallDeltaUpdate {
type: "tool-call-delta";
callId: string;
modelCallId: string;
taskUpdate: NestedTaskUpdate;
}
type NestedTaskUpdate =
| TextDeltaUpdate
| ToolCallStartedUpdate
| ToolCallCompletedUpdate
| ThinkingDeltaUpdate
| ThinkingCompletedUpdate
| PartialToolCallUpdate
| StepStartedUpdate
| StepCompletedUpdate;
interface TokenDeltaUpdate {
type: "token-delta";
tokens: number;
}
interface StepStartedUpdate {
type: "step-started";
stepId: number;
}
interface StepCompletedUpdate {
type: "step-completed";
stepId: number;
stepDurationMs: number;
}
interface TurnEndedUpdate {
type: "turn-ended";
usage?: {
inputTokens: number;
outputTokens: number;
cacheReadTokens: number;
cacheWriteTokens: number;
reasoningTokens?: number;
};
}
interface UserMessageAppendedUpdate {
type: "user-message-appended";
userMessage: UserMessage;
}
interface SummaryUpdate {
type: "summary";
summary: string;
}
interface SummaryStartedUpdate {
type: "summary-started";
}
interface SummaryCompletedUpdate {
type: "summary-completed";
}
interface ShellOutputDeltaUpdate {
type: "shell-output-delta";
event: Record<string, unknown>;
}
ToolCallDeltaUpdate 包含任務或子智能體工具調用中一層嵌套的交互更新。模型在提交工具調用前流式傳入參數時,會發出 PartialToolCallUpdate。適用於 SDKToolUseMessage.args 的穩定性免責聲明同樣適用於此處。
對話類型¶
運行中每輪對話的結構化視圖,由 run.conversation() 返回,並作爲 onStep 回調的參數傳入。
type ConversationTurn =
| { type: "agentConversationTurn"; turn: AgentConversationTurn }
| { type: "shellConversationTurn"; turn: ShellConversationTurn };
interface AgentConversationTurn {
userMessage?: UserMessage;
steps: ConversationStep[];
}
interface ShellConversationTurn {
shellCommand?: ShellCommand;
shellOutput?: ShellOutput;
}
type ConversationStep =
| { type: "assistantMessage"; message: AssistantMessage }
| { type: "toolCall"; message: ToolCall }
| { type: "thinkingMessage"; message: ThinkingMessage };
interface AssistantMessage {
text: string;
}
interface ThinkingMessage {
text: string;
thinkingDurationMs?: number;
}
interface UserMessage {
text: string;
}
interface ShellCommand {
command: string;
workingDirectory?: string;
}
interface ShellOutput {
stdout: string;
stderr: string;
exitCode: number;
}
ToolCall 是一個涵蓋所有內置工具 (shell、edit、read、write、glob、grep、ls、semSearch、mcp、task 等) 的可辨別聯合類型。其結構僅供內部使用;請參閱“Stream events”下的穩定性說明。
恢復智能體會話¶
function Agent.resume(agentId: string, options?: Partial<AgentOptions>): Promise<SDKAgent>;
使用 Agent.resume() 通過 ID 重新連接到現有智能體。常見場景包括:重新連接之前啓動的長時間運行雲端代理,或在本地進程重新啓動後繼續對話。系統會根據 ID 前綴自動檢測運行環境 (bc- 表示雲端,其他表示本地) 。
await using agent = await Agent.resume("bc-abc123", {
apiKey: process.env.CURSOR_API_KEY!,
});
const run = await agent.send("Also update the changelog");
await run.wait();
恢復時,除非再次傳入 model,否則 agent.model 爲 undefined。內聯 mcpServers 不會在恢復後持久保留——它們通常包含機密信息,且僅存於內存中。恢復時請再次傳入,或者對於需要持續保留的服務器,使用基於文件的 MCP 配置 (.cursor/mcp.json + local.settingSources) 。
查看智能體和運行記錄¶
列出、獲取和重新加載歷史智能體。列表端點返回 { items, nextCursor? },支持基於遊標的分頁。
Agent.list()¶
function Agent.list(options?: ListAgentsOptions): Promise<ListResult<SDKAgentInfo>>;
type ListAgentsOptions = {
limit?: number;
cursor?: string;
} & (
| { runtime?: undefined }
| { runtime: "local"; cwd?: string; store?: LocalAgentStore }
| {
runtime: "cloud";
prUrl?: string;
includeArchived?: boolean;
apiKey?: string;
}
);
const { items, nextCursor } = await Agent.list({
runtime: "local",
cwd: process.cwd(),
});
Agent.get()¶
function Agent.get(agentId: string, options?: GetAgentOptions): Promise<SDKAgentInfo>;
interface GetAgentOptions {
cwd?: string; // 本地路由
apiKey?: string; // 雲端路由
store?: LocalAgentStore;
}
運行時會根據智能體 ID 前綴自動判斷 (bc- → 雲端,否則爲本地) 。
Agent.listRuns()¶
function Agent.listRuns(agentId: string, options?: ListRunsOptions): Promise<ListResult<Run>>;
type ListRunsOptions = {
limit?: number;
cursor?: string;
} & (
| { runtime?: "local"; cwd?: string; store?: LocalAgentStore }
| { runtime: "cloud"; apiKey?: string }
);
Agent.getRun()¶
function Agent.getRun(runId: string, options?: GetRunOptions): Promise<Run>;
type GetRunOptions =
| { runtime?: "local"; cwd?: string; store?: LocalAgentStore }
| { runtime: "cloud"; agentId: string; apiKey?: string };
Cloud getRun 需要父級智能體的 agentId。
Agent.cancelRun()¶
function Agent.cancelRun(runId: string, options?: GetRunOptions): Promise<void>;
當你有運行 ID 但沒有 Run 句柄時,取消該運行。
Agent.messages.list()¶
Agent.messages.list(
agentId: string,
options?: GetAgentMessagesOptions
): Promise<AgentMessage[]>;
interface GetAgentMessagesOptions {
limit?: number;
offset?: number;
runtime?: "local";
cwd?: string;
store?: LocalAgentStore;
}
interface AgentMessage {
type: "user" | "assistant";
uuid: string;
agent_id: string;
message: unknown;
}
返回本地智能體中存儲的用戶和助手消息。
Agent.getUsage()¶
獲取智能體運行的計費使用量和美元費用。可通過 handle 調用;如果沒有 handle,也可通過 ID 靜態調用。雲端代理返回按運行細分的數據;智能體返回按輪次細分的數據。傳入 runId 可將結果限定爲單個條目:雲端代理使用 run-<uuid> 格式的運行 ID;智能體使用之前 getUsage().runs[].runId 中的 ID。
agent.getUsage(options?: GetUsageOptions): Promise<AgentUsage>;
function Agent.getUsage(
agentId: string,
options?: GetUsageOptions & { apiKey?: string }
): Promise<AgentUsage>;
interface GetUsageOptions {
runId?: string;
}
interface AgentUsage {
usage: TokenUsage; // 在各個 `runs` 中彙總
cost?: UsageCost; // 在各個 `runs` 中彙總
runs: RunUsage[];
}
interface RunUsage {
runId: string;
usage: TokenUsage;
cost?: UsageCost;
}
interface UsageCost {
rawCostCents: number; // 未享受折扣的模型 token 成本;按請求計費的用量爲 0
chargedCents: number; // 實際收取的金額,已包含折扣和 Cursor Token 費用
}
const { usage, cost, runs } = await agent.getUsage();
console.log(`tokens: ${usage.totalTokens}`);
if (cost) {
console.log(`charged: $${(cost.chargedCents / 100).toFixed(2)}`);
}
for (const run of runs) {
console.log(run.runId, run.usage.totalTokens, run.cost?.chargedCents);
}
費用已包含折扣。一次運行結束後,費用可能需要片刻才能結算;在此之前不會顯示 cost。對於方案內用量、BYOK (自帶密鑰) 用量和信用額度授予的用量,chargedCents 均爲 0。
這與 使用量 是不同的視圖:run.usage 顯示單次運行的即時 token 數量,而 getUsage() 則是智能體運行的計費記錄。
雲端代理生命週期¶
雲端代理會一直保留在你的團隊工作區中,直到你將其歸檔或刪除。Agent.list({ runtime: "cloud" }) 默認不顯示已歸檔的智能體;傳入 includeArchived: true 可查看它們。按 prUrl 篩選,可找到創建特定 PR 的智能體。
function Agent.archive(agentId: string, options?: AgentOperationOptions): Promise<void>;
function Agent.unarchive(agentId: string, options?: AgentOperationOptions): Promise<void>;
function Agent.delete(agentId: string, options?: AgentOperationOptions): Promise<void>;
interface AgentOperationOptions {
cwd?: string;
apiKey?: string;
store?: LocalAgentStore;
}
await Agent.archive(agentId); // 軟刪除;仍可讀取會話記錄
await Agent.unarchive(agentId); // 恢復已歸檔的智能體
await Agent.delete(agentId); // 永久刪除;後續讀取將返回 404
SDKAgentInfo¶
Agent.list() 和 Agent.get() 返回的元數據類型。
type SDKAgentInfo = {
agentId: string;
name: string;
summary: string;
lastModified: number;
status?: "running" | "finished" | "error";
createdAt?: number;
archived?: boolean;
} & (
| { runtime?: undefined }
| { runtime: "local"; cwd?: string }
| {
runtime: "cloud";
env?: { type: "cloud" | "pool" | "machine"; name?: string };
repos?: string[];
metadata?: Record<string, string>;
}
);
Cursor 命名空間¶
提供賬戶級讀取、目錄讀取和進程級 SDK 配置。讀取方法可接受 { apiKey };如未提供,則依次使用 CURSOR_API_KEY 和已保存的瀏覽器登錄。
Cursor.auth¶
爲未預先配備 API 密鑰的主機提供交互式登錄。Cursor.auth.login() 會在瀏覽器中打開 Cursor 網站的登錄頁面,等待登錄完成後簽發用戶 API 密鑰 (默認有效期爲 90 天) ,並將其存儲在 ~/.cursor/sdk/auth.json 中。登錄後,Agent.create()、Cursor.me() 和其他讀取操作無需 apiKey 或 CURSOR_API_KEY 即可使用。
import { Cursor } from "@cursor/sdk";
await Cursor.auth.login();
const status = await Cursor.auth.status();
// { status: "已登錄", backendUrl, email?, apiKeyExpiresAtMs? }
// | { status: "已登出" }
await Cursor.auth.logout();
| 選項 | 描述 |
|---|---|
backendUrl |
API 基礎 URL。默認值依次爲 CURSOR_BACKEND_URL 和生產環境。 |
websiteUrl |
瀏覽器登錄基礎 URL。默認值依次爲 CURSOR_WEBSITE_URL 和生產環境。 |
openBrowser |
true (默認值) 會在適當情況下打開系統瀏覽器;false 則絕不打開;也可傳入函數作爲自定義打開方式。在 SSH 會話中或設置了 NO_OPEN_BROWSER 時將跳過此操作。 |
onLoginUrl |
等待前會使用登錄 URL 調用此函數,以便主機顯示該 URL。若省略此項且未打開瀏覽器,URL 會寫入 stderr。 |
signal |
用於取消等待的 AbortSignal;隨後 login 會拋出 AuthenticationError。 |
store |
持久化保存憑據的位置。默認值爲 ~/.cursor/sdk/auth.json;傳入 null 則僅在結果中返回密鑰。 |
apiKeyName |
儀表盤 API 密鑰列表中所簽發密鑰的顯示名稱。 |
apiKeyTtlMs |
所簽發密鑰的有效期,單位爲毫秒。默認值爲 90 天。 |
Cursor.auth.login() 返回
{ apiKey, email?, apiKeyExpiresAtMs }。使用 FileCredentialStore 或
InMemoryCredentialStore 爲 login()、status()
或 logout() 提供自定義 store。
SDK 中所有位置的憑據解析順序:顯式指定的 apiKey、CURSOR_API_KEY、已存儲的登錄信息。本地存儲的登錄信息不會從已安裝的 Cursor app 中讀取憑據;其中僅保存由 Cursor.auth.login() 簽發的密鑰。
Cursor.configure()¶
function Cursor.configure(options: CursorConfigureOptions): void;
interface CursorConfigureOptions {
local?: {
store?: LocalAgentStore | null;
useHttp1ForAgent?: boolean | null;
workspaceScanCacheTtlMs?: number | null;
};
}
爲後續 Agent.* 調用設置本地智能體的默認值。單次調用中指定的字段會覆蓋這些值;傳入 null 可清除先前設置的默認值。
| 選項 | 描述 |
|---|---|
local.store |
調用未指定 local.store 時使用的默認本地智能體存儲。SQLite 後端可用時,SDK 使用基於磁盤的 SQLite;否則會回退到 JsonlLocalAgentStore。 |
local.useHttp1ForAgent |
強制本地智能體後端流使用帶 SSE 的 HTTP/1.1,而非 HTTP/2。在代理之後運行,或使用不支持 HTTP/2 的 fetch 棧時很有用。由於上游 HTTP/2 兼容性問題,Bun 默認使用 HTTP/1.1。 |
local.workspaceScanCacheTtlMs |
SDK 重用工作區掃描結果 (規則、技能、AGENTS.md、忽略文件) 的時長,單位爲毫秒。默認值爲 20 秒。對於僅在部署時變更的 checkout,可在長期運行的主機中提高此值;代價是時效性降低,因爲進程啓動後添加的規則可能在這段時間內不會被發現。CURSOR_RIPWALK_CACHE_TTL_MS 環境變量可設置相同的值。 |
import { Cursor, JsonlLocalAgentStore } from "@cursor/sdk";
Cursor.configure({
local: {
store: new JsonlLocalAgentStore("/var/lib/cursor-agents"),
useHttp1ForAgent: true,
},
});
Cursor.me()¶
function Cursor.me(options?: CursorRequestOptions): Promise<SDKUser>;
interface CursorRequestOptions {
apiKey?: string;
}
interface SDKUser {
apiKeyName: string;
userId?: number;
userEmail?: string;
userFirstName?: string;
userLastName?: string;
createdAt: string;
}
Cursor.models.list()¶
function Cursor.models.list(options?: CursorRequestOptions): Promise<SDKModel[]>;
type SDKModel = ModelListItem;
interface ModelListItem {
id: string;
displayName: string;
description?: string;
aliases?: string[];
parameters?: ModelParameterDefinition[];
variants?: ModelVariant[];
}
interface ModelParameterDefinition {
id: string;
displayName?: string;
values: Array<{ value: string; displayName?: string }>;
}
interface ModelVariant {
params: ModelParameterValue[];
displayName: string;
description?: string;
isDefault?: boolean;
}
在調用 Agent.create() 或 agent.send() 前,使用 Cursor.models.list() 查詢有效的 model ID 及各模型支持的 params。參數因模型而異。常見參數包括推理 effort,以及 auto-smart 的 Cursor Router optimize_for。
可用目錄因賬戶和團隊而異。只有 API 密鑰所屬團隊可使用 Router 時,Cursor Router 纔會以 auto-smart 形式顯示。請參閱 Cursor Router。
const models = await Cursor.models.list();
const composer = models.find((model) => model.id === "composer-2.5");
console.log(composer?.parameters);
// [
// {
// id: "fast",
// displayName: "快速",
// values: [
// { value: "false" },
// { value: "true", displayName: "快速" },
// ],
// },
// ]
通過 model.params 傳入所選參數值。預設 variants 已包含有效的 params,因此可以將其複製到模型選擇中。
const agent = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
model: {
id: "composer-2.5",
params: [{ id: "fast", value: "true" }],
},
local: { cwd: process.cwd() },
});
最佳實踐¶
- 動態獲取,不要硬編碼。 在啓動時 (或每個進程啓動一次) 調用
Cursor.models.list(),並緩存結果。隨着新模型上線,模型 ID 和參數結構可能發生變化。 - 模型需要參數時,務必顯式傳入。
parameters數組非空的模型屬於參數化模型。請傳入所需參數;否則,運行時會使用每個參數允許的第一個值,這可能不符合你的預期。對於 Cursor Router,始終顯式傳入optimize_for。 - 按能力而非 ID 解析。 如果你需要的是“當前快速模式下的默認模型”,而不是某個特定模型,請按如下方式查找:
const models = await Cursor.models.list();
const composer = models.find((m) => m.id === "composer-2.5");
const fast = composer?.parameters?.find((p) => p.id === "fast");
const fastValue = fast?.values.find((v) => v.value === "true")?.value;
const model = composer
? {
id: composer.id,
params: fastValue ? [{ id: "fast", value: fastValue }] : undefined,
}
: {
id: "auto-smart",
params: [{ id: "optimize_for", value: "balanced" }],
};
當目標模型不可用時,優先顯式選擇 Router (auto-smart + optimize_for) 。只有在希望由服務器選擇 Auto,且不指定 Cost、Balance 或 Intelligence 時,纔回退到 { id: "auto" }。
Cursor.repositories.list()¶
function Cursor.repositories.list(options?: CursorRequestOptions): Promise<SDKRepository[]>;
interface SDKRepository {
url: string;
}
返回調用用戶所屬團隊已連接的 GitHub 倉庫。僅限 Cloud。
配置來源概覽¶
MCP 服務器、子智能體和鉤子都會從內聯選項和磁盤上的配置中解析。三者的優先級結構相同:每次發送時的內聯配置 > 創建時的內聯配置 > 項目文件 > 用戶文件 > 團隊 / 儀表盤配置。
| 功能 | 內聯選項 | 本地文件 (項目) | 本地文件 (用戶) | 雲端 / 儀表盤 | 優先級 |
|---|---|---|---|---|---|
| MCP 服務器 | Agent.create() 和 agent.send() 中的 mcpServers |
.cursor/mcp.json (僅當 local.settingSources 包含 \"project\" 時加載) |
~/.cursor/mcp.json (僅當包含 \"user\" 時加載) |
在 cursor.com/agents 配置的服務器 (僅限雲端) | 發送 > 創建 > 插件 > 項目 > 用戶 (本地) ;發送 > 創建 > 儀表盤 (雲端) |
| 子智能體 | Agent.create() 中的 agents |
.cursor/agents/*.md (frontmatter:name、description、model?) |
不適用 | 智能體針對克隆的倉庫運行時,雲端會加載相同的項目文件 | 內聯配置會覆蓋同名的文件配置 |
| 鉤子 | 無 — 僅支持文件配置 | .cursor/hooks.json (+ 腳本) |
~/.cursor/hooks.json |
雲端運行項目鉤子。企業版方案還會運行團隊和企業管理的鉤子。 | 基於文件;項目配置會與用戶 / 團隊 / 企業配置分層,詳見 Hooks |
| 配置來源 | local.settingSources 用於選擇要加載的磁盤配置層 |
.cursor/ |
~/.cursor/ |
不適用 | 雲端始終加載 project / team / plugins,並忽略 local.settingSources。 |
內聯值適合絕不應寫入磁盤的機密信息 (如單次運行的 API 密鑰、租戶範圍的 token) 。文件配置適合用於策略:鉤子尤其如此,它們屬於項目邊界,而非單次運行的控制項。
MCP 服務器¶
智能體可從多種來源獲取 MCP 服務器。最常見的方式是在 Agent.create() 或 agent.send() 中內聯定義。也支持基於文件的配置和通過儀表盤管理的配置。
加載的內容¶
本地智能體最多可從五個來源加載服務器;如果名稱衝突,以最先匹配的來源爲準:
agent.send()中的mcpServers。會完全替換該次運行創建時的服務器 (不合並) 。Agent.create()中的mcpServers。未提供單次發送覆蓋配置時使用。- 插件服務器,前提是
local.settingSources包含"plugins"。 - 來自
.cursor/mcp.json的項目服務器,前提是local.settingSources包含"project"。 - 來自
~/.cursor/mcp.json的用戶服務器,前提是local.settingSources包含"user"。
未設置 local.settingSources 時,只會加載內聯服務器。如果本地 MCP 服務器需要通過 OAuth 登錄,SDK 無法提示你登錄。只有當你已在 Cursor app 中登錄過該服務器時才能使用;此時 SDK 會複用已保存的登錄憑據。
雲端代理從以下來源加載服務器:
agent.send()中的mcpServers。會完全替換該次運行創建時的服務器 (不合並) 。Agent.create()中的mcpServers。未提供單次發送覆蓋配置時使用。- 來自 cursor.com/agents 的用戶和團隊 MCP 服務器。
如果內聯服務器不包含 auth 或 headers,且你之前已在 cursor.com/agents 授權該服務器 URL,使用個人 API token 認證的運行會自動複用這些 OAuth token。服務賬戶 API 密鑰無法回退使用用戶認證,因爲它們不與用戶關聯。
local.settingSources 不適用於雲端代理。
本地¶
const agent = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
model: { id: "auto" },
local: { cwd: process.cwd() },
mcpServers: {
docs: {
type: "http",
url: "https://example.com/mcp",
auth: {
CLIENT_ID: "client-id",
scopes: ["read", "write"],
},
},
filesystem: {
type: "stdio",
command: "npx",
args: ["-y", "@modelcontextprotocol/server-filesystem", process.cwd()],
cwd: process.cwd(),
},
},
});
雲端¶
雲端代理也可以直接接收已認證的 MCP 配置。當 Cursor 需要通過後端代理遠程 MCP 時,請使用 HTTP 認證。當服務器在雲端 VM 中運行,並從環境變量讀取憑據時,請使用 stdio env。
const agent = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
model: { id: "composer-2.5" },
cloud: {
repos: [{ url: "https://github.com/your-org/your-repo", startingRef: "main" }],
},
mcpServers: {
linear: {
type: "http",
url: "https://mcp.linear.app/sse",
headers: {
Authorization: `Bearer ${process.env.LINEAR_API_KEY!}`,
},
},
figma: {
type: "http",
url: "https://api.figma.com/mcp",
auth: {
CLIENT_ID: process.env.FIGMA_CLIENT_ID!,
CLIENT_SECRET: process.env.FIGMA_CLIENT_SECRET!,
scopes: ["file_content:read"],
},
},
github: {
type: "stdio",
command: "npx",
args: ["-y", "@modelcontextprotocol/server-github"],
env: {
GITHUB_TOKEN: process.env.GITHUB_TOKEN!,
},
},
},
});
靜態 API 密鑰或 Bearer token 請使用 headers,Cursor 會在每次請求中原樣傳遞。受 OAuth 保護的服務器請使用 auth。在雲端,Cursor 會在服務端執行一次 OAuth 流程,並在多次運行間複用 token。在本地,SDK 無法打開瀏覽器讓您登錄;它只能複用您已通過 Cursor app 登錄獲取的 token。
- HTTP
headers和auth由 Cursor 後端處理。敏感字段會被脫敏,不會進入 VM。 - Stdio
env值會傳入 VM,因爲服務器在其中運行。請將其視爲其他運行時機密信息一樣妥善處理。 - 在 cursor.com/agents 上配置的 MCP 服務器,其 OAuth 始終按用戶區分,即使是團隊級服務器也是如此。
完整配置格式請參閱 MCP,雲端特定行爲請參閱 Cloud Agent capabilities。
子智能體¶
定義由主智能體通過 Agent 工具啓動的具名子智能體,並以內聯方式傳入:
const agent = await Agent.create({
model: { id: "composer-2.5" },
apiKey: process.env.CURSOR_API_KEY!,
local: { cwd: process.cwd() },
agents: {
"code-reviewer": {
description: "Expert code reviewer for quality and security.",
prompt: "Review code for bugs, security issues, and proven approaches.",
model: "inherit",
},
"test-writer": {
description: "Writes tests for code changes.",
prompt: "Write comprehensive tests for the given code.",
},
},
});
同樣會識別已提交到倉庫 .cursor/agents/*.md 中的子智能體 (包含 name、description 和可選的 model frontmatter) 。內聯定義會覆蓋同名的基於文件的定義。
嵌套子智能體¶
子智能體可在嵌套層級限制內啓動自己的子智能體。當子智能體使用 Agent 工具時,SDK 會爲其提供與父智能體相同的子智能體執行器,因此父智能體可以將任務委派給還能繼續委派的子智能體。每一層都可訪問同一組具名子智能體和自定義工具。頂層智能體及其直接子智能體可以啓動子智能體,但由子智能體啓動的子智能體無法再啓動下一級子智能體。
限制工具集¶
tools 將模型可用的內置工具限定爲允許列表中的工具;disallowedTools 會移除指定工具,保留其餘工具,包括在您的 SDK 版本發佈後添加到平臺的工具。目前兩者僅支持本地智能體,且都不會持久保存在智能體中:如需在後續運行中保持此限制,請在 Agent.resume() 中再次傳入。
// 只讀智能體:僅可使用這些工具。
const reader = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
model: { id: "composer-2.5" },
tools: ["read", "grep", "glob", "ls"],
local: { cwd: process.cwd() },
});
// 除 shell 外的所有工具。
const noShell = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
model: { id: "composer-2.5" },
disallowedTools: ["shell"],
local: { cwd: process.cwd() },
});
tools: undefined(默認值) 爲所選模型提供標準工具集;tools: []不提供任何內置工具,因此模型只能返回文本響應。- 兩個字段都接受
ToolName聯合類型:公開名稱 ("read"、"edit"、"task"、"webSearch"、……) 、能力羣組"shell"和"mcp",以及原始 proto 工具名稱。未知名稱會在調用Agent.create()/Agent.resume()時拋出ConfigurationError。 - 禁止項優先:要提供某個工具,該工具必須包含在
tools中 (如已設置) ,且不在disallowedTools中。 - 禁用
"mcp"也會移除自定義工具。禁用"task"會阻止子智能體;否則子智能體會保留各自精選的工具集。
自定義工具¶
自定義工具讓你無需單獨搭建 MCP 服務器,即可向智能體公開自己的函數。通過 local.customTools 傳入這些工具後,SDK 會將其註冊爲名爲 custom-user-tools 的 MCP 服務器。智能體會通過與其他服務器相同的 MCP 路徑發現並調用它們。拒絕規則和 沙箱限額仍然適用,但自定義工具無需交互式批准,因此沙箱化和Auto-review 模式運行會直接調用它們,不會提示。自定義工具也可供子智能體 (包括嵌套子智能體) 使用。
自定義工具僅適用於本地智能體。向雲端代理傳入 local.customTools 會拋出 ConfigurationError。
const agent = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
model: { id: "composer-2.5" },
local: {
cwd: process.cwd(),
customTools: {
get_deployment_status: {
description: "Look up the current deployment status for a service.",
inputSchema: {
type: "object",
properties: {
service: { type: "string", description: "Service name" },
},
required: ["service"],
},
async execute({ service }) {
const res = await fetch(`https://deploys.internal/api/${service}`);
const body = await res.json();
return `Service ${service} is ${body.status} (build ${body.build}).`;
},
},
},
},
});
await agent.send("Is the checkout service deployed yet?").then((r) => r.wait());
在 Agent.create() 中設置一次自定義工具,即可應用於每次運行;或者在單次 agent.send() 中傳入 local.customTools,以替換該次運行的自定義工具。
await agent.send("Roll forward if the canary is healthy", {
local: {
customTools: {
promote_canary: {
description: "Promote the current canary build to production.",
async execute() {
await promoteCanary();
return { content: [{ type: "text", text: "Promoted." }] };
},
},
},
},
});
工具定義¶
interface SDKCustomTool {
description?: string;
inputSchema?: Record<string, SDKJsonValue>;
execute: (
args: Record<string, SDKJsonValue>,
context: SDKCustomToolContext
) => SDKCustomToolResult | Promise<SDKCustomToolResult>;
}
interface SDKCustomToolContext {
toolCallId?: string;
}
| 字段 | 描述 |
|---|---|
description |
展示給模型,用於判斷何時調用該工具。默認值爲空 string。 |
inputSchema |
arguments 的 JSON Schema。默認值爲允許任意屬性的開放 object。 |
execute |
您的 callback。接收解析後的 args 以及包含 toolCallId 的 context。在您的 process 中運行,因此可訪問您的代碼能訪問的任何內容。 |
工具結果¶
execute 可以返回普通 string、任意 JSON 值或結構化 envelope。map 的鍵是模型調用的工具名稱。
type SDKCustomToolResult =
| string
| SDKJsonValue
| {
content: SDKCustomToolContent[];
isError?: boolean;
structuredContent?: Record<string, SDKJsonValue>;
};
type SDKCustomToolContent =
| { type: "text"; text: string }
| { type: "image"; data: string; mimeType?: string };
- 純文本輸出請返回 string。
- 返回任意 JSON 值即可將其作爲文本發回;對象還會填充
structuredContent。 - 如需完全控制,請返回 envelope:可混合文本和 base64 圖像
content,設置isError: true以報告失敗,或附加structuredContent供模型解析。execute拋出異常也會作爲工具錯誤報告給智能體。
鉤子¶
鉤子僅支持基於文件的配置方式,不提供可編程的鉤子回調。鉤子是項目策略的邊界,而不是每次運行時可調節的選項。
- 本地: 將
.cursor/hooks.json添加到傳遞給local.cwd的倉庫中,或添加~/.cursor/hooks.json以配置用戶級鉤子。 - 雲端: 將
.cursor/hooks.json及其腳本提交到cloud.repos中傳入的倉庫。由 SDK 創建的雲端代理會自動加載項目鉤子。在企業版方案中,它們還會運行團隊鉤子和企業級管理的鉤子。
有關配置格式,請參閱鉤子;有關雲端行爲,請參閱雲端代理鉤子支持。
沙箱選項¶
默認情況下,本地智能體以 local.sandboxOptions.enabled: false 運行。智能體可讀取和寫入工作目錄、執行 shell 命令,並可不受限制地訪問網絡。無界面 SDK 運行沒有人工批准流程,因此默認啓用沙箱要麼會靜默阻止合法的工具調用,要麼需要不適用於腳本的回調。
啓用沙箱後,SDK 會限制每次 shell 工具調用以及由 shell 啓動的進程:
- 文件系統 — 僅允許寫入工作目錄 (
local.cwd) 和一小部分允許的路徑。禁止讀取工作區以外的內容。 - Shell — 命令在平臺沙箱中運行 (Linux 上使用
bubblewrap,macOS 上使用seatbelt,或使用隨附的@cursor/sdk-<os>-<arch>輔助程序) 。不允許執行特權操作。 - 網絡 — 默認禁止出站網絡訪問。若要允許特定主機,請在工作區中添加
.cursor/sandbox.json,列出允許訪問的主機。如果存在,SDK 也會讀取位於~/.cursor/sandbox.json的同一用戶級策略。
const agent = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
model: { id: "composer-2.5" },
local: {
cwd: process.cwd(),
sandboxOptions: { enabled: true },
},
});
如果主機不支持沙箱 (例如較早版本的 Linux 未安裝 bubblewrap,或缺少輔助二進制文件) ,SDK 會拋出 ConfigurationError,並在消息中指出缺少的依賴項。禁用 sandboxOptions.enabled 或改用雲端模式運行即可恢復。
雲端運行始終在隔離的 VM 中執行,因此 sandboxOptions 不適用。
Auto-review 模式¶
默認情況下,本地智能體會不受限制地執行每個工具調用,因爲無頭運行時沒有人工進行批准。設置 local.autoReview: true 後,本地工具調用將改由 Auto-review 模式 模式處理。該模式使用與 IDE 相同的分類器,根據安全性以及各調用與運行意圖的匹配程度,允許或阻止 Shell、MCP 和 Fetch 調用。
const agent = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
model: { id: "composer-2.5" },
local: {
cwd: process.cwd(),
autoReview: true,
},
});
Auto-review 模式 需要在已連接的後端啓用分類器;如果分類器不可用,運行將回退到默認行爲。由於無界面運行不支持交互式批准,分類器攔截的調用會被拒絕而非升級處理;智能體會收到攔截原因,並可嘗試其他方法。可通過工作區中的 permissions.json autoRun 塊引導分類器,方式與 IDE 相同。格式請參閱 permissions.json。
Auto-review 模式 僅適用於本地智能體。雲端運行已在隔離的 VM 中執行。分類器是一項盡力而爲的便捷功能,並非安全邊界;如需嚴格控制,請結合使用 sandboxOptions 或允許列表。
產物¶
列出並下載智能體工作區中的文件。
interface SDKArtifact {
path: string;
sizeBytes: number;
updatedAt: string;
}
const artifacts: SDKArtifact[] = await agent.listArtifacts();
for (const artifact of artifacts) {
console.log(artifact.path, artifact.sizeBytes);
}
const buffer = await agent.downloadArtifact(artifacts[0].path);
Artifact 支持因運行時而異。Local SDK agents 目前不返回任何 artifact,調用 downloadArtifact 時會拋出錯誤。
資源管理¶
使用完智能體後,務必將其釋放。最簡潔的方式是使用 await using:
await using agent = await Agent.create({ /* ... */ });
// 退出代碼塊時會自動釋放
要顯式釋放資源:
await agent[Symbol.asyncDispose]();
agent.close() 是無需等待即可開始釋放資源的推薦方法。Symbol.asyncDispose 也可用 (await using 基於它實現) ,但對於不使用 await using 語法的代碼,應使用 close()。agent.reload() 可在不釋放資源的情況下加載文件系統配置的更改 (鉤子、項目 MCP、子智能體) 。
智能體生命週期¶
預熱本地工作區¶
解析本地工作區 (規則、技能、MCP 服務器、忽略文件) 是本地智能體首次執行時最耗時的環節,在大型倉庫中甚至可能佔據絕大部分時間。默認情況下,這項開銷會計入首次 send() 調用。主機如果知道智能體將在何處運行,可以通過 prewarmLocalWorkspace() 提前完成這項工作:
import { createAgentPlatform } from "@cursor/sdk";
const platform = await createAgentPlatform();
const release = await platform.prewarmLocalWorkspace({
apiKey: process.env.CURSOR_API_KEY!,
local: { cwd: "/srv/checkout", settingSources: ["project"] },
});
// 此工作區的首次 send() 會立即執行。
await release(); // 主機關閉時
傳入智能體將使用的同一組 AgentOptions;預熱僅對工作區選項相匹配的發送有效。主機關閉時,調用返回的 release 函數。
重新連接到現有智能體¶
Agent.resume(agentId) 會返回一個用於操作現有智能體的新句柄。系統會根據 ID 前綴自動識別運行時 (bc- 表示雲端,其他前綴表示本地) ,並從雲端 (雲端) 或本地檢查點存儲 (本地) 加載對話狀態。這可用於在進程重新啓動後繼續工作,或讓其他 worker 接手由另一個進程啓動的智能體。
const agent = await Agent.resume("bc-abc123", {
apiKey: process.env.CURSOR_API_KEY!,
});
const run = await agent.send("Apply the suggested fix");
const result = await run.wait();
如果重新連接時該運行已在進行中,Agent.getRun(runId, { runtime: "cloud", agentId }) (或本地等效方法) 會返回一個 Run,可對其調用 stream()、wait() 或 cancel()。
對話上下文¶
本地智能體會將對話狀態持久化到檢查點存儲中。默認使用主目錄下基於磁盤的 SQLite;也可通過 local.store 替換爲 JSONL 或自定義後端。每次調用 agent.send() 都會加載該智能體的最新檢查點並傳遞給模型,因此後續交互能獲得上一次運行結束時的相同上下文。該存儲在進程重新啓動後仍會保留,因此在全新的進程中調用 Agent.resume(agentId) 可以從上次結束的位置繼續。
雲端代理會在服務器端持久化狀態。從任何位置重新連接,都會返回同一對話。
以下幾種情況看似丟失了上下文,但其實並非如此:
- 每次調用
Agent.create()都會使用新的agentId創建一個全新的智能體。若要繼續現有對話,請在首次調用時獲取agent.agentId,之後使用Agent.resume(agentId)。 Agent.prompt()會一次性創建、運行並釋放智能體。不會有第二輪交互;這是其合約。- 內聯
mcpServers不會在Agent.resume()後保留,因爲其中通常包含機密信息。恢復時請再次傳入,或使用基於文件的 MCP 配置。
調度器模式¶
調度器管理一個智能體池,並在任務到達時將其分配給相應的智能體。其模式很簡單:維護一個從 agentId 到長期存活的 SDKAgent 的映射,根據某個鍵 (用戶、倉庫、工單) 路由傳入的提示詞;如果進程重啓導致內存中的映射丟失,則從磁盤恢復並調用 Agent.resume()。
import { Agent, type SDKAgent } from "@cursor/sdk";
const agents = new Map<string, SDKAgent>();
async function getAgent(key: string, savedId?: string): Promise<SDKAgent> {
const existing = agents.get(key);
if (existing) return existing;
const agent = savedId
? await Agent.resume(savedId, {
apiKey: process.env.CURSOR_API_KEY!,
})
: await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
model: { id: "composer-2.5" },
local: { cwd: process.cwd() },
});
agents.set(key, agent);
return agent;
}
async function handleMessage(key: string, prompt: string, savedId?: string) {
const agent = await getAgent(key, savedId);
const run = await agent.send(prompt);
return run.wait();
}
雲端 SSE 流會在運行開始後的一段時間內保留積壓事件,因此向多個訂閱者提供流的調度器可讓每個訂閱者調用 run.stream(),而不會丟失先前的事件。對於運行時間特別長的雲端運行,調度器通常會將任務分發給 run.wait(),並讓需要結構化會話記錄的訂閱者輪詢 run.conversation()。
本地智能體存儲¶
本地智能體會將智能體元數據、對話檢查點、運行記錄和運行事件持久化到磁盤,以便後續操作和 Agent.resume() 在進程重啓後仍可繼續執行。默認情況下,SQLite 後端可用時,SDK 會使用基於磁盤的 SQLite;否則回退到 JsonlLocalAgentStore。您可以通過 local.store 替換爲其他後端。
SDK 提供兩種後端,也支持您自定義後端:
| 存儲 | 導入 | 適用場景 |
|---|---|---|
SqliteLocalAgentStore |
@cursor/sdk/sqlite |
工作區狀態根目錄下的基於磁盤的 SQLite。 |
JsonlLocalAgentStore |
@cursor/sdk |
存儲在您指定目錄中的可移植換行分隔 JSON (NDJSON) 文件。便於查看、複製和 diff。 |
自定義 LocalAgentStore |
您的代碼 | 可持久化到任意位置:內存、Redis、Postgres 或託管數據庫。實現該接口或組合子存儲。 |
雲端代理在服務器端持久化,因此 local.store 僅適用於本地智能體。
JSONL 存儲¶
JsonlLocalAgentStore 會在你指定的目錄中寫入四個 NDJSON 文件 (agents.ndjson、runs.ndjson、run_events.ndjson、checkpoints.ndjson) 。創建一個實例,並將其傳給 local.store。
import { Agent, JsonlLocalAgentStore } from "@cursor/sdk";
const store = new JsonlLocalAgentStore("/var/lib/cursor-agents");
const agent = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
model: { id: "composer-2.5" },
local: { cwd: process.cwd(), store },
});
在 Agent.resume() 以及本地列表和獲取 API (Agent.list、Agent.get、Agent.listRuns、Agent.getRun) 中使用同一存儲實例,確保它們讀取相同的數據。
設置進程級默認值¶
爲避免在每次調用時都傳遞存儲,可通過 Cursor.configure() 一次性設置默認值。傳入 local.store 時,仍以該調用中指定的值爲準。
import { Cursor, JsonlLocalAgentStore } from "@cursor/sdk";
Cursor.configure({ local: { store: new JsonlLocalAgentStore("/var/lib/cursor-agents") } });
// 後續調用會使用已配置的存儲,除非自行傳入存儲。
const agent = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
model: { id: "composer-2.5" },
local: { cwd: process.cwd() },
});
向 Cursor.configure({ local: { store: null } }) 傳入 store: null,即可清除先前設置的默認值,並恢復爲使用 SDK’s 默認本地存儲。
自定義存儲¶
如需將數據持久化到其他位置 (如共享的 Postgres、Redis,或供測試使用的內存映射) ,請實現 LocalAgentStore。它由四個子存儲組成,每個都是供 SDK 調用的小型 CRUD 接口:
interface LocalAgentStore {
readonly agents: LocalAgentStoreAgents; // 智能體元數據記錄
readonly checkpoints: LocalAgentStoreCheckpoints; // 按內容尋址的對話 Blob
readonly runs: LocalAgentStoreRuns; // 運行記錄
readonly runEvents: LocalAgentStoreRunEvents; // 僅追加的運行事件日誌
}
直接實現該接口,或分別構建各個子存儲,再使用 composeLocalAgentStore 將其組合起來:
import { composeLocalAgentStore } from "@cursor/sdk";
const store = composeLocalAgentStore({
agents: myAgentsTable,
checkpoints: myCheckpointBlobs,
runs: myRunsTable,
runEvents: myRunEventLog,
});
這些子存儲與默認的 SQLite 表相對應:agents 中每個智能體佔一行 (包含一個精簡的 latestCheckpoint.rootBlobId 指針) ,checkpoints 存儲這些指針所引用的按內容尋址的對話 blob,runs 中每次運行佔一行,runEvents 則是僅追加的流式日誌。目錄子存儲通過不透明的 cursor / nextCursor 實現分頁;運行事件日誌則通過排他性的 afterOffset / nextOffset 恢復。具體的數據結構請參閱導出的 LocalAgentStore、LocalAgentDocument、LocalAgentRunDocument 及相關類型。
配置參考¶
AgentOptions¶
| 屬性 | 類型 | 默認值 | 描述 |
|---|---|---|---|
model |
ModelSelection |
本地必填;雲端會回退到服務器解析的默認值 | 要使用的模型。參見 ModelSelection。 |
apiKey |
string |
CURSOR_API_KEY 環境變量 |
用戶 API 密鑰或服務賬戶密鑰。暫不支持團隊 Admin 密鑰。 |
name |
string |
自動生成 | 供人閱讀的智能體名稱,在 Agent.list() / Agent.get() 中以 name 字段返回。 |
local |
LocalAgentOptions |
本地智能體配置。參見 LocalAgentOptions。 |
|
cloud |
CloudAgentOptions |
雲端代理配置。 | |
mcpServers |
Record<string, McpServerConfig> |
內聯 MCP 服務器定義。 | |
agents |
Record<string, AgentDefinition> |
子智能體定義。 | |
tools |
ToolName[] |
默認工具集 | 限制工具集:僅向模型提供列出的內置工具。[] 表示不提供內置工具。僅適用於本地智能體。 |
disallowedTools |
ToolName[] |
從工具集中移除工具;其他工具仍可用。與 tools 一起使用時,以拒絕爲準。僅適用於本地智能體。 |
|
agentId |
string |
自動生成 | 持久化智能體 ID。傳入此值可在多次調用間保持 ID 穩定。 |
idempotencyKey |
string |
雲端自動生成 | 可選的客戶端生成冪等性密鑰。 |
mode |
"agent" \| "plan" |
"agent" |
智能體首次運行時的初始對話模式。參見對話模式。 |
LocalAgentOptions¶
本地智能體的配置,通過 Agent.create() 的 local 參數傳入。也可作爲獨立類型導出,供 Partial<LocalAgentOptions> 使用。
| 屬性 | 類型 | 默認值 | 描述 |
|---|---|---|---|
cwd |
string |
默認 shell 的主工作目錄,並用於確定智能體存儲的作用域。 | |
dirs |
string[] |
用於多根工作區的其他工作區文件夾。與 cwd 合併 (去除重複項) ,以便從每個路徑加載規則、技能和工作區上下文。 |
|
settingSources |
SettingSource[] |
要加載的全局設置層:"project"、"user"、"team"、"mdm"、"plugins" 或 "all"。 |
|
sandboxOptions |
{ enabled: boolean } |
{ enabled: false } |
沙箱配置。 |
autoReview |
boolean |
false |
通過 Auto-review 模式處理本地工具調用。 |
customTools |
Record<string, SDKCustomTool> |
以 custom-user-tools MCP 服務器形式公開的自定義工具。 |
|
store |
LocalAgentStore |
SDK 默認存儲 | 用於持久化的本地智能體存儲。 |
enableAgentRetries |
boolean |
true |
爲本地智能體運行啓用傳輸錯誤和停滯時的自動重試。設爲 false 可在首次失敗時直接顯示傳輸錯誤。 |
CloudAgentOptions¶
| 屬性 | 類型 | 默認值 | 描述 |
|---|---|---|---|
env |
{ type: "cloud"; name?: string } \| { type: "pool"; name?: string } \| { type: "machine"; name?: string } |
{ type: "cloud" } |
執行環境目標。cloud 使用 Cursor 託管的 VM;設置 name 可使用已保存的 Cursor 託管環境。pool 和 machine 會路由到您運行的自託管 worker。若要創建工作區爲空且不含倉庫的智能體,請省略 repos 並保留 env 的默認值。已命名的 Cursor 託管環境與顯式指定的 repos 互斥。 |
repos |
Array<{ url: string; startingRef?: string; prUrl?: string }> |
要克隆到 VM 的倉庫。單倉庫智能體傳入一個條目,多倉庫智能體最多可傳入 20 個條目。對於無倉庫智能體,請省略此項或傳入 []。與 Cursor 託管環境中指定的 env.name 互斥。傳入 prUrl 可將智能體關聯到現有 PR。 |
|
workOnCurrentBranch |
boolean |
false |
將提交推送到現有分支,而不是新分支。 |
autoCreatePR |
boolean |
false |
運行完成時創建 PR。 |
openAsCursorGithubApp |
boolean |
服務賬戶密鑰爲 true,用戶密鑰爲 false |
以 Cursor GitHub App 的身份而非 API 密鑰所有者的身份創建 PR。解析後的值會在創建、獲取和列出時返回。 |
skipReviewerRequest |
boolean |
false |
不請求將調用用戶添加爲 PR 審閱人。 |
envVars |
Record<string, string> |
雲端代理的會話範圍環境變量。 | |
metadata |
Record<string, string> |
由調用方擁有、持久保存在雲端代理上的 string 標籤。請參閱智能體元數據。 |
AgentDefinition¶
| 屬性 | 類型 | 默認值 | 描述 |
|---|---|---|---|
description |
string |
必填 | 此子智能體的使用時機。會顯示給父智能體,以便其瞭解何時生成該子智能體。 |
prompt |
string |
必填 | 子智能體的系統提示詞。 |
model |
ModelSelection \| "inherit" |
"inherit" |
模型覆蓋。傳入 "inherit" 以使用父智能體的模型選擇。 |
mcpServers |
Array<string \| Record<string, McpServerConfig>> |
此子智能體可用的 MCP 服務器。名稱引用父智能體 mcpServers 中的服務器。 |
ModelSelection¶
interface ModelSelection {
id: string;
params?: ModelParameterValue[];
}
interface ModelParameterValue {
id: string;
value: string;
}
id 是模型標識符 (例如 "composer-2.5" 或 "auto-smart") 。params 用於指定模型專屬參數,例如 reasoning effort 或 Router 的 optimize_for。使用 Cursor.models.list() 查找您的賬戶可用的有效 id、參數定義和預設變體。有關 Router 的選擇合約,請參閱 Cursor Router。
McpServerConfig¶
type McpServerConfig =
// stdio
| {
type?: "stdio";
command: string;
args?: string[];
env?: Record<string, string>;
cwd?: string; // 僅限本地;雲端不支持此字段
}
// HTTP / SSE
| {
type?: "http" | "sse";
url: string;
headers?: Record<string, string>; // 原樣傳遞;可在此處使用 Authorization
auth?: {
CLIENT_ID: string;
CLIENT_SECRET?: string;
scopes?: string[];
};
};
對於在雲端運行的 HTTP 服務器,headers 和 auth 由 Cursor 後端處理。敏感字段會在 VM 接收到之前被脫敏。對於在雲端運行的 stdio 服務器,env 值會傳入 VM (請將其視爲運行時機密信息) 。
SDK用戶消息¶
interface SDKUserMessage {
text: string;
images?: SDKImage[];
}
agent.send() 消息參數的結構化格式。可用於在發送文本時附帶圖像。
SDKImage¶
type SDKImage =
| { url: string; dimension?: SDKImageDimension }
| { data: string; mimeType: string; dimension?: SDKImageDimension };
interface SDKImageDimension {
width: number;
height: number;
}
傳入遠程 url,或包含 mimeType 的 base64 編碼 data。
SettingSource¶
type SettingSource =
| "project"
| "user"
| "team"
| "mdm"
| "plugins"
| "all";
控制本地智能體加載哪些存儲在磁盤上的設置層。雲端代理始終加載 project / team / plugins,並忽略此字段。
| 值 | 來源 |
|---|---|
"project" |
工作區中的 .cursor/ |
"user" |
~/.cursor/ |
"team" |
從儀表盤同步的團隊設置 |
"mdm" |
由 MDM 管理的企業版設置 |
"plugins" |
插件提供的設置 |
"all" |
上述所有設置的簡寫 |
ListResult¶
interface ListResult<T> {
items: T[];
nextCursor?: string;
}
由 Agent.list() 和 Agent.listRuns() 返回。沒有更多頁時,不會返回 nextCursor。
錯誤¶
所有 SDK 錯誤均繼承自 CursorSdkError (爲保持向後兼容性,以 CursorAgentError 重新導出) 。可使用 isRetryable 控制重試邏輯,並通過 code / status / requestId 進行診斷。
class CursorSdkError extends Error {
readonly isRetryable: boolean;
readonly code?: string; // 穩定的 SDK / 後端錯誤代碼
readonly status?: number; // HTTP 狀態碼(如有)
readonly cause?: unknown; // 封裝的底層錯誤
readonly endpoint?: string;
readonly requestId?: string;
readonly operation?: string; // 引發該錯誤的 SDK 操作
}
| 錯誤類 | 典型消息 | 可能原因 | 推薦解決方法 |
|---|---|---|---|
AuthenticationError |
“無效的 API 密鑰” | 缺少或錯誤的 CURSOR_API_KEY、令牌已過期,或管理員已禁用該密鑰。 |
在 API Keys (用戶) 或 團隊設置 (服務賬戶) 中生成新密鑰。確認該密鑰擁有執行此操作的權限。 |
RateLimitError |
“超出速率限制”或 “超出用量限制” | 突發請求限制或每月用量上限。 | 使用指數退避重試 (對於臨時情況,SDK 會報告 isRetryable: true) 。若達到每月上限,請提高套餐的用量限制。 |
ConfigurationError |
“模型名稱錯誤”、”不支持 API 密鑰”、”不支持該文件” | model.id 無效、缺少必需的 params、工具調用中使用了不受支持的文件,或管理員策略阻止了請求。 |
調用 Cursor.models.list() 確認 ID 和參數。檢查倉庫和文件路徑是否存在。 |
AgentBusyError |
“智能體正忙” | 同一雲端代理已有處於 CREATING 或 RUNNING 狀態的運行時,又發送了後續請求。 |
等待活躍運行完成、取消該運行,或在再次發送前輪詢 Agent.listRuns()。 |
IntegrationNotConnectedError |
“[提供商] 集成未連接” | 爲 SCM 提供商尚未連接到 Cursor 團隊的倉庫創建雲端代理。 | 打開 error.helpUrl 重新連接提供商,然後重試。 |
NetworkError |
“服務不可用”、”超時” | 臨時後端問題、網絡分區或超過截止時間。 | 使用退避策略重試。如需提交支持工單,請查看 error.requestId。 |
UnsupportedRunOperationError |
“此運行時不支持操作 “stream”“ | 調用了當前運行時無法支持的 Run 方法 (例如,對已完成的重新獲取的本地運行進行流式處理) 。 |
先通過 run.supports(operation) / run.unsupportedReason(operation) 檢查。 |
AgentNotFoundError |
“未找到智能體” | 請求的智能體不存在,或在解析後的本地工作區中不可見。 | 檢查智能體 ID、cwd 和 local.store。 |
UnknownAgentError |
由服務器定義的消息 | 未分類的後端或運行時錯誤。 | 查看 error.code 和 error.cause 以瞭解底層詳情。 |
檢查 error.helpUrl¶
某些錯誤會附帶一鍵解決鏈接。最常見的是
IntegrationNotConnectedError,但未來更多錯誤類型也可能添加 helpUrl。
捕獲錯誤時,如果存在 error.helpUrl,請記錄並展示給用戶。
IntegrationNotConnectedError¶
class IntegrationNotConnectedError extends ConfigurationError {
readonly provider: string; // 例如:"github"、"gitlab"、"azuredevops"
readonly helpUrl: string; // 用於重新連接的儀表盤鏈接
}
默認錯誤消息不包含 helpUrl,因此請顯式記錄:
import { Agent, IntegrationNotConnectedError } from "@cursor/sdk";
try {
await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
cloud: {
repos: [{ url: "https://github.com/your-org/private-repo" }],
},
});
} catch (err) {
if (err instanceof IntegrationNotConnectedError) {
console.error(err.provider, err.helpUrl);
}
}
AgentBusyError¶
class AgentBusyError extends CursorAgentError {}
對於 agent_busy,isRetryable 爲 false。立即重試會一直失敗,直到正在運行的任務結束或您將其取消。其他 409 響應 (例如 agent_archived) 則會拋出 ConfigurationError。
等待正在運行的任務完成,使用 run.cancel() 將其取消,或在再次發送前輪詢 Agent.listRuns():
import { Agent, AgentBusyError } from "@cursor/sdk";
const agent = await Agent.resume("bc-00000000-0000-0000-0000-000000000001");
try {
await agent.send({ text: "Also add tests for the auth middleware." });
} catch (err) {
if (err instanceof AgentBusyError) {
const runs = await Agent.listRuns(agent.agentId, { runtime: "cloud", limit: 1 });
const active = runs.items[0];
if (active?.status === "running") {
await active.cancel();
}
await agent.send({ text: "Also add tests for the auth middleware." });
return;
}
throw err;
}
本地智能體不會返回 agent_busy。啓動新的本地運行前,使用 send({ local: { force: true } }) 終止卡住的本地運行。
UnsupportedRunOperationError¶
class UnsupportedRunOperationError extends ConfigurationError {
readonly operation: RunOperation;
}
當前運行時無法執行某個 Run 操作時拋出。請在調用前使用 run.supports(operation) 和 run.unsupportedReason(operation) 進行檢查。
已知限制¶
- 內聯
mcpServers不會在Agent.resume()後保留。如有需要,請在恢復時再次傳入。 - 自定義工具 (
local.customTools)、Auto-review 模式 (local.autoReview)、自定義存儲 (local.store) 和工具集限制 (tools、disallowedTools) 僅適用於本地智能體。雲端代理會拒絕local.customTools,並在服務器端持久化。 tools和disallowedTools不會保留在智能體中。請在Agent.resume()時再次傳入,以維持這些限制。- 本地智能體尚不支持下載 Artifact (
agent.listArtifacts()返回空列表,agent.downloadArtifact()會拋出異常) 。 local.settingSources(以及它所控制的基於文件的 MCP / 子智能體路徑) 不適用於雲端代理。雲端始終加載project/team/plugins。- 鉤子僅支持基於文件的方式 (
.cursor/hooks.json) ,不支持編程式回調。 - SDK 不會自動從本地安裝的 Cursor app 中發現憑據。請顯式設置
CURSOR_API_KEY(或傳入apiKey) ,或通過Cursor.auth.login()創建密鑰。 - 本地模式需要 Node.js 22.13 或更高版本,以及平臺對 sandbox-helper 的支持。SQLite 後端不可用時,默認存儲會回退到
JsonlLocalAgentStore。