chore: import upstream snapshot with attribution
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
+122
View File
@@ -0,0 +1,122 @@
import type { AddFollowupParams, AddFollowupResponse } from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const addFollowupBase = {
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cursor API key',
},
agentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique identifier for the cloud agent (e.g., bc_abc123)',
},
followupPromptText: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The follow-up instruction text for the agent',
},
promptImages: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'JSON array of image objects with base64 data and dimensions (max 5)',
},
},
request: {
url: (params: AddFollowupParams) =>
`https://api.cursor.com/v0/agents/${params.agentId.trim()}/followup`,
method: 'POST',
headers: (params: AddFollowupParams) => ({
'Content-Type': 'application/json',
Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`,
}),
body: (params: AddFollowupParams) => {
const body: Record<string, any> = {
prompt: {
text: params.followupPromptText,
},
}
if (params.promptImages) {
try {
body.prompt.images = JSON.parse(params.promptImages)
} catch {
body.prompt.images = []
}
}
return body
},
},
} satisfies Pick<ToolConfig<AddFollowupParams, any>, 'params' | 'request'>
export const addFollowupTool: ToolConfig<AddFollowupParams, AddFollowupResponse> = {
id: 'cursor_add_followup',
name: 'Cursor Add Follow-up',
description: 'Add a follow-up instruction to an existing cloud agent.',
version: '1.0.0',
...addFollowupBase,
transformResponse: async (response) => {
const data = await response.json()
const content = `Follow-up added to agent ${data.id}`
return {
success: true,
output: {
content,
metadata: {
id: data.id,
},
},
}
},
outputs: {
content: { type: 'string', description: 'Success message' },
metadata: {
type: 'object',
description: 'Result metadata',
properties: {
id: { type: 'string', description: 'Agent ID' },
},
},
},
}
interface AddFollowupV2Response {
success: boolean
output: {
id: string
}
}
export const addFollowupV2Tool: ToolConfig<AddFollowupParams, AddFollowupV2Response> = {
...addFollowupBase,
id: 'cursor_add_followup_v2',
name: 'Cursor Add Follow-up',
description:
'Add a follow-up instruction to an existing cloud agent. Returns API-aligned fields only.',
version: '2.0.0',
transformResponse: async (response) => {
const data = await response.json()
return {
success: true,
output: {
id: data.id,
},
}
},
outputs: {
id: { type: 'string', description: 'Agent ID' },
},
}
+90
View File
@@ -0,0 +1,90 @@
import type { DeleteAgentParams, DeleteAgentResponse } from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const deleteAgentBase = {
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cursor API key',
},
agentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique identifier for the cloud agent (e.g., bc_abc123)',
},
},
request: {
url: (params: DeleteAgentParams) => `https://api.cursor.com/v0/agents/${params.agentId.trim()}`,
method: 'DELETE',
headers: (params: DeleteAgentParams) => ({
Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`,
}),
},
} satisfies Pick<ToolConfig<DeleteAgentParams, any>, 'params' | 'request'>
export const deleteAgentTool: ToolConfig<DeleteAgentParams, DeleteAgentResponse> = {
id: 'cursor_delete_agent',
name: 'Cursor Delete Agent',
description: 'Permanently delete a cloud agent. This action cannot be undone.',
version: '1.0.0',
...deleteAgentBase,
transformResponse: async (response) => {
const data = await response.json()
const content = `Agent ${data.id} has been deleted`
return {
success: true,
output: {
content,
metadata: {
id: data.id,
},
},
}
},
outputs: {
content: { type: 'string', description: 'Success message' },
metadata: {
type: 'object',
description: 'Result metadata',
properties: {
id: { type: 'string', description: 'Agent ID' },
},
},
},
}
interface DeleteAgentV2Response {
success: boolean
output: {
id: string
}
}
export const deleteAgentV2Tool: ToolConfig<DeleteAgentParams, DeleteAgentV2Response> = {
...deleteAgentBase,
id: 'cursor_delete_agent_v2',
name: 'Cursor Delete Agent',
description: 'Permanently delete a cloud agent. Returns API-aligned fields only.',
version: '2.0.0',
transformResponse: async (response) => {
const data = await response.json()
return {
success: true,
output: {
id: data.id,
},
}
},
outputs: {
id: { type: 'string', description: 'Agent ID' },
},
}
+119
View File
@@ -0,0 +1,119 @@
import type {
DownloadArtifactParams,
DownloadArtifactResponse,
DownloadArtifactV2Response,
} from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const downloadArtifactBase = {
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cursor API key',
},
agentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique identifier for the cloud agent (e.g., bc_abc123)',
},
path: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Absolute path of the artifact to download (e.g., /src/index.ts)',
},
},
request: {
url: '/api/tools/cursor/download-artifact',
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params: DownloadArtifactParams) => ({
apiKey: params.apiKey,
agentId: params.agentId?.trim(),
path: params.path?.trim(),
}),
},
} satisfies Pick<ToolConfig<DownloadArtifactParams, any>, 'params' | 'request'>
export const downloadArtifactTool: ToolConfig<DownloadArtifactParams, DownloadArtifactResponse> = {
id: 'cursor_download_artifact',
name: 'Cursor Download Artifact',
description: 'Download a generated artifact file from a cloud agent.',
version: '1.0.0',
...downloadArtifactBase,
transformResponse: async (response) => {
const data = await response.json()
if (!data.success) {
throw new Error(data.error || 'Failed to download artifact')
}
return {
success: true,
output: {
content: `Downloaded artifact: ${data.output.file.name}`,
metadata: {
name: data.output.file.name,
mimeType: data.output.file.mimeType,
data: data.output.file.data,
size: data.output.file.size,
},
},
}
},
outputs: {
content: { type: 'string', description: 'Human-readable download result' },
metadata: {
type: 'object',
description: 'Downloaded file metadata',
properties: {
name: { type: 'string', description: 'File name' },
mimeType: { type: 'string', description: 'MIME type' },
data: { type: 'string', description: 'Base64-encoded file contents' },
size: { type: 'number', description: 'File size in bytes' },
},
},
},
}
export const downloadArtifactV2Tool: ToolConfig<
DownloadArtifactParams,
DownloadArtifactV2Response
> = {
...downloadArtifactBase,
id: 'cursor_download_artifact_v2',
name: 'Cursor Download Artifact',
description:
'Download a generated artifact file from a cloud agent. Returns the file for execution storage.',
version: '2.0.0',
transformResponse: async (response) => {
const data = await response.json()
if (!data.success) {
throw new Error(data.error || 'Failed to download artifact')
}
return {
success: true,
output: {
file: data.output.file,
},
}
},
outputs: {
file: {
type: 'file',
description: 'Downloaded artifact file stored in execution files',
},
},
}
+111
View File
@@ -0,0 +1,111 @@
import type { GetAgentParams, GetAgentResponse } from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const getAgentBase = {
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cursor API key',
},
agentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique identifier for the cloud agent (e.g., bc_abc123)',
},
},
request: {
url: (params: GetAgentParams) => `https://api.cursor.com/v0/agents/${params.agentId.trim()}`,
method: 'GET',
headers: (params: GetAgentParams) => ({
Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`,
}),
},
} satisfies Pick<ToolConfig<GetAgentParams, any>, 'params' | 'request'>
export const getAgentTool: ToolConfig<GetAgentParams, GetAgentResponse> = {
id: 'cursor_get_agent',
name: 'Cursor Get Agent',
description: 'Retrieve the current status and results of a cloud agent.',
version: '1.0.0',
...getAgentBase,
transformResponse: async (response) => {
const data = await response.json()
return {
success: true,
output: {
content: `Agent "${data.name}" is ${data.status}`,
metadata: data,
},
}
},
outputs: {
content: { type: 'string', description: 'Human-readable agent details' },
metadata: {
type: 'object',
description: 'Agent metadata',
properties: {
id: { type: 'string', description: 'Agent ID' },
name: { type: 'string', description: 'Agent name' },
status: { type: 'string', description: 'Agent status' },
source: { type: 'object', description: 'Source repository info' },
target: { type: 'object', description: 'Target branch info' },
summary: { type: 'string', description: 'Agent summary', optional: true },
createdAt: { type: 'string', description: 'Creation timestamp' },
},
},
},
}
interface GetAgentV2Response {
success: boolean
output: {
id: string
name: string
status: string
source: Record<string, any>
target: Record<string, any>
summary?: string
createdAt: string
}
}
export const getAgentV2Tool: ToolConfig<GetAgentParams, GetAgentV2Response> = {
...getAgentBase,
id: 'cursor_get_agent_v2',
name: 'Cursor Get Agent',
description:
'Retrieve the current status and results of a cloud agent. Returns API-aligned fields only.',
version: '2.0.0',
transformResponse: async (response) => {
const data = await response.json()
return {
success: true,
output: {
id: data.id,
name: data.name,
status: data.status,
source: data.source,
target: data.target,
summary: data.summary ?? null,
createdAt: data.createdAt,
},
}
},
outputs: {
id: { type: 'string', description: 'Agent ID' },
name: { type: 'string', description: 'Agent name' },
status: { type: 'string', description: 'Agent status' },
source: { type: 'json', description: 'Source repository info' },
target: { type: 'json', description: 'Target branch/PR info' },
summary: { type: 'string', description: 'Agent summary', optional: true },
createdAt: { type: 'string', description: 'Creation timestamp' },
},
}
+93
View File
@@ -0,0 +1,93 @@
import type { GetApiKeyInfoParams, GetApiKeyInfoResponse } from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const getApiKeyInfoBase = {
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cursor API key',
},
},
request: {
url: () => 'https://api.cursor.com/v0/me',
method: 'GET',
headers: (params: GetApiKeyInfoParams) => ({
Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`,
}),
},
} satisfies Pick<ToolConfig<GetApiKeyInfoParams, any>, 'params' | 'request'>
export const getApiKeyInfoTool: ToolConfig<GetApiKeyInfoParams, GetApiKeyInfoResponse> = {
id: 'cursor_get_api_key_info',
name: 'Cursor Get API Key Info',
description: 'Retrieve details about the API key currently in use.',
version: '1.0.0',
...getApiKeyInfoBase,
transformResponse: async (response) => {
const data = await response.json()
return {
success: true,
output: {
content: `API key "${data.apiKeyName}" for ${data.userEmail}`,
metadata: {
apiKeyName: data.apiKeyName,
createdAt: data.createdAt,
userEmail: data.userEmail,
},
},
}
},
outputs: {
content: { type: 'string', description: 'Human-readable API key summary' },
metadata: {
type: 'object',
description: 'API key metadata',
properties: {
apiKeyName: { type: 'string', description: 'Name of the API key' },
createdAt: { type: 'string', description: 'API key creation timestamp' },
userEmail: { type: 'string', description: 'Email of the key owner' },
},
},
},
}
interface GetApiKeyInfoV2Response {
success: boolean
output: {
apiKeyName: string
createdAt: string
userEmail: string
}
}
export const getApiKeyInfoV2Tool: ToolConfig<GetApiKeyInfoParams, GetApiKeyInfoV2Response> = {
...getApiKeyInfoBase,
id: 'cursor_get_api_key_info_v2',
name: 'Cursor Get API Key Info',
description:
'Retrieve details about the API key currently in use. Returns API-aligned fields only.',
version: '2.0.0',
transformResponse: async (response) => {
const data = await response.json()
return {
success: true,
output: {
apiKeyName: data.apiKeyName,
createdAt: data.createdAt,
userEmail: data.userEmail,
},
}
},
outputs: {
apiKeyName: { type: 'string', description: 'Name of the API key' },
createdAt: { type: 'string', description: 'API key creation timestamp' },
userEmail: { type: 'string', description: 'Email of the key owner' },
},
}
+99
View File
@@ -0,0 +1,99 @@
import type { GetConversationParams, GetConversationResponse } from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const getConversationBase = {
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cursor API key',
},
agentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique identifier for the cloud agent (e.g., bc_abc123)',
},
},
request: {
url: (params: GetConversationParams) =>
`https://api.cursor.com/v0/agents/${params.agentId.trim()}/conversation`,
method: 'GET',
headers: (params: GetConversationParams) => ({
Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`,
}),
},
} satisfies Pick<ToolConfig<GetConversationParams, any>, 'params' | 'request'>
export const getConversationTool: ToolConfig<GetConversationParams, GetConversationResponse> = {
id: 'cursor_get_conversation',
name: 'Cursor Get Conversation',
description:
'Retrieve the conversation history of a cloud agent, including all user prompts and assistant responses.',
version: '1.0.0',
...getConversationBase,
transformResponse: async (response) => {
const data = await response.json()
return {
success: true,
output: {
content: `Retrieved ${data.messages.length} messages`,
metadata: {
id: data.id,
messages: data.messages,
},
},
}
},
outputs: {
content: { type: 'string', description: 'Human-readable conversation history' },
metadata: {
type: 'object',
description: 'Conversation metadata',
properties: {
id: { type: 'string', description: 'Agent ID' },
messages: {
type: 'array',
description: 'Array of conversation messages',
},
},
},
},
}
interface GetConversationV2Response {
success: boolean
output: {
id: string
messages: unknown[]
}
}
export const getConversationV2Tool: ToolConfig<GetConversationParams, GetConversationV2Response> = {
...getConversationBase,
id: 'cursor_get_conversation_v2',
name: 'Cursor Get Conversation',
description:
'Retrieve the conversation history of a cloud agent, including all user prompts and assistant responses. Returns API-aligned fields only.',
version: '2.0.0',
transformResponse: async (response) => {
const data = await response.json()
return {
success: true,
output: {
id: data.id,
messages: data.messages,
},
}
},
outputs: {
id: { type: 'string', description: 'Agent ID' },
messages: { type: 'array', description: 'Array of conversation messages' },
},
}
+38
View File
@@ -0,0 +1,38 @@
import { addFollowupTool, addFollowupV2Tool } from '@/tools/cursor/add_followup'
import { deleteAgentTool, deleteAgentV2Tool } from '@/tools/cursor/delete_agent'
import { downloadArtifactTool, downloadArtifactV2Tool } from '@/tools/cursor/download_artifact'
import { getAgentTool, getAgentV2Tool } from '@/tools/cursor/get_agent'
import { getApiKeyInfoTool, getApiKeyInfoV2Tool } from '@/tools/cursor/get_api_key_info'
import { getConversationTool, getConversationV2Tool } from '@/tools/cursor/get_conversation'
import { launchAgentTool, launchAgentV2Tool } from '@/tools/cursor/launch_agent'
import { listAgentsTool, listAgentsV2Tool } from '@/tools/cursor/list_agents'
import { listArtifactsTool, listArtifactsV2Tool } from '@/tools/cursor/list_artifacts'
import { listModelsTool, listModelsV2Tool } from '@/tools/cursor/list_models'
import { listRepositoriesTool, listRepositoriesV2Tool } from '@/tools/cursor/list_repositories'
import { stopAgentTool, stopAgentV2Tool } from '@/tools/cursor/stop_agent'
export const cursorListAgentsTool = listAgentsTool
export const cursorGetAgentTool = getAgentTool
export const cursorGetConversationTool = getConversationTool
export const cursorLaunchAgentTool = launchAgentTool
export const cursorAddFollowupTool = addFollowupTool
export const cursorStopAgentTool = stopAgentTool
export const cursorDeleteAgentTool = deleteAgentTool
export const cursorDownloadArtifactTool = downloadArtifactTool
export const cursorListArtifactsTool = listArtifactsTool
export const cursorListModelsTool = listModelsTool
export const cursorListRepositoriesTool = listRepositoriesTool
export const cursorGetApiKeyInfoTool = getApiKeyInfoTool
export const cursorListAgentsV2Tool = listAgentsV2Tool
export const cursorGetAgentV2Tool = getAgentV2Tool
export const cursorGetConversationV2Tool = getConversationV2Tool
export const cursorLaunchAgentV2Tool = launchAgentV2Tool
export const cursorAddFollowupV2Tool = addFollowupV2Tool
export const cursorStopAgentV2Tool = stopAgentV2Tool
export const cursorDeleteAgentV2Tool = deleteAgentV2Tool
export const cursorDownloadArtifactV2Tool = downloadArtifactV2Tool
export const cursorListArtifactsV2Tool = listArtifactsV2Tool
export const cursorListModelsV2Tool = listModelsV2Tool
export const cursorListRepositoriesV2Tool = listRepositoriesV2Tool
export const cursorGetApiKeyInfoV2Tool = getApiKeyInfoV2Tool
+186
View File
@@ -0,0 +1,186 @@
import type { LaunchAgentParams, LaunchAgentResponse } from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const launchAgentBase = {
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cursor API key',
},
repository: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'GitHub repository URL (e.g., https://github.com/your-org/your-repo)',
},
ref: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Branch, tag, or commit to work from (defaults to default branch)',
},
promptText: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The instruction text for the agent',
},
promptImages: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'JSON array of image objects with base64 data and dimensions',
},
model: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Model to use (leave empty for auto-selection)',
},
branchName: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Custom branch name for the agent to use',
},
autoCreatePr: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Automatically create a PR when the agent finishes',
},
openAsCursorGithubApp: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Open the PR as the Cursor GitHub App',
},
skipReviewerRequest: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Skip requesting reviewers on the PR',
},
},
request: {
url: () => 'https://api.cursor.com/v0/agents',
method: 'POST',
headers: (params: LaunchAgentParams) => ({
'Content-Type': 'application/json',
Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`,
}),
body: (params: LaunchAgentParams) => {
const body: Record<string, any> = {
source: {
repository: params.repository,
},
prompt: {
text: params.promptText,
},
}
if (params.ref) {
body.source.ref = params.ref
}
if (params.promptImages) {
try {
body.prompt.images = JSON.parse(params.promptImages)
} catch {
body.prompt.images = []
}
}
if (params.model) {
body.model = params.model
}
const target: Record<string, any> = {}
if (params.branchName) target.branchName = params.branchName
if (typeof params.autoCreatePr === 'boolean') target.autoCreatePr = params.autoCreatePr
if (typeof params.openAsCursorGithubApp === 'boolean')
target.openAsCursorGithubApp = params.openAsCursorGithubApp
if (typeof params.skipReviewerRequest === 'boolean')
target.skipReviewerRequest = params.skipReviewerRequest
if (Object.keys(target).length > 0) {
body.target = target
}
return body
},
},
} satisfies Pick<ToolConfig<LaunchAgentParams, any>, 'params' | 'request'>
export const launchAgentTool: ToolConfig<LaunchAgentParams, LaunchAgentResponse> = {
id: 'cursor_launch_agent',
name: 'Cursor Launch Agent',
description:
'Start a new cloud agent to work on a GitHub repository with the given instructions.',
version: '1.0.0',
...launchAgentBase,
transformResponse: async (response) => {
const data = await response.json()
const agentUrl = `https://cursor.com/agents?selectedBcId=${data.id}`
return {
success: true,
output: {
content: 'Agent launched successfully!',
metadata: {
id: data.id,
url: agentUrl,
},
},
}
},
outputs: {
content: { type: 'string', description: 'Success message with agent details' },
metadata: {
type: 'object',
description: 'Launch result metadata',
properties: {
id: { type: 'string', description: 'Agent ID' },
url: { type: 'string', description: 'Agent URL' },
},
},
},
}
interface LaunchAgentV2Response {
success: boolean
output: {
id: string
url: string
}
}
export const launchAgentV2Tool: ToolConfig<LaunchAgentParams, LaunchAgentV2Response> = {
...launchAgentBase,
id: 'cursor_launch_agent_v2',
name: 'Cursor Launch Agent',
description:
'Start a new cloud agent to work on a GitHub repository with the given instructions. Returns API-aligned fields only.',
version: '2.0.0',
transformResponse: async (response) => {
const data = await response.json()
const agentUrl = `https://cursor.com/agents?selectedBcId=${data.id}`
return {
success: true,
output: {
id: data.id,
url: agentUrl,
},
}
},
outputs: {
id: { type: 'string', description: 'Agent ID' },
url: { type: 'string', description: 'Agent URL' },
},
}
+119
View File
@@ -0,0 +1,119 @@
import type { ListAgentsParams, ListAgentsResponse } from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const listAgentsBase = {
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cursor API key',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of agents to return (default: 20, max: 100)',
},
cursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor from previous response',
},
prUrl: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter agents by pull request URL',
},
},
request: {
url: (params: ListAgentsParams) => {
const url = new URL('https://api.cursor.com/v0/agents')
if (params.limit) url.searchParams.set('limit', String(params.limit))
if (params.cursor) url.searchParams.set('cursor', params.cursor)
if (params.prUrl) url.searchParams.set('prUrl', params.prUrl)
return url.toString()
},
method: 'GET',
headers: (params: ListAgentsParams) => ({
Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`,
}),
},
} satisfies Pick<ToolConfig<ListAgentsParams, any>, 'params' | 'request'>
export const listAgentsTool: ToolConfig<ListAgentsParams, ListAgentsResponse> = {
id: 'cursor_list_agents',
name: 'Cursor List Agents',
description: 'List all cloud agents for the authenticated user with optional pagination.',
version: '1.0.0',
...listAgentsBase,
transformResponse: async (response) => {
const data = await response.json()
return {
success: true,
output: {
content: `Found ${data.agents.length} agents`,
metadata: {
agents: data.agents,
nextCursor: data.nextCursor ?? null,
},
},
}
},
outputs: {
content: { type: 'string', description: 'Human-readable list of agents' },
metadata: {
type: 'object',
description: 'Agent list metadata',
properties: {
agents: {
type: 'array',
description: 'Array of agent objects',
},
nextCursor: {
type: 'string',
description: 'Pagination cursor for next page',
optional: true,
},
},
},
},
}
interface ListAgentsV2Response {
success: boolean
output: {
agents: unknown[]
nextCursor?: string
}
}
export const listAgentsV2Tool: ToolConfig<ListAgentsParams, ListAgentsV2Response> = {
...listAgentsBase,
id: 'cursor_list_agents_v2',
name: 'Cursor List Agents',
description:
'List all cloud agents for the authenticated user with optional pagination. Returns API-aligned fields only.',
version: '2.0.0',
transformResponse: async (response) => {
const data = await response.json()
return {
success: true,
output: {
agents: data.agents,
nextCursor: data.nextCursor ?? null,
},
}
},
outputs: {
agents: { type: 'array', description: 'Array of agent objects' },
nextCursor: { type: 'string', description: 'Pagination cursor for next page', optional: true },
},
}
+113
View File
@@ -0,0 +1,113 @@
import type { ListArtifactsParams, ListArtifactsResponse } from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const listArtifactsBase = {
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cursor API key',
},
agentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique identifier for the cloud agent (e.g., bc_abc123)',
},
},
request: {
url: (params: ListArtifactsParams) =>
`https://api.cursor.com/v0/agents/${params.agentId.trim()}/artifacts`,
method: 'GET',
headers: (params: ListArtifactsParams) => ({
Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`,
}),
},
} satisfies Pick<ToolConfig<ListArtifactsParams, any>, 'params' | 'request'>
export const listArtifactsTool: ToolConfig<ListArtifactsParams, ListArtifactsResponse> = {
id: 'cursor_list_artifacts',
name: 'Cursor List Artifacts',
description: 'List generated artifact files for a cloud agent.',
version: '1.0.0',
...listArtifactsBase,
transformResponse: async (response) => {
const data = await response.json()
const artifacts = data.artifacts ?? []
return {
success: true,
output: {
content: `Found ${artifacts.length} artifact(s)`,
metadata: {
artifacts,
},
},
}
},
outputs: {
content: { type: 'string', description: 'Human-readable artifact count' },
metadata: {
type: 'object',
description: 'Artifacts metadata',
properties: {
artifacts: {
type: 'array',
description: 'List of artifacts',
items: {
type: 'object',
properties: {
path: { type: 'string', description: 'Artifact file path' },
size: { type: 'number', description: 'File size in bytes', optional: true },
},
},
},
},
},
},
}
interface ListArtifactsV2Response {
success: boolean
output: {
artifacts: Array<{ path: string; size?: number }>
}
}
export const listArtifactsV2Tool: ToolConfig<ListArtifactsParams, ListArtifactsV2Response> = {
...listArtifactsBase,
id: 'cursor_list_artifacts_v2',
name: 'Cursor List Artifacts',
description: 'List generated artifact files for a cloud agent. Returns API-aligned fields only.',
version: '2.0.0',
transformResponse: async (response) => {
const data = await response.json()
const artifacts = data.artifacts ?? []
return {
success: true,
output: {
artifacts: Array.isArray(artifacts) ? artifacts : [],
},
}
},
outputs: {
artifacts: {
type: 'array',
description: 'List of artifact files',
items: {
type: 'object',
properties: {
path: { type: 'string', description: 'Artifact file path' },
size: { type: 'number', description: 'File size in bytes', optional: true },
},
},
},
},
}
+92
View File
@@ -0,0 +1,92 @@
import type { ListModelsParams, ListModelsResponse } from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const listModelsBase = {
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cursor API key',
},
},
request: {
url: () => 'https://api.cursor.com/v0/models',
method: 'GET',
headers: (params: ListModelsParams) => ({
Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`,
}),
},
} satisfies Pick<ToolConfig<ListModelsParams, any>, 'params' | 'request'>
export const listModelsTool: ToolConfig<ListModelsParams, ListModelsResponse> = {
id: 'cursor_list_models',
name: 'Cursor List Models',
description: 'List the models available for launching cloud agents.',
version: '1.0.0',
...listModelsBase,
transformResponse: async (response) => {
const data = await response.json()
const models = data.models ?? []
return {
success: true,
output: {
content: `Found ${models.length} model(s)`,
metadata: {
models,
},
},
}
},
outputs: {
content: { type: 'string', description: 'Human-readable model count' },
metadata: {
type: 'object',
description: 'Models metadata',
properties: {
models: {
type: 'array',
description: 'Array of available model names',
items: { type: 'string', description: 'Model name' },
},
},
},
},
}
interface ListModelsV2Response {
success: boolean
output: {
models: string[]
}
}
export const listModelsV2Tool: ToolConfig<ListModelsParams, ListModelsV2Response> = {
...listModelsBase,
id: 'cursor_list_models_v2',
name: 'Cursor List Models',
description:
'List the models available for launching cloud agents. Returns API-aligned fields only.',
version: '2.0.0',
transformResponse: async (response) => {
const data = await response.json()
return {
success: true,
output: {
models: Array.isArray(data.models) ? data.models : [],
},
}
},
outputs: {
models: {
type: 'array',
description: 'Array of available model names',
items: { type: 'string', description: 'Model name' },
},
},
}
+109
View File
@@ -0,0 +1,109 @@
import type { ListRepositoriesParams, ListRepositoriesResponse } from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const listRepositoriesBase = {
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cursor API key',
},
},
request: {
url: () => 'https://api.cursor.com/v0/repositories',
method: 'GET',
headers: (params: ListRepositoriesParams) => ({
Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`,
}),
},
} satisfies Pick<ToolConfig<ListRepositoriesParams, any>, 'params' | 'request'>
export const listRepositoriesTool: ToolConfig<ListRepositoriesParams, ListRepositoriesResponse> = {
id: 'cursor_list_repositories',
name: 'Cursor List Repositories',
description: 'List the GitHub repositories accessible to the authenticated user.',
version: '1.0.0',
...listRepositoriesBase,
transformResponse: async (response) => {
const data = await response.json()
const repositories = data.repositories ?? []
return {
success: true,
output: {
content: `Found ${repositories.length} repository(ies)`,
metadata: {
repositories,
},
},
}
},
outputs: {
content: { type: 'string', description: 'Human-readable repository count' },
metadata: {
type: 'object',
description: 'Repositories metadata',
properties: {
repositories: {
type: 'array',
description: 'Array of accessible repositories',
items: {
type: 'object',
properties: {
owner: { type: 'string', description: 'Repository owner' },
name: { type: 'string', description: 'Repository name' },
repository: { type: 'string', description: 'Repository URL' },
},
},
},
},
},
},
}
interface ListRepositoriesV2Response {
success: boolean
output: {
repositories: Array<{ owner: string; name: string; repository: string }>
}
}
export const listRepositoriesV2Tool: ToolConfig<
ListRepositoriesParams,
ListRepositoriesV2Response
> = {
...listRepositoriesBase,
id: 'cursor_list_repositories_v2',
name: 'Cursor List Repositories',
description:
'List the GitHub repositories accessible to the authenticated user. Returns API-aligned fields only.',
version: '2.0.0',
transformResponse: async (response) => {
const data = await response.json()
return {
success: true,
output: {
repositories: Array.isArray(data.repositories) ? data.repositories : [],
},
}
},
outputs: {
repositories: {
type: 'array',
description: 'Array of accessible repositories',
items: {
type: 'object',
properties: {
owner: { type: 'string', description: 'Repository owner' },
name: { type: 'string', description: 'Repository name' },
repository: { type: 'string', description: 'Repository URL' },
},
},
},
},
}
+91
View File
@@ -0,0 +1,91 @@
import type { StopAgentParams, StopAgentResponse } from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const stopAgentBase = {
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Cursor API key',
},
agentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique identifier for the cloud agent (e.g., bc_abc123)',
},
},
request: {
url: (params: StopAgentParams) =>
`https://api.cursor.com/v0/agents/${params.agentId.trim()}/stop`,
method: 'POST',
headers: (params: StopAgentParams) => ({
Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`,
}),
},
} satisfies Pick<ToolConfig<StopAgentParams, any>, 'params' | 'request'>
export const stopAgentTool: ToolConfig<StopAgentParams, StopAgentResponse> = {
id: 'cursor_stop_agent',
name: 'Cursor Stop Agent',
description: 'Stop a running cloud agent. This pauses the agent without deleting it.',
version: '1.0.0',
...stopAgentBase,
transformResponse: async (response) => {
const data = await response.json()
const content = `Agent ${data.id} has been stopped`
return {
success: true,
output: {
content,
metadata: {
id: data.id,
},
},
}
},
outputs: {
content: { type: 'string', description: 'Success message' },
metadata: {
type: 'object',
description: 'Result metadata',
properties: {
id: { type: 'string', description: 'Agent ID' },
},
},
},
}
interface StopAgentV2Response {
success: boolean
output: {
id: string
}
}
export const stopAgentV2Tool: ToolConfig<StopAgentParams, StopAgentV2Response> = {
...stopAgentBase,
id: 'cursor_stop_agent_v2',
name: 'Cursor Stop Agent',
description: 'Stop a running cloud agent. Returns API-aligned fields only.',
version: '2.0.0',
transformResponse: async (response) => {
const data = await response.json()
return {
success: true,
output: {
id: data.id,
},
}
},
outputs: {
id: { type: 'string', description: 'Agent ID' },
},
}
+243
View File
@@ -0,0 +1,243 @@
import type { ToolResponse } from '@/tools/types'
interface BaseCursorParams {
apiKey: string
}
export interface ListAgentsParams extends BaseCursorParams {
limit?: number
cursor?: string
prUrl?: string
}
export interface GetAgentParams extends BaseCursorParams {
agentId: string
}
export interface GetConversationParams extends BaseCursorParams {
agentId: string
}
export interface LaunchAgentParams extends BaseCursorParams {
repository: string
ref?: string
promptText: string
promptImages?: string
model?: string
branchName?: string
autoCreatePr?: boolean
openAsCursorGithubApp?: boolean
skipReviewerRequest?: boolean
}
export interface AddFollowupParams extends BaseCursorParams {
agentId: string
followupPromptText: string
promptImages?: string
}
export interface StopAgentParams extends BaseCursorParams {
agentId: string
}
export interface DeleteAgentParams extends BaseCursorParams {
agentId: string
}
export type ListModelsParams = BaseCursorParams
export type ListRepositoriesParams = BaseCursorParams
export type GetApiKeyInfoParams = BaseCursorParams
interface AgentSource {
repository: string
ref: string
}
interface AgentTarget {
branchName: string
url: string
prUrl?: string
autoCreatePr: boolean
openAsCursorGithubApp?: boolean
skipReviewerRequest?: boolean
}
interface AgentMetadata {
id: string
name: string
status: string
source: AgentSource
target: AgentTarget
summary?: string
createdAt: string
}
interface ConversationMessage {
id: string
type: 'user_message' | 'assistant_message'
text: string
}
interface RepositoryMetadata {
owner: string
name: string
repository: string
}
interface ApiKeyInfoMetadata {
apiKeyName: string
createdAt: string
userEmail: string
}
export interface ListAgentsResponse extends ToolResponse {
output: {
content: string
metadata: {
agents: AgentMetadata[]
nextCursor?: string
}
}
}
export interface GetAgentResponse extends ToolResponse {
output: {
content: string
metadata: AgentMetadata
}
}
export interface GetConversationResponse extends ToolResponse {
output: {
content: string
metadata: {
id: string
messages: ConversationMessage[]
}
}
}
export interface LaunchAgentResponse extends ToolResponse {
output: {
content: string
metadata: {
id: string
url: string
}
}
}
export interface AddFollowupResponse extends ToolResponse {
output: {
content: string
metadata: {
id: string
}
}
}
export interface StopAgentResponse extends ToolResponse {
output: {
content: string
metadata: {
id: string
}
}
}
export interface DeleteAgentResponse extends ToolResponse {
output: {
content: string
metadata: {
id: string
}
}
}
export interface GetApiKeyInfoResponse extends ToolResponse {
output: {
content: string
metadata: ApiKeyInfoMetadata
}
}
export interface ListModelsResponse extends ToolResponse {
output: {
content: string
metadata: {
models: string[]
}
}
}
export interface ListRepositoriesResponse extends ToolResponse {
output: {
content: string
metadata: {
repositories: RepositoryMetadata[]
}
}
}
export interface ListArtifactsParams extends BaseCursorParams {
agentId: string
}
interface ArtifactMetadata {
path: string
size?: number
}
export interface ListArtifactsResponse extends ToolResponse {
output: {
content: string
metadata: {
artifacts: ArtifactMetadata[]
}
}
}
export interface DownloadArtifactParams extends BaseCursorParams {
agentId: string
path: string
}
export interface DownloadArtifactResponse extends ToolResponse {
output: {
content: string
metadata: {
name: string
mimeType: string
data: string
size: number
}
}
}
export interface DownloadArtifactV2Response extends ToolResponse {
output: {
file: {
name: string
mimeType: string
data: string
size: number
}
}
}
export type CursorResponse =
| ListAgentsResponse
| GetAgentResponse
| GetConversationResponse
| LaunchAgentResponse
| AddFollowupResponse
| StopAgentResponse
| DeleteAgentResponse
| GetApiKeyInfoResponse
| ListModelsResponse
| ListRepositoriesResponse
| ListArtifactsResponse
| DownloadArtifactResponse
| DownloadArtifactV2Response