Cursor TypeScript SDK 中文版
Cursor TypeScript SDK
@cursor/sdk 包允许你在自己的代码中调用 Cursor 的 agent。在 Cursor IDE、CLI 和 Web 应用中运行的同一个 agent,现在可以通过 TypeScript 编写脚本调用。在 Cursor 中运行 /sdk 技能即可开始使用。
Cookbook(示例手册)
端到端示例位于 Cursor Cookbook 中:SDK 快速入门、应用构建器原型工具、云 agent 的看板,以及编码 agent CLI。这些是 CI 自动修复机器人、bug 分类 worker、代码审查流程、嵌入式产品内 agent 和编排器的良好起点。
概述
SDK 将本地和云端运行时封装在同一个接口之后。无论 agent 在哪里运行,你编写的代码都相同。
| 运行时 | 作用 | 使用场景 |
|---|---|---|
| 本地(Local) | 在 Node 进程内联运行 agent 循环。文件来自磁盘。 | 针对工作树的开发脚本和 CI 检查。 |
| 云端(Cloud,Cursor 托管) | 在隔离的 VM 中运行,仓库已克隆进去。Cursor 负责运行 VM。 | 当调用方没有仓库、需要并行运行多个 agent,或运行需要存活于调用方断开之后。 |
"本地"指本地 agent 循环,而非本地模型
"本地"描述的是 agent 循环和文件系统访问运行的位置,而不是模型运行的位置。两种模式下所有推理都通过 Cursor 的托管模型进行。本地模式将文件保留在你的机器上;云端模式在 Cursor 环境中运行。模型本身在两种情况下都是托管的。
运行时由你传给 Agent.create() 的键决定(local 或 cloud)。两种模式使用相同的 CURSOR_API_KEY。
REST API 请参阅 Cloud Agents API。其他语言请参阅 SDK Bridge。
认证
在创建 agent 之前设置 CURSOR_API_KEY(或传入 apiKey)。对于没有预置密钥的交互式宿主,Cursor.auth.login() 会通过浏览器登录铸造并存储一个密钥。
SDK 接受用户 API 密钥和服务账号 API 密钥,本地和云端运行均适用。Team Admin API 密钥尚不支持。
- 用户 API 密钥:Cursor Dashboard → API Keys
- 服务账号 API 密钥:Team 设置。参见 Service accounts
export CURSOR_API_KEY="your-key"
用量与计费
SDK 运行遵循与 IDE 和 Cloud Agents 运行相同的定价、请求池和隐私模式规则。支出会显示在你团队的用量仪表板中,标签为 SDK。
服务账号 API 密钥计入拥有该服务账号的团队。用户 API 密钥计入该用户的计划。
要在代码中读取每次运行的 token 计数,参见 Token usage。要获取 agent 运行的计费用量和美元成本,参见 Agent.getUsage()。
核心概念
| 概念 | 描述 |
|---|---|
| Agent | 持久容器,保存对话状态、工作区配置和设置。跨多个提示存活。 |
| Run | 一次提示提交。拥有自己的流、状态、结果和取消能力。 |
| SDKMessage | 运行期间发出的规范化流事件。所有运行时形状相同。 |
安装
npm install @cursor/sdk
包名以 @ 开头。npm 上不存在裸的 cursor/sdk。
运行时支持
SDK 要求 Node.js 22.13 或更高版本。它附带按平台划分的 @cursor/sdk-<os>-<arch> 二进制文件用于沙箱和 ripgrep,因此是 Node 优先的包。
导入 @cursor/sdk 不会急切加载本地 agent 栈。本地执行器在首次本地获取时加载,因此仅云端和仅类型的消费者不必承担本地导入成本。进程中第一个本地 agent 承担一次性导入,之后模块保持缓存。
@cursor/sdk 发布自包含的 .d.ts 文件,因此类型解析无需拉取未发布的工作区包。升级后请重新运行类型检查。流类型(如 TurnEndedUpdate)解析为真实类型而非 any。
单文件打包和编译可执行文件
默认构建在运行时惰性加载自身部分内容。单文件打包器无法跟随这些加载,因此编译后的应用在首次 Agent.create() 时会失败,错误类似 Cannot find module './986.js'。SDK 还提供了具有相同公共 API 的扁平单文件构建。它将所有内容放在一个文件中,因此打包器会预先嵌入整个 SDK。
在 Bun 下,@cursor/sdk 会自动解析到扁平构建。照常导入并编译:
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() },
});
bun build --compile main.ts --outfile my-agent
对于其他单文件打包器(如 esbuild),或要显式固定扁平构建,请导入 bundled 入口:
| 入口 | 内容 |
|---|---|
@cursor/sdk/bundled | @cursor/sdk 导出的所有内容。 |
@cursor/sdk/bundled/sqlite | SqliteLocalAgentStore,与 @cursor/sdk/sqlite 一致。 |
几点须知:
- 扁平构建在 Bun 上运行,包括
bun build --compile生成的可执行文件。它也能在 Node 上加载,但 SQLite 存储在那里不可用,因此需通过local.store配置JsonlLocalAgentStore,否则Agent.create()会抛出ConfigurationError。不以单文件形式分发的 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。 - bundled 入口的类型解析方式与
@cursor/sdk相同。无需更改 TypeScript 配置。
快速开始
最快的入门方式:针对当前工作树运行本地 agent,事件实时流入。云端设置见下文"创建 agent"。
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。Streaming 一节展示了如何提取助手文本、处理工具调用,以及用 await using 清理。一次性提示(创建、运行、销毁)请参见 Agent.prompt()。
快速开始会自动批准工具调用
默认本地 agent 运行工具调用(shell、edit、write 等)时不会请求批准;无头模式下没有人在环提示。要限制工具调用,请配置 hooks(如 beforeShellExecution 或 preToolUse),或使用 local.sandboxOptions.enabled: true 运行。
创建 agent
function Agent.create(options: AgentOptions): Promise<SDKAgent>;
Agent.create() 验证选项并立即返回句柄。传入 local 或 cloud 选择运行时。
// 本地 agent
const agent = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
model: { id: "composer-2.5" },
local: { cwd: "/path/to/repo" },
});
// 云端 agent
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 会立即填充。本地 agent 获得 agent-<uuid> ID;云端 agent 获得 bc-<uuid> ID。
由 SDK 启动的云端 agent 会从默认 agent 列表中过滤掉。要在 Cursor Web 或 Cursor 窗口中查看它们,点击 Filter > Source > SDK。
无仓库云端 agent
云端 agent 可以在没有仓库的空 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);
无仓库 agent 必须为你的账号或团队启用。仓库作用域的 API 密钥无法创建它们;请使用无限制的服务账号密钥或用户 API 密钥。
会话环境变量
对于云端 agent,当某次运行需要短期凭证或其他只应存在于该 agent 的值时,传入 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!,
},
},
});
这些值静态加密,注入云端 agent 的 shell,并随 agent 删除。envVars 不能与调用方提供的 agentId 一起使用;省略 agentId,在首次 send() 后从 agent.agentId 读取服务端铸造的 ID。变量名不能以 CURSOR_ 开头。
对于只应在单次运行期间存在的值,请在 agent.send() 上传递。参见 Per-run environment variables。
Agent 元数据
使用 cloud.metadata 给云端 agent 附加你自己的字符串标签。标签与 agent 一起持久化,并通过 Agent.get() 和 Agent.list() 的 SDKAgentInfo.metadata 返回。这些标签不是 VM 内的 agent 元数据 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 传递按模型的选项,如推理力度。参数 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 和 Enterprise 上可用。Enterprise 管理员必须先为团队启用 Router,auto-smart 才会出现在目录中。
Cursor SDK 是 agent SDK,不是独立的模型推理或聊天补全 API。Router 为 Cursor agent 运行选择模型,这些运行可以推理工作区、调用工具、运行命令和编辑文件。Cursor 目前未记录用于任意模型调用的原始 Router 端点。
选择 Cost、Balance 或 Intelligence
传入 auto-smart 并显式设置 optimize_for:
| 产品标签 | SDK 值 |
|---|---|
| Cost | cost |
| Balance | balanced |
| Intelligence | intelligence |
在产品文案中使用 Balance。仅在 SDK 传输值中使用 balanced。
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。不要省略它,也不要发送旧版默认值;通过目录发现是支持的契约。
在模型目录中发现 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" }],
},
});
每次运行的模型覆盖是粘性的。后续不带覆盖的发送继续使用新选择。参见 Per-run model override。
模型 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。
- Enterprise 模型允许列表塑造路由池。阻止所需模型可能禁用 Router。
当前费率和路由池请参见 Cursor Router and Auto modes。
排查 Router 缺失
如果 auto-smart 缺失或优化模式被拒绝:
- 调用
Cursor.models.list()。 - 确认结果中包含
auto-smart。 - 确认
optimize_for包含你想要的值(cost、balanced或intelligence)。 - 确认 API 密钥绑定的团队已启用 Router。
- 如果你属于多个团队,确认密钥在预期的团队上下文中运行。
- 如果 Router 不可用或无法选择有效的底层模型,检查团队模型访问策略。
替换系统提示
systemPrompt 用你自己的文本替换 Cursor 内置的主 agent 循环系统提示。模型会失去编码助手身份、工具使用协议和沟通指导,因此需重述 agent 仍需要的内容。工具 schema、规则和技能仍会加载,子 agent 保留自己的提示。
const agent = await Agent.create({
apiKey: process.env.CURSOR_API_KEY!,
model: { id: "composer-2.5" },
systemPrompt:
"You are a release manager. Only edit CHANGELOG.md, and answer in one paragraph.",
local: { cwd: process.cwd() },
});
- 仅本地 agent。将
systemPrompt与cloud组合会抛出ConfigurationError。 - 必须非空。仅空白文本会在
Agent.create()或Agent.resume()时抛出ConfigurationError。 - 不在 agent 上持久化。在
Agent.resume()时再次传递systemPrompt以保留用于后续运行。 - 访问权限按账号启用。没有权限时,首次
send()失败,错误中提及--system-prompt。
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 标识符。本地为 agent-<uuid>,云端为 bc-<uuid>。 |
model | 当前模型选择。每次成功的 send({ model }) 后更新。在设置之前为 undefined(包括调用方未传 model 的恢复 agent)。 |
send | 用给定提示启动新运行。返回 Run 句柄。 |
close | 不等待地开始销毁。即发即忘。 |
reload | 在不销毁的情况下重新读取文件系统配置(hooks、项目 MCP、子 agent)。 |
[Symbol.asyncDispose] | 异步销毁。与 await using 配对以自动清理。 |
listArtifacts | 列出 agent 产生的文件(仅云端;本地返回空)。 |
downloadArtifact | 按路径下载文件(仅云端;本地抛出)。 |
getUsage | 获取 agent 的计费 token 用量和美元成本。本地 agent 需要按账号启用用量访问;参见 Agent.getUsage()。 |
Agent.prompt()
function Agent.prompt(message: string, options?: AgentOptions): Promise<RunResult>;
一次性便捷方法:创建 agent,发送单个提示,等待运行完成,然后销毁。
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。agent 跨运行保留对话上下文;run 是一次提示的工作单元。
Run
type RunStatus = "running" | "finished" | "error" | "cancelled";
type RunOperation = "stream" | "wait" | "cancel" | "conversation";
type SteerAckOutcome = "complete_delivered" | "revert_to_followup";
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>;
steer?(text: string): Promise<SteerAckOutcome>;
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;
}
}
// 在同一 agent 上跟进。上一次运行的对话状态会自动加载。
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); // 云端为 { branches: [{ repoUrl, branch?, prUrl? }] }
最终助手文本在 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 对象上。
取消在运行中的本地和云端运行上受支持,如果运行已完成则为无操作。
在飞行中引导运行
run.steer(text) 将消息注入已运行的轮次,而不是等待其完成。一旦该轮确认是否附加了文本,promise 即结算。complete_delivered 表示该轮已收到消息,不要重发。revert_to_followup 表示该轮未接收,需在运行后用 agent.send() 传递。
const run = await agent.send("Migrate the auth module to the new session API");
const outcome = await run.steer?.("Skip the admin routes for now");
if (outcome !== "complete_delivered") {
await run.wait();
await agent.send("Skip the admin routes for now");
}
- 仅本地运行。云端运行和分离的本地句柄暴露
steer,但总是解析为revert_to_followup。 - 前台子 agent 运行时引导也有效。子 agent 移到后台继续运行,以便父轮接收消息。
steer在Run上是可选的,不是RunOperation。调用前检查run.steer,而非run.supports()。
读取运行状态
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[](带步骤的 agent 轮次,或带命令和输出的 shell 轮次)。用它渲染或持久化运行的结构化历史,而无需订阅实时流。
Token 用量
运行时提供时,运行会报告 token 用量。运行期间从 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`);
}
}
Token 计数是运行时报告的内容;它们不说明成本。要获取计费用量和 agent 运行的美元成本,调用 agent.getUsage()。
用 requestId 关联运行
每次 agent.send() 获得平台生成的 UUID,在 Run 和 RunResult 上都暴露为 requestId。用它把脚本或 CI 运行与后端日志、分析和支持线程关联,而不是仅凭 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() 的模型覆盖该次运行的 agent 选择,然后变为粘性:后续不带覆盖的发送继续使用新模型。要切回,传递另一个模型覆盖或从 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 也可以为单次运行接受环境变量。在 agent.send() 上传递 cloud.envVars,值仅为该次运行注入 agent 的 shell——运行结束后从 VM 移除,下一次运行看不到它们。这适用于轮次之间轮换的凭证,比如在让 agent 使用前铸造的短期部署 token。
const run = await agent.send("Deploy the preview environment", {
cloud: {
envVars: {
DEPLOY_TOKEN: await mintShortLivedToken(),
},
},
});
如果运行作用域变量与 Agent.create() 上 cloud.envVars 的 agent 作用域变量同名,运行作用域值在该次运行中胜出,之后下一次运行恢复 agent 作用域值。
每次运行变量在首次发送时也有效。SDK 将它们与 agent 创建一起传递,作用域限于初始运行,因此不在 agent 上持久化。与 agent 作用域变量一样,它们静态加密,名称不能以 CURSOR_ 开头。
每次运行环境变量仅适用于云端 agent,且不适用于针对公共仓库运行的 agent。对于本地 agent,agent 进程继承你自己的环境,因此在调用 send() 之前在进程上设置变量。
对话模式
传入 mode: "plan" 或 mode: "agent" 控制运行是先探索和规划还是直接实现更改。参见 Plan mode 了解产品中计划模式的作用。
在 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 文本、工具调用参数流入、思考增量、嵌套任务更新、步骤边界),向 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> | 仅云端 agent。为本次运行注入的环境变量,运行结束时移除。仅本次运行按名称覆盖 agent 作用域的 cloud.envVars。 |
local.force | boolean | 仅本地 agent。默认为 false。在开始此消息前使卡住的活跃运行过期。云端返回 409 agent_busy 服务端,因此无需等效项。 |
local.customTools | Record<string, SDKCustomTool> | 仅本地 agent。本次运行的自定义工具。替换该次运行的 agent 创建时 local.customTools。 |
接下来三节是 SDKMessage、InteractionUpdate 和 ConversationTurn 的详细参考。首次阅读可略过;Resuming agents 继续叙述。
流事件
来自 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 视为未知并防御性解析。事件信封(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 是 agent 在工作;其余是终止状态。
SDKUsageMessage 在每个报告 token 用量的轮次结束时发出一次,携带该轮次的 TokenUsage。跨轮次的累计总量保留在 run.usage 和 result.usage 上。参见 Token usage。
交互更新
InteractionUpdate 是传给 agent.send() 上 onDelta 回调的原始增量类型。更新比 SDKMessage 事件更细粒度:文本逐 token 流入,工具调用在参数累积时报告部分状态,思考实时到达。
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 携带任务或子 agent 工具调用的一层嵌套交互更新。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 下的稳定性说明。
恢复 agent
function Agent.resume(agentId: string, options?: Partial<AgentOptions>): Promise<SDKAgent>;
使用 Agent.resume() 按 ID 重新附加到现有 agent。常见流程:重新连接到之前启动的长时间运行的云端 agent,或在本地进程重启后继续对话。运行时从 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)。
检查 agent 和运行
列出、获取和重新加载过去的 agent。列表端点返回 { 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;
}
运行时从 agent 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 };
云端 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 存储的用户和助手消息。
Agent.getUsage()
获取 agent 运行的计费 token 用量和美元成本。在句柄上调用,或没有句柄时按 ID 静态调用。云端 agent 返回逐运行细分;本地 agent 返回逐轮细分。传递 runId 将结果限制为一条:云端 agent 为 run-<uuid> 运行 ID,本地 agent 为之前 getUsage().runs[].runId 中的 ID。
本地 agent 的用量正在逐步推出,按账号启用。在 API 密钥的账号启用之前,本地 agent 上的 getUsage() 返回 403 feature_unavailable,SDK 将其抛出为 UnknownAgentError,error.code === "feature_unavailable"。云端 agent 不受限制。同时,从 run.usage 或 result.usage 读取每次运行的 token 计数(参见 Token usage),并从用量仪表板的 SDK 标签读取计费成本。
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; // agent 总计
cost?: UsageCost; // agent 总计
runs: RunUsage[];
}
interface RunUsage {
runId: string;
usage: TokenUsage;
cost?: UsageCost;
}
interface UsageCost {
rawCostCents: number; // 未折扣的模型 token 成本;按请求定价的用量为 0
chargedCents: number; // 收取金额,包含折扣和 Cursor Token Fee
}
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);
}
对于不带 runId 调用的云端 agent,usage 和 cost 也计入 agent 的 Task 子 agent 和侧聊,因此可能大于运行之和。带 runId 时,usage、cost 和该运行的条目也计入从运行开始到 agent 下一次运行开始之间的子 agent 和侧聊用量,如 Get Agent Usage 所述。
成本包含折扣,运行结束后可能需要片刻结算;结算前 cost 不存在。chargedCents 对于计划包含、BYOK 和信用授予的用量为 0。
这是与 Token usage 不同的视图:run.usage 是一次运行的实时 token 计数,而 getUsage() 是 agent 运行的计费记录。
云端 agent 生命周期
云端 agent 留在你团队的工作区中,直到你归档或删除它们。Agent.list({ runtime: "cloud" }) 默认隐藏已归档 agent;传递 includeArchived: true 以查看它们。按 prUrl 过滤以找到打开特定拉取请求的 agent。
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); // 恢复已归档 agent
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: "logged-in", backendUrl, email?, apiKeyExpiresAtMs? }
// | { status: "logged-out" }
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 写入 stderr。 |
signal | 取消等待的 AbortSignal;登录然后抛出 AuthenticationError。 |
store | 持久化凭证的位置。默认为 ~/.cursor/sdk/auth.json;传 null 仅在结果中接收密钥。 |
apiKeyName | 仪表板 API 密钥列表中铸造密钥的显示名称。 |
apiKeyTtlMs | 铸造密钥的生命周期,以毫秒为单位。默认 90 天。 |
Cursor.auth.login() 返回 { apiKey, email?, apiKeyExpiresAtMs }。使用 FileCredentialStore 或 InMemoryCredentialStore 为 login()、status() 或 logout() 提供自定义存储。
SDK 中各处的凭证解析顺序:显式 apiKey,然后 CURSOR_API_KEY,然后存储的登录。存储的登录不会从本地 Cursor 应用安装读取凭证;它只持有由 Cursor.auth.login() 铸造的密钥。
Cursor.configure()
function Cursor.configure(options: CursorConfigureOptions): void;
interface CursorConfigureOptions {
local?: {
store?: LocalAgentStore | null;
useHttp1ForAgent?: boolean | null;
workspaceScanCacheTtlMs?: number | null;
};
}
为本地 agent 设置默认值,适用于后续 Agent.* 调用。单个调用上的字段覆盖这些值;传 null 清除之前的默认值。
| 选项 | 描述 |
|---|---|
local.store | 调用省略 local.store 时的默认本地 agent 存储。SDK 通过 node:sqlite 使用磁盘上的 SQLite;当该模块不可用时,Agent.create() 抛出 ConfigurationError,除非你在此配置 JsonlLocalAgentStore 或其他存储。 |
local.useHttp1ForAgent | 强制本地 agent 后端流使用 HTTP/1.1 与 SSE 而非 HTTP/2。在代理后面或在不支持 HTTP/2 的 fetch 栈上有用。 |
Bun 由于上游 HTTP/2 兼容性问题默认使用 HTTP/1.1。
| local.workspaceScanCacheTtlMs | SDK 重用工作区扫描(规则、技能、AGENTS.md、忽略文件)的时长,以毫秒为单位。默认 20 秒。在服务于仅部署时更改的检出的长期宿主中提高它;代价是新鲜度,因为进程启动后添加的规则可能在此时间内不可见。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() 发现有效的模型 id 和按模型的参数。参数是模型特定的。常见示例包括推理力度和 Cursor Router 在 auto-smart 上的 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: "Fast",
// values: [
// { value: "false" },
// { value: "true", displayName: "Fast" },
// ],
// },
// ]
通过 model.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 仓库。仅云端。
配置源一览
MCP 服务器、子 agent 和 hooks 都从内联选项和磁盘配置的混合中解析。三者的优先级形状相同:每次发送内联 > 创建时内联 > 项目文件 > 用户文件 > 团队/仪表板配置。
| 功能 | 内联选项 | 本地文件(项目) | 本地文件(用户) | 云端/仪表板 | 优先级 |
|---|---|---|---|---|---|
| MCP 服务器 | Agent.create() 和 agent.send() 上的 mcpServers | .cursor/mcp.json(由包含 "project" 的 local.settingSources 控制) | ~/.cursor/mcp.json(由 "user" 控制) | 在 cursor.com/agents 配置的服务器(仅云端) | 发送 > 创建 > 插件 > 项目 > 用户(本地);发送 > 创建 > 仪表板(云端) |
| 子 agent | Agent.create() 上的 agents | .cursor/agents/*.md(frontmatter:name、description、model?) | 不适用 | 云端在针对克隆仓库运行时拾取相同的项目文件 | 内联以相同名称覆盖基于文件的 |
| Hooks | 无——仅基于文件 | .cursor/hooks.json(+ 脚本) | ~/.cursor/hooks.json | 云端运行项目 hooks。Enterprise 计划还运行团队和企业管理的 hooks。 | 基于文件;项目与用户/团队/企业按 Hooks 分层 |
| 设置源 | local.settingSources 选择要加载的磁盘层 | .cursor/ | ~/.cursor/ | 不适用 | 云端始终加载项目/团队/插件并忽略 local.settingSources。 |
内联值适合不应接触磁盘的密钥(每次运行的 API 密钥、租户作用域 token)。基于文件的配置适合策略:hooks 尤其是项目边界,而非每次运行的旋钮。
MCP 服务器
Agent 可以从多个源拾取 MCP 服务器。Agent.create() 或 agent.send() 中的内联定义是最常见的路径。也支持基于文件和仪表板管理的配置。
加载内容
本地 agent 从最多五个源加载服务器,冲突名称上先匹配者胜:
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 应用登录该服务器时才有效,此时 SDK 重用保存的登录。
云端 agent 从以下加载服务器:
agent.send()上的mcpServers。完全替换该次运行的创建时服务器(不合并)。Agent.create()上的mcpServers。未提供每次发送覆盖时使用。- 你在 cursor.com/agents 的用户和团队 MCP 服务器。
如果内联服务器不包含 auth 或 headers,且你之前在 cursor.com/agents 授权过该服务器 URL,使用个人 API token 认证的运行会自动重用那些 OAuth token。服务账号 API 密钥不能回退到用户认证,因为它们不与用户关联。
local.settingSources 不适用于云端 agent。
本地
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(),
},
},
});
云端
云端 agent 也可以内联接收认证的 MCP 配置。当 Cursor 应通过后端代理远程 MCP 时使用 HTTP auth。当服务器在云端 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!,
},
},
},
});
使用 headers 传递静态 API 密钥或 Bearer token——Cursor 在每个请求上传递它们。使用 auth 传递 OAuth 保护的服务器。对于云端,Cursor 在服务端运行一次 OAuth 流程并在运行之间重用 token。本地,SDK 无法打开浏览器让你登录;它只重用你已通过 Cursor 应用登录获得的 token。
- HTTP headers 和 auth 由 Cursor 后端处理。敏感字段被编辑,不进入 VM。
- Stdio env 值传入 VM,因为服务器在那里运行。像任何其他运行时密钥一样对待它们。
- 在 cursor.com/agents 配置的 MCP 服务器的 OAuth 保持每用户,即使团队级服务器也是如此。
完整配置格式参见 MCP,云端特定行为参见 Cloud Agent capabilities。
子 agent
定义主 agent 通过 Agent 工具生成的命名子 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 也会被拾取。内联定义以相同名称覆盖基于文件的。
嵌套子 agent
子 agent 可以在嵌套限制内生成自己的子 agent。当子 agent 使用 Agent 工具时,SDK 给它父级拥有的相同子 agent 执行器,因此父级可以委托给进一步委托的子 agent。每一层到达相同的命名子 agent 和自定义工具集。顶层 agent 及其直接子 agent 可以启动子 agent,但由另一个子 agent 启动的子 agent 不能再启动进一步的。
后台子 agent
当 agent 在后台运行子 agent 时,子 agent 的结果作为同一运行上的后续轮次返回给父级,而不是在父轮结束时丢弃。run.stream() 继续在这些轮次中产生事件,run.wait() 在它们之后解析,以最后一轮的文本作为 result。仅本地 agent。
限制工具集
tools 允许列表模型提供的内置工具;disallowedTools 移除工具并保留其余,包括 SDK 版本发布后添加到平台的工具。两者目前仅本地 agent,且都不在 agent 上持久化:在 Agent.resume() 时再次传递它们以保留后续运行的限制。
// 只读 agent:只提供这些工具。
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"阻止子 agent;否则子 agent 保留自己精选的工具集。
自定义工具
自定义工具让你向 agent 暴露自己的函数,而无需搭建单独的 MCP 服务器。在 local.customTools 上传递它们,SDK 将它们注册为名为 custom-user-tools 的 MCP 服务器。agent 通过与任何其他服务器相同的 MCP 路径发现并调用它们。拒绝规则和沙箱限制仍适用,但自定义工具跳过交互式批准,因此沙箱化和自动审查运行调用它们时不会提示。自定义工具也到达子 agent(包括嵌套的)。
自定义工具仅本地 agent。云端 agent 在创建时忽略 local.customTools,在 send() 上传入时抛出 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>;
outputSchema?: Record<string, SDKJsonValue>;
annotations?: SDKToolAnnotations;
execute: (
args: Record<string, SDKJsonValue>,
context: SDKCustomToolContext
) => SDKCustomToolResult | Promise<SDKCustomToolResult>;
}
interface SDKToolAnnotations {
title?: string;
readOnlyHint?: boolean;
destructiveHint?: boolean;
idempotentHint?: boolean;
openWorldHint?: boolean;
}
interface SDKCustomToolContext {
toolCallId?: string;
sessionId?: string;
}
| 字段 | 描述 |
|---|---|
description | 展示给模型,使其知道何时调用工具。默认为空字符串。 |
inputSchema | 参数的 JSON Schema。默认为接受任何属性的开放对象。 |
outputSchema | 工具结构化结果的 JSON Schema,作为 MCP Tool.outputSchema 向模型宣传。结果不针对其验证。 |
annotations | MCP 工具注解(title、readOnlyHint、destructiveHint、idempotentHint、openWorldHint)传递给模型。仅描述性提示;SDK 中没有任何东西强制执行它们。 |
execute | 你的回调。接收解析后的参数和带有调用工具的本地会话的 toolCallId 和 sessionId 的上下文。每个子 agent 获得自己的 sessionId。在你的进程中运行,因此可以到达你的代码能到达的任何东西。 |
工具结果
execute 可以返回纯字符串、任何 JSON 值或结构化信封。映射键是模型调用的工具名称。
type SDKCustomToolResult =
| string
| SDKJsonValue
| {
content: SDKCustomToolContent[];
isError?: boolean;
structuredContent?: Record<string, SDKJsonValue>;
};
type SDKCustomToolContent =
| { type: "text"; text: string }
| { type: "image"; data: string; mimeType?: string };
- 返回字符串以输出纯文本。
- 返回任何 JSON 值将其作为文本发回;对象还填充
structuredContent。 - 返回信封以获得完全控制:混合文本和 base64 图像内容,设置
isError: true报告失败,或附加structuredContent供模型解析。从execute抛出也作为工具错误报告回 agent。
Hooks
Hooks 仅基于文件。没有程序化 hook 回调。Hooks 是项目策略边界,不是每次运行的旋钮。
- 本地:将
.cursor/hooks.json添加到作为local.cwd传递的仓库,或添加~/.cursor/hooks.json用于用户级 hooks。 - 云端:将
.cursor/hooks.json及其脚本提交到cloud.repos中传递的仓库。SDK 创建的云端 agent 自动加载项目 hooks。在 Enterprise 计划上,它们还运行团队 hooks 和企业管理的 hooks。
配置格式参见 Hooks,云端行为参见 Cloud Agents hooks support。
沙箱选项
本地 agent 默认使用 local.sandboxOptions.enabled: false 运行。agent 可以读写工作目录、执行 shell 命令并访问网络,无限制。无头 SDK 运行中没有人在环批准流程,因此默认沙箱要么静默阻止合法的工具调用,要么需要不适合脚本的回调。
启用沙箱时,SDK 约束每个 shell 工具调用和 shell 生成的进程:
- 文件系统。写入限于工作目录(
local.cwd)、临时目录和你在sandbox.json中允许的路径。读取不限于工作区。 - 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 },
},
});
如果宿主不支持沙箱(缺少 bubblewrap 的旧 Linux、缺少助手二进制),SDK 抛出 ConfigurationError,消息指明缺少的依赖。禁用 sandboxOptions.enabled 或在云端模式运行以恢复。
云端运行始终在隔离的 VM 内执行,因此 sandboxOptions 不适用。
自动审查
默认情况下,本地 agent 无限制地运行每个工具调用,因为无头运行没有人来批准它们。设置 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 需要在连接的后端启用分类器;不可用时,运行回退到默认行为。因为无头运行中没有交互式批准,分类器阻止的调用被拒绝而非升级,agent 获得阻止原因并可以尝试另一种方法。用工作区中的 permissions.json autoRun 块引导分类器,与 IDE 中相同。格式参见 permissions.json。
Auto-review 仅本地 agent。云端运行已在隔离的 VM 中执行。分类器是尽力而为的便利,不是安全边界;将其与 sandboxOptions 或允许列表结合以实现严格控制。
工件
列出并下载 agent 工作区中的文件。
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);
工件支持因运行时而异。本地 SDK agent 当前不返回工件,downloadArtifact 抛出。
资源管理
完成后始终销毁 agent。最干净的模式是 await using:
await using agent = await Agent.create({ /* ... */ });
// 块退出时自动销毁
要显式销毁:
await agent[Symbol.asyncDispose]();
agent.close() 是开始销毁而不等待的文档化方式。Symbol.asyncDispose 有效(await using 基于它构建),但 close() 是不使用 await using 语法的代码中应采用的路径。agent.reload() 在不销毁的情况下拾取文件系统配置更改(hooks、项目 MCP、子 agent)。
Agent 生命周期
预热本地工作区
解析本地工作区(规则、技能、MCP 服务器、忽略文件)是本地 agent 首轮最慢的部分,在大型仓库上可能主导它。默认该成本落在首次 send() 内。知道 agent 将在哪里运行的宿主可以用 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(); // 关闭时
传递你的 agent 将使用的相同 AgentOptions;预热仅帮助工作区选项匹配的发送。宿主关闭时调用返回的 release 函数。
重新附加到现有 agent
Agent.resume(agentId) 返回已存在 agent 的新句柄。运行时从 ID 前缀自动检测(bc- 是云端,其他是本地),对话状态从云端(云端)或本地检查点存储(本地)加载。这是在进程重启后继续工作,或不同 worker 拾取另一个进程启动的 agent 的方式。
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 })(或本地等效项)返回一个可以 stream()、wait() 或 cancel() 的 Run。
对话上下文
本地 agent 在检查点存储中持久化对话状态。默认是主目录下的磁盘 SQLite;用 local.store 换为 JSONL 或自定义后端。每次 agent.send() 调用加载该 agent 的最新检查点并将其传给模型,因此后续调用看到上一次运行结束时的相同上下文。存储存活于进程重启,这意味着从全新进程 Agent.resume(agentId) 从上一个进程离开的地方继续。
云端 agent 在服务端持久化状态。从任何地方重新附加返回相同的对话。
一些看起来像上下文丢失但实际不是的情况:
- 新的
Agent.create()总是以新agentId启动全新 agent。要继续现有对话,从首次调用捕获agent.agentId,之后使用Agent.resume(agentId)。 Agent.prompt()一次性创建、运行和销毁。没有第二轮;这就是契约。- 内联
mcpServers不在Agent.resume()之间持久化,因为它们通常携带密钥。在恢复时再次传递它们,或使用基于文件的 MCP 配置。
调度器模式
调度器拥有 agent 池,并在工作到达时将工作交给它们。形状很直接:保持 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 存储
本地 agent 将 agent 元数据、对话检查点、运行和运行事件持久化到磁盘,以便后续调用和 Agent.resume() 存活于进程重启。默认 SDK 通过 node:sqlite 使用磁盘上的 SQLite。当该模块不可用时,Agent.create() 抛出 ConfigurationError 而不是回退。你可以用 local.store 换入不同的后端。
SDK 附带两个后端并允许你自带:
| 存储 | 导入 | 使用场景 |
|---|---|---|
SqliteLocalAgentStore | @cursor/sdk/sqlite | 工作区状态根下的磁盘 SQLite。 |
JsonlLocalAgentStore | @cursor/sdk | 你选择的目录下的可移植换行分隔 JSON(NDJSON)文件。易于检查、复制和 diff。 |
自定义 LocalAgentStore | 你的代码 | 持久化到任何地方:内存、Redis、Postgres 或托管数据库。实现接口或组合子存储。 |
云端 agent 在服务端持久化,因此 local.store 仅适用于本地 agent。
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() },
});
传 store: null 到 Cursor.configure({ local: { store: null } }) 以清除之前的默认值并返回 SDK 的默认本地存储选择。
自定义存储
要持久化到其他地方(共享 Postgres、Redis 或测试用的内存映射),实现 LocalAgentStore。它是四个子存储,每个是 SDK 调用的小型 CRUD 表面:
interface LocalAgentStore {
readonly agents: LocalAgentStoreAgents; // agent 元数据行
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 每 agent 一行(带一个精简的 latestCheckpoint.rootBlobId 指针),checkpoints 持有那些指针引用的内容寻址对话 blob,runs 每次运行一行,runEvents 是仅追加的流日志。目录子存储用不透明 cursor / nextCursor 分页;运行事件日志用排他 afterOffset / nextOffset 恢复。确切形状参见导出的 LocalAgentStore、LocalAgentDocument、LocalAgentRunDocument 和相关类型。
配置参考
AgentOptions
| 属性 | 类型 | 默认 | 描述 |
|---|---|---|---|
model | ModelSelection | 首次本地发送前必需;云端回退到服务器解析的默认值 | 使用的模型。参见 ModelSelection。 |
apiKey | string | CURSOR_API_KEY 环境变量 | 用户 API 密钥或服务账号密钥。Team Admin 密钥尚不支持。 |
name | string | 自动生成 | 人类可读的 agent 名称,作为 Agent.list() / Agent.get() 中的 name 返回。 |
local | LocalAgentOptions | 本地 agent 配置。参见 LocalAgentOptions。 | |
cloud | CloudAgentOptions | 云端 agent 配置。 | |
mcpServers | Record<string, McpServerConfig> | 内联 MCP 服务器定义。 | |
agents | Record<string, AgentDefinition> | 子 agent 定义。 | |
tools | ToolName[] | 默认工具集 | 限制工具集:只向模型提供列出的内置工具。[] 表示无内置工具。仅本地 agent。 |
disallowedTools | ToolName[] | 从工具集中移除工具;其余保持可用。与 tools 组合时拒绝优先。仅本地 agent。 | |
systemPrompt | string | Cursor 内置提示 | 替换主 agent 循环的系统提示。必须非空。仅本地 agent,且不在 Agent.resume() 之间持久化。 |
agentId | string | 自动生成 | 持久 agent ID。传递以在调用之间保持稳定 ID。 |
idempotencyKey | string | 云端自动生成 | 可选的客户端生成的幂等键。 |
mode | "agent" | "plan" | "agent" | agent 首次运行的初始对话模式。参见 Conversation mode。 |
LocalAgentOptions
本地 agent 的配置,作为 Agent.create() 上的 local 传递。也作为独立类型导出为 Partial<LocalAgentOptions>。
| 属性 | 类型 | 默认 | 描述 |
|---|---|---|---|
cwd | string | 默认 shell 和 agent 存储作用域的主工作目录。 | |
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 默认存储 | 支持持久化的本地 agent 存储。 |
enableAgentRetries | boolean | true | 为本地 agent 运行启用传输和停滞自动重试。设为 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 为默认值以获得空工作区的无仓库 agent。命名 Cursor 托管环境和显式 repos 互斥。 |
repos | Array<{ url: string; startingRef?: string; prUrl?: string }> | 克隆到 VM 的仓库。单仓库 agent 传一个条目,多仓库 agent 最多传 20 个。自托管目标接受一个条目,除非 env.name 命名 any-repo 池。省略或传 [] 为无仓库 agent。与 Cursor 托管环境的命名 env.name 互斥。传 prUrl 将 agent 附加到现有 PR。 | |
workOnCurrentBranch | boolean | false | 将提交推送到现有分支而非新分支。 |
autoCreatePR | boolean | false | 运行结束时打开 PR。 |
openAsCursorGithubApp | boolean | 服务账号密钥为 true,用户密钥为 false | 以 Cursor GitHub App 而非 API 密钥所有者打开 PR。解析值在 create、get 和 list 上回显。 |
skipReviewerRequest | boolean | false | 跳过请求调用用户作为 PR 审查者。 |
envVars | Record<string, string> | 云端 agent 的会话作用域环境变量。 | |
metadata | Record<string, string> | 调用方拥有的字符串标签,持久化在云端 agent 上。参见 Agent metadata。 |
AgentDefinition
| 属性 | 类型 | 默认 | 描述 |
|---|---|---|---|
description | string | 必需 | 何时使用此子 agent。展示给父 agent,使其知道何时生成。 |
prompt | string | 必需 | 子 agent 的系统提示。 |
model | ModelSelection | "inherit" | "inherit" | 模型覆盖。传 "inherit" 使用父级的选择。 |
mcpServers | Array<string | Record<string, McpServerConfig>> | 为前向兼容而接受。字符串引用被忽略,内联配置抛出 ConfigurationError;子 agent 继承父级的 MCP 服务器。 |
ModelSelection
interface ModelSelection {
id: string;
params?: ModelParameterValue[];
}
interface ModelParameterValue {
id: string;
value: string;
}
id 是模型标识符(例如 "composer-2.5" 或 "auto-smart")。params 携带按模型的参数,如推理力度或 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(像任何其他运行时密钥一样对待它们)。
SDKUserMessage
interface SDKUserMessage {
text: string;
images?: SDKImage[];
}
agent.send() 的 message 参数的结构化形式。用它随文本发送图片。
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";
控制本地 agent 加载哪些磁盘设置层。云端 agent 始终加载项目/团队/插件并忽略此字段。
| 值 | 源 |
|---|---|
"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 | “Invalid API key” | 缺少或错误的 CURSOR_API_KEY、过期 token 或管理员禁用了密钥。 | 从 API Keys(用户)或 Team 设置(服务账号)生成新密钥。确认密钥有操作权限。 |
RateLimitError | “Rate limit exceeded” 或 “Usage limit exceeded” | 突发限制或每月用量上限。 | 使用指数延迟退避(SDK 对瞬时情况报告 isRetryable: true)。对于每月上限,提高计划的用量限制。 |
ConfigurationError | “Bad model name”、“API key not supported”、“File unsupported” | 无效的 model.id、缺少必需参数、工具调用中不支持的文件,或阻止请求的管理员策略。 | 调用 Cursor.models.list() 确认 id 和参数。检查仓库/文件路径存在。 |
AgentBusyError | “Agent is busy” | 同一云端 agent 已在 CREATING 或 RUNNING 状态时发送后续消息。 | 等待活跃运行完成、取消它,或在再次发送前轮询 Agent.listRuns()。 |
IntegrationNotConnectedError | “[provider] integration is not connected” | 为 SCM 提供方未连接到你的 Cursor 团队的仓库创建云端 agent。 | 打开 error.helpUrl 重新连接提供方,然后重试。 |
NetworkError | “Service unavailable”、“Timeout” | 瞬时后端问题、网络分区或截止时间超出。 | 退避重试。需要提交支持工单时检查 error.requestId。 |
UnsupportedRunOperationError | “Operation “stream” is not supported on this runtime” | 调用当前运行时无法满足的 Run 方法(例如在已完成的重新获取的本地运行上流式传输)。 | 先用 run.supports(operation) / run.unsupportedReason(operation) 检查。 |
AgentNotFoundError | “Agent not found” | 请求的 agent 不存在或在解析的本地工作区下不可见。 | 检查 agent 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"、"azure-devops"
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 不返回 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)和systemPrompt仅本地 agent。云端 agent 在send()上拒绝local.customTools并在服务端持久化。 tools、disallowedTools和systemPrompt不在 agent 上持久化。在Agent.resume()时再次传递它们以保留。- 工件下载未为本地 agent 实现(
agent.listArtifacts()返回空列表,agent.downloadArtifact()抛出)。 local.settingSources(及其控制的基于文件的 MCP / 子 agent 路径)不适用于云端 agent。云端始终加载项目/团队/插件。- Hooks 仅基于文件(
.cursor/hooks.json)。无程序化回调。 - SDK 不从本地 Cursor 应用安装自动发现凭证。显式设置
CURSOR_API_KEY(或传入apiKey),或用Cursor.auth.login()铸造密钥。 - 本地模式需要 Node.js 22.13 或更高版本和平台沙箱助手支持。默认存储需要
node:sqlite;当它不可用时,Agent.create()抛出ConfigurationError,直到你配置JsonlLocalAgentStore或其他存储。
以上是完整的简体中文版 Markdown 文档。
更多推荐


所有评论(0)