《Cursor文档》-Cursor TypeScript SDK

@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() 的键 (localcloud) 决定。两种运行时都使用相同的 CURSOR_API_KEY

如需了解 REST API,请参阅 Cloud Agents API。如需了解其他语言,请参阅 SDK Bridge

身份验证

创建智能体前,请设置 CURSOR_API_KEY (或传入 apiKey) 。对于尚未预配密钥的交互式主机,Cursor.auth.login() 会通过浏览器登录签发并存储密钥。

SDK 支持将用户 API 密钥和服务账户 API 密钥用于本地和云端运行。暂不支持团队 Admin 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() 会验证选项,并立即返回句柄。传入 localcloud 以选择运行时。

// 本地智能体
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

产品文案中使用 Balancebalanced 仅用作 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-smartautodefault

选择 含义
搭配 optimize_for 使用 auto-smart Cursor Router。需要 Cost、Balance 或 Intelligence 时使用。
{ id: "auto" } 当目录中没有指定模型时,由服务器选择的 Auto 回退方案。如需显式指定 Router 模式,优先使用 auto-smart
省略 optimize_for 或传入 default 不受支持的 Router 合约。请始终查询允许的值,并传入 costbalancedintelligence

计费与路由用量池

  • 所有 Auto 模式均按每个请求所路由模型的标价计费。
  • 底层模型可能因请求而异。需要进行可复现的比较时,请优先使用固定的模型 ID。
  • 企业版模型允许列表决定路由用量池。屏蔽必需模型可能会禁用 Router。

有关当前费率和路由用量池,请参阅 Cursor RouterAuto 模式

Router 缺失的疑难排查

如果找不到 auto-smart,或优化模式被拒绝:

  1. 调用 Cursor.models.list()
  2. 确认结果中包含 auto-smart
  3. 确认 optimize_for 包含所需的值 (costbalancedintelligence) 。
  4. 确认与 API 密钥关联的团队已启用 Router。
  5. 如果您属于多个团队,请确认该密钥在预期的团队上下文中使用。
  6. 如果 Router 不可用或无法选择有效的底层模型,请检查团队的模型访问策略。

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 中。无需在 textmessagemessagescontent 字段中查找。如果需要按步骤获取会话记录,请调用 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)。它会在每个上报用量的轮次结束时触发一次,并携带该轮的 TokenUsagerun.usageresult.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 字段在 RunRunResult 中提供。使用它将脚本或 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.modelresult.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() 传入 onDeltaonStep 回调:

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-deltathinking-deltathinking-completedtool-call-startedtool-call-completedtool-call-deltapartial-tool-calltoken-deltastep-startedstep-completedturn-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,仅对此次运行生效。

接下来的三个部分详细介绍 SDKMessageInteractionUpdateConversationTurn。首次阅读时可快速浏览或跳过;恢复智能体将继续正文。

流事件

run.stream() 产生的事件。可通过 type 区分。所有事件均包含 agent_idrun_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 事件中的 argsresult 负载反映各工具的内部结构,可能会随工具演进而变化。工具名称也可能被重命名或替换。请将 argsresult 视为 unknown,并进行防御性解析。事件信封 (typecall_idnamestatus) 是稳定的。

消息类型

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") ,并填充 resulttruncated 标志表示 SDK 是否因负载过大而截断了 argsresult

SDKStatusMessage 涵盖云端的生命周期状态转换。CREATING 表示 VM 配置和仓库克隆;RUNNING 表示智能体正在工作;其余均为终态。

每个报告使用量的轮次结束时,都会发出一次 SDKUsageMessage,其中包含该轮的 TokenUsage。跨轮次的累计总用量保存在 run.usageresult.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.modelundefined。内联 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() 和其他读取操作无需 apiKeyCURSOR_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
InMemoryCredentialStorelogin()status()
logout() 提供自定义 store

