diff --git a/apps/docs/components/icons.tsx b/apps/docs/components/icons.tsx index 972597cf86..06fd3443e4 100644 --- a/apps/docs/components/icons.tsx +++ b/apps/docs/components/icons.tsx @@ -4121,3 +4121,11 @@ export function GoogleGroupsIcon(props: SVGProps) { ) } + +export function CursorIcon(props: SVGProps) { + return ( + + + + ) +} diff --git a/apps/docs/components/ui/icon-mapping.ts b/apps/docs/components/ui/icon-mapping.ts index 235dc6642e..f9b546e686 100644 --- a/apps/docs/components/ui/icon-mapping.ts +++ b/apps/docs/components/ui/icon-mapping.ts @@ -15,6 +15,7 @@ import { CalendlyIcon, ClayIcon, ConfluenceIcon, + CursorIcon, DatadogIcon, DiscordIcon, DocumentIcon, @@ -115,113 +116,114 @@ import { type IconComponent = ComponentType> export const blockTypeToIconMap: Record = { - zoom: ZoomIcon, - zep: ZepIcon, - zendesk: ZendeskIcon, - youtube: YouTubeIcon, - x: xIcon, - wordpress: WordpressIcon, - wikipedia: WikipediaIcon, - whatsapp: WhatsAppIcon, - webflow: WebflowIcon, - wealthbox: WealthboxIcon, - vision: EyeIcon, - video_generator: VideoIcon, - typeform: TypeformIcon, - twilio_voice: TwilioIcon, - twilio_sms: TwilioIcon, - tts: TTSIcon, - trello: TrelloIcon, - translate: TranslateIcon, - thinking: BrainIcon, - telegram: TelegramIcon, - tavily: TavilyIcon, - supabase: SupabaseIcon, - stt: STTIcon, - stripe: StripeIcon, - stagehand_agent: StagehandIcon, - stagehand: StagehandIcon, - ssh: SshIcon, - smtp: SmtpIcon, - slack: SlackIcon, - shopify: ShopifyIcon, - sharepoint: MicrosoftSharepointIcon, - serper: SerperIcon, - sentry: SentryIcon, - sendgrid: SendgridIcon, - search: SearchIcon, - salesforce: SalesforceIcon, - s3: S3Icon, - resend: ResendIcon, - reddit: RedditIcon, - rds: RDSIcon, - qdrant: QdrantIcon, - pylon: PylonIcon, - posthog: PosthogIcon, - postgresql: PostgresIcon, - polymarket: PolymarketIcon, - pipedrive: PipedriveIcon, - pinecone: PineconeIcon, - perplexity: PerplexityIcon, - parallel_ai: ParallelIcon, - outlook: OutlookIcon, - openai: OpenAIIcon, - onedrive: MicrosoftOneDriveIcon, - notion: NotionIcon, - neo4j: Neo4jIcon, - mysql: MySQLIcon, - mongodb: MongoDBIcon, - mistral_parse: MistralIcon, - microsoft_teams: MicrosoftTeamsIcon, - microsoft_planner: MicrosoftPlannerIcon, - microsoft_excel: MicrosoftExcelIcon, - memory: BrainIcon, - mem0: Mem0Icon, - mailgun: MailgunIcon, - mailchimp: MailchimpIcon, - linkup: LinkupIcon, - linkedin: LinkedInIcon, - linear: LinearIcon, - knowledge: PackageSearchIcon, - kalshi: KalshiIcon, - jira: JiraIcon, - jina: JinaAIIcon, - intercom: IntercomIcon, - incidentio: IncidentioIcon, - image_generator: ImageIcon, - hunter: HunterIOIcon, - huggingface: HuggingFaceIcon, - hubspot: HubspotIcon, - grafana: GrafanaIcon, - google_vault: GoogleVaultIcon, - google_slides: GoogleSlidesIcon, - google_sheets: GoogleSheetsIcon, - google_groups: GoogleGroupsIcon, - google_forms: GoogleFormsIcon, - google_drive: GoogleDriveIcon, - google_docs: GoogleDocsIcon, - google_calendar: GoogleCalendarIcon, - google_search: GoogleIcon, - gmail: GmailIcon, - gitlab: GitLabIcon, - github: GithubIcon, - firecrawl: FirecrawlIcon, - file: DocumentIcon, - exa: ExaAIIcon, - elevenlabs: ElevenLabsIcon, - elasticsearch: ElasticsearchIcon, - dynamodb: DynamoDBIcon, - dropbox: DropboxIcon, - discord: DiscordIcon, - datadog: DatadogIcon, - confluence: ConfluenceIcon, - clay: ClayIcon, calendly: CalendlyIcon, - browser_use: BrowserUseIcon, - asana: AsanaIcon, + mailchimp: MailchimpIcon, + postgresql: PostgresIcon, + twilio_voice: TwilioIcon, + elasticsearch: ElasticsearchIcon, + rds: RDSIcon, + translate: TranslateIcon, + dynamodb: DynamoDBIcon, + wordpress: WordpressIcon, + tavily: TavilyIcon, + zendesk: ZendeskIcon, + stagehand_agent: StagehandIcon, + youtube: YouTubeIcon, + supabase: SupabaseIcon, + vision: EyeIcon, + zoom: ZoomIcon, + confluence: ConfluenceIcon, arxiv: ArxivIcon, + webflow: WebflowIcon, + pinecone: PineconeIcon, apollo: ApolloIcon, + whatsapp: WhatsAppIcon, + typeform: TypeformIcon, + qdrant: QdrantIcon, + shopify: ShopifyIcon, + asana: AsanaIcon, apify: ApifyIcon, + memory: BrainIcon, + gitlab: GitLabIcon, + polymarket: PolymarketIcon, + serper: SerperIcon, + linear: LinearIcon, + exa: ExaAIIcon, + telegram: TelegramIcon, + salesforce: SalesforceIcon, + hubspot: HubspotIcon, + hunter: HunterIOIcon, + linkup: LinkupIcon, + mongodb: MongoDBIcon, + pylon: PylonIcon, airtable: AirtableIcon, + discord: DiscordIcon, ahrefs: AhrefsIcon, + neo4j: Neo4jIcon, + tts: TTSIcon, + jina: JinaAIIcon, + google_docs: GoogleDocsIcon, + perplexity: PerplexityIcon, + google_search: GoogleIcon, + x: xIcon, + kalshi: KalshiIcon, + google_calendar: GoogleCalendarIcon, + zep: ZepIcon, + posthog: PosthogIcon, + grafana: GrafanaIcon, + google_slides: GoogleSlidesIcon, + microsoft_planner: MicrosoftPlannerIcon, + thinking: BrainIcon, + pipedrive: PipedriveIcon, + dropbox: DropboxIcon, + stagehand: StagehandIcon, + google_forms: GoogleFormsIcon, + file: DocumentIcon, + mistral_parse: MistralIcon, + gmail: GmailIcon, + openai: OpenAIIcon, + outlook: OutlookIcon, + incidentio: IncidentioIcon, + onedrive: MicrosoftOneDriveIcon, + resend: ResendIcon, + google_vault: GoogleVaultIcon, + sharepoint: MicrosoftSharepointIcon, + huggingface: HuggingFaceIcon, + sendgrid: SendgridIcon, + video_generator: VideoIcon, + smtp: SmtpIcon, + google_groups: GoogleGroupsIcon, + mailgun: MailgunIcon, + clay: ClayIcon, + jira: JiraIcon, + search: SearchIcon, + linkedin: LinkedInIcon, + wealthbox: WealthboxIcon, + notion: NotionIcon, + elevenlabs: ElevenLabsIcon, + microsoft_teams: MicrosoftTeamsIcon, + github: GithubIcon, + ssh: SshIcon, + google_drive: GoogleDriveIcon, + sentry: SentryIcon, + reddit: RedditIcon, + parallel_ai: ParallelIcon, + stripe: StripeIcon, + s3: S3Icon, + trello: TrelloIcon, + mem0: Mem0Icon, + knowledge: PackageSearchIcon, + intercom: IntercomIcon, + twilio_sms: TwilioIcon, + slack: SlackIcon, + datadog: DatadogIcon, + microsoft_excel: MicrosoftExcelIcon, + image_generator: ImageIcon, + google_sheets: GoogleSheetsIcon, + wikipedia: WikipediaIcon, + cursor: CursorIcon, + firecrawl: FirecrawlIcon, + mysql: MySQLIcon, + browser_use: BrowserUseIcon, + stt: STTIcon, } diff --git a/apps/docs/content/docs/en/tools/cursor.mdx b/apps/docs/content/docs/en/tools/cursor.mdx new file mode 100644 index 0000000000..f7463ae4fb --- /dev/null +++ b/apps/docs/content/docs/en/tools/cursor.mdx @@ -0,0 +1,163 @@ +--- +title: Cursor +description: Launch and manage Cursor cloud agents to work on GitHub repositories +--- + +import { BlockInfoCard } from "@/components/ui/block-info-card" + + + +## Usage Instructions + +Interact with Cursor Cloud Agents API to launch AI agents that can work on your GitHub repositories. Supports launching agents, adding follow-up instructions, checking status, viewing conversations, and managing agent lifecycle. + + + +## Tools + +### `cursor_list_agents` + +List all cloud agents for the authenticated user with optional pagination. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Cursor API key | +| `limit` | number | No | Number of agents to return \(default: 20, max: 100\) | +| `cursor` | string | No | Pagination cursor from previous response | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `content` | string | Human-readable list of agents | +| `metadata` | object | Agent list metadata | + +### `cursor_get_agent` + +Retrieve the current status and results of a cloud agent. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Cursor API key | +| `agentId` | string | Yes | Unique identifier for the cloud agent \(e.g., bc_abc123\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `content` | string | Human-readable agent details | +| `metadata` | object | Agent metadata | + +### `cursor_get_conversation` + +Retrieve the conversation history of a cloud agent, including all user prompts and assistant responses. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Cursor API key | +| `agentId` | string | Yes | Unique identifier for the cloud agent \(e.g., bc_abc123\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `content` | string | Human-readable conversation history | +| `metadata` | object | Conversation metadata | + +### `cursor_launch_agent` + +Start a new cloud agent to work on a GitHub repository with the given instructions. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Cursor API key | +| `repository` | string | Yes | GitHub repository URL \(e.g., https://github.com/your-org/your-repo\) | +| `ref` | string | No | Branch, tag, or commit to work from \(defaults to default branch\) | +| `promptText` | string | Yes | The instruction text for the agent | +| `promptImages` | string | No | JSON array of image objects with base64 data and dimensions | +| `model` | string | No | Model to use \(leave empty for auto-selection\) | +| `branchName` | string | No | Custom branch name for the agent to use | +| `autoCreatePr` | boolean | No | Automatically create a PR when the agent finishes | +| `openAsCursorGithubApp` | boolean | No | Open the PR as the Cursor GitHub App | +| `skipReviewerRequest` | boolean | No | Skip requesting reviewers on the PR | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `content` | string | Success message with agent details | +| `metadata` | object | Launch result metadata | + +### `cursor_add_followup` + +Add a follow-up instruction to an existing cloud agent. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Cursor API key | +| `agentId` | string | Yes | Unique identifier for the cloud agent \(e.g., bc_abc123\) | +| `promptText` | string | Yes | The follow-up instruction text for the agent | +| `promptImages` | string | No | JSON array of image objects with base64 data and dimensions \(max 5\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `content` | string | Success message | +| `metadata` | object | Result metadata | + +### `cursor_stop_agent` + +Stop a running cloud agent. This pauses the agent without deleting it. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Cursor API key | +| `agentId` | string | Yes | Unique identifier for the cloud agent \(e.g., bc_abc123\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `content` | string | Success message | +| `metadata` | object | Result metadata | + +### `cursor_delete_agent` + +Permanently delete a cloud agent. This action cannot be undone. + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `apiKey` | string | Yes | Cursor API key | +| `agentId` | string | Yes | Unique identifier for the cloud agent \(e.g., bc_abc123\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `content` | string | Success message | +| `metadata` | object | Result metadata | + + + +## Notes + +- Category: `tools` +- Type: `cursor` diff --git a/apps/docs/content/docs/en/tools/meta.json b/apps/docs/content/docs/en/tools/meta.json index 60406fa4bb..73c1125a1c 100644 --- a/apps/docs/content/docs/en/tools/meta.json +++ b/apps/docs/content/docs/en/tools/meta.json @@ -11,6 +11,7 @@ "calendly", "clay", "confluence", + "cursor", "datadog", "discord", "dropbox", diff --git a/apps/docs/content/docs/en/tools/salesforce.mdx b/apps/docs/content/docs/en/tools/salesforce.mdx index ff898f20ad..c41c27ba4b 100644 --- a/apps/docs/content/docs/en/tools/salesforce.mdx +++ b/apps/docs/content/docs/en/tools/salesforce.mdx @@ -416,6 +416,165 @@ Delete an account from Salesforce CRM | `success` | boolean | Operation success status | | `output` | json | Operation result data | +### `salesforce_list_reports` + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | json | Operation result data | + +### `salesforce_get_report` + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | json | Operation result data | + +### `salesforce_run_report` + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | json | Operation result data | + +### `salesforce_list_report_types` + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | json | Operation result data | + +### `salesforce_list_dashboards` + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | json | Operation result data | + +### `salesforce_get_dashboard` + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | json | Operation result data | + +### `salesforce_refresh_dashboard` + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | json | Operation result data | + +### `salesforce_query` + +Execute a custom SOQL query to retrieve data from Salesforce + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `idToken` | string | No | No description | +| `instanceUrl` | string | No | No description | +| `query` | string | Yes | SOQL query to execute \(e.g., SELECT Id, Name FROM Account LIMIT 10\) | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Success status | +| `output` | object | Query results | + +### `salesforce_query_more` + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | json | Operation result data | + +### `salesforce_describe_object` + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | json | Operation result data | + +### `salesforce_list_objects` + +#### Input + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | + +#### Output + +| Parameter | Type | Description | +| --------- | ---- | ----------- | +| `success` | boolean | Operation success status | +| `output` | json | Operation result data | + ## Notes diff --git a/apps/sim/blocks/blocks/cursor.ts b/apps/sim/blocks/blocks/cursor.ts new file mode 100644 index 0000000000..a57856b1a9 --- /dev/null +++ b/apps/sim/blocks/blocks/cursor.ts @@ -0,0 +1,171 @@ +import { CursorIcon } from '@/components/icons' +import type { BlockConfig } from '@/blocks/types' +import { AuthMode } from '@/blocks/types' +import type { CursorResponse } from '@/tools/cursor/types' + +export const CursorBlock: BlockConfig = { + type: 'cursor', + name: 'Cursor', + description: 'Launch and manage Cursor cloud agents to work on GitHub repositories', + longDescription: + 'Interact with Cursor Cloud Agents API to launch AI agents that can work on your GitHub repositories. Supports launching agents, adding follow-up instructions, checking status, viewing conversations, and managing agent lifecycle.', + docsLink: 'https://cursor.com/docs/cloud-agent/api/endpoints', + category: 'tools', + bgColor: '#1E1E1E', + icon: CursorIcon, + authMode: AuthMode.ApiKey, + subBlocks: [ + { + id: 'operation', + title: 'Operation', + type: 'dropdown', + options: [ + { label: 'Launch Agent', id: 'cursor_launch_agent' }, + { label: 'Add Follow-up', id: 'cursor_add_followup' }, + { label: 'Get Agent Status', id: 'cursor_get_agent' }, + { label: 'Get Conversation', id: 'cursor_get_conversation' }, + { label: 'List Agents', id: 'cursor_list_agents' }, + { label: 'Stop Agent', id: 'cursor_stop_agent' }, + { label: 'Delete Agent', id: 'cursor_delete_agent' }, + ], + value: () => 'cursor_launch_agent', + }, + { + id: 'repository', + title: 'Repository URL', + type: 'short-input', + placeholder: 'https://github.com/your-org/your-repo', + condition: { field: 'operation', value: 'cursor_launch_agent' }, + required: true, + }, + { + id: 'ref', + title: 'Branch/Ref', + type: 'short-input', + placeholder: 'main (optional)', + condition: { field: 'operation', value: 'cursor_launch_agent' }, + }, + { + id: 'promptText', + title: 'Prompt', + type: 'long-input', + placeholder: 'Describe the task for the agent...', + condition: { field: 'operation', value: 'cursor_launch_agent' }, + required: true, + }, + { + id: 'model', + title: 'Model', + type: 'short-input', + placeholder: 'Auto-selection by default', + condition: { field: 'operation', value: 'cursor_launch_agent' }, + }, + { + id: 'branchName', + title: 'Branch Name', + type: 'short-input', + placeholder: 'Custom branch name (optional)', + condition: { field: 'operation', value: 'cursor_launch_agent' }, + }, + { + id: 'autoCreatePr', + title: 'Auto Create PR', + type: 'switch', + condition: { field: 'operation', value: 'cursor_launch_agent' }, + }, + { + id: 'openAsCursorGithubApp', + title: 'Open as Cursor GitHub App', + type: 'switch', + condition: { field: 'operation', value: 'cursor_launch_agent' }, + }, + { + id: 'skipReviewerRequest', + title: 'Skip Reviewer Request', + type: 'switch', + condition: { field: 'operation', value: 'cursor_launch_agent' }, + }, + { + id: 'agentId', + title: 'Agent ID', + type: 'short-input', + placeholder: 'e.g., bc_abc123', + condition: { + field: 'operation', + value: [ + 'cursor_get_agent', + 'cursor_get_conversation', + 'cursor_add_followup', + 'cursor_stop_agent', + 'cursor_delete_agent', + ], + }, + required: true, + }, + { + id: 'followupPromptText', + title: 'Follow-up Prompt', + type: 'long-input', + placeholder: 'Additional instructions for the agent...', + condition: { field: 'operation', value: 'cursor_add_followup' }, + required: true, + }, + { + id: 'limit', + title: 'Limit', + type: 'short-input', + placeholder: '20 (default, max 100)', + condition: { field: 'operation', value: 'cursor_list_agents' }, + }, + { + id: 'cursor', + title: 'Pagination Cursor', + type: 'short-input', + placeholder: 'Cursor from previous response', + condition: { field: 'operation', value: 'cursor_list_agents' }, + }, + { + id: 'apiKey', + title: 'API Key', + type: 'short-input', + placeholder: 'Enter Cursor API Key', + password: true, + required: true, + }, + ], + tools: { + access: [ + 'cursor_list_agents', + 'cursor_get_agent', + 'cursor_get_conversation', + 'cursor_launch_agent', + 'cursor_add_followup', + 'cursor_stop_agent', + 'cursor_delete_agent', + ], + config: { + tool: (params) => params.operation || 'cursor_launch_agent', + }, + }, + inputs: { + operation: { type: 'string', description: 'Operation to perform' }, + repository: { type: 'string', description: 'GitHub repository URL' }, + ref: { type: 'string', description: 'Branch, tag, or commit reference' }, + promptText: { type: 'string', description: 'Instruction text for the agent' }, + followupPromptText: { type: 'string', description: 'Follow-up instruction text for the agent' }, + promptImages: { type: 'string', description: 'JSON array of image objects' }, + model: { type: 'string', description: 'Model to use (empty for auto-selection)' }, + branchName: { type: 'string', description: 'Custom branch name' }, + autoCreatePr: { type: 'boolean', description: 'Auto-create PR when done' }, + openAsCursorGithubApp: { type: 'boolean', description: 'Open PR as Cursor GitHub App' }, + skipReviewerRequest: { type: 'boolean', description: 'Skip reviewer request' }, + agentId: { type: 'string', description: 'Agent identifier' }, + limit: { type: 'number', description: 'Number of results to return' }, + cursor: { type: 'string', description: 'Pagination cursor' }, + apiKey: { type: 'string', description: 'Cursor API key' }, + }, + outputs: { + content: { type: 'string', description: 'Human-readable response content' }, + metadata: { type: 'json', description: 'Response metadata' }, + }, +} diff --git a/apps/sim/blocks/registry.ts b/apps/sim/blocks/registry.ts index 6062e8c400..bd76a05109 100644 --- a/apps/sim/blocks/registry.ts +++ b/apps/sim/blocks/registry.ts @@ -14,6 +14,7 @@ import { ChatTriggerBlock } from '@/blocks/blocks/chat_trigger' import { ClayBlock } from '@/blocks/blocks/clay' import { ConditionBlock } from '@/blocks/blocks/condition' import { ConfluenceBlock } from '@/blocks/blocks/confluence' +import { CursorBlock } from '@/blocks/blocks/cursor' import { DatadogBlock } from '@/blocks/blocks/datadog' import { DiscordBlock } from '@/blocks/blocks/discord' import { DropboxBlock } from '@/blocks/blocks/dropbox' @@ -152,6 +153,7 @@ export const registry: Record = { clay: ClayBlock, condition: ConditionBlock, confluence: ConfluenceBlock, + cursor: CursorBlock, datadog: DatadogBlock, discord: DiscordBlock, dropbox: DropboxBlock, diff --git a/apps/sim/components/icons.tsx b/apps/sim/components/icons.tsx index 972597cf86..06fd3443e4 100644 --- a/apps/sim/components/icons.tsx +++ b/apps/sim/components/icons.tsx @@ -4121,3 +4121,11 @@ export function GoogleGroupsIcon(props: SVGProps) { ) } + +export function CursorIcon(props: SVGProps) { + return ( + + + + ) +} diff --git a/apps/sim/tools/cursor/add_followup.ts b/apps/sim/tools/cursor/add_followup.ts new file mode 100644 index 0000000000..5291d57ade --- /dev/null +++ b/apps/sim/tools/cursor/add_followup.ts @@ -0,0 +1,89 @@ +import type { AddFollowupParams, AddFollowupResponse } from '@/tools/cursor/types' +import type { ToolConfig } from '@/tools/types' + +export const addFollowupTool: ToolConfig = { + id: 'cursor_add_followup', + name: 'Cursor Add Follow-up', + description: 'Add a follow-up instruction to an existing cloud agent.', + version: '1.0.0', + + 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) => `https://api.cursor.com/v0/agents/${params.agentId}/followup`, + method: 'POST', + headers: (params) => ({ + 'Content-Type': 'application/json', + Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`, + }), + body: (params) => { + const body: Record = { + prompt: { + text: params.followupPromptText, + }, + } + + if (params.promptImages) { + try { + body.prompt.images = JSON.parse(params.promptImages) + } catch { + body.prompt.images = [] + } + } + + return body + }, + }, + + 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' }, + }, + }, + }, +} diff --git a/apps/sim/tools/cursor/delete_agent.ts b/apps/sim/tools/cursor/delete_agent.ts new file mode 100644 index 0000000000..ba6d10f7bb --- /dev/null +++ b/apps/sim/tools/cursor/delete_agent.ts @@ -0,0 +1,59 @@ +import type { DeleteAgentParams, DeleteAgentResponse } from '@/tools/cursor/types' +import type { ToolConfig } from '@/tools/types' + +export const deleteAgentTool: ToolConfig = { + id: 'cursor_delete_agent', + name: 'Cursor Delete Agent', + description: 'Permanently delete a cloud agent. This action cannot be undone.', + version: '1.0.0', + + 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) => `https://api.cursor.com/v0/agents/${params.agentId}`, + method: 'DELETE', + headers: (params) => ({ + Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`, + }), + }, + + 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' }, + }, + }, + }, +} diff --git a/apps/sim/tools/cursor/get_agent.ts b/apps/sim/tools/cursor/get_agent.ts new file mode 100644 index 0000000000..7dd62ff24b --- /dev/null +++ b/apps/sim/tools/cursor/get_agent.ts @@ -0,0 +1,61 @@ +import type { GetAgentParams, GetAgentResponse } from '@/tools/cursor/types' +import type { ToolConfig } from '@/tools/types' + +export const getAgentTool: ToolConfig = { + id: 'cursor_get_agent', + name: 'Cursor Get Agent', + description: 'Retrieve the current status and results of a cloud agent.', + version: '1.0.0', + + 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) => `https://api.cursor.com/v0/agents/${params.agentId}`, + method: 'GET', + headers: (params) => ({ + Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`, + }), + }, + + 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' }, + }, + }, + }, +} diff --git a/apps/sim/tools/cursor/get_conversation.ts b/apps/sim/tools/cursor/get_conversation.ts new file mode 100644 index 0000000000..f9c231f656 --- /dev/null +++ b/apps/sim/tools/cursor/get_conversation.ts @@ -0,0 +1,63 @@ +import type { GetConversationParams, GetConversationResponse } from '@/tools/cursor/types' +import type { ToolConfig } from '@/tools/types' + +export const getConversationTool: ToolConfig = { + 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', + + 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) => `https://api.cursor.com/v0/agents/${params.agentId}/conversation`, + method: 'GET', + headers: (params) => ({ + Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`, + }), + }, + + 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', + }, + }, + }, + }, +} diff --git a/apps/sim/tools/cursor/index.ts b/apps/sim/tools/cursor/index.ts new file mode 100644 index 0000000000..009eaec6c5 --- /dev/null +++ b/apps/sim/tools/cursor/index.ts @@ -0,0 +1,15 @@ +import { addFollowupTool } from '@/tools/cursor/add_followup' +import { deleteAgentTool } from '@/tools/cursor/delete_agent' +import { getAgentTool } from '@/tools/cursor/get_agent' +import { getConversationTool } from '@/tools/cursor/get_conversation' +import { launchAgentTool } from '@/tools/cursor/launch_agent' +import { listAgentsTool } from '@/tools/cursor/list_agents' +import { stopAgentTool } 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 diff --git a/apps/sim/tools/cursor/launch_agent.ts b/apps/sim/tools/cursor/launch_agent.ts new file mode 100644 index 0000000000..87a4887610 --- /dev/null +++ b/apps/sim/tools/cursor/launch_agent.ts @@ -0,0 +1,150 @@ +import type { LaunchAgentParams, LaunchAgentResponse } from '@/tools/cursor/types' +import type { ToolConfig } from '@/tools/types' + +export const launchAgentTool: ToolConfig = { + 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', + + 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) => ({ + 'Content-Type': 'application/json', + Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`, + }), + body: (params) => { + const body: Record = { + 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 = {} + 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 + }, + }, + + 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' }, + }, + }, + }, +} diff --git a/apps/sim/tools/cursor/list_agents.ts b/apps/sim/tools/cursor/list_agents.ts new file mode 100644 index 0000000000..7f96f67812 --- /dev/null +++ b/apps/sim/tools/cursor/list_agents.ts @@ -0,0 +1,77 @@ +import type { ListAgentsParams, ListAgentsResponse } from '@/tools/cursor/types' +import type { ToolConfig } from '@/tools/types' + +export const listAgentsTool: ToolConfig = { + id: 'cursor_list_agents', + name: 'Cursor List Agents', + description: 'List all cloud agents for the authenticated user with optional pagination.', + version: '1.0.0', + + 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', + }, + }, + + request: { + url: (params) => { + 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) + return url.toString() + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`, + }), + }, + + 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, + }, + }, + } + }, + + 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, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/cursor/stop_agent.ts b/apps/sim/tools/cursor/stop_agent.ts new file mode 100644 index 0000000000..6680bb681f --- /dev/null +++ b/apps/sim/tools/cursor/stop_agent.ts @@ -0,0 +1,59 @@ +import type { StopAgentParams, StopAgentResponse } from '@/tools/cursor/types' +import type { ToolConfig } from '@/tools/types' + +export const stopAgentTool: ToolConfig = { + 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', + + 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) => `https://api.cursor.com/v0/agents/${params.agentId}/stop`, + method: 'POST', + headers: (params) => ({ + Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`, + }), + }, + + 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' }, + }, + }, + }, +} diff --git a/apps/sim/tools/cursor/types.ts b/apps/sim/tools/cursor/types.ts new file mode 100644 index 0000000000..4ec843ce28 --- /dev/null +++ b/apps/sim/tools/cursor/types.ts @@ -0,0 +1,187 @@ +import type { ToolResponse } from '@/tools/types' + +export interface BaseCursorParams { + apiKey: string +} + +export interface ListAgentsParams extends BaseCursorParams { + limit?: number + cursor?: 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 +} + +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: 'RUNNING' | 'FINISHED' | 'STOPPED' | 'FAILED' + 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 type CursorResponse = + | ListAgentsResponse + | GetAgentResponse + | GetConversationResponse + | LaunchAgentResponse + | AddFollowupResponse + | StopAgentResponse + | DeleteAgentResponse + | GetApiKeyInfoResponse + | ListModelsResponse + | ListRepositoriesResponse diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index 2f3930b3bf..b49e63788d 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -81,6 +81,15 @@ import { confluenceUpdateCommentTool, confluenceUpdateTool, } from '@/tools/confluence' +import { + cursorAddFollowupTool, + cursorDeleteAgentTool, + cursorGetAgentTool, + cursorGetConversationTool, + cursorLaunchAgentTool, + cursorListAgentsTool, + cursorStopAgentTool, +} from '@/tools/cursor' import { datadogCancelDowntimeTool, datadogCreateDowntimeTool, @@ -1787,6 +1796,13 @@ export const tools: Record = { confluence_list_labels: confluenceListLabelsTool, confluence_get_space: confluenceGetSpaceTool, confluence_list_spaces: confluenceListSpacesTool, + cursor_list_agents: cursorListAgentsTool, + cursor_get_agent: cursorGetAgentTool, + cursor_get_conversation: cursorGetConversationTool, + cursor_launch_agent: cursorLaunchAgentTool, + cursor_add_followup: cursorAddFollowupTool, + cursor_stop_agent: cursorStopAgentTool, + cursor_delete_agent: cursorDeleteAgentTool, trello_list_lists: trelloListListsTool, trello_list_cards: trelloListCardsTool, trello_create_card: trelloCreateCardTool,