Usando a API e o SDK do Cursor Cloud Agents

A API e o SDK do Cursor Cloud Agents oferecem controle programático sobre agentes de codificação baseados em nuvem. Em vez de iniciar e monitorar agentes manualmente pelo editor, você pode iniciá-los, orientá-los durante a execução, capturar a saída de suas telas e receber retornos de chamada webhook quando as tarefas são concluídas. Este guia percorre autenticação, gerenciamento de ciclo de vida, padrões de integração do SDK e dicas de solução de problemas coletadas de experiências reais de desenvolvedores.
Pré-requisitos e Configuração
Antes de integrar com a API Cloud Agents, certifique-se de ter o seguinte:
- Uma conta Cursor com acesso ao Cloud Agents ativado
- Uma chave de API gerada no painel de configurações do Cursor
- Node.js 18 ou superior (para o SDK TypeScript/JavaScript)
- Compreensão básica de padrões de programação assíncrona
Armazene sua chave de API em uma variável de ambiente em vez de codificá-la diretamente no código. Use um arquivo .env durante o desenvolvimento e um gerenciador de segredos em produção.
Instalando o SDK
Instale o SDK do Cursor Cloud Agents do registro público:
npm install @cursor/cloud-agents-sdk
# or
yarn add @cursor/cloud-agents-sdk
# or
pnpm add @cursor/cloud-agents-sdk
Verifique a instalação conferindo a versão do pacote:
npx @cursor/cloud-agents-sdk --version
Autenticação da API
Cada solicitação à API Cloud Agents requer um token bearer. O SDK lida com isso automaticamente quando você inicializa um cliente:
import { CursorCloudClient } from "@cursor/cloud-agents-sdk";
const client = new CursorCloudClient({
apiKey: process.env.CURSOR_API_KEY,
// Opcional: substituir o endpoint da API padrão
endpoint: "https://api.cursor.sh/v1",
// Opcional: definir um tempo limite padrão para todas as operações
timeout: 300000, // 5 minutos
});
Se preferir chamadas HTTP brutas em vez do SDK, inclua o cabeçalho manualmente:
import os
import requests
headers = {
"Authorization": f"Bearer {os.environ['CURSOR_API_KEY']}",
"Content-Type": "application/json",
}
response = requests.post(
"https://api.cursor.sh/v1/agents",
headers=headers,
json={
"repo": "https://github.com/my-org/my-repo",
"branch": "feature/auth-refactor",
"task": "Refactor the authentication module to use JWT",
},
)
print(response.json())
Nunca faça commit da sua chave de API no controle de versão. Se uma chave for comprometida, revogue-a imediatamente no painel do Cursor e gere uma nova. Faça rotação das chaves regularmente.
Ciclo de Vida do Agente em Nuvem
Um agente em nuvem progride por um ciclo de vida bem definido. Entender cada estado ajuda a construir pipelines de automação robustos.
Estados do Ciclo de Vida
| Estado | Descrição |
|---|---|
queued | O agente foi criado e está aguardando um slot na nuvem |
running | O agente está executando ativamente a tarefa |
paused | O agente foi pausado por um steering durante a execução ou intervenção manual |
completed | O agente concluiu a tarefa com sucesso |
failed | O agente encontrou um erro do qual não pôde se recuperar |
cancelled | O agente foi cancelado pelo usuário ou por um tempo limite |
Criando um Novo Agente
const agent = await client.agents.create({
repo: "https://github.com/my-org/my-repo",
branch: "feature/payment-gateway",
task: "Integrate Stripe payment gateway with proper error handling",
// Configurações opcionais
model: "cursor-agent-pro",
maxSteps: 50,
autoMerge: false,
environment: {
STRIPE_SECRET_KEY: process.env.STRIPE_SECRET_KEY,
},
});
console.log(`Agent created with ID: ${agent.id}`);
console.log(`Initial status: ${agent.status}`);
Monitorando o Status do Agente
Você pode consultar o status do agente ou assinar atualizações em tempo real:
// Abordagem de consulta (polling)
async function waitForCompletion(agentId: string) {
while (true) {
const status = await client.agents.get(agentId);
console.log(`[${new Date().toISOString()}] Status: ${status.state}`);
if (status.state === "completed") {
return status;
}
if (status.state === "failed" || status.state === "cancelled") {
throw new Error(`Agent ended in state: ${status.state}`);
}
await new Promise((resolve) => setTimeout(resolve, 10000)); // consulta a cada 10s
}
}
// Abordagem de streaming (recomendada)
const stream = await client.agents.stream(agent.id, (event) => {
console.log(`Event: ${event.type}`, event.data);
});
stream.on("step", (data) => {
console.log(`Agent step: ${data.description}`);
});
stream.on("file_change", (data) => {
console.log(`File modified: ${data.path}`);
});
stream.on("error", (data) => {
console.error(`Agent error: ${data.message}`);
});
Prefira a abordagem de streaming em vez de consulta (polling). Ela reduz chamadas de API, fornece atualizações de menor latência e evita problemas de limite de taxa durante tarefas de longa duração.
Steering Durante a Execução
Um dos recursos mais poderosos da API Cloud Agents é a capacidade de orientar um agente enquanto ele está em execução ativa. Isso permite corrigir o rumo, adicionar contexto ou mudar de direção sem recomeçar do zero.
Enviando uma Mensagem de Steering
const steerResult = await client.agents.steer(agent.id, {
message: "Stop using the mock data approach. Please connect to the real database using the connection string in the .env file.",
// Opcional: anexar uma referência de arquivo
attachments: ["src/config/database.ts"],
// Opcional: alterar o modelo durante a execução
model: "cursor-agent-pro",
});
console.log(`Steer accepted: ${steerResult.accepted}`);
console.log(`Agent now running with updated context`);
Cenários Comuns de Steering
O steering durante a execução é útil em várias situações:
- Corrigir uma abordagem errada: O agente começa a escrever testes simulados quando você queria testes de integração.
- Adicionar contexto ausente: O agente não sabe sobre um módulo utilitário compartilhado que você criou na semana passada.
- Mudar o escopo: Você quer que o agente também adicione documentação ao código que acabou de escrever.
- Impor restrições: O agente está prestes a modificar arquivos fora do escopo pretendido.
// Exemplo: Steering para adicionar escopo de documentação
await client.agents.steer(agent.id, {
message: "Great progress on the API endpoints. Now also add JSDoc comments to every exported function and update the README with the new endpoint list.",
});
// Exemplo: Steering para impor um limite de segurança
await client.agents.steer(agent.id, {
message: "Do not modify any files in the src/legacy/ directory. Those are deprecated modules scheduled for removal.",
});
As mensagens de steering são processadas de forma assíncrona. Há uma breve janela entre o envio do steering e a incorporação pelo agente. Não envie várias mensagens de steering conflitantes em rápida sucessão, pois isso pode confundir o agente e levar a um comportamento inconsistente.
Pausando e Retomando Agentes
// Pausar um agente em execução
await client.agents.pause(agent.id);
console.log("Agent paused");
// Revisar o estado atual
const state = await client.agents.get(agent.id);
console.log("Files changed so far:", state.filesChanged);
// Retomar quando estiver pronto
await client.agents.resume(agent.id);
console.log("Agent resumed");
API RecordScreen
A API RecordScreen captura instantâneos visuais da tela do agente em nuvem em momentos específicos. Isso é inestimável para depuração, auditoria e construção de painéis visuais.
Capturando uma Captura de Tela
// Capturar uma única captura de tela
const screenshot = await client.agents.recordScreen(agent.id, {
format: "png",
// Opcional: capturar apenas uma região
region: { x: 0, y: 0, width: 1920, height: 1080 },
// Opcional: incluir sobreposição da posição do cursor
showCursor: true,
});
// A captura de tela é retornada como uma string base64
const fs = require("fs");
fs.writeFileSync(`agent-${agent.id}-screenshot.png`, Buffer.from(screenshot.data, "base64"));
console.log(`Screenshot saved. Size: ${screenshot.width}x${screenshot.height}`);
Gravando um Clipe de Vídeo
// Iniciar uma gravação de tela
const recording = await client.agents.recordScreen(agent.id, {
mode: "video",
duration: 30000, // 30 segundos
fps: 15,
format: "webm",
});
// A gravação retorna uma URL para download
console.log(`Recording available at: ${recording.url}`);
console.log(`Recording expires at: ${recording.expiresAt}`);
Solução de Problemas do RecordScreen
Chamadas do RecordScreen podem falhar por vários motivos. Aqui estão os problemas mais comuns e suas soluções:
O RecordScreen retorna um erro 409 Conflict se o agente não estiver no estado running. Certifique-se de que o agente esteja em execução ativa antes de tentar capturar sua tela. Se o agente foi pausado ou concluído, você não pode gravar sua tela.
// Wrapper seguro do RecordScreen com tratamento de erros
async function safeRecordScreen(agentId: string, options: any) {
const agent = await client.agents.get(agentId);
if (agent.state !== "running") {
console.warn(`Cannot record screen: agent is in ${agent.state} state`);
return null;
}
try {
return await client.agents.recordScreen(agentId, options);
} catch (error: any) {
if (error.code === "SCREEN_CAPTURE_UNAVAILABLE") {
console.error("Screen capture is not available for this agent configuration.");
console.error("Make sure the agent was launched with screen capture enabled.");
} else if (error.code === "RATE_LIMITED") {
console.error("Too many screen capture requests. Please wait before retrying.");
console.log(`Retry after: ${error.retryAfter} seconds`);
} else {
throw error;
}
return null;
}
}
Para ativar a captura de tela ao criar um agente, defina a opção screenCapture:
const agent = await client.agents.create({
repo: "https://github.com/my-org/my-repo",
branch: "main",
task: "Fix the flaky integration tests",
screenCapture: {
enabled: true,
autoCapture: true, // Capturar automaticamente em cada etapa
captureInterval: 5000, // Capturar a cada 5 segundos
},
});
Ativar o autoCapture gera uma linha do tempo visual do trabalho do agente. Você pode reproduzir toda a sessão posteriormente para depuração ou revisões de conformidade. Esteja ciente de que isso aumenta o uso de armazenamento e pode afetar ligeiramente o desempenho do agente.
Retornos de Chamada Webhook
Webhooks permitem receber notificações em tempo real quando eventos do agente ocorrem. Isso é essencial para construir pipelines de CI/CD automatizados e painéis de monitoramento.
Registrando um Webhook
const webhook = await client.webhooks.create({
url: "https://my-app.com/api/cursor-webhook",
events: [
"agent.created",
"agent.step_completed",
"agent.completed",
"agent.failed",
"agent.steer_received",
],
// Opcional: adicionar um segredo para verificação de assinatura
secret: process.env.WEBHOOK_SECRET,
});
console.log(`Webhook registered with ID: ${webhook.id}`);
Processando Cargas Úteis de Webhook
Aqui está um exemplo de endpoint Express que recebe e verifica retornos de chamada webhook:
const express = require("express");
const crypto = require("crypto");
const app = express();
app.use(express.raw({ type: "application/json" }));
app.post("/api/cursor-webhook", (req, res) => {
// Verificar a assinatura do webhook
const signature = req.headers["x-cursor-signature"];
const expectedSignature = crypto
.createHmac("sha256", process.env.WEBHOOK_SECRET)
.update(req.body)
.digest("hex");
if (signature !== expectedSignature) {
return res.status(401).send("Invalid signature");
}
const event = JSON.parse(req.body.toString());
switch (event.type) {
case "agent.created":
console.log(`Agent ${event.data.agentId} created for repo ${event.data.repo}`);
break;
case "agent.step_completed":
console.log(`Agent ${event.data.agentId} completed step ${event.data.stepNumber}`);
console.log(` Files changed: ${event.data.filesChanged.join(", ")}`);
break;
case "agent.completed":
console.log(`Agent ${event.data.agentId} completed successfully`);
console.log(` Pull request: ${event.data.pullRequestUrl}`);
// Acionar pipeline de CI a jusante
triggerCIPipeline(event.data.agentId);
break;
case "agent.failed":
console.error(`Agent ${event.data.agentId} failed: ${event.data.error}`);
// Enviar alerta para o canal da equipe
sendAlert(event.data);
break;
}
// Sempre responder com 200 para confirmar o recebimento
res.status(200).send("OK");
});
app.listen(3000, () => {
console.log("Webhook server listening on port 3000");
});
Sempre verifique as assinaturas de webhook. Sem verificação de assinatura, um invasor poderia enviar cargas úteis de webhook falsificadas para seu endpoint. O cabeçalho x-cursor-signature contém um hash HMAC-SHA256 do corpo da solicitação bruta assinado com seu segredo de webhook.
Comportamento de Nova Tentativa de Webhook
Se o seu endpoint não responder com um status 200 em 10 segundos, a API tentará novamente a entrega. O cronograma de novas tentativas é:
| Tentativa | Atraso |
|---|---|
| 1ª nova tentativa | 1 minuto |
| 2ª nova tentativa | 5 minutos |
| 3ª nova tentativa | 30 minutos |
| 4ª nova tentativa | 2 horas |
| Final | 12 horas |
Após a tentativa final, a entrega do webhook é marcada como falha e você precisará verificar o status do agente manualmente via API.
Se o processamento do seu webhook envolver operações de longa duração, responda com 200 imediatamente e envie o trabalho para uma fila em segundo plano. Isso evita tempos limite e garante entrega confiável de webhook.
Padrões de Integração do SDK
Padrão 1: Integração de Pipeline de CI/CD
Gerar automaticamente um agente em nuvem quando um pull request é aberto:
import { CursorCloudClient } from "@cursor/cloud-agents-sdk";
const client = new CursorCloudClient({
apiKey: process.env.CURSOR_API_KEY,
});
export async function onPullRequestOpened(pr: any) {
const agent = await client.agents.create({
repo: pr.repositoryUrl,
branch: pr.headBranch,
task: `Review and improve this pull request. Focus on: ${pr.description}`,
autoMerge: false,
screenCapture: { enabled: true },
});
// Comentar no PR com o link do agente
await pr.addComment(
`A Cursor Cloud Agent is now reviewing this PR. ` +
`Track progress: https://cursor.sh/agents/${agent.id}`
);
return agent;
}
Padrão 2: Orquestração de Múltiplos Agentes
Executar vários agentes em paralelo em tarefas diferentes:
async function runParallelAgents(repo: string) {
const tasks = [
"Write unit tests for the authentication module",
"Write unit tests for the payment module",
"Write integration tests for the API endpoints",
"Update API documentation with OpenAPI specs",
];
const agents = await Promise.all(
tasks.map((task) =>
client.agents.create({
repo,
branch: "main",
task,
model: "cursor-agent-pro",
})
)
);
console.log(`Launched ${agents.length} agents in parallel`);
// Aguardar a conclusão de todos os agentes
const results = await Promise.allSettled(
agents.map((agent) => waitForCompletion(agent.id))
);
// Resumir resultados
results.forEach((result, index) => {
if (result.status === "fulfilled") {
console.log(`Task ${index + 1}: Completed - ${result.value.filesChanged.length} files changed`);
} else {
console.error(`Task ${index + 1}: Failed - ${result.reason.message}`);
}
});
}
Executar vários agentes em paralelo consome recursos de nuvem rapidamente. Monitore seu uso e defina um limite razoável de maxSteps para cada agente para controlar custos. Verifique o limite de agentes simultâneos do seu plano antes de lançar grandes lotes.
Padrão 3: Revisão Humana no Processo
Combinar webhooks com steering durante a execução para criar um ponto de verificação de revisão humana:
// Quando o agente atinge uma certa etapa, pausar para revisão humana
const stream = await client.agents.stream(agent.id, async (event) => {
if (event.type === "step" && event.data.stepNumber === 10) {
// Pausar o agente para revisão humana
await client.agents.pause(agent.id);
// Enviar uma notificação ao canal de revisão
await sendSlackNotification({
channel: "#code-review",
text: `Agent ${agent.id} has paused for review. Check the changes before resuming.`,
});
// O revisor humano retomará ou orientará o agente manualmente
}
});
Padrão 4: Recuperação Automática de Erros
async function runWithRetry(repo: string, task: string, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
const agent = await client.agents.create({
repo,
branch: "main",
task,
maxSteps: 30,
});
try {
const result = await waitForCompletion(agent.id);
if (result.state === "completed") {
return result;
}
} catch (error) {
console.error(`Attempt ${attempt} failed: ${error.message}`);
if (attempt < maxRetries) {
// Orientar a próxima tentativa com o contexto do erro
task = `${task}\n\nPrevious attempt failed with: ${error.message}. Please avoid this approach.`;
}
}
}
throw new Error(`Agent failed after ${maxRetries} attempts`);
}
Solução de Problemas Comuns
Agente Preso no Estado de Fila
Se um agente permanecer no estado queued por um período prolongado, geralmente significa que todos os slots de nuvem estão ocupados.
// Verificar o uso atual da conta
const usage = await client.usage.get();
console.log(`Active agents: ${usage.activeAgents}/${usage.maxConcurrentAgents}`);
console.log(`Queue length: ${usage.queueLength}`);
if (usage.activeAgents >= usage.maxConcurrentAgents) {
console.log("All slots are in use. Consider upgrading your plan or waiting for agents to complete.");
}
Erros de Autenticação do SDK
Se você receber um erro 401 Unauthorized, verifique o seguinte:
- Sua chave de API é válida e não foi revogada
- A chave tem o escopo
cloud-agentsativado - Você está usando a URL de endpoint correta
- A variável de ambiente está carregada corretamente
// Depurar autenticação
const client = new CursorCloudClient({
apiKey: process.env.CURSOR_API_KEY,
});
try {
const me = await client.auth.verify();
console.log("Authentication successful");
console.log(`Account: ${me.accountName}`);
console.log(`Plan: ${me.plan}`);
console.log(`Scopes: ${me.scopes.join(", ")}`);
} catch (error) {
console.error("Authentication failed:", error.message);
console.log("Check your API key and ensure it has the 'cloud-agents' scope.");
}
Falhas de Entrega de Webhook
Se os webhooks não estiverem chegando ao seu endpoint:
- Verifique se a URL do webhook é publicamente acessível (não localhost)
- Confirme que seu servidor retorna 200 em 10 segundos
- Verifique se seu certificado SSL é válido
- Certifique-se de que seu firewall permite conexões de entrada das faixas de IP do Cursor
// Testar acessibilidade do endpoint de webhook
const test = await client.webhooks.test(webhook.id);
console.log(`Test result: ${test.status}`);
console.log(`Response time: ${test.responseTime}ms`);
if (test.error) {
console.error(`Error: ${test.error}`);
}
Use um serviço como webhook.site ou ngrok durante o desenvolvimento para testar rapidamente a entrega de webhook sem implantar um servidor completo. Isso ajuda a isolar se o problema está no seu endpoint ou na configuração do webhook.
Resumo das Melhores Práticas
Aqui está uma lista de verificação das melhores práticas a seguir ao construir com a API e o SDK do Cursor Cloud Agents:
- Armazene sempre as chaves de API em variáveis de ambiente ou um gerenciador de segredos
- Use streaming em vez de consulta (polling) para atualizações em tempo real
- Implemente verificação de assinatura de webhook em cada endpoint
- Defina limites razoáveis de
maxStepspara controlar custos e evitar agentes descontrolados - Use steering durante a execução para corrigir o rumo em vez de reiniciar agentes
- Ative a captura de tela para depuração e trilhas de auditoria em tarefas críticas
- Implemente backoff exponencial ao repetir chamadas de API com falha
- Monitore o uso simultâneo de agentes para evitar inanição de fila
- Teste endpoints de webhook com o endpoint de teste integrado antes de entrar em produção
- Registre todos os eventos de agente para análise post-mortem e conformidade
Atenção aos limites de taxa. A API impõe um limite padrão de 100 solicitações por minuto. Se você exceder este limite, receberá uma resposta 429 Too Many Requests. Implemente backoff exponencial com jitter para lidar com repetições de limite de taxa de forma elegante.
Conclusão
A API e o SDK do Cursor Cloud Agents fornecem uma poderosa interface programática para automatizar tarefas de codificação em escala. Ao combinar gerenciamento de ciclo de vida do agente, steering durante a execução, API RecordScreen e retornos de chamada webhook, você pode construir pipelines de automação sofisticados que se integram perfeitamente ao seu fluxo de trabalho de desenvolvimento existente.
Comece com uma configuração simples de agente único, depois adicione gradualmente integração de webhook, orquestração paralela e pontos de verificação de revisão humana conforme sua confiança cresce. O design TypeScript-first do SDK facilita a integração em aplicações Node.js modernas, enquanto a API HTTP bruta suporta qualquer linguagem de programação.