SDK 中所有位置的凭据解析顺序:显式指定的 apiKeyCURSOR_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:namedescriptionmodel?) 不适用 智能体针对克隆的仓库运行时,云端会加载相同的项目文件 内联配置会覆盖同名的文件配置
钩子 无 — 仅支持文件配置 .cursor/hooks.json (+ 脚本) ~/.cursor/hooks.json 云端运行项目钩子。企业版方案还会运行团队和企业管理的钩子。 基于文件;项目配置会与用户 / 团队 / 企业配置分层,详见 Hooks
配置来源 local.settingSources 用于选择要加载的磁盘配置层 .cursor/ ~/.cursor/ 不适用 云端始终加载 project / team / plugins,并忽略 local.settingSources

内联值适合绝不应写入磁盘的机密信息 (如单次运行的 API 密钥、租户范围的 token) 。文件配置适合用于策略:钩子尤其如此,它们属于项目边界,而非单次运行的控制项。

MCP 服务器

智能体可从多种来源获取 MCP 服务器。最常见的方式是在 Agent.create()agent.send() 中内联定义。也支持基于文件的配置和通过仪表盘管理的配置。

加载的内容

本地智能体最多可从五个来源加载服务器;如果名称冲突,以最先匹配的来源为准:

  1. agent.send() 中的 mcpServers。会完全替换该次运行创建时的服务器 (不合并) 。
  2. Agent.create() 中的 mcpServers。未提供单次发送覆盖配置时使用。
  3. 插件服务器,前提是 local.settingSources 包含 "plugins"
  4. 来自 .cursor/mcp.json 的项目服务器,前提是 local.settingSources 包含 "project"
  5. 来自 ~/.cursor/mcp.json 的用户服务器,前提是 local.settingSources 包含 "user"

未设置 local.settingSources 时,只会加载内联服务器。如果本地 MCP 服务器需要通过 OAuth 登录,SDK 无法提示你登录。只有当你已在 Cursor app 中登录过该服务器时才能使用;此时 SDK 会复用已保存的登录凭据。

云端代理从以下来源加载服务器:

  1. agent.send() 中的 mcpServers。会完全替换该次运行创建时的服务器 (不合并) 。
  2. Agent.create() 中的 mcpServers。未提供单次发送覆盖配置时使用。
  3. 来自 cursor.com/agents 的用户和团队 MCP 服务器。

如果内联服务器不包含 authheaders,且你之前已在 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 headersauth 由 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 中的子智能体 (包含 namedescription 和可选的 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 以及包含 toolCallIdcontext。在您的 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.ndjsonruns.ndjsonrun_events.ndjsoncheckpoints.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.listAgent.getAgent.listRunsAgent.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 恢复。具体的数据结构请参阅导出的 LocalAgentStoreLocalAgentDocumentLocalAgentRunDocument 及相关类型。

配置参考

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 托管环境。poolmachine 会路由到您运行的自托管 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 服务器,headersauth 由 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 “智能体正忙” 同一云端代理已有处于 CREATINGRUNNING 状态的运行时,又发送了后续请求。 等待活跃运行完成、取消该运行,或在再次发送前轮询 Agent.listRuns()
IntegrationNotConnectedError “[提供商] 集成未连接” 为 SCM 提供商尚未连接到 Cursor 团队的仓库创建云端代理。 打开 error.helpUrl 重新连接提供商,然后重试。
NetworkError “服务不可用”、”超时” 临时后端问题、网络分区或超过截止时间。 使用退避策略重试。如需提交支持工单,请查看 error.requestId
UnsupportedRunOperationError “此运行时不支持操作 “stream”“ 调用了当前运行时无法支持的 Run 方法 (例如,对已完成的重新获取的本地运行进行流式处理) 。 先通过 run.supports(operation) / run.unsupportedReason(operation) 检查。
AgentNotFoundError “未找到智能体” 请求的智能体不存在,或在解析后的本地工作区中不可见。 检查智能体 ID、cwdlocal.store
UnknownAgentError 由服务器定义的消息 未分类的后端或运行时错误。 查看 error.codeerror.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_busyisRetryablefalse。立即重试会一直失败,直到正在运行的任务结束或您将其取消。其他 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) 和工具集限制 (toolsdisallowedTools) 仅适用于本地智能体。云端代理会拒绝 local.customTools,并在服务器端持久化。
  • toolsdisallowedTools 不会保留在智能体中。请在 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
羽毛球分组比赛记分
小程序二维码

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

小夜