Compare commits

..

5 Commits

Author SHA1 Message Date
Waleed
7f18d96d32 feat(popover): add expandOnHover, added the ability to change the color of a workflow icon, new workflow naming convention (#2770)
* feat(popover): add expandOnHover, added the ability to change the color of a workflow icon

* updated workflow naming conventions
2026-01-10 21:30:34 -08:00
Siddharth Ganesan
e347486f50 fix(copilot): fix copilot chat loading (#2769)
* Fix loading

* Fix Lint

* Scroll stickiness

* Scroll stickiness

* improvement: diff controls and notifications positioning

* feat(copilot): editable input component

---------

Co-authored-by: Emir Karabeg <emirkarabeg@berkeley.edu>
2026-01-10 18:24:21 -08:00
Waleed
e21cc1132b fix(subflow): updated subflow border to match block border (#2768) 2026-01-10 17:40:52 -08:00
Waleed
ab32a19cf4 fix(tag-input): add onInputChange to clear errors when new text is entered (#2765)
* fix(tag-input): add onInputChange to clear errors when new text is entered

* added paste case too
2026-01-10 16:48:57 -08:00
Waleed
ead2413b95 fix(context-menu): make divider on context menu aware of available options (#2766) 2026-01-10 14:06:51 -08:00
461 changed files with 6825 additions and 11140 deletions

View File

@@ -137,7 +137,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
circleback: CirclebackIcon,
clay: ClayIcon,
confluence: ConfluenceIcon,
cursor_v2: CursorIcon,
cursor: CursorIcon,
datadog: DatadogIcon,
discord: DiscordIcon,
dropbox: DropboxIcon,
@@ -149,10 +149,10 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
file: DocumentIcon,
firecrawl: FirecrawlIcon,
fireflies: FirefliesIcon,
github_v2: GithubIcon,
github: GithubIcon,
gitlab: GitLabIcon,
gmail_v2: GmailIcon,
google_calendar_v2: GoogleCalendarIcon,
gmail: GmailIcon,
google_calendar: GoogleCalendarIcon,
google_docs: GoogleDocsIcon,
google_drive: GoogleDriveIcon,
google_forms: GoogleFormsIcon,
@@ -170,7 +170,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
image_generator: ImageIcon,
imap: MailServerIcon,
incidentio: IncidentioIcon,
intercom_v2: IntercomIcon,
intercom: IntercomIcon,
jina: JinaAIIcon,
jira: JiraIcon,
jira_service_management: JiraServiceManagementIcon,
@@ -190,7 +190,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
mongodb: MongoDBIcon,
mysql: MySQLIcon,
neo4j: Neo4jIcon,
notion_v2: NotionIcon,
notion: NotionIcon,
onedrive: MicrosoftOneDriveIcon,
openai: OpenAIIcon,
outlook: OutlookIcon,
@@ -226,6 +226,7 @@ export const blockTypeToIconMap: Record<string, IconComponent> = {
supabase: SupabaseIcon,
tavily: TavilyIcon,
telegram: TelegramIcon,
thinking: BrainIcon,
translate: TranslateIcon,
trello: TrelloIcon,
tts: TTSIcon,

View File

@@ -61,9 +61,7 @@ Search Apollo
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `people` | json | Array of people matching the search criteria |
| `page` | number | Current page number |
| `per_page` | number | Results per page |
| `total_entries` | number | Total matching entries |
| `metadata` | json | Pagination information including page, per_page, and total_entries |
### `apollo_people_enrich`
@@ -88,7 +86,7 @@ Enrich data for a single person using Apollo
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `person` | json | Enriched person data from Apollo |
| `enriched` | boolean | Whether the person was successfully enriched |
| `metadata` | json | Enrichment metadata including enriched status |
### `apollo_people_bulk_enrich`
@@ -108,8 +106,7 @@ Enrich data for up to 10 people at once using Apollo
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `people` | json | Array of enriched people data |
| `total` | number | Total number of people processed |
| `enriched` | number | Number of people successfully enriched |
| `metadata` | json | Bulk enrichment metadata including total and enriched counts |
### `apollo_organization_search`
@@ -132,9 +129,7 @@ Search Apollo
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `organizations` | json | Array of organizations matching the search criteria |
| `page` | number | Current page number |
| `per_page` | number | Results per page |
| `total_entries` | number | Total matching entries |
| `metadata` | json | Pagination information including page, per_page, and total_entries |
### `apollo_organization_enrich`
@@ -153,7 +148,7 @@ Enrich data for a single organization using Apollo
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `organization` | json | Enriched organization data from Apollo |
| `enriched` | boolean | Whether the organization was successfully enriched |
| `metadata` | json | Enrichment metadata including enriched status |
### `apollo_organization_bulk_enrich`
@@ -171,8 +166,7 @@ Enrich data for up to 10 organizations at once using Apollo
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `organizations` | json | Array of enriched organization data |
| `total` | number | Total number of organizations processed |
| `enriched` | number | Number of organizations successfully enriched |
| `metadata` | json | Bulk enrichment metadata including total and enriched counts |
### `apollo_contact_create`
@@ -195,7 +189,7 @@ Create a new contact in your Apollo database
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | json | Created contact data from Apollo |
| `created` | boolean | Whether the contact was successfully created |
| `metadata` | json | Creation metadata including created status |
### `apollo_contact_update`
@@ -219,7 +213,7 @@ Update an existing contact in your Apollo database
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | json | Updated contact data from Apollo |
| `updated` | boolean | Whether the contact was successfully updated |
| `metadata` | json | Update metadata including updated status |
### `apollo_contact_search`
@@ -240,9 +234,7 @@ Search your team
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contacts` | json | Array of contacts matching the search criteria |
| `page` | number | Current page number |
| `per_page` | number | Results per page |
| `total_entries` | number | Total matching entries |
| `metadata` | json | Pagination information including page, per_page, and total_entries |
### `apollo_contact_bulk_create`
@@ -262,9 +254,7 @@ Create up to 100 contacts at once in your Apollo database. Supports deduplicatio
| --------- | ---- | ----------- |
| `created_contacts` | json | Array of newly created contacts |
| `existing_contacts` | json | Array of existing contacts \(when deduplication is enabled\) |
| `total_submitted` | number | Total number of contacts submitted |
| `created` | number | Number of contacts successfully created |
| `existing` | number | Number of existing contacts found |
| `metadata` | json | Bulk creation metadata including counts of created and existing contacts |
### `apollo_contact_bulk_update`
@@ -283,9 +273,7 @@ Update up to 100 existing contacts at once in your Apollo database. Each contact
| --------- | ---- | ----------- |
| `updated_contacts` | json | Array of successfully updated contacts |
| `failed_contacts` | json | Array of contacts that failed to update |
| `total_submitted` | number | Total number of contacts submitted |
| `updated` | number | Number of contacts successfully updated |
| `failed` | number | Number of contacts that failed to update |
| `metadata` | json | Bulk update metadata including counts of updated and failed contacts |
### `apollo_account_create`
@@ -306,7 +294,7 @@ Create a new account (company) in your Apollo database
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `account` | json | Created account data from Apollo |
| `created` | boolean | Whether the account was successfully created |
| `metadata` | json | Creation metadata including created status |
### `apollo_account_update`
@@ -328,7 +316,7 @@ Update an existing account in your Apollo database
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `account` | json | Updated account data from Apollo |
| `updated` | boolean | Whether the account was successfully updated |
| `metadata` | json | Update metadata including updated status |
### `apollo_account_search`
@@ -350,9 +338,7 @@ Search your team
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `accounts` | json | Array of accounts matching the search criteria |
| `page` | number | Current page number |
| `per_page` | number | Results per page |
| `total_entries` | number | Total matching entries |
| `metadata` | json | Pagination information including page, per_page, and total_entries |
### `apollo_account_bulk_create`
@@ -371,9 +357,7 @@ Create up to 100 accounts at once in your Apollo database. Note: Apollo does not
| --------- | ---- | ----------- |
| `created_accounts` | json | Array of newly created accounts |
| `failed_accounts` | json | Array of accounts that failed to create |
| `total_submitted` | number | Total number of accounts submitted |
| `created` | number | Number of accounts successfully created |
| `failed` | number | Number of accounts that failed to create |
| `metadata` | json | Bulk creation metadata including counts of created and failed accounts |
### `apollo_account_bulk_update`
@@ -392,9 +376,7 @@ Update up to 1000 existing accounts at once in your Apollo database (higher limi
| --------- | ---- | ----------- |
| `updated_accounts` | json | Array of successfully updated accounts |
| `failed_accounts` | json | Array of accounts that failed to update |
| `total_submitted` | number | Total number of accounts submitted |
| `updated` | number | Number of accounts successfully updated |
| `failed` | number | Number of accounts that failed to update |
| `metadata` | json | Bulk update metadata including counts of updated and failed accounts |
### `apollo_opportunity_create`
@@ -418,7 +400,7 @@ Create a new deal for an account in your Apollo database (master key required)
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `opportunity` | json | Created opportunity data from Apollo |
| `created` | boolean | Whether the opportunity was successfully created |
| `metadata` | json | Creation metadata including created status |
### `apollo_opportunity_search`
@@ -441,9 +423,7 @@ Search and list all deals/opportunities in your team
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `opportunities` | json | Array of opportunities matching the search criteria |
| `page` | number | Current page number |
| `per_page` | number | Results per page |
| `total_entries` | number | Total matching entries |
| `metadata` | json | Pagination information including page, per_page, and total_entries |
### `apollo_opportunity_get`
@@ -461,7 +441,7 @@ Retrieve complete details of a specific deal/opportunity by ID
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `opportunity` | json | Complete opportunity data from Apollo |
| `found` | boolean | Whether the opportunity was found |
| `metadata` | json | Retrieval metadata including found status |
### `apollo_opportunity_update`
@@ -485,7 +465,7 @@ Update an existing deal/opportunity in your Apollo database
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `opportunity` | json | Updated opportunity data from Apollo |
| `updated` | boolean | Whether the opportunity was successfully updated |
| `metadata` | json | Update metadata including updated status |
### `apollo_sequence_search`
@@ -506,9 +486,7 @@ Search for sequences/campaigns in your team
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `sequences` | json | Array of sequences/campaigns matching the search criteria |
| `page` | number | Current page number |
| `per_page` | number | Results per page |
| `total_entries` | number | Total matching entries |
| `metadata` | json | Pagination information including page, per_page, and total_entries |
### `apollo_sequence_add_contacts`
@@ -529,8 +507,7 @@ Add contacts to an Apollo sequence
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contacts_added` | json | Array of contact IDs added to the sequence |
| `sequence_id` | string | ID of the sequence contacts were added to |
| `total_added` | number | Total number of contacts added |
| `metadata` | json | Sequence metadata including sequence_id and total_added count |
### `apollo_task_create`
@@ -553,7 +530,7 @@ Create a new task in Apollo
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `task` | json | Created task data from Apollo |
| `created` | boolean | Whether the task was successfully created |
| `metadata` | json | Creation metadata including created status |
### `apollo_task_search`
@@ -575,9 +552,7 @@ Search for tasks in Apollo
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `tasks` | json | Array of tasks matching the search criteria |
| `page` | number | Current page number |
| `per_page` | number | Results per page |
| `total_entries` | number | Total matching entries |
| `metadata` | json | Pagination information including page, per_page, and total_entries |
### `apollo_email_accounts`
@@ -594,7 +569,7 @@ Get list of team
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `email_accounts` | json | Array of team email accounts linked in Apollo |
| `total` | number | Total count of email accounts |
| `metadata` | json | Metadata including total count of email accounts |

View File

@@ -0,0 +1,186 @@
---
title: Cursor
description: Launch and manage Cursor cloud agents to work on GitHub repositories
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="cursor"
color="#1E1E1E"
/>
{/* MANUAL-CONTENT-START:intro */}
[Cursor](https://www.cursor.so/) is an AI IDE and cloud-based platform that lets you launch and manage powerful AI agents able to work directly on your GitHub repositories. Cursor agents can automate development tasks, enhance your team's productivity, and collaborate with you by making code changes, responding to natural language instructions, and maintaining conversation history about their activities.
With Cursor, you can:
- **Launch cloud agents for codebases**: Instantly create new AI agents that work on your repositories in the cloud
- **Delegate coding tasks using natural language**: Guide agents with written instructions, amendments, and clarifications
- **Monitor progress and outputs**: Retrieve agent status, view detailed results, and inspect current or completed tasks
- **Access full conversation history**: Review all prompts and AI responses for transparency and auditability
- **Control and manage agent lifecycle**: List active agents, terminate agents, and manage API-based agent launches and follow-ups
In Sim, the Cursor integration enables your agents and workflows to interact programmatically with Cursor cloud agents. This means you can use Sim to:
- List all cloud agents and browse their current state (`cursor_list_agents`)
- Retrieve up-to-date status and outputs for any agent (`cursor_get_agent`)
- View the full conversation history for any coding agent (`cursor_get_conversation`)
- Add follow-up instructions or new prompts to a running agent
- Manage and terminate agents as needed
This integration helps you combine the flexible intelligence of Sim agents with the powerful development automation capabilities of Cursor, making it possible to scale AI-driven development across your projects.
{/* MANUAL-CONTENT-END */}
## 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\) |
| `followupPromptText` | 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`

View File

@@ -1,183 +0,0 @@
---
title: Cursor
description: Agent identifier
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="cursor_v2"
color="#F5F5F5"
/>
## Tools
### `cursor_list_agents_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Agent identifier |
| `url` | string | Agent URL \(launch operation\) |
| `name` | string | Agent name |
| `status` | string | Agent status |
| `source` | json | Agent source repository info |
| `target` | json | Agent target branch/PR info |
| `summary` | string | Agent summary |
| `createdAt` | string | Agent creation timestamp |
| `agents` | json | Array of agent objects \(list operation\) |
| `nextCursor` | string | Pagination cursor \(list operation\) |
| `messages` | json | Conversation messages \(get conversation operation\) |
### `cursor_get_agent_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Agent identifier |
| `url` | string | Agent URL \(launch operation\) |
| `name` | string | Agent name |
| `status` | string | Agent status |
| `source` | json | Agent source repository info |
| `target` | json | Agent target branch/PR info |
| `summary` | string | Agent summary |
| `createdAt` | string | Agent creation timestamp |
| `agents` | json | Array of agent objects \(list operation\) |
| `nextCursor` | string | Pagination cursor \(list operation\) |
| `messages` | json | Conversation messages \(get conversation operation\) |
### `cursor_get_conversation_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Agent identifier |
| `url` | string | Agent URL \(launch operation\) |
| `name` | string | Agent name |
| `status` | string | Agent status |
| `source` | json | Agent source repository info |
| `target` | json | Agent target branch/PR info |
| `summary` | string | Agent summary |
| `createdAt` | string | Agent creation timestamp |
| `agents` | json | Array of agent objects \(list operation\) |
| `nextCursor` | string | Pagination cursor \(list operation\) |
| `messages` | json | Conversation messages \(get conversation operation\) |
### `cursor_launch_agent_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Agent identifier |
| `url` | string | Agent URL \(launch operation\) |
| `name` | string | Agent name |
| `status` | string | Agent status |
| `source` | json | Agent source repository info |
| `target` | json | Agent target branch/PR info |
| `summary` | string | Agent summary |
| `createdAt` | string | Agent creation timestamp |
| `agents` | json | Array of agent objects \(list operation\) |
| `nextCursor` | string | Pagination cursor \(list operation\) |
| `messages` | json | Conversation messages \(get conversation operation\) |
### `cursor_add_followup_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Agent identifier |
| `url` | string | Agent URL \(launch operation\) |
| `name` | string | Agent name |
| `status` | string | Agent status |
| `source` | json | Agent source repository info |
| `target` | json | Agent target branch/PR info |
| `summary` | string | Agent summary |
| `createdAt` | string | Agent creation timestamp |
| `agents` | json | Array of agent objects \(list operation\) |
| `nextCursor` | string | Pagination cursor \(list operation\) |
| `messages` | json | Conversation messages \(get conversation operation\) |
### `cursor_stop_agent_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Agent identifier |
| `url` | string | Agent URL \(launch operation\) |
| `name` | string | Agent name |
| `status` | string | Agent status |
| `source` | json | Agent source repository info |
| `target` | json | Agent target branch/PR info |
| `summary` | string | Agent summary |
| `createdAt` | string | Agent creation timestamp |
| `agents` | json | Array of agent objects \(list operation\) |
| `nextCursor` | string | Pagination cursor \(list operation\) |
| `messages` | json | Conversation messages \(get conversation operation\) |
### `cursor_delete_agent_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Agent identifier |
| `url` | string | Agent URL \(launch operation\) |
| `name` | string | Agent name |
| `status` | string | Agent status |
| `source` | json | Agent source repository info |
| `target` | json | Agent target branch/PR info |
| `summary` | string | Agent summary |
| `createdAt` | string | Agent creation timestamp |
| `agents` | json | Array of agent objects \(list operation\) |
| `nextCursor` | string | Pagination cursor \(list operation\) |
| `messages` | json | Conversation messages \(get conversation operation\) |
## Notes
- Category: `misc`
- Type: `cursor_v2`

File diff suppressed because it is too large Load Diff

View File

@@ -1,20 +0,0 @@
---
title: GitHub
description: Operation result data (API-aligned)
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="github_v2"
color="#F5F5F5"
/>
## Notes
- Category: `misc`
- Type: `github_v2`

View File

@@ -0,0 +1,280 @@
---
title: Gmail
description: Send, read, search, and move Gmail messages or trigger workflows from Gmail events
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="gmail"
color="#E0E0E0"
/>
{/* MANUAL-CONTENT-START:intro */}
[Gmail](https://gmail.com) is Google's popular email service that provides a robust platform for sending, receiving, and managing email communications. With over 1.8 billion active users worldwide, Gmail offers a feature-rich experience with powerful search capabilities, organizational tools, and integration options.
With Gmail, you can:
- **Send and receive emails**: Communicate with contacts through a clean, intuitive interface
- **Organize messages**: Use labels, folders, and filters to keep your inbox organized
- **Search efficiently**: Find specific messages quickly with Google's powerful search technology
- **Automate workflows**: Create filters and rules to automatically process incoming emails
- **Access from anywhere**: Use Gmail across devices with synchronized content and settings
- **Integrate with other services**: Connect with Google Calendar, Drive, and other productivity tools
In Sim, the Gmail integration enables your agents to fully manage emails programmatically with comprehensive automation capabilities. This allows for powerful automation scenarios such as sending notifications, processing incoming messages, extracting information from emails, and managing communication workflows at scale. Your agents can:
- **Compose and send**: Create personalized emails with attachments and send to recipients
- **Read and search**: Find specific messages using Gmail's query syntax and extract content
- **Organize intelligently**: Mark messages as read/unread, archive or unarchive emails, and manage labels
- **Clean up inbox**: Delete messages, move emails between labels, and maintain inbox zero
- **Trigger workflows**: Listen for new emails in real-time, enabling responsive workflows that react to incoming messages
This integration bridges the gap between your AI workflows and email communications, enabling seamless interaction with one of the world's most widely used communication platforms. Whether you're automating customer support responses, processing receipts, managing subscriptions, or coordinating team communications, the Gmail integration provides all the tools you need for comprehensive email automation.
{/* MANUAL-CONTENT-END */}
## Usage Instructions
Integrate Gmail into the workflow. Can send, read, search, and move emails. Can be used in trigger mode to trigger a workflow when a new email is received.
## Tools
### `gmail_send`
Send emails using Gmail
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `to` | string | Yes | Recipient email address |
| `subject` | string | No | Email subject |
| `body` | string | Yes | Email body content |
| `contentType` | string | No | Content type for the email body \(text or html\) |
| `threadId` | string | No | Thread ID to reply to \(for threading\) |
| `replyToMessageId` | string | No | Gmail message ID to reply to - use the "id" field from Gmail Read results \(not the RFC "messageId"\) |
| `cc` | string | No | CC recipients \(comma-separated\) |
| `bcc` | string | No | BCC recipients \(comma-separated\) |
| `attachments` | file[] | No | Files to attach to the email |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Success message |
| `metadata` | object | Email metadata |
### `gmail_draft`
Draft emails using Gmail
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `to` | string | Yes | Recipient email address |
| `subject` | string | No | Email subject |
| `body` | string | Yes | Email body content |
| `contentType` | string | No | Content type for the email body \(text or html\) |
| `threadId` | string | No | Thread ID to reply to \(for threading\) |
| `replyToMessageId` | string | No | Gmail message ID to reply to - use the "id" field from Gmail Read results \(not the RFC "messageId"\) |
| `cc` | string | No | CC recipients \(comma-separated\) |
| `bcc` | string | No | BCC recipients \(comma-separated\) |
| `attachments` | file[] | No | Files to attach to the email draft |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Success message |
| `metadata` | object | Draft metadata |
### `gmail_read`
Read emails from Gmail
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `messageId` | string | No | ID of the message to read |
| `folder` | string | No | Folder/label to read emails from |
| `unreadOnly` | boolean | No | Only retrieve unread messages |
| `maxResults` | number | No | Maximum number of messages to retrieve \(default: 1, max: 10\) |
| `includeAttachments` | boolean | No | Download and include email attachments |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Text content of the email |
| `metadata` | json | Metadata of the email |
| `attachments` | file[] | Attachments of the email |
### `gmail_search`
Search emails in Gmail
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `query` | string | Yes | Search query for emails |
| `maxResults` | number | No | Maximum number of results to return |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Search results summary |
| `metadata` | object | Search metadata |
### `gmail_move`
Move emails between Gmail labels/folders
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `messageId` | string | Yes | ID of the message to move |
| `addLabelIds` | string | Yes | Comma-separated label IDs to add \(e.g., INBOX, Label_123\) |
| `removeLabelIds` | string | No | Comma-separated label IDs to remove \(e.g., INBOX, SPAM\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Success message |
| `metadata` | object | Email metadata |
### `gmail_mark_read`
Mark a Gmail message as read
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `messageId` | string | Yes | ID of the message to mark as read |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Success message |
| `metadata` | object | Email metadata |
### `gmail_mark_unread`
Mark a Gmail message as unread
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `messageId` | string | Yes | ID of the message to mark as unread |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Success message |
| `metadata` | object | Email metadata |
### `gmail_archive`
Archive a Gmail message (remove from inbox)
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `messageId` | string | Yes | ID of the message to archive |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Success message |
| `metadata` | object | Email metadata |
### `gmail_unarchive`
Unarchive a Gmail message (move back to inbox)
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `messageId` | string | Yes | ID of the message to unarchive |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Success message |
| `metadata` | object | Email metadata |
### `gmail_delete`
Delete a Gmail message (move to trash)
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `messageId` | string | Yes | ID of the message to delete |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Success message |
| `metadata` | object | Email metadata |
### `gmail_add_label`
Add label(s) to a Gmail message
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `messageId` | string | Yes | ID of the message to add labels to |
| `labelIds` | string | Yes | Comma-separated label IDs to add \(e.g., INBOX, Label_123\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Success message |
| `metadata` | object | Email metadata |
### `gmail_remove_label`
Remove label(s) from a Gmail message
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `messageId` | string | Yes | ID of the message to remove labels from |
| `labelIds` | string | Yes | Comma-separated label IDs to remove \(e.g., INBOX, Label_123\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Success message |
| `metadata` | object | Email metadata |
## Notes
- Category: `tools`
- Type: `gmail`

View File

@@ -1,394 +0,0 @@
---
title: Gmail
description: Gmail message ID
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="gmail_v2"
color="#F5F5F5"
/>
## Tools
### `gmail_send_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Gmail message ID |
| `threadId` | string | Gmail thread ID |
| `labelIds` | array | Email label IDs |
| `from` | string | Sender |
| `to` | string | To |
| `subject` | string | Subject |
| `date` | string | Date |
| `body` | string | Email body text \(best-effort\) |
| `results` | json | Search/read summary results |
| `attachments` | json | Downloaded attachments \(if enabled\) |
| `email_id` | string | Gmail message ID |
| `thread_id` | string | Gmail thread ID |
| `cc` | string | CC recipients \(comma-separated\) |
| `body_text` | string | Plain text email body |
| `body_html` | string | HTML email body |
| `labels` | string | Email labels \(comma-separated\) |
| `has_attachments` | boolean | Whether email has attachments |
| `raw_email` | json | Complete raw email data from Gmail API \(if enabled\) |
| `timestamp` | string | Event timestamp |
### `gmail_draft_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Gmail message ID |
| `threadId` | string | Gmail thread ID |
| `labelIds` | array | Email label IDs |
| `from` | string | Sender |
| `to` | string | To |
| `subject` | string | Subject |
| `date` | string | Date |
| `body` | string | Email body text \(best-effort\) |
| `results` | json | Search/read summary results |
| `attachments` | json | Downloaded attachments \(if enabled\) |
| `email_id` | string | Gmail message ID |
| `thread_id` | string | Gmail thread ID |
| `cc` | string | CC recipients \(comma-separated\) |
| `body_text` | string | Plain text email body |
| `body_html` | string | HTML email body |
| `labels` | string | Email labels \(comma-separated\) |
| `has_attachments` | boolean | Whether email has attachments |
| `raw_email` | json | Complete raw email data from Gmail API \(if enabled\) |
| `timestamp` | string | Event timestamp |
### `gmail_read_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Gmail message ID |
| `threadId` | string | Gmail thread ID |
| `labelIds` | array | Email label IDs |
| `from` | string | Sender |
| `to` | string | To |
| `subject` | string | Subject |
| `date` | string | Date |
| `body` | string | Email body text \(best-effort\) |
| `results` | json | Search/read summary results |
| `attachments` | json | Downloaded attachments \(if enabled\) |
| `email_id` | string | Gmail message ID |
| `thread_id` | string | Gmail thread ID |
| `cc` | string | CC recipients \(comma-separated\) |
| `body_text` | string | Plain text email body |
| `body_html` | string | HTML email body |
| `labels` | string | Email labels \(comma-separated\) |
| `has_attachments` | boolean | Whether email has attachments |
| `raw_email` | json | Complete raw email data from Gmail API \(if enabled\) |
| `timestamp` | string | Event timestamp |
### `gmail_search_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Gmail message ID |
| `threadId` | string | Gmail thread ID |
| `labelIds` | array | Email label IDs |
| `from` | string | Sender |
| `to` | string | To |
| `subject` | string | Subject |
| `date` | string | Date |
| `body` | string | Email body text \(best-effort\) |
| `results` | json | Search/read summary results |
| `attachments` | json | Downloaded attachments \(if enabled\) |
| `email_id` | string | Gmail message ID |
| `thread_id` | string | Gmail thread ID |
| `cc` | string | CC recipients \(comma-separated\) |
| `body_text` | string | Plain text email body |
| `body_html` | string | HTML email body |
| `labels` | string | Email labels \(comma-separated\) |
| `has_attachments` | boolean | Whether email has attachments |
| `raw_email` | json | Complete raw email data from Gmail API \(if enabled\) |
| `timestamp` | string | Event timestamp |
### `gmail_move_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Gmail message ID |
| `threadId` | string | Gmail thread ID |
| `labelIds` | array | Email label IDs |
| `from` | string | Sender |
| `to` | string | To |
| `subject` | string | Subject |
| `date` | string | Date |
| `body` | string | Email body text \(best-effort\) |
| `results` | json | Search/read summary results |
| `attachments` | json | Downloaded attachments \(if enabled\) |
| `email_id` | string | Gmail message ID |
| `thread_id` | string | Gmail thread ID |
| `cc` | string | CC recipients \(comma-separated\) |
| `body_text` | string | Plain text email body |
| `body_html` | string | HTML email body |
| `labels` | string | Email labels \(comma-separated\) |
| `has_attachments` | boolean | Whether email has attachments |
| `raw_email` | json | Complete raw email data from Gmail API \(if enabled\) |
| `timestamp` | string | Event timestamp |
### `gmail_mark_read_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Gmail message ID |
| `threadId` | string | Gmail thread ID |
| `labelIds` | array | Email label IDs |
| `from` | string | Sender |
| `to` | string | To |
| `subject` | string | Subject |
| `date` | string | Date |
| `body` | string | Email body text \(best-effort\) |
| `results` | json | Search/read summary results |
| `attachments` | json | Downloaded attachments \(if enabled\) |
| `email_id` | string | Gmail message ID |
| `thread_id` | string | Gmail thread ID |
| `cc` | string | CC recipients \(comma-separated\) |
| `body_text` | string | Plain text email body |
| `body_html` | string | HTML email body |
| `labels` | string | Email labels \(comma-separated\) |
| `has_attachments` | boolean | Whether email has attachments |
| `raw_email` | json | Complete raw email data from Gmail API \(if enabled\) |
| `timestamp` | string | Event timestamp |
### `gmail_mark_unread_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Gmail message ID |
| `threadId` | string | Gmail thread ID |
| `labelIds` | array | Email label IDs |
| `from` | string | Sender |
| `to` | string | To |
| `subject` | string | Subject |
| `date` | string | Date |
| `body` | string | Email body text \(best-effort\) |
| `results` | json | Search/read summary results |
| `attachments` | json | Downloaded attachments \(if enabled\) |
| `email_id` | string | Gmail message ID |
| `thread_id` | string | Gmail thread ID |
| `cc` | string | CC recipients \(comma-separated\) |
| `body_text` | string | Plain text email body |
| `body_html` | string | HTML email body |
| `labels` | string | Email labels \(comma-separated\) |
| `has_attachments` | boolean | Whether email has attachments |
| `raw_email` | json | Complete raw email data from Gmail API \(if enabled\) |
| `timestamp` | string | Event timestamp |
### `gmail_archive_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Gmail message ID |
| `threadId` | string | Gmail thread ID |
| `labelIds` | array | Email label IDs |
| `from` | string | Sender |
| `to` | string | To |
| `subject` | string | Subject |
| `date` | string | Date |
| `body` | string | Email body text \(best-effort\) |
| `results` | json | Search/read summary results |
| `attachments` | json | Downloaded attachments \(if enabled\) |
| `email_id` | string | Gmail message ID |
| `thread_id` | string | Gmail thread ID |
| `cc` | string | CC recipients \(comma-separated\) |
| `body_text` | string | Plain text email body |
| `body_html` | string | HTML email body |
| `labels` | string | Email labels \(comma-separated\) |
| `has_attachments` | boolean | Whether email has attachments |
| `raw_email` | json | Complete raw email data from Gmail API \(if enabled\) |
| `timestamp` | string | Event timestamp |
### `gmail_unarchive_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Gmail message ID |
| `threadId` | string | Gmail thread ID |
| `labelIds` | array | Email label IDs |
| `from` | string | Sender |
| `to` | string | To |
| `subject` | string | Subject |
| `date` | string | Date |
| `body` | string | Email body text \(best-effort\) |
| `results` | json | Search/read summary results |
| `attachments` | json | Downloaded attachments \(if enabled\) |
| `email_id` | string | Gmail message ID |
| `thread_id` | string | Gmail thread ID |
| `cc` | string | CC recipients \(comma-separated\) |
| `body_text` | string | Plain text email body |
| `body_html` | string | HTML email body |
| `labels` | string | Email labels \(comma-separated\) |
| `has_attachments` | boolean | Whether email has attachments |
| `raw_email` | json | Complete raw email data from Gmail API \(if enabled\) |
| `timestamp` | string | Event timestamp |
### `gmail_delete_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Gmail message ID |
| `threadId` | string | Gmail thread ID |
| `labelIds` | array | Email label IDs |
| `from` | string | Sender |
| `to` | string | To |
| `subject` | string | Subject |
| `date` | string | Date |
| `body` | string | Email body text \(best-effort\) |
| `results` | json | Search/read summary results |
| `attachments` | json | Downloaded attachments \(if enabled\) |
| `email_id` | string | Gmail message ID |
| `thread_id` | string | Gmail thread ID |
| `cc` | string | CC recipients \(comma-separated\) |
| `body_text` | string | Plain text email body |
| `body_html` | string | HTML email body |
| `labels` | string | Email labels \(comma-separated\) |
| `has_attachments` | boolean | Whether email has attachments |
| `raw_email` | json | Complete raw email data from Gmail API \(if enabled\) |
| `timestamp` | string | Event timestamp |
### `gmail_add_label_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Gmail message ID |
| `threadId` | string | Gmail thread ID |
| `labelIds` | array | Email label IDs |
| `from` | string | Sender |
| `to` | string | To |
| `subject` | string | Subject |
| `date` | string | Date |
| `body` | string | Email body text \(best-effort\) |
| `results` | json | Search/read summary results |
| `attachments` | json | Downloaded attachments \(if enabled\) |
| `email_id` | string | Gmail message ID |
| `thread_id` | string | Gmail thread ID |
| `cc` | string | CC recipients \(comma-separated\) |
| `body_text` | string | Plain text email body |
| `body_html` | string | HTML email body |
| `labels` | string | Email labels \(comma-separated\) |
| `has_attachments` | boolean | Whether email has attachments |
| `raw_email` | json | Complete raw email data from Gmail API \(if enabled\) |
| `timestamp` | string | Event timestamp |
### `gmail_remove_label_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Gmail message ID |
| `threadId` | string | Gmail thread ID |
| `labelIds` | array | Email label IDs |
| `from` | string | Sender |
| `to` | string | To |
| `subject` | string | Subject |
| `date` | string | Date |
| `body` | string | Email body text \(best-effort\) |
| `results` | json | Search/read summary results |
| `attachments` | json | Downloaded attachments \(if enabled\) |
| `email_id` | string | Gmail message ID |
| `thread_id` | string | Gmail thread ID |
| `cc` | string | CC recipients \(comma-separated\) |
| `body_text` | string | Plain text email body |
| `body_html` | string | HTML email body |
| `labels` | string | Email labels \(comma-separated\) |
| `has_attachments` | boolean | Whether email has attachments |
| `raw_email` | json | Complete raw email data from Gmail API \(if enabled\) |
| `timestamp` | string | Event timestamp |
## Notes
- Category: `misc`
- Type: `gmail_v2`

View File

@@ -0,0 +1,146 @@
---
title: Google Calendar
description: Manage Google Calendar events
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="google_calendar"
color="#E0E0E0"
/>
{/* MANUAL-CONTENT-START:intro */}
[Google Calendar](https://calendar.google.com) is Google's powerful calendar and scheduling service that provides a comprehensive platform for managing events, meetings, and appointments. With seamless integration across Google's ecosystem and widespread adoption, Google Calendar offers robust features for both personal and professional scheduling needs.
With Google Calendar, you can:
- **Create and manage events**: Schedule meetings, appointments, and reminders with detailed information
- **Send calendar invites**: Automatically notify and coordinate with attendees through email invitations
- **Natural language event creation**: Quickly add events using conversational language like "Meeting with John tomorrow at 3pm"
- **View and search events**: Easily find and access your scheduled events across multiple calendars
- **Manage multiple calendars**: Organize different types of events across various calendars
In Sim, the Google Calendar integration enables your agents to programmatically create, read, and manage calendar events. This allows for powerful automation scenarios such as scheduling meetings, sending calendar invites, checking availability, and managing event details. Your agents can create events with natural language input, send automated calendar invitations to attendees, retrieve event information, and list upcoming events. This integration bridges the gap between your AI workflows and calendar management, enabling seamless scheduling automation and coordination with one of the world's most widely used calendar platforms.
{/* MANUAL-CONTENT-END */}
## Usage Instructions
Integrate Google Calendar into the workflow. Can create, read, update, and list calendar events.
## Tools
### `google_calendar_create`
Create a new event in Google Calendar
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `calendarId` | string | No | Calendar ID \(defaults to primary\) |
| `summary` | string | Yes | Event title/summary |
| `description` | string | No | Event description |
| `location` | string | No | Event location |
| `startDateTime` | string | Yes | Start date and time. MUST include timezone offset \(e.g., 2025-06-03T10:00:00-08:00\) OR provide timeZone parameter |
| `endDateTime` | string | Yes | End date and time. MUST include timezone offset \(e.g., 2025-06-03T11:00:00-08:00\) OR provide timeZone parameter |
| `timeZone` | string | No | Time zone \(e.g., America/Los_Angeles\). Required if datetime does not include offset. Defaults to America/Los_Angeles if not provided. |
| `attendees` | array | No | Array of attendee email addresses |
| `sendUpdates` | string | No | How to send updates to attendees: all, externalOnly, or none |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Event creation confirmation message |
| `metadata` | json | Created event metadata including ID, status, and details |
### `google_calendar_list`
List events from Google Calendar
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `calendarId` | string | No | Calendar ID \(defaults to primary\) |
| `timeMin` | string | No | Lower bound for events \(RFC3339 timestamp, e.g., 2025-06-03T00:00:00Z\) |
| `timeMax` | string | No | Upper bound for events \(RFC3339 timestamp, e.g., 2025-06-04T00:00:00Z\) |
| `orderBy` | string | No | Order of events returned \(startTime or updated\) |
| `showDeleted` | boolean | No | Include deleted events |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Summary of found events count |
| `metadata` | json | List of events with pagination tokens and event details |
### `google_calendar_get`
Get a specific event from Google Calendar
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `calendarId` | string | No | Calendar ID \(defaults to primary\) |
| `eventId` | string | Yes | Event ID to retrieve |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Event retrieval confirmation message |
| `metadata` | json | Event details including ID, status, times, and attendees |
### `google_calendar_quick_add`
Create events from natural language text
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `calendarId` | string | No | Calendar ID \(defaults to primary\) |
| `text` | string | Yes | Natural language text describing the event \(e.g., "Meeting with John tomorrow at 3pm"\) |
| `attendees` | array | No | Array of attendee email addresses \(comma-separated string also accepted\) |
| `sendUpdates` | string | No | How to send updates to attendees: all, externalOnly, or none |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Event creation confirmation message from natural language |
| `metadata` | json | Created event metadata including parsed details |
### `google_calendar_invite`
Invite attendees to an existing Google Calendar event
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `calendarId` | string | No | Calendar ID \(defaults to primary\) |
| `eventId` | string | Yes | Event ID to invite attendees to |
| `attendees` | array | Yes | Array of attendee email addresses to invite |
| `sendUpdates` | string | No | How to send updates to attendees: all, externalOnly, or none |
| `replaceExisting` | boolean | No | Whether to replace existing attendees or add to them \(defaults to false\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Attendee invitation confirmation message with email delivery status |
| `metadata` | json | Updated event metadata including attendee list and details |
## Notes
- Category: `tools`
- Type: `google_calendar`

View File

@@ -1,157 +0,0 @@
---
title: Google Calendar
description: Event ID
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="google_calendar_v2"
color="#F5F5F5"
/>
## Tools
### `google_calendar_create_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Event ID |
| `htmlLink` | string | Event link |
| `status` | string | Event status |
| `summary` | string | Event title |
| `description` | string | Event description |
| `location` | string | Event location |
| `start` | json | Event start |
| `end` | json | Event end |
| `attendees` | json | Event attendees |
| `creator` | json | Event creator |
| `organizer` | json | Event organizer |
| `events` | json | List of events \(list operation\) |
| `nextPageToken` | string | Next page token |
| `nextSyncToken` | string | Next sync token |
| `timeZone` | string | Calendar time zone |
### `google_calendar_list_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Event ID |
| `htmlLink` | string | Event link |
| `status` | string | Event status |
| `summary` | string | Event title |
| `description` | string | Event description |
| `location` | string | Event location |
| `start` | json | Event start |
| `end` | json | Event end |
| `attendees` | json | Event attendees |
| `creator` | json | Event creator |
| `organizer` | json | Event organizer |
| `events` | json | List of events \(list operation\) |
| `nextPageToken` | string | Next page token |
| `nextSyncToken` | string | Next sync token |
| `timeZone` | string | Calendar time zone |
### `google_calendar_get_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Event ID |
| `htmlLink` | string | Event link |
| `status` | string | Event status |
| `summary` | string | Event title |
| `description` | string | Event description |
| `location` | string | Event location |
| `start` | json | Event start |
| `end` | json | Event end |
| `attendees` | json | Event attendees |
| `creator` | json | Event creator |
| `organizer` | json | Event organizer |
| `events` | json | List of events \(list operation\) |
| `nextPageToken` | string | Next page token |
| `nextSyncToken` | string | Next sync token |
| `timeZone` | string | Calendar time zone |
### `google_calendar_quick_add_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Event ID |
| `htmlLink` | string | Event link |
| `status` | string | Event status |
| `summary` | string | Event title |
| `description` | string | Event description |
| `location` | string | Event location |
| `start` | json | Event start |
| `end` | json | Event end |
| `attendees` | json | Event attendees |
| `creator` | json | Event creator |
| `organizer` | json | Event organizer |
| `events` | json | List of events \(list operation\) |
| `nextPageToken` | string | Next page token |
| `nextSyncToken` | string | Next sync token |
| `timeZone` | string | Calendar time zone |
### `google_calendar_invite_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | Event ID |
| `htmlLink` | string | Event link |
| `status` | string | Event status |
| `summary` | string | Event title |
| `description` | string | Event description |
| `location` | string | Event location |
| `start` | json | Event start |
| `end` | json | Event end |
| `attendees` | json | Event attendees |
| `creator` | json | Event creator |
| `organizer` | json | Event organizer |
| `events` | json | List of events \(list operation\) |
| `nextPageToken` | string | Next page token |
| `nextSyncToken` | string | Next sync token |
| `timeZone` | string | Calendar time zone |
## Notes
- Category: `misc`
- Type: `google_calendar_v2`

View File

@@ -96,13 +96,13 @@ Download a file from Google Drive with complete metadata (exports Google Workspa
| `fileId` | string | Yes | The ID of the file to download |
| `mimeType` | string | No | The MIME type to export Google Workspace files to \(optional\) |
| `fileName` | string | No | Optional filename override |
| `includeRevisions` | boolean | No | Whether to include revision history in the metadata \(default: true, returns first 100 revisions\) |
| `includeRevisions` | boolean | No | Whether to include revision history in the metadata \(default: true\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `file` | object | Downloaded file data |
| `file` | object | Downloaded file stored in execution files |
### `google_drive_list`

View File

@@ -51,7 +51,7 @@ Retrieve all users from HubSpot account
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `users` | array | Array of HubSpot user objects |
| `totalItems` | number | Total number of users returned |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `hubspot_list_contacts`
@@ -73,7 +73,7 @@ Retrieve all contacts from HubSpot account with pagination support
| --------- | ---- | ----------- |
| `contacts` | array | Array of HubSpot contact objects |
| `paging` | object | Pagination information |
| `metadata` | object | Metadata with totalReturned and hasMore |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `hubspot_get_contact`
@@ -94,7 +94,7 @@ Retrieve a single contact by ID or email from HubSpot
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | object | HubSpot contact object with properties |
| `contactId` | string | The retrieved contact ID |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `hubspot_create_contact`
@@ -113,7 +113,7 @@ Create a new contact in HubSpot. Requires at least one of: email, firstname, or
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | object | Created HubSpot contact object |
| `contactId` | string | The created contact ID |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `hubspot_update_contact`
@@ -133,7 +133,7 @@ Update an existing contact in HubSpot by ID or email
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | object | Updated HubSpot contact object |
| `contactId` | string | The updated contact ID |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `hubspot_search_contacts`
@@ -158,7 +158,7 @@ Search for contacts in HubSpot using filters, sorting, and queries
| `contacts` | array | Array of matching HubSpot contact objects |
| `total` | number | Total number of matching contacts |
| `paging` | object | Pagination information |
| `metadata` | object | Metadata with totalReturned and hasMore |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `hubspot_list_companies`
@@ -180,7 +180,7 @@ Retrieve all companies from HubSpot account with pagination support
| --------- | ---- | ----------- |
| `companies` | array | Array of HubSpot company objects |
| `paging` | object | Pagination information |
| `metadata` | object | Metadata with totalReturned and hasMore |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `hubspot_get_company`
@@ -201,7 +201,7 @@ Retrieve a single company by ID or domain from HubSpot
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `company` | object | HubSpot company object with properties |
| `companyId` | string | The retrieved company ID |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `hubspot_create_company`
@@ -220,7 +220,7 @@ Create a new company in HubSpot
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `company` | object | Created HubSpot company object |
| `companyId` | string | The created company ID |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `hubspot_update_company`
@@ -240,7 +240,7 @@ Update an existing company in HubSpot by ID or domain
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `company` | object | Updated HubSpot company object |
| `companyId` | string | The updated company ID |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `hubspot_search_companies`
@@ -265,7 +265,7 @@ Search for companies in HubSpot using filters, sorting, and queries
| `companies` | array | Array of matching HubSpot company objects |
| `total` | number | Total number of matching companies |
| `paging` | object | Pagination information |
| `metadata` | object | Metadata with totalReturned and hasMore |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `hubspot_list_deals`
@@ -287,7 +287,7 @@ Retrieve all deals from HubSpot account with pagination support
| --------- | ---- | ----------- |
| `deals` | array | Array of HubSpot deal objects |
| `paging` | object | Pagination information |
| `metadata` | object | Metadata with totalReturned and hasMore |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |

View File

@@ -0,0 +1,365 @@
---
title: Intercom
description: Manage contacts, companies, conversations, tickets, and messages in Intercom
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="intercom"
color="#E0E0E0"
/>
{/* MANUAL-CONTENT-START:intro */}
[Intercom](https://www.intercom.com/) is a leading customer communications platform that enables you to manage and automate your interactions with contacts, companies, conversations, tickets, and messages—all in one place. The Intercom integration in Sim lets your agents programmatically manage customer relationships, support requests, and conversations directly from your automated workflows.
With the Intercom tools, you can:
- **Contacts Management:** Create, get, update, list, search, and delete contacts—automate your CRM processes and keep your customer records up-to-date.
- **Company Management:** Create new companies, retrieve company details, and list all companies related to your users or business clients.
- **Conversation Handling:** Get, list, reply to, and search through conversations—allowing agents to track ongoing support threads, provide answers, and automate follow-up actions.
- **Ticket Management:** Create and retrieve tickets programmatically, helping you automate customer service, support issue tracking, and workflow escalations.
- **Send Messages:** Trigger messages to users or leads for onboarding, support, or marketing, all from within your workflow automation.
By integrating Intercom tools into Sim, you empower your workflows to communicate directly with your users, automate customer support processes, manage leads, and streamline communications at scale. Whether you need to create new contacts, keep customer data synchronized, manage support tickets, or send personalized engagement messages, the Intercom tools provide a comprehensive way to manage customer interactions as part of your intelligent automations.
{/* MANUAL-CONTENT-END */}
## Usage Instructions
Integrate Intercom into the workflow. Can create, get, update, list, search, and delete contacts; create, get, and list companies; get, list, reply, and search conversations; create and get tickets; and create messages.
## Tools
### `intercom_create_contact`
Create a new contact in Intercom with email, external_id, or role
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `role` | string | No | The role of the contact. Accepts 'user' or 'lead'. Defaults to 'lead' if not specified. |
| `email` | string | No | The contact's email address |
| `external_id` | string | No | A unique identifier for the contact provided by the client |
| `phone` | string | No | The contact's phone number |
| `name` | string | No | The contact's name |
| `avatar` | string | No | An avatar image URL for the contact |
| `signed_up_at` | number | No | The time the user signed up as a Unix timestamp |
| `last_seen_at` | number | No | The time the user was last seen as a Unix timestamp |
| `owner_id` | string | No | The id of an admin that has been assigned account ownership of the contact |
| `unsubscribed_from_emails` | boolean | No | Whether the contact is unsubscribed from emails |
| `custom_attributes` | string | No | Custom attributes as JSON object \(e.g., \{"attribute_name": "value"\}\) |
| `company_id` | string | No | Company ID to associate the contact with during creation |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | object | Created contact object |
### `intercom_get_contact`
Get a single contact by ID from Intercom
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `contactId` | string | Yes | Contact ID to retrieve |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | object | Contact object |
### `intercom_update_contact`
Update an existing contact in Intercom
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `contactId` | string | Yes | Contact ID to update |
| `role` | string | No | The role of the contact. Accepts 'user' or 'lead'. |
| `external_id` | string | No | A unique identifier for the contact provided by the client |
| `email` | string | No | The contact's email address |
| `phone` | string | No | The contact's phone number |
| `name` | string | No | The contact's name |
| `avatar` | string | No | An avatar image URL for the contact |
| `signed_up_at` | number | No | The time the user signed up as a Unix timestamp |
| `last_seen_at` | number | No | The time the user was last seen as a Unix timestamp |
| `owner_id` | string | No | The id of an admin that has been assigned account ownership of the contact |
| `unsubscribed_from_emails` | boolean | No | Whether the contact is unsubscribed from emails |
| `custom_attributes` | string | No | Custom attributes as JSON object \(e.g., \{"attribute_name": "value"\}\) |
| `company_id` | string | No | Company ID to associate the contact with |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | object | Updated contact object |
### `intercom_list_contacts`
List all contacts from Intercom with pagination support
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `per_page` | number | No | Number of results per page \(max: 150\) |
| `starting_after` | string | No | Cursor for pagination - ID to start after |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contacts` | array | Array of contact objects |
### `intercom_search_contacts`
Search for contacts in Intercom using a query
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `query` | string | Yes | Search query \(e.g., \{"field":"email","operator":"=","value":"user@example.com"\}\) |
| `per_page` | number | No | Number of results per page \(max: 150\) |
| `starting_after` | string | No | Cursor for pagination |
| `sort_field` | string | No | Field to sort by \(e.g., "name", "created_at", "last_seen_at"\) |
| `sort_order` | string | No | Sort order: "ascending" or "descending" |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contacts` | array | Array of matching contact objects |
### `intercom_delete_contact`
Delete a contact from Intercom by ID
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `contactId` | string | Yes | Contact ID to delete |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `id` | string | ID of deleted contact |
| `deleted` | boolean | Whether the contact was deleted |
| `metadata` | object | Operation metadata |
### `intercom_create_company`
Create or update a company in Intercom
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `company_id` | string | Yes | Your unique identifier for the company |
| `name` | string | No | The name of the company |
| `website` | string | No | The company website |
| `plan` | string | No | The company plan name |
| `size` | number | No | The number of employees in the company |
| `industry` | string | No | The industry the company operates in |
| `monthly_spend` | number | No | How much revenue the company generates for your business. Note: This field truncates floats to whole integers \(e.g., 155.98 becomes 155\) |
| `custom_attributes` | string | No | Custom attributes as JSON object |
| `remote_created_at` | number | No | The time the company was created by you as a Unix timestamp |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `company` | object | Created or updated company object |
### `intercom_get_company`
Retrieve a single company by ID from Intercom
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `companyId` | string | Yes | Company ID to retrieve |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `company` | object | Company object |
### `intercom_list_companies`
List all companies from Intercom with pagination support. Note: This endpoint has a limit of 10,000 companies that can be returned using pagination. For datasets larger than 10,000 companies, use the Scroll API instead.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `per_page` | number | No | Number of results per page |
| `page` | number | No | Page number |
| `starting_after` | string | No | Cursor for pagination \(preferred over page-based pagination\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `companies` | array | Array of company objects |
### `intercom_get_conversation`
Retrieve a single conversation by ID from Intercom
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `conversationId` | string | Yes | Conversation ID to retrieve |
| `display_as` | string | No | Set to "plaintext" to retrieve messages in plain text |
| `include_translations` | boolean | No | When true, conversation parts will be translated to the detected language of the conversation |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `conversation` | object | Conversation object |
### `intercom_list_conversations`
List all conversations from Intercom with pagination support
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `per_page` | number | No | Number of results per page \(max: 150\) |
| `starting_after` | string | No | Cursor for pagination |
| `sort` | string | No | Field to sort by \(e.g., "waiting_since", "updated_at", "created_at"\) |
| `order` | string | No | Sort order: "asc" \(ascending\) or "desc" \(descending\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `conversations` | array | Array of conversation objects |
### `intercom_reply_conversation`
Reply to a conversation as an admin in Intercom
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `conversationId` | string | Yes | Conversation ID to reply to |
| `message_type` | string | Yes | Message type: "comment" or "note" |
| `body` | string | Yes | The text body of the reply |
| `admin_id` | string | No | The ID of the admin authoring the reply. If not provided, a default admin \(Operator/Fin\) will be used. |
| `attachment_urls` | string | No | Comma-separated list of image URLs \(max 10\) |
| `created_at` | number | No | Unix timestamp for when the reply was created. If not provided, current time is used. |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `conversation` | object | Updated conversation object |
### `intercom_search_conversations`
Search for conversations in Intercom using a query
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `query` | string | Yes | Search query as JSON object |
| `per_page` | number | No | Number of results per page \(max: 150\) |
| `starting_after` | string | No | Cursor for pagination |
| `sort_field` | string | No | Field to sort by \(e.g., "created_at", "updated_at"\) |
| `sort_order` | string | No | Sort order: "ascending" or "descending" |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `conversations` | array | Array of matching conversation objects |
### `intercom_create_ticket`
Create a new ticket in Intercom
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `ticket_type_id` | string | Yes | The ID of the ticket type |
| `contacts` | string | Yes | JSON array of contact identifiers \(e.g., \[\{"id": "contact_id"\}\]\) |
| `ticket_attributes` | string | Yes | JSON object with ticket attributes including _default_title_ and _default_description_ |
| `company_id` | string | No | Company ID to associate the ticket with |
| `created_at` | number | No | Unix timestamp for when the ticket was created. If not provided, current time is used. |
| `conversation_to_link_id` | string | No | ID of an existing conversation to link to this ticket |
| `disable_notifications` | boolean | No | When true, suppresses notifications when the ticket is created |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `ticket` | object | Created ticket object |
### `intercom_get_ticket`
Retrieve a single ticket by ID from Intercom
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `ticketId` | string | Yes | Ticket ID to retrieve |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `ticket` | object | Ticket object |
### `intercom_create_message`
Create and send a new admin-initiated message in Intercom
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `message_type` | string | Yes | Message type: "inapp" for in-app messages or "email" for email messages |
| `template` | string | Yes | Message template style: "plain" for plain text or "personal" for personalized style |
| `subject` | string | No | The subject of the message \(for email type\) |
| `body` | string | Yes | The body of the message |
| `from_type` | string | Yes | Sender type: "admin" |
| `from_id` | string | Yes | The ID of the admin sending the message |
| `to_type` | string | Yes | Recipient type: "contact" |
| `to_id` | string | Yes | The ID of the contact receiving the message |
| `created_at` | number | No | Unix timestamp for when the message was created. If not provided, current time is used. |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `message` | object | Created message object |
## Notes
- Category: `tools`
- Type: `intercom`

View File

@@ -1,486 +0,0 @@
---
title: Intercom
description: Contact object with id, type, role, email, phone, name, external_id, created_at, updated_at
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="intercom_v2"
color="#F5F5F5"
/>
## Tools
### `intercom_create_contact_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | json | Contact object with id, type, role, email, phone, name, external_id, created_at, updated_at |
| `contactId` | string | ID of the contact \(for create/update operations\) |
| `contacts` | array | Array of contacts \(for list/search operations\) |
| `company` | json | Company object with id, company_id, name, website |
| `companyId` | string | ID of the company \(for create operations\) |
| `companies` | array | Array of companies \(for list operations\) |
| `conversation` | json | Conversation object with id, title, state, open |
| `conversationId` | string | ID of the conversation \(for reply operations\) |
| `conversations` | array | Array of conversations \(for list/search operations\) |
| `ticket` | json | Ticket object with id, ticket_id, ticket_state |
| `ticketId` | string | ID of the ticket \(for create operations\) |
| `message` | json | Message object with id, type |
| `messageId` | string | ID of the message \(for create operations\) |
| `total_count` | number | Total count \(for list/search operations\) |
| `pages` | json | Pagination info with page, per_page, total_pages |
| `id` | string | ID of the deleted item \(for delete operations\) |
| `deleted` | boolean | Whether the item was deleted \(for delete operations\) |
### `intercom_get_contact_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | json | Contact object with id, type, role, email, phone, name, external_id, created_at, updated_at |
| `contactId` | string | ID of the contact \(for create/update operations\) |
| `contacts` | array | Array of contacts \(for list/search operations\) |
| `company` | json | Company object with id, company_id, name, website |
| `companyId` | string | ID of the company \(for create operations\) |
| `companies` | array | Array of companies \(for list operations\) |
| `conversation` | json | Conversation object with id, title, state, open |
| `conversationId` | string | ID of the conversation \(for reply operations\) |
| `conversations` | array | Array of conversations \(for list/search operations\) |
| `ticket` | json | Ticket object with id, ticket_id, ticket_state |
| `ticketId` | string | ID of the ticket \(for create operations\) |
| `message` | json | Message object with id, type |
| `messageId` | string | ID of the message \(for create operations\) |
| `total_count` | number | Total count \(for list/search operations\) |
| `pages` | json | Pagination info with page, per_page, total_pages |
| `id` | string | ID of the deleted item \(for delete operations\) |
| `deleted` | boolean | Whether the item was deleted \(for delete operations\) |
### `intercom_update_contact_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | json | Contact object with id, type, role, email, phone, name, external_id, created_at, updated_at |
| `contactId` | string | ID of the contact \(for create/update operations\) |
| `contacts` | array | Array of contacts \(for list/search operations\) |
| `company` | json | Company object with id, company_id, name, website |
| `companyId` | string | ID of the company \(for create operations\) |
| `companies` | array | Array of companies \(for list operations\) |
| `conversation` | json | Conversation object with id, title, state, open |
| `conversationId` | string | ID of the conversation \(for reply operations\) |
| `conversations` | array | Array of conversations \(for list/search operations\) |
| `ticket` | json | Ticket object with id, ticket_id, ticket_state |
| `ticketId` | string | ID of the ticket \(for create operations\) |
| `message` | json | Message object with id, type |
| `messageId` | string | ID of the message \(for create operations\) |
| `total_count` | number | Total count \(for list/search operations\) |
| `pages` | json | Pagination info with page, per_page, total_pages |
| `id` | string | ID of the deleted item \(for delete operations\) |
| `deleted` | boolean | Whether the item was deleted \(for delete operations\) |
### `intercom_list_contacts_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | json | Contact object with id, type, role, email, phone, name, external_id, created_at, updated_at |
| `contactId` | string | ID of the contact \(for create/update operations\) |
| `contacts` | array | Array of contacts \(for list/search operations\) |
| `company` | json | Company object with id, company_id, name, website |
| `companyId` | string | ID of the company \(for create operations\) |
| `companies` | array | Array of companies \(for list operations\) |
| `conversation` | json | Conversation object with id, title, state, open |
| `conversationId` | string | ID of the conversation \(for reply operations\) |
| `conversations` | array | Array of conversations \(for list/search operations\) |
| `ticket` | json | Ticket object with id, ticket_id, ticket_state |
| `ticketId` | string | ID of the ticket \(for create operations\) |
| `message` | json | Message object with id, type |
| `messageId` | string | ID of the message \(for create operations\) |
| `total_count` | number | Total count \(for list/search operations\) |
| `pages` | json | Pagination info with page, per_page, total_pages |
| `id` | string | ID of the deleted item \(for delete operations\) |
| `deleted` | boolean | Whether the item was deleted \(for delete operations\) |
### `intercom_search_contacts_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | json | Contact object with id, type, role, email, phone, name, external_id, created_at, updated_at |
| `contactId` | string | ID of the contact \(for create/update operations\) |
| `contacts` | array | Array of contacts \(for list/search operations\) |
| `company` | json | Company object with id, company_id, name, website |
| `companyId` | string | ID of the company \(for create operations\) |
| `companies` | array | Array of companies \(for list operations\) |
| `conversation` | json | Conversation object with id, title, state, open |
| `conversationId` | string | ID of the conversation \(for reply operations\) |
| `conversations` | array | Array of conversations \(for list/search operations\) |
| `ticket` | json | Ticket object with id, ticket_id, ticket_state |
| `ticketId` | string | ID of the ticket \(for create operations\) |
| `message` | json | Message object with id, type |
| `messageId` | string | ID of the message \(for create operations\) |
| `total_count` | number | Total count \(for list/search operations\) |
| `pages` | json | Pagination info with page, per_page, total_pages |
| `id` | string | ID of the deleted item \(for delete operations\) |
| `deleted` | boolean | Whether the item was deleted \(for delete operations\) |
### `intercom_delete_contact_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | json | Contact object with id, type, role, email, phone, name, external_id, created_at, updated_at |
| `contactId` | string | ID of the contact \(for create/update operations\) |
| `contacts` | array | Array of contacts \(for list/search operations\) |
| `company` | json | Company object with id, company_id, name, website |
| `companyId` | string | ID of the company \(for create operations\) |
| `companies` | array | Array of companies \(for list operations\) |
| `conversation` | json | Conversation object with id, title, state, open |
| `conversationId` | string | ID of the conversation \(for reply operations\) |
| `conversations` | array | Array of conversations \(for list/search operations\) |
| `ticket` | json | Ticket object with id, ticket_id, ticket_state |
| `ticketId` | string | ID of the ticket \(for create operations\) |
| `message` | json | Message object with id, type |
| `messageId` | string | ID of the message \(for create operations\) |
| `total_count` | number | Total count \(for list/search operations\) |
| `pages` | json | Pagination info with page, per_page, total_pages |
| `id` | string | ID of the deleted item \(for delete operations\) |
| `deleted` | boolean | Whether the item was deleted \(for delete operations\) |
### `intercom_create_company_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | json | Contact object with id, type, role, email, phone, name, external_id, created_at, updated_at |
| `contactId` | string | ID of the contact \(for create/update operations\) |
| `contacts` | array | Array of contacts \(for list/search operations\) |
| `company` | json | Company object with id, company_id, name, website |
| `companyId` | string | ID of the company \(for create operations\) |
| `companies` | array | Array of companies \(for list operations\) |
| `conversation` | json | Conversation object with id, title, state, open |
| `conversationId` | string | ID of the conversation \(for reply operations\) |
| `conversations` | array | Array of conversations \(for list/search operations\) |
| `ticket` | json | Ticket object with id, ticket_id, ticket_state |
| `ticketId` | string | ID of the ticket \(for create operations\) |
| `message` | json | Message object with id, type |
| `messageId` | string | ID of the message \(for create operations\) |
| `total_count` | number | Total count \(for list/search operations\) |
| `pages` | json | Pagination info with page, per_page, total_pages |
| `id` | string | ID of the deleted item \(for delete operations\) |
| `deleted` | boolean | Whether the item was deleted \(for delete operations\) |
### `intercom_get_company_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | json | Contact object with id, type, role, email, phone, name, external_id, created_at, updated_at |
| `contactId` | string | ID of the contact \(for create/update operations\) |
| `contacts` | array | Array of contacts \(for list/search operations\) |
| `company` | json | Company object with id, company_id, name, website |
| `companyId` | string | ID of the company \(for create operations\) |
| `companies` | array | Array of companies \(for list operations\) |
| `conversation` | json | Conversation object with id, title, state, open |
| `conversationId` | string | ID of the conversation \(for reply operations\) |
| `conversations` | array | Array of conversations \(for list/search operations\) |
| `ticket` | json | Ticket object with id, ticket_id, ticket_state |
| `ticketId` | string | ID of the ticket \(for create operations\) |
| `message` | json | Message object with id, type |
| `messageId` | string | ID of the message \(for create operations\) |
| `total_count` | number | Total count \(for list/search operations\) |
| `pages` | json | Pagination info with page, per_page, total_pages |
| `id` | string | ID of the deleted item \(for delete operations\) |
| `deleted` | boolean | Whether the item was deleted \(for delete operations\) |
### `intercom_list_companies_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | json | Contact object with id, type, role, email, phone, name, external_id, created_at, updated_at |
| `contactId` | string | ID of the contact \(for create/update operations\) |
| `contacts` | array | Array of contacts \(for list/search operations\) |
| `company` | json | Company object with id, company_id, name, website |
| `companyId` | string | ID of the company \(for create operations\) |
| `companies` | array | Array of companies \(for list operations\) |
| `conversation` | json | Conversation object with id, title, state, open |
| `conversationId` | string | ID of the conversation \(for reply operations\) |
| `conversations` | array | Array of conversations \(for list/search operations\) |
| `ticket` | json | Ticket object with id, ticket_id, ticket_state |
| `ticketId` | string | ID of the ticket \(for create operations\) |
| `message` | json | Message object with id, type |
| `messageId` | string | ID of the message \(for create operations\) |
| `total_count` | number | Total count \(for list/search operations\) |
| `pages` | json | Pagination info with page, per_page, total_pages |
| `id` | string | ID of the deleted item \(for delete operations\) |
| `deleted` | boolean | Whether the item was deleted \(for delete operations\) |
### `intercom_get_conversation_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | json | Contact object with id, type, role, email, phone, name, external_id, created_at, updated_at |
| `contactId` | string | ID of the contact \(for create/update operations\) |
| `contacts` | array | Array of contacts \(for list/search operations\) |
| `company` | json | Company object with id, company_id, name, website |
| `companyId` | string | ID of the company \(for create operations\) |
| `companies` | array | Array of companies \(for list operations\) |
| `conversation` | json | Conversation object with id, title, state, open |
| `conversationId` | string | ID of the conversation \(for reply operations\) |
| `conversations` | array | Array of conversations \(for list/search operations\) |
| `ticket` | json | Ticket object with id, ticket_id, ticket_state |
| `ticketId` | string | ID of the ticket \(for create operations\) |
| `message` | json | Message object with id, type |
| `messageId` | string | ID of the message \(for create operations\) |
| `total_count` | number | Total count \(for list/search operations\) |
| `pages` | json | Pagination info with page, per_page, total_pages |
| `id` | string | ID of the deleted item \(for delete operations\) |
| `deleted` | boolean | Whether the item was deleted \(for delete operations\) |
### `intercom_list_conversations_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | json | Contact object with id, type, role, email, phone, name, external_id, created_at, updated_at |
| `contactId` | string | ID of the contact \(for create/update operations\) |
| `contacts` | array | Array of contacts \(for list/search operations\) |
| `company` | json | Company object with id, company_id, name, website |
| `companyId` | string | ID of the company \(for create operations\) |
| `companies` | array | Array of companies \(for list operations\) |
| `conversation` | json | Conversation object with id, title, state, open |
| `conversationId` | string | ID of the conversation \(for reply operations\) |
| `conversations` | array | Array of conversations \(for list/search operations\) |
| `ticket` | json | Ticket object with id, ticket_id, ticket_state |
| `ticketId` | string | ID of the ticket \(for create operations\) |
| `message` | json | Message object with id, type |
| `messageId` | string | ID of the message \(for create operations\) |
| `total_count` | number | Total count \(for list/search operations\) |
| `pages` | json | Pagination info with page, per_page, total_pages |
| `id` | string | ID of the deleted item \(for delete operations\) |
| `deleted` | boolean | Whether the item was deleted \(for delete operations\) |
### `intercom_reply_conversation_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | json | Contact object with id, type, role, email, phone, name, external_id, created_at, updated_at |
| `contactId` | string | ID of the contact \(for create/update operations\) |
| `contacts` | array | Array of contacts \(for list/search operations\) |
| `company` | json | Company object with id, company_id, name, website |
| `companyId` | string | ID of the company \(for create operations\) |
| `companies` | array | Array of companies \(for list operations\) |
| `conversation` | json | Conversation object with id, title, state, open |
| `conversationId` | string | ID of the conversation \(for reply operations\) |
| `conversations` | array | Array of conversations \(for list/search operations\) |
| `ticket` | json | Ticket object with id, ticket_id, ticket_state |
| `ticketId` | string | ID of the ticket \(for create operations\) |
| `message` | json | Message object with id, type |
| `messageId` | string | ID of the message \(for create operations\) |
| `total_count` | number | Total count \(for list/search operations\) |
| `pages` | json | Pagination info with page, per_page, total_pages |
| `id` | string | ID of the deleted item \(for delete operations\) |
| `deleted` | boolean | Whether the item was deleted \(for delete operations\) |
### `intercom_search_conversations_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | json | Contact object with id, type, role, email, phone, name, external_id, created_at, updated_at |
| `contactId` | string | ID of the contact \(for create/update operations\) |
| `contacts` | array | Array of contacts \(for list/search operations\) |
| `company` | json | Company object with id, company_id, name, website |
| `companyId` | string | ID of the company \(for create operations\) |
| `companies` | array | Array of companies \(for list operations\) |
| `conversation` | json | Conversation object with id, title, state, open |
| `conversationId` | string | ID of the conversation \(for reply operations\) |
| `conversations` | array | Array of conversations \(for list/search operations\) |
| `ticket` | json | Ticket object with id, ticket_id, ticket_state |
| `ticketId` | string | ID of the ticket \(for create operations\) |
| `message` | json | Message object with id, type |
| `messageId` | string | ID of the message \(for create operations\) |
| `total_count` | number | Total count \(for list/search operations\) |
| `pages` | json | Pagination info with page, per_page, total_pages |
| `id` | string | ID of the deleted item \(for delete operations\) |
| `deleted` | boolean | Whether the item was deleted \(for delete operations\) |
### `intercom_create_ticket_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | json | Contact object with id, type, role, email, phone, name, external_id, created_at, updated_at |
| `contactId` | string | ID of the contact \(for create/update operations\) |
| `contacts` | array | Array of contacts \(for list/search operations\) |
| `company` | json | Company object with id, company_id, name, website |
| `companyId` | string | ID of the company \(for create operations\) |
| `companies` | array | Array of companies \(for list operations\) |
| `conversation` | json | Conversation object with id, title, state, open |
| `conversationId` | string | ID of the conversation \(for reply operations\) |
| `conversations` | array | Array of conversations \(for list/search operations\) |
| `ticket` | json | Ticket object with id, ticket_id, ticket_state |
| `ticketId` | string | ID of the ticket \(for create operations\) |
| `message` | json | Message object with id, type |
| `messageId` | string | ID of the message \(for create operations\) |
| `total_count` | number | Total count \(for list/search operations\) |
| `pages` | json | Pagination info with page, per_page, total_pages |
| `id` | string | ID of the deleted item \(for delete operations\) |
| `deleted` | boolean | Whether the item was deleted \(for delete operations\) |
### `intercom_get_ticket_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | json | Contact object with id, type, role, email, phone, name, external_id, created_at, updated_at |
| `contactId` | string | ID of the contact \(for create/update operations\) |
| `contacts` | array | Array of contacts \(for list/search operations\) |
| `company` | json | Company object with id, company_id, name, website |
| `companyId` | string | ID of the company \(for create operations\) |
| `companies` | array | Array of companies \(for list operations\) |
| `conversation` | json | Conversation object with id, title, state, open |
| `conversationId` | string | ID of the conversation \(for reply operations\) |
| `conversations` | array | Array of conversations \(for list/search operations\) |
| `ticket` | json | Ticket object with id, ticket_id, ticket_state |
| `ticketId` | string | ID of the ticket \(for create operations\) |
| `message` | json | Message object with id, type |
| `messageId` | string | ID of the message \(for create operations\) |
| `total_count` | number | Total count \(for list/search operations\) |
| `pages` | json | Pagination info with page, per_page, total_pages |
| `id` | string | ID of the deleted item \(for delete operations\) |
| `deleted` | boolean | Whether the item was deleted \(for delete operations\) |
### `intercom_create_message_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `contact` | json | Contact object with id, type, role, email, phone, name, external_id, created_at, updated_at |
| `contactId` | string | ID of the contact \(for create/update operations\) |
| `contacts` | array | Array of contacts \(for list/search operations\) |
| `company` | json | Company object with id, company_id, name, website |
| `companyId` | string | ID of the company \(for create operations\) |
| `companies` | array | Array of companies \(for list operations\) |
| `conversation` | json | Conversation object with id, title, state, open |
| `conversationId` | string | ID of the conversation \(for reply operations\) |
| `conversations` | array | Array of conversations \(for list/search operations\) |
| `ticket` | json | Ticket object with id, ticket_id, ticket_state |
| `ticketId` | string | ID of the ticket \(for create operations\) |
| `message` | json | Message object with id, type |
| `messageId` | string | ID of the message \(for create operations\) |
| `total_count` | number | Total count \(for list/search operations\) |
| `pages` | json | Pagination info with page, per_page, total_pages |
| `id` | string | ID of the deleted item \(for delete operations\) |
| `deleted` | boolean | Whether the item was deleted \(for delete operations\) |
## Notes
- Category: `misc`
- Type: `intercom_v2`

View File

@@ -70,8 +70,8 @@ Retrieve a list of audiences (lists) from Mailchimp
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the audiences were successfully retrieved |
| `output` | object | Audiences data |
| `success` | boolean | Operation success status |
| `output` | object | Audiences data and metadata |
### `mailchimp_get_audience`
@@ -88,8 +88,8 @@ Retrieve details of a specific audience (list) from Mailchimp
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the audience was successfully retrieved |
| `output` | object | Audience data |
| `success` | boolean | Operation success status |
| `output` | object | Audience data and metadata |
### `mailchimp_create_audience`
@@ -150,7 +150,8 @@ Delete an audience (list) from Mailchimp
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the audience was successfully deleted |
| `success` | boolean | Operation success status |
| `output` | object | Deletion confirmation |
### `mailchimp_get_members`
@@ -170,8 +171,8 @@ Retrieve a list of members from a Mailchimp audience
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the members were successfully retrieved |
| `output` | object | Members data |
| `success` | boolean | Operation success status |
| `output` | object | Members data and metadata |
### `mailchimp_get_member`
@@ -189,8 +190,8 @@ Retrieve details of a specific member from a Mailchimp audience
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the member was successfully retrieved |
| `output` | object | Member data |
| `success` | boolean | Operation success status |
| `output` | object | Member data and metadata |
### `mailchimp_add_member`
@@ -276,7 +277,8 @@ Delete a member from a Mailchimp audience
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the member was successfully deleted |
| `success` | boolean | Operation success status |
| `output` | object | Deletion confirmation |
### `mailchimp_archive_member`
@@ -336,8 +338,8 @@ Retrieve a list of campaigns from Mailchimp
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the campaigns were successfully retrieved |
| `output` | object | Campaigns data |
| `success` | boolean | Operation success status |
| `output` | object | Campaigns data and metadata |
### `mailchimp_get_campaign`
@@ -354,8 +356,8 @@ Retrieve details of a specific campaign from Mailchimp
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the campaign was successfully retrieved |
| `output` | object | Campaign data |
| `success` | boolean | Operation success status |
| `output` | object | Campaign data and metadata |
### `mailchimp_create_campaign`
@@ -412,7 +414,8 @@ Delete a campaign from Mailchimp
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the campaign was successfully deleted |
| `success` | boolean | Operation success status |
| `output` | object | Deletion confirmation |
### `mailchimp_send_campaign`
@@ -448,7 +451,8 @@ Schedule a Mailchimp campaign to be sent at a specific time
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the campaign was successfully scheduled |
| `success` | boolean | Operation success status |
| `output` | object | Schedule confirmation |
### `mailchimp_unschedule_campaign`
@@ -501,7 +505,7 @@ Retrieve the HTML and plain-text content for a Mailchimp campaign
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the campaign content was successfully retrieved |
| `success` | boolean | Operation success status |
| `output` | object | Campaign content data |
### `mailchimp_set_campaign_content`
@@ -541,8 +545,8 @@ Retrieve a list of automations from Mailchimp
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the automations were successfully retrieved |
| `output` | object | Automations data |
| `success` | boolean | Operation success status |
| `output` | object | Automations data and metadata |
### `mailchimp_get_automation`
@@ -559,8 +563,8 @@ Retrieve details of a specific automation from Mailchimp
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the automation was successfully retrieved |
| `output` | object | Automation data |
| `success` | boolean | Operation success status |
| `output` | object | Automation data and metadata |
### `mailchimp_start_automation`
@@ -634,8 +638,8 @@ Retrieve a list of templates from Mailchimp
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the templates were successfully retrieved |
| `output` | object | Templates data |
| `success` | boolean | Operation success status |
| `output` | object | Templates data and metadata |
### `mailchimp_get_template`
@@ -652,8 +656,8 @@ Retrieve details of a specific template from Mailchimp
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the template was successfully retrieved |
| `output` | object | Template data |
| `success` | boolean | Operation success status |
| `output` | object | Template data and metadata |
### `mailchimp_create_template`
@@ -709,7 +713,8 @@ Delete a template from Mailchimp
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the template was successfully deleted |
| `success` | boolean | Operation success status |
| `output` | object | Deletion confirmation |
### `mailchimp_get_campaign_reports`
@@ -727,8 +732,8 @@ Retrieve a list of campaign reports from Mailchimp
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the campaign reports were successfully retrieved |
| `output` | object | Campaign reports data |
| `success` | boolean | Operation success status |
| `output` | object | Campaign reports data and metadata |
### `mailchimp_get_campaign_report`
@@ -745,8 +750,8 @@ Retrieve the report for a specific campaign from Mailchimp
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the campaign report was successfully retrieved |
| `output` | object | Campaign report data |
| `success` | boolean | Operation success status |
| `output` | object | Campaign report data and metadata |
### `mailchimp_get_segments`
@@ -765,8 +770,8 @@ Retrieve a list of segments from a Mailchimp audience
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the segments were successfully retrieved |
| `output` | object | Segments data |
| `success` | boolean | Operation success status |
| `output` | object | Segments data and metadata |
### `mailchimp_get_segment`
@@ -784,8 +789,8 @@ Retrieve details of a specific segment from a Mailchimp audience
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the segment was successfully retrieved |
| `output` | object | Segment data |
| `success` | boolean | Operation success status |
| `output` | object | Segment data and metadata |
### `mailchimp_create_segment`
@@ -844,7 +849,8 @@ Delete a segment from a Mailchimp audience
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the segment was successfully deleted |
| `success` | boolean | Operation success status |
| `output` | object | Deletion confirmation |
### `mailchimp_get_segment_members`
@@ -864,8 +870,8 @@ Retrieve members of a specific segment from a Mailchimp audience
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the segment members were successfully retrieved |
| `output` | object | Segment members data |
| `success` | boolean | Operation success status |
| `output` | object | Segment members data and metadata |
### `mailchimp_add_segment_member`
@@ -923,8 +929,8 @@ Retrieve tags associated with a member in a Mailchimp audience
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the member tags were successfully retrieved |
| `output` | object | Member tags data |
| `success` | boolean | Operation success status |
| `output` | object | Member tags data and metadata |
### `mailchimp_add_member_tags`
@@ -983,8 +989,8 @@ Retrieve a list of merge fields from a Mailchimp audience
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the merge fields were successfully retrieved |
| `output` | object | Merge fields data |
| `success` | boolean | Operation success status |
| `output` | object | Merge fields data and metadata |
### `mailchimp_get_merge_field`
@@ -1002,8 +1008,8 @@ Retrieve details of a specific merge field from a Mailchimp audience
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the merge field was successfully retrieved |
| `output` | object | Merge field data |
| `success` | boolean | Operation success status |
| `output` | object | Merge field data and metadata |
### `mailchimp_create_merge_field`
@@ -1061,7 +1067,8 @@ Delete a merge field from a Mailchimp audience
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the merge field was successfully deleted |
| `success` | boolean | Operation success status |
| `output` | object | Deletion confirmation |
### `mailchimp_get_interest_categories`
@@ -1080,8 +1087,8 @@ Retrieve a list of interest categories from a Mailchimp audience
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the interest categories were successfully retrieved |
| `output` | object | Interest categories data |
| `success` | boolean | Operation success status |
| `output` | object | Interest categories data and metadata |
### `mailchimp_get_interest_category`
@@ -1099,8 +1106,8 @@ Retrieve details of a specific interest category from a Mailchimp audience
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the interest category was successfully retrieved |
| `output` | object | Interest category data |
| `success` | boolean | Operation success status |
| `output` | object | Interest category data and metadata |
### `mailchimp_create_interest_category`
@@ -1158,7 +1165,8 @@ Delete an interest category from a Mailchimp audience
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the interest category was successfully deleted |
| `success` | boolean | Operation success status |
| `output` | object | Deletion confirmation |
### `mailchimp_get_interests`
@@ -1178,8 +1186,8 @@ Retrieve a list of interests from an interest category in a Mailchimp audience
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the interests were successfully retrieved |
| `output` | object | Interests data |
| `success` | boolean | Operation success status |
| `output` | object | Interests data and metadata |
### `mailchimp_get_interest`
@@ -1198,8 +1206,8 @@ Retrieve details of a specific interest from an interest category in a Mailchimp
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the interest was successfully retrieved |
| `output` | object | Interest data |
| `success` | boolean | Operation success status |
| `output` | object | Interest data and metadata |
### `mailchimp_create_interest`
@@ -1259,7 +1267,8 @@ Delete an interest from an interest category in a Mailchimp audience
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the interest was successfully deleted |
| `success` | boolean | Operation success status |
| `output` | object | Deletion confirmation |
### `mailchimp_get_landing_pages`
@@ -1277,8 +1286,8 @@ Retrieve a list of landing pages from Mailchimp
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the landing pages were successfully retrieved |
| `output` | object | Landing pages data |
| `success` | boolean | Operation success status |
| `output` | object | Landing pages data and metadata |
### `mailchimp_get_landing_page`
@@ -1295,8 +1304,8 @@ Retrieve details of a specific landing page from Mailchimp
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the landing page was successfully retrieved |
| `output` | object | Landing page data |
| `success` | boolean | Operation success status |
| `output` | object | Landing page data and metadata |
### `mailchimp_create_landing_page`
@@ -1351,7 +1360,8 @@ Delete a landing page from Mailchimp
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the landing page was successfully deleted |
| `success` | boolean | Operation success status |
| `output` | object | Deletion confirmation |
### `mailchimp_publish_landing_page`
@@ -1405,8 +1415,8 @@ Retrieve a list of batch operations from Mailchimp
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the batch operations were successfully retrieved |
| `output` | object | Batch operations data |
| `success` | boolean | Operation success status |
| `output` | object | Batch operations data and metadata |
### `mailchimp_get_batch_operation`
@@ -1423,8 +1433,8 @@ Retrieve details of a specific batch operation from Mailchimp
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the batch operation was successfully retrieved |
| `output` | object | Batch operation data |
| `success` | boolean | Operation success status |
| `output` | object | Batch operation data and metadata |
### `mailchimp_create_batch_operation`
@@ -1459,7 +1469,8 @@ Delete a batch operation from Mailchimp
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the batch operation was successfully deleted |
| `success` | boolean | Operation success status |
| `output` | object | Deletion confirmation |

View File

@@ -12,7 +12,7 @@
"circleback",
"clay",
"confluence",
"cursor_v2",
"cursor",
"datadog",
"discord",
"dropbox",
@@ -24,10 +24,10 @@
"file",
"firecrawl",
"fireflies",
"github_v2",
"github",
"gitlab",
"gmail_v2",
"google_calendar_v2",
"gmail",
"google_calendar",
"google_docs",
"google_drive",
"google_forms",
@@ -45,7 +45,7 @@
"image_generator",
"imap",
"incidentio",
"intercom_v2",
"intercom",
"jina",
"jira",
"jira_service_management",
@@ -65,7 +65,7 @@
"mongodb",
"mysql",
"neo4j",
"notion_v2",
"notion",
"onedrive",
"openai",
"outlook",
@@ -101,6 +101,7 @@
"supabase",
"tavily",
"telegram",
"thinking",
"translate",
"trello",
"tts",

View File

@@ -0,0 +1,180 @@
---
title: Notion
description: Manage Notion pages
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="notion"
color="#181C1E"
/>
{/* MANUAL-CONTENT-START:intro */}
[Notion](https://www.notion.so) is an all-in-one workspace that combines notes, documents, wikis, and project management tools into a single platform. It offers a flexible and customizable environment where users can create, organize, and collaborate on content in various formats.
With Notion, you can:
- **Create versatile content**: Build documents, wikis, databases, kanban boards, calendars, and more
- **Organize information**: Structure content hierarchically with nested pages and powerful databases
- **Collaborate seamlessly**: Share workspaces and pages with team members for real-time collaboration
- **Customize your workspace**: Design your ideal workflow with flexible templates and building blocks
- **Connect information**: Link between pages and databases to create a knowledge network
- **Access anywhere**: Use Notion across web, desktop, and mobile platforms with automatic syncing
In Sim, the Notion integration enables your agents to interact directly with your Notion workspace programmatically. This allows for powerful automation scenarios such as knowledge management, content creation, and information retrieval. Your agents can:
- **Read Notion pages**: Extract content and metadata from any Notion page.
- **Read Notion databases**: Retrieve database structure and information.
- **Write to pages**: Append new content to existing Notion pages.
- **Create new pages**: Generate new Notion pages under a parent page, with custom titles and content.
- **Query databases**: Search and filter database entries using advanced filter and sort criteria.
- **Search workspace**: Search across your entire Notion workspace for pages or databases matching specific queries.
- **Create new databases**: Programmatically create new databases with custom properties and structure.
This integration bridges the gap between your AI workflows and your knowledge base, enabling seamless documentation and information management. By connecting Sim with Notion, you can automate documentation processes, maintain up-to-date information repositories, generate reports, and organize information intelligently—all through your intelligent agents.
{/* MANUAL-CONTENT-END */}
## Usage Instructions
Integrate with Notion into the workflow. Can read page, read database, create page, create database, append content, query database, and search workspace.
## Tools
### `notion_read`
Read content from a Notion page
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `pageId` | string | Yes | The ID of the Notion page to read |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Page content in markdown format with headers, paragraphs, lists, and todos |
| `metadata` | object | Page metadata including title, URL, and timestamps |
### `notion_read_database`
Read database information and structure from Notion
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `databaseId` | string | Yes | The ID of the Notion database to read |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Database information including title, properties schema, and metadata |
| `metadata` | object | Database metadata including title, ID, URL, timestamps, and properties schema |
### `notion_write`
Append content to a Notion page
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `pageId` | string | Yes | The ID of the Notion page to append content to |
| `content` | string | Yes | The content to append to the page |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Success message confirming content was appended to page |
### `notion_create_page`
Create a new page in Notion
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `parentId` | string | Yes | ID of the parent page |
| `title` | string | No | Title of the new page |
| `content` | string | No | Optional content to add to the page upon creation |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Success message confirming page creation |
| `metadata` | object | Page metadata including title, page ID, URL, and timestamps |
### `notion_query_database`
Query and filter Notion database entries with advanced filtering
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `databaseId` | string | Yes | The ID of the database to query |
| `filter` | string | No | Filter conditions as JSON \(optional\) |
| `sorts` | string | No | Sort criteria as JSON array \(optional\) |
| `pageSize` | number | No | Number of results to return \(default: 100, max: 100\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Formatted list of database entries with their properties |
| `metadata` | object | Query metadata including total results count, pagination info, and raw results array |
### `notion_search`
Search across all pages and databases in Notion workspace
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `query` | string | No | Search terms \(leave empty to get all pages\) |
| `filterType` | string | No | Filter by object type: page, database, or leave empty for all |
| `pageSize` | number | No | Number of results to return \(default: 100, max: 100\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Formatted list of search results including pages and databases |
| `metadata` | object | Search metadata including total results count, pagination info, and raw results array |
### `notion_create_database`
Create a new database in Notion with custom properties
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `parentId` | string | Yes | ID of the parent page where the database will be created |
| `title` | string | Yes | Title for the new database |
| `properties` | string | No | Database properties as JSON object \(optional, will create a default "Name" property if empty\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Success message with database details and properties list |
| `metadata` | object | Database metadata including ID, title, URL, creation time, and properties schema |
## Notes
- Category: `tools`
- Type: `notion`

View File

@@ -1,194 +0,0 @@
---
title: Notion
description: Manage Notion pages
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="notion_v2"
color="#181C1E"
/>
## Usage Instructions
Integrate with Notion into the workflow. Can read page, read database, create page, create database, append content, query database, and search workspace.
## Tools
### `notion_read_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Page content in markdown format |
| `title` | string | Page or database title |
| `url` | string | Notion URL |
| `id` | string | Page or database ID |
| `created_time` | string | Creation timestamp |
| `last_edited_time` | string | Last edit timestamp |
| `results` | array | Array of results from query or search |
| `has_more` | boolean | Whether more results are available |
| `next_cursor` | string | Cursor for pagination |
| `total_results` | number | Number of results returned |
| `properties` | json | Database properties schema |
| `appended` | boolean | Whether content was successfully appended |
### `notion_read_database_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Page content in markdown format |
| `title` | string | Page or database title |
| `url` | string | Notion URL |
| `id` | string | Page or database ID |
| `created_time` | string | Creation timestamp |
| `last_edited_time` | string | Last edit timestamp |
| `results` | array | Array of results from query or search |
| `has_more` | boolean | Whether more results are available |
| `next_cursor` | string | Cursor for pagination |
| `total_results` | number | Number of results returned |
| `properties` | json | Database properties schema |
| `appended` | boolean | Whether content was successfully appended |
### `notion_write_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Page content in markdown format |
| `title` | string | Page or database title |
| `url` | string | Notion URL |
| `id` | string | Page or database ID |
| `created_time` | string | Creation timestamp |
| `last_edited_time` | string | Last edit timestamp |
| `results` | array | Array of results from query or search |
| `has_more` | boolean | Whether more results are available |
| `next_cursor` | string | Cursor for pagination |
| `total_results` | number | Number of results returned |
| `properties` | json | Database properties schema |
| `appended` | boolean | Whether content was successfully appended |
### `notion_create_page_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Page content in markdown format |
| `title` | string | Page or database title |
| `url` | string | Notion URL |
| `id` | string | Page or database ID |
| `created_time` | string | Creation timestamp |
| `last_edited_time` | string | Last edit timestamp |
| `results` | array | Array of results from query or search |
| `has_more` | boolean | Whether more results are available |
| `next_cursor` | string | Cursor for pagination |
| `total_results` | number | Number of results returned |
| `properties` | json | Database properties schema |
| `appended` | boolean | Whether content was successfully appended |
### `notion_query_database_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Page content in markdown format |
| `title` | string | Page or database title |
| `url` | string | Notion URL |
| `id` | string | Page or database ID |
| `created_time` | string | Creation timestamp |
| `last_edited_time` | string | Last edit timestamp |
| `results` | array | Array of results from query or search |
| `has_more` | boolean | Whether more results are available |
| `next_cursor` | string | Cursor for pagination |
| `total_results` | number | Number of results returned |
| `properties` | json | Database properties schema |
| `appended` | boolean | Whether content was successfully appended |
### `notion_search_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Page content in markdown format |
| `title` | string | Page or database title |
| `url` | string | Notion URL |
| `id` | string | Page or database ID |
| `created_time` | string | Creation timestamp |
| `last_edited_time` | string | Last edit timestamp |
| `results` | array | Array of results from query or search |
| `has_more` | boolean | Whether more results are available |
| `next_cursor` | string | Cursor for pagination |
| `total_results` | number | Number of results returned |
| `properties` | json | Database properties schema |
| `appended` | boolean | Whether content was successfully appended |
### `notion_create_database_v2`
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Page content in markdown format |
| `title` | string | Page or database title |
| `url` | string | Notion URL |
| `id` | string | Page or database ID |
| `created_time` | string | Creation timestamp |
| `last_edited_time` | string | Last edit timestamp |
| `results` | array | Array of results from query or search |
| `has_more` | boolean | Whether more results are available |
| `next_cursor` | string | Cursor for pagination |
| `total_results` | number | Number of results returned |
| `properties` | json | Database properties schema |
| `appended` | boolean | Whether content was successfully appended |
## Notes
- Category: `tools`
- Type: `notion_v2`

View File

@@ -55,7 +55,7 @@ Retrieve all deals from Pipedrive with optional filters
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `deals` | array | Array of deal objects from Pipedrive |
| `metadata` | object | Pagination metadata for the response |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `pipedrive_get_deal`
@@ -73,6 +73,7 @@ Retrieve detailed information about a specific deal
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `deal` | object | Deal object with full details |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `pipedrive_create_deal`
@@ -98,6 +99,7 @@ Create a new deal in Pipedrive
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `deal` | object | The created deal object |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `pipedrive_update_deal`
@@ -120,6 +122,7 @@ Update an existing deal in Pipedrive
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `deal` | object | The updated deal object |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `pipedrive_get_files`
@@ -140,7 +143,7 @@ Retrieve files from Pipedrive with optional filters
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `files` | array | Array of file objects from Pipedrive |
| `total_items` | number | Total number of files returned |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `pipedrive_get_mail_messages`
@@ -159,7 +162,7 @@ Retrieve mail threads from Pipedrive mailbox
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `messages` | array | Array of mail thread objects from Pipedrive mailbox |
| `total_items` | number | Total number of mail threads returned |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `pipedrive_get_mail_thread`
@@ -177,7 +180,7 @@ Retrieve all messages from a specific mail thread
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `messages` | array | Array of mail message objects from the thread |
| `metadata` | object | Thread and pagination metadata |
| `metadata` | object | Operation metadata including thread ID |
| `success` | boolean | Operation success status |
### `pipedrive_get_pipelines`
@@ -198,7 +201,7 @@ Retrieve all pipelines from Pipedrive
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `pipelines` | array | Array of pipeline objects from Pipedrive |
| `total_items` | number | Total number of pipelines returned |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `pipedrive_get_pipeline_deals`
@@ -219,7 +222,7 @@ Retrieve all deals in a specific pipeline
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `deals` | array | Array of deal objects from the pipeline |
| `metadata` | object | Pipeline and pagination metadata |
| `metadata` | object | Operation metadata including pipeline ID |
| `success` | boolean | Operation success status |
### `pipedrive_get_projects`
@@ -240,7 +243,7 @@ Retrieve all projects or a specific project from Pipedrive
| --------- | ---- | ----------- |
| `projects` | array | Array of project objects \(when listing all\) |
| `project` | object | Single project object \(when project_id is provided\) |
| `total_items` | number | Total number of projects returned |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `pipedrive_create_project`
@@ -261,6 +264,7 @@ Create a new project in Pipedrive
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `project` | object | The created project object |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `pipedrive_get_activities`
@@ -283,7 +287,7 @@ Retrieve activities (tasks) from Pipedrive with optional filters
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `activities` | array | Array of activity objects from Pipedrive |
| `total_items` | number | Total number of activities returned |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `pipedrive_create_activity`
@@ -309,6 +313,7 @@ Create a new activity (task) in Pipedrive
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `activity` | object | The created activity object |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `pipedrive_update_activity`
@@ -332,6 +337,7 @@ Update an existing activity (task) in Pipedrive
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `activity` | object | The updated activity object |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `pipedrive_get_leads`
@@ -355,7 +361,7 @@ Retrieve all leads or a specific lead from Pipedrive
| --------- | ---- | ----------- |
| `leads` | array | Array of lead objects \(when listing all\) |
| `lead` | object | Single lead object \(when lead_id is provided\) |
| `total_items` | number | Total number of leads returned |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `pipedrive_create_lead`
@@ -380,6 +386,7 @@ Create a new lead in Pipedrive
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `lead` | object | The created lead object |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `pipedrive_update_lead`
@@ -405,6 +412,7 @@ Update an existing lead in Pipedrive
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `lead` | object | The updated lead object |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |
### `pipedrive_delete_lead`
@@ -422,6 +430,7 @@ Delete a specific lead from Pipedrive
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `data` | object | Deletion confirmation data |
| `metadata` | object | Operation metadata |
| `success` | boolean | Operation success status |

View File

@@ -77,7 +77,7 @@ Capture multiple events at once in PostHog. Use this for bulk event ingestion to
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `status` | string | Status message indicating whether the batch was captured successfully |
| `events_processed` | number | Number of events processed in the batch |
| `eventsProcessed` | number | Number of events processed in the batch |
### `posthog_list_persons`
@@ -600,9 +600,9 @@ Evaluate feature flags for a specific user or group. This is a public endpoint t
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `feature_flags` | object | Feature flag evaluations \(key-value pairs where values are boolean or string variants\) |
| `feature_flag_payloads` | object | Additional payloads attached to feature flags |
| `errors_while_computing_flags` | boolean | Whether there were errors while computing flags |
| `featureFlags` | object | Feature flag evaluations \(key-value pairs where values are boolean or string variants\) |
| `featureFlagPayloads` | object | Additional payloads attached to feature flags |
| `errorsWhileComputingFlags` | boolean | Whether there were errors while computing flags |
### `posthog_list_experiments`

View File

@@ -259,7 +259,7 @@ Get lead(s) from Salesforce
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `success` | boolean | Success status |
| `output` | object | Lead data |
### `salesforce_create_lead`
@@ -286,8 +286,8 @@ Create a new lead
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `output` | object | Created lead data |
| `success` | boolean | Success |
| `output` | object | Created lead |
### `salesforce_update_lead`
@@ -314,8 +314,8 @@ Update an existing lead
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `output` | object | Updated lead data |
| `success` | boolean | Success |
| `output` | object | Updated lead |
### `salesforce_delete_lead`
@@ -333,8 +333,8 @@ Delete a lead
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `output` | object | Deleted lead data |
| `success` | boolean | Success |
| `output` | object | Deleted lead |
### `salesforce_get_opportunities`
@@ -355,7 +355,7 @@ Get opportunity(ies) from Salesforce
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `success` | boolean | Success |
| `output` | object | Opportunity data |
### `salesforce_create_opportunity`
@@ -380,8 +380,8 @@ Create a new opportunity
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `output` | object | Created opportunity data |
| `success` | boolean | Success |
| `output` | object | Created opportunity |
### `salesforce_update_opportunity`
@@ -406,8 +406,8 @@ Update an existing opportunity
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `output` | object | Updated opportunity data |
| `success` | boolean | Success |
| `output` | object | Updated opportunity |
### `salesforce_delete_opportunity`
@@ -425,8 +425,8 @@ Delete an opportunity
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `output` | object | Deleted opportunity data |
| `success` | boolean | Success |
| `output` | object | Deleted opportunity |
### `salesforce_get_cases`
@@ -447,7 +447,7 @@ Get case(s) from Salesforce
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `success` | boolean | Success |
| `output` | object | Case data |
### `salesforce_create_case`
@@ -472,8 +472,8 @@ Create a new case
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `output` | object | Created case data |
| `success` | boolean | Success |
| `output` | object | Created case |
### `salesforce_update_case`
@@ -495,8 +495,8 @@ Update an existing case
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `output` | object | Updated case data |
| `success` | boolean | Success |
| `output` | object | Updated case |
### `salesforce_delete_case`
@@ -514,8 +514,8 @@ Delete a case
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `output` | object | Deleted case data |
| `success` | boolean | Success |
| `output` | object | Deleted case |
### `salesforce_get_tasks`
@@ -536,7 +536,7 @@ Get task(s) from Salesforce
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `success` | boolean | Success |
| `output` | object | Task data |
### `salesforce_create_task`
@@ -561,8 +561,8 @@ Create a new task
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `output` | object | Created task data |
| `success` | boolean | Success |
| `output` | object | Created task |
### `salesforce_update_task`
@@ -585,8 +585,8 @@ Update an existing task
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `output` | object | Updated task data |
| `success` | boolean | Success |
| `output` | object | Updated task |
### `salesforce_delete_task`
@@ -604,8 +604,8 @@ Delete a task
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `output` | object | Deleted task data |
| `success` | boolean | Success |
| `output` | object | Deleted task |
### `salesforce_list_reports`
@@ -624,7 +624,7 @@ Get a list of reports accessible by the current user
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `success` | boolean | Success status |
| `output` | object | Reports data |
### `salesforce_get_report`
@@ -643,7 +643,7 @@ Get metadata and describe information for a specific report
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `success` | boolean | Success status |
| `output` | object | Report metadata |
### `salesforce_run_report`
@@ -664,7 +664,7 @@ Execute a report and retrieve the results
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `success` | boolean | Success status |
| `output` | object | Report results |
### `salesforce_list_report_types`
@@ -682,7 +682,7 @@ Get a list of available report types
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `success` | boolean | Success status |
| `output` | object | Report types data |
### `salesforce_list_dashboards`
@@ -701,7 +701,7 @@ Get a list of dashboards accessible by the current user
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `success` | boolean | Success status |
| `output` | object | Dashboards data |
### `salesforce_get_dashboard`
@@ -720,7 +720,7 @@ Get details and results for a specific dashboard
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `success` | boolean | Success status |
| `output` | object | Dashboard data |
### `salesforce_refresh_dashboard`
@@ -739,7 +739,7 @@ Refresh a dashboard to get the latest data
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `success` | boolean | Success status |
| `output` | object | Refreshed dashboard data |
### `salesforce_query`
@@ -758,7 +758,7 @@ Execute a custom SOQL query to retrieve data from Salesforce
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `success` | boolean | Success status |
| `output` | object | Query results |
### `salesforce_query_more`
@@ -777,7 +777,7 @@ Retrieve additional query results using the nextRecordsUrl from a previous query
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `success` | boolean | Success status |
| `output` | object | Query results |
### `salesforce_describe_object`
@@ -796,7 +796,7 @@ Get metadata and field information for a Salesforce object
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `success` | boolean | Success status |
| `output` | object | Object metadata |
### `salesforce_list_objects`
@@ -814,7 +814,7 @@ Get a list of all available Salesforce objects
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Operation success status |
| `success` | boolean | Success status |
| `output` | object | Objects list |

View File

@@ -282,6 +282,7 @@ Permanently delete a customer
| --------- | ---- | ----------- |
| `deleted` | boolean | Whether the customer was deleted |
| `id` | string | The ID of the deleted customer |
| `metadata` | json | Deletion metadata |
### `stripe_list_customers`
@@ -540,6 +541,7 @@ Permanently delete a draft invoice
| --------- | ---- | ----------- |
| `deleted` | boolean | Whether the invoice was deleted |
| `id` | string | The ID of the deleted invoice |
| `metadata` | json | Deletion metadata |
### `stripe_finalize_invoice`
@@ -854,6 +856,7 @@ Permanently delete a product
| --------- | ---- | ----------- |
| `deleted` | boolean | Whether the product was deleted |
| `id` | string | The ID of the deleted product |
| `metadata` | json | Deletion metadata |
### `stripe_list_products`

View File

@@ -0,0 +1,56 @@
---
title: Thinking
description: Forces model to outline its thought process.
---
import { BlockInfoCard } from "@/components/ui/block-info-card"
<BlockInfoCard
type="thinking"
color="#181C1E"
/>
{/* MANUAL-CONTENT-START:intro */}
The Thinking tool encourages AI models to engage in explicit reasoning before responding to complex queries. By providing a dedicated space for step-by-step analysis, this tool helps models break down problems, consider multiple perspectives, and arrive at more thoughtful conclusions.
Research has shown that prompting language models to "think step by step" can significantly improve their reasoning capabilities. According to [Anthropic's research on Claude's Think tool](https://www.anthropic.com/engineering/claude-think-tool), when models are given space to work through their reasoning explicitly, they demonstrate:
- **Improved problem-solving**: Breaking complex problems into manageable steps
- **Enhanced accuracy**: Reducing errors by carefully working through each component of a problem
- **Greater transparency**: Making the model's reasoning process visible and auditable
- **More nuanced responses**: Considering multiple angles before arriving at conclusions
In Sim, the Thinking tool creates a structured opportunity for your agents to engage in this kind of deliberate reasoning. By incorporating thinking steps into your workflows, you can help your agents tackle complex tasks more effectively, avoid common reasoning pitfalls, and produce higher-quality outputs. This is particularly valuable for tasks involving multi-step reasoning, complex decision-making, or situations where accuracy is critical.
{/* MANUAL-CONTENT-END */}
## Usage Instructions
Adds a step where the model explicitly outlines its thought process before proceeding. This can improve reasoning quality by encouraging step-by-step analysis.
## Tools
### `thinking_tool`
Processes a provided thought/instruction, making it available for subsequent steps.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `thought` | string | Yes | Your internal reasoning, analysis, or thought process. Use this to think through the problem step by step before responding. |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `acknowledgedThought` | string | The thought that was processed and acknowledged |
## Notes
- Category: `tools`
- Type: `thinking`

View File

@@ -78,6 +78,7 @@ Retrieve a list of tickets from Zendesk with optional filtering
| --------- | ---- | ----------- |
| `tickets` | array | Array of ticket objects |
| `paging` | object | Pagination information |
| `metadata` | object | Operation metadata |
### `zendesk_get_ticket`
@@ -97,7 +98,7 @@ Get a single ticket by ID from Zendesk
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `ticket` | object | Ticket object |
| `ticket_id` | number | The ticket ID |
| `metadata` | object | Operation metadata |
### `zendesk_create_ticket`
@@ -126,7 +127,7 @@ Create a new ticket in Zendesk with support for custom fields
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `ticket` | object | Created ticket object |
| `ticket_id` | number | The created ticket ID |
| `metadata` | object | Operation metadata |
### `zendesk_create_tickets_bulk`
@@ -145,8 +146,8 @@ Create multiple tickets in Zendesk at once (max 100)
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `job_status` | object | Job status object |
| `job_id` | string | The bulk operation job ID |
| `jobStatus` | object | Job status object |
| `metadata` | object | Operation metadata |
### `zendesk_update_ticket`
@@ -175,7 +176,7 @@ Update an existing ticket in Zendesk with support for custom fields
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `ticket` | object | Updated ticket object |
| `ticket_id` | number | The updated ticket ID |
| `metadata` | object | Operation metadata |
### `zendesk_update_tickets_bulk`
@@ -199,8 +200,8 @@ Update multiple tickets in Zendesk at once (max 100)
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `job_status` | object | Job status object |
| `job_id` | string | The bulk operation job ID |
| `jobStatus` | object | Job status object |
| `metadata` | object | Operation metadata |
### `zendesk_delete_ticket`
@@ -220,7 +221,7 @@ Delete a ticket from Zendesk
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `deleted` | boolean | Deletion success |
| `ticket_id` | string | The deleted ticket ID |
| `metadata` | object | Operation metadata |
### `zendesk_merge_tickets`
@@ -241,9 +242,8 @@ Merge multiple tickets into a target ticket
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `job_status` | object | Job status object |
| `job_id` | string | The merge job ID |
| `target_ticket_id` | string | The target ticket ID that tickets were merged into |
| `jobStatus` | object | Job status object |
| `metadata` | object | Operation metadata |
### `zendesk_get_users`
@@ -267,6 +267,7 @@ Retrieve a list of users from Zendesk with optional filtering
| --------- | ---- | ----------- |
| `users` | array | Array of user objects |
| `paging` | object | Pagination information |
| `metadata` | object | Operation metadata |
### `zendesk_get_user`
@@ -286,7 +287,7 @@ Get a single user by ID from Zendesk
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `user` | object | User object |
| `user_id` | number | The user ID |
| `metadata` | object | Operation metadata |
### `zendesk_get_current_user`
@@ -305,7 +306,7 @@ Get the currently authenticated user from Zendesk
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `user` | object | Current user object |
| `user_id` | number | The current user ID |
| `metadata` | object | Operation metadata |
### `zendesk_search_users`
@@ -329,6 +330,7 @@ Search for users in Zendesk using a query string
| --------- | ---- | ----------- |
| `users` | array | Array of user objects |
| `paging` | object | Pagination information |
| `metadata` | object | Operation metadata |
### `zendesk_create_user`
@@ -355,7 +357,7 @@ Create a new user in Zendesk
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `user` | object | Created user object |
| `user_id` | number | The created user ID |
| `metadata` | object | Operation metadata |
### `zendesk_create_users_bulk`
@@ -374,8 +376,8 @@ Create multiple users in Zendesk using bulk import
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `job_status` | object | Job status object |
| `job_id` | string | The bulk operation job ID |
| `jobStatus` | object | Job status object |
| `metadata` | object | Operation metadata |
### `zendesk_update_user`
@@ -402,8 +404,8 @@ Update an existing user in Zendesk
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `user` | json | Updated user object |
| `user_id` | number | The updated user ID |
| `user` | object | Updated user object |
| `metadata` | object | Operation metadata |
### `zendesk_update_users_bulk`
@@ -422,8 +424,8 @@ Update multiple users in Zendesk using bulk update
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `job_status` | object | Job status object |
| `job_id` | string | The bulk operation job ID |
| `jobStatus` | object | Job status object |
| `metadata` | object | Operation metadata |
### `zendesk_delete_user`
@@ -443,7 +445,7 @@ Delete a user from Zendesk
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `deleted` | boolean | Deletion success |
| `user_id` | string | The deleted user ID |
| `metadata` | object | Operation metadata |
### `zendesk_get_organizations`
@@ -465,6 +467,7 @@ Retrieve a list of organizations from Zendesk
| --------- | ---- | ----------- |
| `organizations` | array | Array of organization objects |
| `paging` | object | Pagination information |
| `metadata` | object | Operation metadata |
### `zendesk_get_organization`
@@ -483,8 +486,8 @@ Get a single organization by ID from Zendesk
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `organization` | json | Organization object |
| `organization_id` | number | The organization ID |
| `organization` | object | Organization object |
| `metadata` | object | Operation metadata |
### `zendesk_autocomplete_organizations`
@@ -507,6 +510,7 @@ Autocomplete organizations in Zendesk by name prefix (for name matching/autocomp
| --------- | ---- | ----------- |
| `organizations` | array | Array of organization objects |
| `paging` | object | Pagination information |
| `metadata` | object | Operation metadata |
### `zendesk_create_organization`
@@ -530,8 +534,8 @@ Create a new organization in Zendesk
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `organization` | json | Created organization object |
| `organization_id` | number | The created organization ID |
| `organization` | object | Created organization object |
| `metadata` | object | Operation metadata |
### `zendesk_create_organizations_bulk`
@@ -550,8 +554,8 @@ Create multiple organizations in Zendesk using bulk import
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `job_status` | object | Job status object |
| `job_id` | string | The bulk operation job ID |
| `jobStatus` | object | Job status object |
| `metadata` | object | Operation metadata |
### `zendesk_update_organization`
@@ -576,8 +580,8 @@ Update an existing organization in Zendesk
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `organization` | json | Updated organization object |
| `organization_id` | number | The updated organization ID |
| `organization` | object | Updated organization object |
| `metadata` | object | Operation metadata |
### `zendesk_delete_organization`
@@ -596,8 +600,8 @@ Delete an organization from Zendesk
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `deleted` | boolean | Whether the organization was successfully deleted |
| `organization_id` | string | The deleted organization ID |
| `deleted` | boolean | Deletion success |
| `metadata` | object | Operation metadata |
### `zendesk_search`
@@ -622,6 +626,7 @@ Unified search across tickets, users, and organizations in Zendesk
| --------- | ---- | ----------- |
| `results` | array | Array of result objects |
| `paging` | object | Pagination information |
| `metadata` | object | Operation metadata |
### `zendesk_search_count`
@@ -641,6 +646,7 @@ Count the number of search results matching a query in Zendesk
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `count` | number | Number of matching results |
| `metadata` | object | Operation metadata |

View File

@@ -802,49 +802,29 @@ export async function POST(req: NextRequest) {
toolNames: toolCalls.map((tc) => tc?.name).filter(Boolean),
})
// Save messages to database after streaming completes (including aborted messages)
// NOTE: Messages are saved by the client via update-messages endpoint with full contentBlocks.
// Server only updates conversationId here to avoid overwriting client's richer save.
if (currentChat) {
const updatedMessages = [...conversationHistory, userMessage]
// Save assistant message if there's any content or tool calls (even partial from abort)
if (assistantContent.trim() || toolCalls.length > 0) {
const assistantMessage = {
id: crypto.randomUUID(),
role: 'assistant',
content: assistantContent,
timestamp: new Date().toISOString(),
...(toolCalls.length > 0 && { toolCalls }),
}
updatedMessages.push(assistantMessage)
logger.info(
`[${tracker.requestId}] Saving assistant message with content (${assistantContent.length} chars) and ${toolCalls.length} tool calls`
)
} else {
logger.info(
`[${tracker.requestId}] No assistant content or tool calls to save (aborted before response)`
)
}
// Persist only a safe conversationId to avoid continuing from a state that expects tool outputs
const previousConversationId = currentChat?.conversationId as string | undefined
const responseId = lastSafeDoneResponseId || previousConversationId || undefined
// Update chat in database immediately (without title)
await db
.update(copilotChats)
.set({
messages: updatedMessages,
updatedAt: new Date(),
...(responseId ? { conversationId: responseId } : {}),
})
.where(eq(copilotChats.id, actualChatId!))
if (responseId) {
await db
.update(copilotChats)
.set({
updatedAt: new Date(),
conversationId: responseId,
})
.where(eq(copilotChats.id, actualChatId!))
logger.info(`[${tracker.requestId}] Updated chat ${actualChatId} with new messages`, {
messageCount: updatedMessages.length,
savedUserMessage: true,
savedAssistantMessage: assistantContent.trim().length > 0,
updatedConversationId: responseId || null,
})
logger.info(
`[${tracker.requestId}] Updated conversationId for chat ${actualChatId}`,
{
updatedConversationId: responseId,
}
)
}
}
} catch (error) {
logger.error(`[${tracker.requestId}] Error processing stream:`, error)

View File

@@ -77,6 +77,18 @@ export async function POST(req: NextRequest) {
const { chatId, messages, planArtifact, config } = UpdateMessagesSchema.parse(body)
// Debug: Log what we're about to save
const lastMsgParsed = messages[messages.length - 1]
if (lastMsgParsed?.role === 'assistant') {
logger.info(`[${tracker.requestId}] Parsed messages to save`, {
messageCount: messages.length,
lastMsgId: lastMsgParsed.id,
lastMsgContentLength: lastMsgParsed.content?.length || 0,
lastMsgContentBlockCount: lastMsgParsed.contentBlocks?.length || 0,
lastMsgContentBlockTypes: lastMsgParsed.contentBlocks?.map((b: any) => b?.type) || [],
})
}
// Verify that the chat belongs to the user
const [chat] = await db
.select()

View File

@@ -462,9 +462,6 @@ export default function PlaygroundPage() {
<Avatar size='lg'>
<AvatarFallback>LG</AvatarFallback>
</Avatar>
<Avatar size='xl'>
<AvatarFallback>XL</AvatarFallback>
</Avatar>
</VariantRow>
<VariantRow label='with image'>
<Avatar size='md'>
@@ -505,9 +502,6 @@ export default function PlaygroundPage() {
<Avatar size='lg' status='online'>
<AvatarFallback>LG</AvatarFallback>
</Avatar>
<Avatar size='xl' status='online'>
<AvatarFallback>XL</AvatarFallback>
</Avatar>
</VariantRow>
</Section>

View File

@@ -303,8 +303,8 @@ export const DiffControls = memo(function DiffControls() {
!isResizing && 'transition-[bottom,right] duration-100 ease-out'
)}
style={{
bottom: 'calc(var(--terminal-height) + 8px)',
right: 'calc(var(--panel-width) + 8px)',
bottom: 'calc(var(--terminal-height) + 16px)',
right: 'calc(var(--panel-width) + 16px)',
}}
>
<div

View File

@@ -470,17 +470,8 @@ const CopilotMessage: FC<CopilotMessageProps> = memo(
{/* Content blocks in chronological order */}
{memoizedContentBlocks}
{/* Show streaming indicator if streaming but no text content yet after tool calls */}
{isStreaming &&
!message.content &&
message.contentBlocks?.every((block) => block.type === 'tool_call') && (
<StreamingIndicator />
)}
{/* Streaming indicator when no content yet */}
{!cleanTextContent && !message.contentBlocks?.length && isStreaming && (
<StreamingIndicator />
)}
{/* Always show streaming indicator at the end while streaming */}
{isStreaming && <StreamingIndicator />}
{message.errorType === 'usage_limit' && (
<div className='flex gap-1.5'>

View File

@@ -3,7 +3,8 @@
import { useEffect, useMemo, useRef, useState } from 'react'
import clsx from 'clsx'
import { ChevronUp, LayoutList } from 'lucide-react'
import { Button, Code } from '@/components/emcn'
import Editor from 'react-simple-code-editor'
import { Button, Code, getCodeEditorProps, highlight, languages } from '@/components/emcn'
import { ClientToolCallState } from '@/lib/copilot/tools/client/base-tool'
import { getClientTool } from '@/lib/copilot/tools/client/manager'
import { getRegisteredTools } from '@/lib/copilot/tools/client/registry'
@@ -413,6 +414,8 @@ const ACTION_VERBS = [
'Listed',
'Editing',
'Edited',
'Executing',
'Executed',
'Running',
'Ran',
'Designing',
@@ -751,36 +754,70 @@ function SubAgentToolCall({ toolCall: toolCallProp }: { toolCall: CopilotToolCal
const safeInputs = inputs && typeof inputs === 'object' ? inputs : {}
const inputEntries = Object.entries(safeInputs)
if (inputEntries.length === 0) return null
/**
* Format a value for display - handles objects, arrays, and primitives
*/
const formatValue = (value: unknown): string => {
if (value === null || value === undefined) return '-'
if (typeof value === 'string') return value || '-'
if (typeof value === 'number' || typeof value === 'boolean') return String(value)
try {
return JSON.stringify(value, null, 2)
} catch {
return String(value)
}
}
/**
* Check if a value is a complex type (object or array)
*/
const isComplex = (value: unknown): boolean => {
return typeof value === 'object' && value !== null
}
return (
<div className='mt-1.5 w-full overflow-hidden rounded-[4px] border border-[var(--border-1)] bg-[var(--surface-1)]'>
<table className='w-full table-fixed bg-transparent'>
<thead className='bg-transparent'>
<tr className='border-[var(--border-1)] border-b bg-transparent'>
<th className='w-[36%] border-[var(--border-1)] border-r bg-transparent px-[10px] py-[5px] text-left font-medium text-[12px] text-[var(--text-tertiary)]'>
Input
</th>
<th className='w-[64%] bg-transparent px-[10px] py-[5px] text-left font-medium text-[12px] text-[var(--text-tertiary)]'>
Value
</th>
</tr>
</thead>
<tbody className='bg-transparent'>
{inputEntries.map(([key, value]) => (
<tr key={key} className='border-[var(--border-1)] border-t bg-transparent'>
<td className='w-[36%] border-[var(--border-1)] border-r bg-transparent px-[10px] py-[6px]'>
<span className='truncate font-medium text-[var(--text-primary)] text-xs'>
{key}
<div className='mt-1.5 w-full overflow-hidden rounded-md border border-[var(--border-1)] bg-[var(--surface-1)]'>
{/* Header */}
<div className='flex items-center gap-[8px] border-[var(--border-1)] border-b bg-[var(--surface-2)] p-[8px]'>
<span className='font-medium text-[12px] text-[var(--text-primary)]'>Input</span>
<span className='flex-shrink-0 font-medium text-[12px] text-[var(--text-tertiary)]'>
{inputEntries.length}
</span>
</div>
{/* Input entries */}
<div className='flex flex-col'>
{inputEntries.map(([key, value], index) => {
const formattedValue = formatValue(value)
const needsCodeViewer = isComplex(value)
return (
<div
key={key}
className={clsx(
'flex flex-col gap-1 px-[10px] py-[6px]',
index > 0 && 'border-[var(--border-1)] border-t'
)}
>
{/* Input key */}
<span className='font-medium text-[11px] text-[var(--text-primary)]'>{key}</span>
{/* Value display */}
{needsCodeViewer ? (
<Code.Viewer
code={formattedValue}
language='json'
showGutter={false}
className='max-h-[80px] min-h-0'
/>
) : (
<span className='font-mono text-[11px] text-[var(--text-muted)] leading-[1.3]'>
{formattedValue}
</span>
</td>
<td className='w-[64%] bg-transparent px-[10px] py-[6px]'>
<span className='font-mono text-[var(--text-muted)] text-xs'>
{String(value)}
</span>
</td>
</tr>
))}
</tbody>
</table>
)}
</div>
)
})}
</div>
</div>
)
}
@@ -2290,74 +2327,136 @@ export function ToolCall({ toolCall: toolCallProp, toolCallId, onStateChange }:
const safeInputs = inputs && typeof inputs === 'object' ? inputs : {}
const inputEntries = Object.entries(safeInputs)
// Don't show the table if there are no inputs
// Don't show the section if there are no inputs
if (inputEntries.length === 0) {
return null
}
return (
<div className='w-full overflow-hidden rounded-[4px] border border-[var(--border-1)] bg-[var(--surface-1)]'>
<table className='w-full table-fixed bg-transparent'>
<thead className='bg-transparent'>
<tr className='border-[var(--border-1)] border-b bg-transparent'>
<th className='w-[36%] border-[var(--border-1)] border-r bg-transparent px-[10px] py-[5px] text-left font-medium text-[14px] text-[var(--text-tertiary)]'>
Input
</th>
<th className='w-[64%] bg-transparent px-[10px] py-[5px] text-left font-medium text-[14px] text-[var(--text-tertiary)]'>
Value
</th>
</tr>
</thead>
<tbody className='bg-transparent'>
{inputEntries.map(([key, value]) => (
<tr
key={key}
className='group relative border-[var(--border-1)] border-t bg-transparent'
>
<td className='relative w-[36%] border-[var(--border-1)] border-r bg-transparent p-0'>
<div className='px-[10px] py-[8px]'>
<span className='truncate font-medium text-[var(--text-primary)] text-xs'>
{key}
</span>
</div>
</td>
<td className='relative w-[64%] bg-transparent p-0'>
<div className='min-w-0 px-[10px] py-[8px]'>
<input
type='text'
value={String(value)}
onChange={(e) => {
const newInputs = { ...safeInputs, [key]: e.target.value }
/**
* Format a value for display - handles objects, arrays, and primitives
*/
const formatValueForDisplay = (value: unknown): string => {
if (value === null || value === undefined) return ''
if (typeof value === 'string') return value
if (typeof value === 'number' || typeof value === 'boolean') return String(value)
// For objects and arrays, use JSON.stringify with formatting
try {
return JSON.stringify(value, null, 2)
} catch {
return String(value)
}
}
// Determine how to update based on original structure
if (isNestedInWorkflowInput) {
// Update workflow_input
setEditedParams({ ...editedParams, workflow_input: newInputs })
} else if (typeof editedParams.input === 'string') {
// Input was a JSON string, serialize back
setEditedParams({ ...editedParams, input: JSON.stringify(newInputs) })
} else if (editedParams.input && typeof editedParams.input === 'object') {
// Input is an object
setEditedParams({ ...editedParams, input: newInputs })
} else if (
editedParams.inputs &&
typeof editedParams.inputs === 'object'
) {
// Inputs is an object
setEditedParams({ ...editedParams, inputs: newInputs })
} else {
// Flat structure - update at base level
setEditedParams({ ...editedParams, [key]: e.target.value })
}
}}
className='w-full bg-transparent font-mono text-[var(--text-muted)] text-xs outline-none focus:text-[var(--text-primary)]'
/>
</div>
</td>
</tr>
))}
</tbody>
</table>
/**
* Parse a string value back to its original type if possible
*/
const parseInputValue = (value: string, originalValue: unknown): unknown => {
// If original was a primitive, keep as string
if (typeof originalValue !== 'object' || originalValue === null) {
return value
}
// Try to parse as JSON for objects/arrays
try {
return JSON.parse(value)
} catch {
return value
}
}
/**
* Check if a value is a complex type (object or array)
*/
const isComplexValue = (value: unknown): boolean => {
return typeof value === 'object' && value !== null
}
return (
<div className='w-full overflow-hidden rounded-md border border-[var(--border-1)] bg-[var(--surface-1)]'>
{/* Header */}
<div className='flex items-center gap-[8px] border-[var(--border-1)] border-b bg-[var(--surface-2)] p-[8px]'>
<span className='font-medium text-[12px] text-[var(--text-primary)]'>Edit Input</span>
<span className='flex-shrink-0 font-medium text-[12px] text-[var(--text-tertiary)]'>
{inputEntries.length}
</span>
</div>
{/* Input entries */}
<div className='flex flex-col'>
{inputEntries.map(([key, value], index) => {
const isComplex = isComplexValue(value)
const displayValue = formatValueForDisplay(value)
return (
<div
key={key}
className={clsx(
'flex flex-col gap-1.5 px-[10px] py-[8px]',
index > 0 && 'border-[var(--border-1)] border-t'
)}
>
{/* Input key */}
<span className='font-medium text-[11px] text-[var(--text-primary)]'>{key}</span>
{/* Value editor */}
{isComplex ? (
<Code.Container className='max-h-[168px] min-h-[60px]'>
<Code.Content>
<Editor
value={displayValue}
onValueChange={(newCode) => {
const parsedValue = parseInputValue(newCode, value)
const newInputs = { ...safeInputs, [key]: parsedValue }
if (isNestedInWorkflowInput) {
setEditedParams({ ...editedParams, workflow_input: newInputs })
} else if (typeof editedParams.input === 'string') {
setEditedParams({ ...editedParams, input: JSON.stringify(newInputs) })
} else if (
editedParams.input &&
typeof editedParams.input === 'object'
) {
setEditedParams({ ...editedParams, input: newInputs })
} else if (
editedParams.inputs &&
typeof editedParams.inputs === 'object'
) {
setEditedParams({ ...editedParams, inputs: newInputs })
} else {
setEditedParams({ ...editedParams, [key]: parsedValue })
}
}}
highlight={(code) => highlight(code, languages.json, 'json')}
{...getCodeEditorProps()}
className={clsx(getCodeEditorProps().className, 'min-h-[40px]')}
style={{ minHeight: '40px' }}
/>
</Code.Content>
</Code.Container>
) : (
<input
type='text'
value={displayValue}
onChange={(e) => {
const parsedValue = parseInputValue(e.target.value, value)
const newInputs = { ...safeInputs, [key]: parsedValue }
if (isNestedInWorkflowInput) {
setEditedParams({ ...editedParams, workflow_input: newInputs })
} else if (typeof editedParams.input === 'string') {
setEditedParams({ ...editedParams, input: JSON.stringify(newInputs) })
} else if (editedParams.input && typeof editedParams.input === 'object') {
setEditedParams({ ...editedParams, input: newInputs })
} else if (editedParams.inputs && typeof editedParams.inputs === 'object') {
setEditedParams({ ...editedParams, inputs: newInputs })
} else {
setEditedParams({ ...editedParams, [key]: parsedValue })
}
}}
className='w-full rounded-[4px] border border-[var(--border-1)] bg-[var(--surface-1)] px-[8px] py-[6px] font-medium font-mono text-[13px] text-[var(--text-primary)] outline-none transition-colors placeholder:text-[var(--text-muted)] focus:outline-none'
/>
)}
</div>
)
})}
</div>
</div>
)
}
@@ -2443,8 +2542,8 @@ export function ToolCall({ toolCall: toolCallProp, toolCallId, onStateChange }:
<ShimmerOverlayText
text={displayName}
active={isLoadingState}
isSpecial={false}
className='font-[470] font-season text-[var(--text-muted)] text-sm'
isSpecial={isSpecial}
className='font-[470] font-season text-[var(--text-secondary)] text-sm dark:text-[var(--text-muted)]'
/>
</div>
{code && (

View File

@@ -124,8 +124,10 @@ export const Copilot = forwardRef<CopilotRef, CopilotProps>(({ panelWidth }, ref
isSendingMessage,
})
// Handle scroll management
const { scrollAreaRef, scrollToBottom } = useScrollManagement(messages, isSendingMessage)
// Handle scroll management (80px stickiness for copilot)
const { scrollAreaRef, scrollToBottom } = useScrollManagement(messages, isSendingMessage, {
stickinessThreshold: 80,
})
// Handle chat history grouping
const { groupedChats, handleHistoryDropdownOpen: handleHistoryDropdownOpenHook } = useChatHistory(

View File

@@ -240,7 +240,7 @@ const generateOutputPaths = (outputs: Record<string, any>, prefix = ''): string[
} else if (typeof value === 'object' && value !== null) {
if ('type' in value && typeof value.type === 'string') {
const hasNestedProperties =
((value.type === 'object' || value.type === 'json') && value.properties) ||
(value.type === 'object' && value.properties) ||
(value.type === 'array' && value.items?.properties) ||
(value.type === 'array' &&
value.items &&
@@ -251,7 +251,7 @@ const generateOutputPaths = (outputs: Record<string, any>, prefix = ''): string[
paths.push(currentPath)
}
if ((value.type === 'object' || value.type === 'json') && value.properties) {
if (value.type === 'object' && value.properties) {
paths.push(...generateOutputPaths(value.properties, currentPath))
} else if (value.type === 'array' && value.items?.properties) {
paths.push(...generateOutputPaths(value.items.properties, currentPath))

View File

@@ -1016,7 +1016,6 @@ export function ToolInput({
const toolBlocks = useMemo(() => {
const allToolBlocks = getAllBlocks().filter(
(block) =>
!block.hideFromToolbar &&
(block.category === 'tools' ||
block.type === 'api' ||
block.type === 'webhook_request' ||

View File

@@ -148,7 +148,7 @@ export const SubflowNodeComponent = memo(({ data, id }: NodeProps<SubflowNodeDat
ref={blockRef}
onClick={() => setCurrentBlockId(id)}
className={cn(
'relative cursor-pointer select-none rounded-[8px] border border-[var(--border)]',
'relative cursor-pointer select-none rounded-[8px] border border-[var(--border-1)]',
'transition-block-bg transition-ring',
'z-[20]'
)}

View File

@@ -12,6 +12,12 @@ interface UseScrollManagementOptions {
* - `auto`: immediate scroll to bottom (used by floating chat to avoid jitter).
*/
behavior?: 'auto' | 'smooth'
/**
* Distance from bottom (in pixels) within which auto-scroll stays active.
* Lower values = less sticky (user can scroll away easier).
* Default is 100px.
*/
stickinessThreshold?: number
}
/**
@@ -34,6 +40,7 @@ export function useScrollManagement(
const programmaticScrollInProgressRef = useRef(false)
const lastScrollTopRef = useRef(0)
const scrollBehavior: 'auto' | 'smooth' = options?.behavior ?? 'smooth'
const stickinessThreshold = options?.stickinessThreshold ?? 100
/**
* Scrolls the container to the bottom with smooth animation
@@ -74,7 +81,7 @@ export function useScrollManagement(
const { scrollTop, scrollHeight, clientHeight } = scrollContainer
const distanceFromBottom = scrollHeight - scrollTop - clientHeight
const nearBottom = distanceFromBottom <= 100
const nearBottom = distanceFromBottom <= stickinessThreshold
setIsNearBottom(nearBottom)
if (isSendingMessage) {
@@ -95,7 +102,7 @@ export function useScrollManagement(
// Track last scrollTop for direction detection
lastScrollTopRef.current = scrollTop
}, [getScrollContainer, isSendingMessage, userHasScrolledDuringStream])
}, [getScrollContainer, isSendingMessage, userHasScrolledDuringStream, stickinessThreshold])
// Attach scroll listener
useEffect(() => {
@@ -174,14 +181,20 @@ export function useScrollManagement(
const { scrollTop, scrollHeight, clientHeight } = scrollContainer
const distanceFromBottom = scrollHeight - scrollTop - clientHeight
const nearBottom = distanceFromBottom <= 120
const nearBottom = distanceFromBottom <= stickinessThreshold
if (nearBottom) {
scrollToBottom()
}
}, 100)
return () => window.clearInterval(intervalId)
}, [isSendingMessage, userHasScrolledDuringStream, getScrollContainer, scrollToBottom])
}, [
isSendingMessage,
userHasScrolledDuringStream,
getScrollContainer,
scrollToBottom,
stickinessThreshold,
])
return {
scrollAreaRef,

View File

@@ -38,7 +38,7 @@ function WorkflowPreviewSubflowInner({ data }: NodeProps<WorkflowPreviewSubflowD
return (
<div
className='relative select-none rounded-[8px] border border-[var(--border)]'
className='relative select-none rounded-[8px] border border-[var(--border-1)]'
style={{
width,
height,

View File

@@ -182,7 +182,7 @@ export function SearchModal({
const allBlocks = getAllBlocks()
const filteredAllBlocks = filterBlocks(allBlocks)
return filteredAllBlocks
.filter((block) => !block.hideFromToolbar && block.category === 'tools')
.filter((block) => block.category === 'tools')
.map(
(block): ToolItem => ({
id: block.type,
@@ -225,7 +225,7 @@ export function SearchModal({
const docsItems: DocItem[] = []
allBlocks.forEach((block) => {
if (block.docsLink && !block.hideFromToolbar) {
if (block.docsLink) {
docsItems.push({
id: `docs-${block.type}`,
name: block.name,

View File

@@ -163,7 +163,7 @@ function AddMembersModal({
className='flex items-center gap-[10px] rounded-[4px] px-[8px] py-[6px] hover:bg-[var(--surface-2)]'
>
<Checkbox checked={isSelected} />
<Avatar size='xs'>
<Avatar size='sm'>
{member.user?.image && (
<AvatarImage src={member.user.image} alt={name} />
)}
@@ -663,7 +663,7 @@ export function AccessControl() {
return (
<div key={member.id} className='flex items-center justify-between'>
<div className='flex flex-1 items-center gap-[12px]'>
<Avatar size='sm'>
<Avatar size='md'>
{member.userImage && <AvatarImage src={member.userImage} alt={name} />}
<AvatarFallback
style={{

View File

@@ -434,12 +434,10 @@ export function CredentialSets() {
filteredOwnedSets.length === 0 &&
!hasNoContent
// Early returns AFTER all hooks
if (membershipsLoading || invitationsLoading) {
return <CredentialSetsSkeleton />
}
// Detail view for a polling group
if (viewingSet) {
const activeMembers = members.filter((m) => m.status === 'active')
const totalCount = activeMembers.length + pendingInvitations.length
@@ -529,7 +527,7 @@ export function CredentialSets() {
return (
<div key={member.id} className='flex items-center justify-between'>
<div className='flex flex-1 items-center gap-[12px]'>
<Avatar size='sm'>
<Avatar size='md'>
{member.userImage && (
<AvatarImage src={member.userImage} alt={name} />
)}
@@ -583,7 +581,7 @@ export function CredentialSets() {
return (
<div key={invitation.id} className='flex items-center justify-between'>
<div className='flex flex-1 items-center gap-[12px]'>
<Avatar size='sm'>
<Avatar size='md'>
<AvatarFallback
style={{ background: getUserColor(email) }}
className='border-0 text-white'

View File

@@ -1,12 +1,41 @@
'use client'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { Check } from 'lucide-react'
import {
Popover,
PopoverAnchor,
PopoverBackButton,
PopoverContent,
PopoverDivider,
PopoverFolder,
PopoverItem,
} from '@/components/emcn'
import { cn } from '@/lib/core/utils/cn'
import { WORKFLOW_COLORS } from '@/lib/workflows/colors'
/**
* Validates a hex color string.
* Accepts 3 or 6 character hex codes with or without #.
*/
function isValidHex(hex: string): boolean {
const cleaned = hex.replace('#', '')
return /^[0-9A-Fa-f]{3}$|^[0-9A-Fa-f]{6}$/.test(cleaned)
}
/**
* Normalizes a hex color to lowercase 6-character format with #.
*/
function normalizeHex(hex: string): string {
let cleaned = hex.replace('#', '').toLowerCase()
if (cleaned.length === 3) {
cleaned = cleaned
.split('')
.map((c) => c + c)
.join('')
}
return `#${cleaned}`
}
interface ContextMenuProps {
/**
@@ -53,6 +82,14 @@ interface ContextMenuProps {
* Callback when delete is clicked
*/
onDelete: () => void
/**
* Callback when color is changed
*/
onColorChange?: (color: string) => void
/**
* Current workflow color (for showing selected state)
*/
currentColor?: string
/**
* Whether to show the open in new tab option (default: false)
* Set to true for items that can be opened in a new tab
@@ -83,11 +120,21 @@ interface ContextMenuProps {
* Set to true for items that can be exported (like workspaces)
*/
showExport?: boolean
/**
* Whether to show the change color option (default: false)
* Set to true for workflows to allow color customization
*/
showColorChange?: boolean
/**
* Whether the export option is disabled (default: false)
* Set to true when user lacks permissions
*/
disableExport?: boolean
/**
* Whether the change color option is disabled (default: false)
* Set to true when user lacks permissions
*/
disableColorChange?: boolean
/**
* Whether the rename option is disabled (default: false)
* Set to true when user lacks permissions
@@ -134,19 +181,76 @@ export function ContextMenu({
onDuplicate,
onExport,
onDelete,
onColorChange,
currentColor,
showOpenInNewTab = false,
showRename = true,
showCreate = false,
showCreateFolder = false,
showDuplicate = true,
showExport = false,
showColorChange = false,
disableExport = false,
disableColorChange = false,
disableRename = false,
disableDuplicate = false,
disableDelete = false,
disableCreate = false,
disableCreateFolder = false,
}: ContextMenuProps) {
const [hexInput, setHexInput] = useState(currentColor || '#ffffff')
// Sync hexInput when currentColor changes (e.g., opening menu on different workflow)
useEffect(() => {
setHexInput(currentColor || '#ffffff')
}, [currentColor])
const canSubmitHex = useMemo(() => {
if (!isValidHex(hexInput)) return false
const normalized = normalizeHex(hexInput)
if (currentColor && normalized.toLowerCase() === currentColor.toLowerCase()) return false
return true
}, [hexInput, currentColor])
const handleHexSubmit = useCallback(() => {
if (!canSubmitHex || !onColorChange) return
const normalized = normalizeHex(hexInput)
onColorChange(normalized)
setHexInput(normalized)
}, [hexInput, canSubmitHex, onColorChange])
const handleHexKeyDown = useCallback(
(e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
e.preventDefault()
handleHexSubmit()
}
},
[handleHexSubmit]
)
const handleHexChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
let value = e.target.value.trim()
if (value && !value.startsWith('#')) {
value = `#${value}`
}
value = value.slice(0, 1) + value.slice(1).replace(/[^0-9a-fA-F]/g, '')
setHexInput(value.slice(0, 7))
}, [])
const handleHexFocus = useCallback((e: React.FocusEvent<HTMLInputElement>) => {
e.target.select()
}, [])
const hasNavigationSection = showOpenInNewTab && onOpenInNewTab
const hasEditSection =
(showRename && onRename) ||
(showCreate && onCreate) ||
(showCreateFolder && onCreateFolder) ||
(showColorChange && onColorChange)
const hasCopySection = (showDuplicate && onDuplicate) || (showExport && onExport)
return (
<Popover
open={isOpen}
@@ -164,10 +268,21 @@ export function ContextMenu({
height: '1px',
}}
/>
<PopoverContent ref={menuRef} align='start' side='bottom' sideOffset={4}>
<PopoverContent
ref={menuRef}
align='start'
side='bottom'
sideOffset={4}
onPointerDownOutside={(e) => e.preventDefault()}
onInteractOutside={(e) => e.preventDefault()}
>
{/* Back button - shown only when in a folder */}
<PopoverBackButton />
{/* Navigation actions */}
{showOpenInNewTab && onOpenInNewTab && (
<PopoverItem
rootOnly
onClick={() => {
onOpenInNewTab()
onClose()
@@ -176,11 +291,12 @@ export function ContextMenu({
Open in new tab
</PopoverItem>
)}
{showOpenInNewTab && onOpenInNewTab && <PopoverDivider />}
{hasNavigationSection && (hasEditSection || hasCopySection) && <PopoverDivider rootOnly />}
{/* Edit and create actions */}
{showRename && onRename && (
<PopoverItem
rootOnly
disabled={disableRename}
onClick={() => {
onRename()
@@ -192,6 +308,7 @@ export function ContextMenu({
)}
{showCreate && onCreate && (
<PopoverItem
rootOnly
disabled={disableCreate}
onClick={() => {
onCreate()
@@ -203,6 +320,7 @@ export function ContextMenu({
)}
{showCreateFolder && onCreateFolder && (
<PopoverItem
rootOnly
disabled={disableCreateFolder}
onClick={() => {
onCreateFolder()
@@ -212,11 +330,72 @@ export function ContextMenu({
Create folder
</PopoverItem>
)}
{showColorChange && onColorChange && (
<PopoverFolder
id='color-picker'
title='Change color'
expandOnHover
className={disableColorChange ? 'pointer-events-none opacity-50' : ''}
>
<div className='flex w-[140px] flex-col gap-[8px] p-[2px]'>
{/* Preset colors */}
<div className='grid grid-cols-6 gap-[4px]'>
{WORKFLOW_COLORS.map(({ color, name }) => (
<button
key={color}
type='button'
title={name}
onClick={(e) => {
e.stopPropagation()
onColorChange(color)
}}
className={cn(
'h-[20px] w-[20px] rounded-[4px]',
currentColor?.toLowerCase() === color.toLowerCase() && 'ring-1 ring-white'
)}
style={{ backgroundColor: color }}
/>
))}
</div>
{/* Hex input */}
<div className='flex items-center gap-[4px]'>
<div
className='h-[20px] w-[20px] flex-shrink-0 rounded-[4px]'
style={{
backgroundColor: isValidHex(hexInput) ? normalizeHex(hexInput) : '#ffffff',
}}
/>
<input
type='text'
value={hexInput}
onChange={handleHexChange}
onKeyDown={handleHexKeyDown}
onFocus={handleHexFocus}
onClick={(e) => e.stopPropagation()}
className='h-[20px] min-w-0 flex-1 rounded-[4px] bg-[#363636] px-[6px] text-[11px] text-white uppercase focus:outline-none'
/>
<button
type='button'
disabled={!canSubmitHex}
onClick={(e) => {
e.stopPropagation()
handleHexSubmit()
}}
className='flex h-[20px] w-[20px] flex-shrink-0 items-center justify-center rounded-[4px] bg-[var(--brand-tertiary-2)] text-white disabled:opacity-40'
>
<Check className='h-[12px] w-[12px]' />
</button>
</div>
</div>
</PopoverFolder>
)}
{/* Copy and export actions */}
{(showDuplicate || showExport) && <PopoverDivider />}
{hasEditSection && hasCopySection && <PopoverDivider rootOnly />}
{showDuplicate && onDuplicate && (
<PopoverItem
rootOnly
disabled={disableDuplicate}
onClick={() => {
onDuplicate()
@@ -228,6 +407,7 @@ export function ContextMenu({
)}
{showExport && onExport && (
<PopoverItem
rootOnly
disabled={disableExport}
onClick={() => {
onExport()
@@ -239,8 +419,9 @@ export function ContextMenu({
)}
{/* Destructive action */}
<PopoverDivider />
{(hasNavigationSection || hasEditSection || hasCopySection) && <PopoverDivider rootOnly />}
<PopoverItem
rootOnly
disabled={disableDelete}
onClick={() => {
onDelete()

View File

@@ -3,8 +3,9 @@
import { useCallback, useMemo, useState } from 'react'
import { createLogger } from '@sim/logger'
import clsx from 'clsx'
import { ChevronRight, Folder, FolderOpen } from 'lucide-react'
import { ChevronRight, Folder, FolderOpen, MoreHorizontal } from 'lucide-react'
import { useParams, useRouter } from 'next/navigation'
import { getNextWorkflowColor } from '@/lib/workflows/colors'
import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider'
import { ContextMenu } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/context-menu/context-menu'
import { DeleteModal } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/delete-modal/delete-modal'
@@ -23,10 +24,7 @@ import {
import { useCreateFolder, useUpdateFolder } from '@/hooks/queries/folders'
import { useCreateWorkflow } from '@/hooks/queries/workflows'
import type { FolderTreeNode } from '@/stores/folders/types'
import {
generateCreativeWorkflowName,
getNextWorkflowColor,
} from '@/stores/workflows/registry/utils'
import { generateCreativeWorkflowName } from '@/stores/workflows/registry/utils'
const logger = createLogger('FolderItem')
@@ -173,6 +171,7 @@ export function FolderItem({ folder, level, hoverHandlers }: FolderItemProps) {
menuRef,
handleContextMenu,
closeMenu,
preventDismiss,
} = useContextMenu()
// Rename hook
@@ -242,6 +241,40 @@ export function FolderItem({ folder, level, hoverHandlers }: FolderItemProps) {
[isEditing, handleRenameKeyDown, handleExpandKeyDown]
)
/**
* Handle more button pointerdown - prevents click-outside dismissal when toggling
*/
const handleMorePointerDown = useCallback(() => {
if (isContextMenuOpen) {
preventDismiss()
}
}, [isContextMenuOpen, preventDismiss])
/**
* Handle more button click - toggles context menu at button position
*/
const handleMoreClick = useCallback(
(e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault()
e.stopPropagation()
// Toggle: close if open, open if closed
if (isContextMenuOpen) {
closeMenu()
return
}
const rect = e.currentTarget.getBoundingClientRect()
handleContextMenu({
preventDefault: () => {},
stopPropagation: () => {},
clientX: rect.right,
clientY: rect.top,
} as React.MouseEvent)
},
[isContextMenuOpen, closeMenu, handleContextMenu]
)
return (
<>
<div
@@ -303,12 +336,22 @@ export function FolderItem({ folder, level, hoverHandlers }: FolderItemProps) {
spellCheck='false'
/>
) : (
<span
className='truncate font-medium text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)]'
onDoubleClick={handleDoubleClick}
>
{folder.name}
</span>
<>
<span
className='min-w-0 flex-1 truncate font-medium text-[var(--text-tertiary)] group-hover:text-[var(--text-primary)]'
onDoubleClick={handleDoubleClick}
>
{folder.name}
</span>
<button
type='button'
onPointerDown={handleMorePointerDown}
onClick={handleMoreClick}
className='flex h-[18px] w-[18px] flex-shrink-0 items-center justify-center rounded-[4px] opacity-0 transition-opacity hover:bg-[var(--surface-7)] group-hover:opacity-100'
>
<MoreHorizontal className='h-[14px] w-[14px] text-[var(--text-tertiary)]' />
</button>
</>
)}
</div>

View File

@@ -1,15 +1,24 @@
'use client'
import { type CSSProperties, useEffect, useMemo, useState } from 'react'
import Image from 'next/image'
import { Tooltip } from '@/components/emcn'
import { type CSSProperties, useEffect, useMemo } from 'react'
import { Avatar, AvatarFallback, AvatarImage, Tooltip } from '@/components/emcn'
import { useSession } from '@/lib/auth/auth-client'
import { getUserColor } from '@/lib/workspaces/colors'
import { useSocket } from '@/app/workspace/providers/socket-provider'
import { SIDEBAR_WIDTH } from '@/stores/constants'
import { useSidebarStore } from '@/stores/sidebar/store'
/**
* Avatar display configuration for responsive layout.
*/
const AVATAR_CONFIG = {
MIN_COUNT: 3,
MAX_COUNT: 12,
WIDTH_PER_AVATAR: 20,
} as const
interface AvatarsProps {
workflowId: string
maxVisible?: number
/**
* Callback fired when the presence visibility changes.
* Used by parent components to adjust layout (e.g., text truncation spacing).
@@ -30,45 +39,29 @@ interface UserAvatarProps {
}
/**
* Individual user avatar with error handling for image loading.
* Individual user avatar using emcn Avatar component.
* Falls back to colored circle with initials if image fails to load.
*/
function UserAvatar({ user, index }: UserAvatarProps) {
const [imageError, setImageError] = useState(false)
const color = getUserColor(user.userId)
const initials = user.userName ? user.userName.charAt(0).toUpperCase() : '?'
const hasAvatar = Boolean(user.avatarUrl) && !imageError
// Reset error state when avatar URL changes
useEffect(() => {
setImageError(false)
}, [user.avatarUrl])
const avatarElement = (
<div
className='relative flex h-[14px] w-[14px] flex-shrink-0 cursor-default items-center justify-center overflow-hidden rounded-full font-semibold text-[7px] text-white'
style={
{
background: hasAvatar ? undefined : color,
zIndex: 10 - index,
} as CSSProperties
}
>
{hasAvatar && user.avatarUrl ? (
<Image
<Avatar size='xs' style={{ zIndex: index + 1 } as CSSProperties}>
{user.avatarUrl && (
<AvatarImage
src={user.avatarUrl}
alt={user.userName ? `${user.userName}'s avatar` : 'User avatar'}
fill
sizes='14px'
className='object-cover'
referrerPolicy='no-referrer'
unoptimized
onError={() => setImageError(true)}
/>
) : (
initials
)}
</div>
<AvatarFallback
style={{ background: color }}
className='border-0 font-semibold text-[7px] text-white'
>
{initials}
</AvatarFallback>
</Avatar>
)
if (user.userName) {
@@ -92,14 +85,26 @@ function UserAvatar({ user, index }: UserAvatarProps) {
* @param props - Component props
* @returns Avatar stack for workflow presence
*/
export function Avatars({ workflowId, maxVisible = 3, onPresenceChange }: AvatarsProps) {
export function Avatars({ workflowId, onPresenceChange }: AvatarsProps) {
const { presenceUsers, currentWorkflowId } = useSocket()
const { data: session } = useSession()
const currentUserId = session?.user?.id
const sidebarWidth = useSidebarStore((state) => state.sidebarWidth)
/**
* Only show presence for the currently active workflow
* Filter out the current user from the list
* Calculate max visible avatars based on sidebar width.
* Scales between MIN_COUNT and MAX_COUNT as sidebar expands.
*/
const maxVisible = useMemo(() => {
const widthDelta = sidebarWidth - SIDEBAR_WIDTH.MIN
const additionalAvatars = Math.floor(widthDelta / AVATAR_CONFIG.WIDTH_PER_AVATAR)
const calculated = AVATAR_CONFIG.MIN_COUNT + additionalAvatars
return Math.max(AVATAR_CONFIG.MIN_COUNT, Math.min(AVATAR_CONFIG.MAX_COUNT, calculated))
}, [sidebarWidth])
/**
* Only show presence for the currently active workflow.
* Filter out the current user from the list.
*/
const workflowUsers = useMemo(() => {
if (currentWorkflowId !== workflowId) {
@@ -122,7 +127,6 @@ export function Avatars({ workflowId, maxVisible = 3, onPresenceChange }: Avatar
return { visibleUsers: visible, overflowCount: overflow }
}, [workflowUsers, maxVisible])
// Notify parent when avatars are present or not
useEffect(() => {
const hasAnyAvatars = visibleUsers.length > 0
if (typeof onPresenceChange === 'function') {
@@ -135,26 +139,25 @@ export function Avatars({ workflowId, maxVisible = 3, onPresenceChange }: Avatar
}
return (
<div className='-space-x-1 ml-[-8px] flex items-center'>
{visibleUsers.map((user, index) => (
<UserAvatar key={user.socketId} user={user} index={index} />
))}
<div className='-space-x-1 flex items-center'>
{overflowCount > 0 && (
<Tooltip.Root>
<Tooltip.Trigger asChild>
<div
className='relative flex h-[14px] w-[14px] flex-shrink-0 cursor-default items-center justify-center overflow-hidden rounded-full bg-[#404040] font-semibold text-[7px] text-white'
style={{ zIndex: 10 - visibleUsers.length } as CSSProperties}
>
+{overflowCount}
</div>
<Avatar size='xs' style={{ zIndex: 0 } as CSSProperties}>
<AvatarFallback className='border-0 bg-[#404040] font-semibold text-[7px] text-white'>
+{overflowCount}
</AvatarFallback>
</Avatar>
</Tooltip.Trigger>
<Tooltip.Content side='bottom'>
{overflowCount} more user{overflowCount > 1 ? 's' : ''}
</Tooltip.Content>
</Tooltip.Root>
)}
{visibleUsers.map((user, index) => (
<UserAvatar key={user.socketId} user={user} index={overflowCount > 0 ? index + 1 : index} />
))}
</div>
)
}

View File

@@ -2,6 +2,7 @@
import { useCallback, useRef, useState } from 'react'
import clsx from 'clsx'
import { MoreHorizontal } from 'lucide-react'
import Link from 'next/link'
import { useParams } from 'next/navigation'
import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider'
@@ -108,6 +109,16 @@ export function WorkflowItem({ workflow, active, level, onWorkflowClick }: Workf
window.open(`/workspace/${workspaceId}/w/${workflow.id}`, '_blank')
}, [workspaceId, workflow.id])
/**
* Changes the workflow color
*/
const handleColorChange = useCallback(
(color: string) => {
updateWorkflow(workflow.id, { color })
},
[workflow.id, updateWorkflow]
)
/**
* Drag start handler - handles workflow dragging with multi-selection support
*
@@ -142,8 +153,38 @@ export function WorkflowItem({ workflow, active, level, onWorkflowClick }: Workf
menuRef,
handleContextMenu: handleContextMenuBase,
closeMenu,
preventDismiss,
} = useContextMenu()
/**
* Captures selection state for context menu operations
*/
const captureSelectionState = useCallback(() => {
const { selectedWorkflows: currentSelection, selectOnly } = useFolderStore.getState()
const isCurrentlySelected = currentSelection.has(workflow.id)
if (!isCurrentlySelected) {
selectOnly(workflow.id)
}
const finalSelection = useFolderStore.getState().selectedWorkflows
const finalIsSelected = finalSelection.has(workflow.id)
const workflowIds =
finalIsSelected && finalSelection.size > 1 ? Array.from(finalSelection) : [workflow.id]
const workflowNames = workflowIds
.map((id) => workflows[id]?.name)
.filter((name): name is string => !!name)
capturedSelectionRef.current = {
workflowIds,
workflowNames: workflowNames.length > 1 ? workflowNames : workflowNames[0],
}
setCanDeleteCaptured(canDeleteWorkflows(workflowIds))
}, [workflow.id, workflows, canDeleteWorkflows])
/**
* Handle right-click - ensure proper selection behavior and capture selection state
* If right-clicking on an unselected workflow, select only that workflow
@@ -151,39 +192,46 @@ export function WorkflowItem({ workflow, active, level, onWorkflowClick }: Workf
*/
const handleContextMenu = useCallback(
(e: React.MouseEvent) => {
// Check current selection state at time of right-click
const { selectedWorkflows: currentSelection, selectOnly } = useFolderStore.getState()
const isCurrentlySelected = currentSelection.has(workflow.id)
// If this workflow is not in the current selection, select only this workflow
if (!isCurrentlySelected) {
selectOnly(workflow.id)
}
// Capture the selection state at right-click time
const finalSelection = useFolderStore.getState().selectedWorkflows
const finalIsSelected = finalSelection.has(workflow.id)
const workflowIds =
finalIsSelected && finalSelection.size > 1 ? Array.from(finalSelection) : [workflow.id]
const workflowNames = workflowIds
.map((id) => workflows[id]?.name)
.filter((name): name is string => !!name)
// Store in ref so it persists even if selection changes
capturedSelectionRef.current = {
workflowIds,
workflowNames: workflowNames.length > 1 ? workflowNames : workflowNames[0],
}
// Check if the captured selection can be deleted
setCanDeleteCaptured(canDeleteWorkflows(workflowIds))
// If already selected with multiple selections, keep all selections
captureSelectionState()
handleContextMenuBase(e)
},
[workflow.id, workflows, handleContextMenuBase, canDeleteWorkflows]
[captureSelectionState, handleContextMenuBase]
)
/**
* Handle more button pointerdown - prevents click-outside dismissal when toggling
*/
const handleMorePointerDown = useCallback(() => {
if (isContextMenuOpen) {
preventDismiss()
}
}, [isContextMenuOpen, preventDismiss])
/**
* Handle more button click - toggles context menu at button position
*/
const handleMoreClick = useCallback(
(e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault()
e.stopPropagation()
// Toggle: close if open, open if closed
if (isContextMenuOpen) {
closeMenu()
return
}
captureSelectionState()
// Open context menu aligned with the button
const rect = e.currentTarget.getBoundingClientRect()
handleContextMenuBase({
preventDefault: () => {},
stopPropagation: () => {},
clientX: rect.right,
clientY: rect.top,
} as React.MouseEvent)
},
[isContextMenuOpen, closeMenu, captureSelectionState, handleContextMenuBase]
)
// Rename hook
@@ -309,7 +357,17 @@ export function WorkflowItem({ workflow, active, level, onWorkflowClick }: Workf
)}
</div>
{!isEditing && (
<Avatars workflowId={workflow.id} maxVisible={3} onPresenceChange={setHasAvatars} />
<>
<Avatars workflowId={workflow.id} onPresenceChange={setHasAvatars} />
<button
type='button'
onPointerDown={handleMorePointerDown}
onClick={handleMoreClick}
className='flex h-[18px] w-[18px] flex-shrink-0 items-center justify-center rounded-[4px] opacity-0 transition-opacity hover:bg-[var(--surface-7)] group-hover:opacity-100'
>
<MoreHorizontal className='h-[14px] w-[14px] text-[var(--text-tertiary)]' />
</button>
</>
)}
</Link>
@@ -324,13 +382,17 @@ export function WorkflowItem({ workflow, active, level, onWorkflowClick }: Workf
onDuplicate={handleDuplicateWorkflow}
onExport={handleExportWorkflow}
onDelete={handleOpenDeleteModal}
onColorChange={handleColorChange}
currentColor={workflow.color}
showOpenInNewTab={selectedWorkflows.size <= 1}
showRename={selectedWorkflows.size <= 1}
showDuplicate={true}
showExport={true}
showColorChange={selectedWorkflows.size <= 1}
disableRename={!userPermissions.canEdit}
disableDuplicate={!userPermissions.canEdit}
disableExport={!userPermissions.canEdit}
disableColorChange={!userPermissions.canEdit}
disableDelete={!userPermissions.canEdit || !canDeleteCaptured}
/>

View File

@@ -657,6 +657,7 @@ export function InviteModal({ open, onOpenChange, workspaceName }: InviteModalPr
items={emailItems}
onAdd={(value) => addEmail(value)}
onRemove={removeEmailItem}
onInputChange={() => setErrorMessage(null)}
placeholder={
!userPerms.canAdmin
? 'Only administrators can invite new members'

View File

@@ -27,6 +27,8 @@ export function useContextMenu({ onContextMenu }: UseContextMenuProps = {}) {
const [isOpen, setIsOpen] = useState(false)
const [position, setPosition] = useState<ContextMenuPosition>({ x: 0, y: 0 })
const menuRef = useRef<HTMLDivElement>(null)
// Used to prevent click-outside dismissal when trigger is clicked
const dismissPreventedRef = useRef(false)
/**
* Handle right-click event
@@ -55,6 +57,14 @@ export function useContextMenu({ onContextMenu }: UseContextMenuProps = {}) {
setIsOpen(false)
}, [])
/**
* Prevent the next click-outside from dismissing the menu.
* Call this on pointerdown of a toggle trigger to allow proper toggle behavior.
*/
const preventDismiss = useCallback(() => {
dismissPreventedRef.current = true
}, [])
/**
* Handle clicks outside the menu to close it
*/
@@ -62,6 +72,11 @@ export function useContextMenu({ onContextMenu }: UseContextMenuProps = {}) {
if (!isOpen) return
const handleClickOutside = (e: MouseEvent) => {
// Check if dismissal was prevented (e.g., by toggle trigger's pointerdown)
if (dismissPreventedRef.current) {
dismissPreventedRef.current = false
return
}
if (menuRef.current && !menuRef.current.contains(e.target as Node)) {
closeMenu()
}
@@ -84,5 +99,6 @@ export function useContextMenu({ onContextMenu }: UseContextMenuProps = {}) {
menuRef,
handleContextMenu,
closeMenu,
preventDismiss,
}
}

View File

@@ -1,13 +1,11 @@
import { useCallback } from 'react'
import { createLogger } from '@sim/logger'
import { useRouter } from 'next/navigation'
import { getNextWorkflowColor } from '@/lib/workflows/colors'
import { useCreateWorkflow, useWorkflows } from '@/hooks/queries/workflows'
import { useWorkflowDiffStore } from '@/stores/workflow-diff/store'
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
import {
generateCreativeWorkflowName,
getNextWorkflowColor,
} from '@/stores/workflows/registry/utils'
import { generateCreativeWorkflowName } from '@/stores/workflows/registry/utils'
const logger = createLogger('useWorkflowOperations')

View File

@@ -1,10 +1,10 @@
import { useCallback } from 'react'
import { createLogger } from '@sim/logger'
import { useRouter } from 'next/navigation'
import { getNextWorkflowColor } from '@/lib/workflows/colors'
import { useDuplicateWorkflowMutation } from '@/hooks/queries/workflows'
import { useFolderStore } from '@/stores/folders/store'
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
import { getNextWorkflowColor } from '@/stores/workflows/registry/utils'
const logger = createLogger('useDuplicateWorkflow')

View File

@@ -1,12 +1,11 @@
import { CursorIcon } from '@/components/icons'
import type { BlockConfig } from '@/blocks/types'
import { AuthMode } from '@/blocks/types'
import { createVersionedToolSelector } from '@/blocks/utils'
import type { CursorResponse } from '@/tools/cursor/types'
export const CursorBlock: BlockConfig<CursorResponse> = {
type: 'cursor',
name: 'Cursor (Legacy)',
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.',
@@ -15,7 +14,6 @@ export const CursorBlock: BlockConfig<CursorResponse> = {
bgColor: '#1E1E1E',
icon: CursorIcon,
authMode: AuthMode.ApiKey,
hideFromToolbar: true,
subBlocks: [
{
id: 'operation',
@@ -171,42 +169,3 @@ export const CursorBlock: BlockConfig<CursorResponse> = {
metadata: { type: 'json', description: 'Response metadata' },
},
}
export const CursorV2Block: BlockConfig<CursorResponse> = {
...CursorBlock,
type: 'cursor_v2',
name: 'Cursor',
hideFromToolbar: false,
tools: {
...CursorBlock.tools,
access: [
'cursor_list_agents_v2',
'cursor_get_agent_v2',
'cursor_get_conversation_v2',
'cursor_launch_agent_v2',
'cursor_add_followup_v2',
'cursor_stop_agent_v2',
'cursor_delete_agent_v2',
],
config: {
tool: createVersionedToolSelector({
baseToolSelector: (params) => params.operation || 'cursor_launch_agent',
suffix: '_v2',
fallbackToolId: 'cursor_launch_agent_v2',
}),
},
},
outputs: {
id: { type: 'string', description: 'Agent identifier' },
url: { type: 'string', description: 'Agent URL (launch operation)' },
name: { type: 'string', description: 'Agent name' },
status: { type: 'string', description: 'Agent status' },
source: { type: 'json', description: 'Agent source repository info' },
target: { type: 'json', description: 'Agent target branch/PR info' },
summary: { type: 'string', description: 'Agent summary' },
createdAt: { type: 'string', description: 'Agent creation timestamp' },
agents: { type: 'json', description: 'Array of agent objects (list operation)' },
nextCursor: { type: 'string', description: 'Pagination cursor (list operation)' },
messages: { type: 'json', description: 'Conversation messages (get conversation operation)' },
},
}

View File

@@ -6,7 +6,7 @@ import { getTrigger } from '@/triggers'
export const GitHubBlock: BlockConfig<GitHubResponse> = {
type: 'github',
name: 'GitHub (Legacy)',
name: 'GitHub',
description: 'Interact with GitHub or trigger workflows from GitHub events',
authMode: AuthMode.ApiKey,
longDescription:
@@ -16,7 +16,6 @@ export const GitHubBlock: BlockConfig<GitHubResponse> = {
bgColor: '#181C1E',
icon: GithubIcon,
triggerAllowed: true,
hideFromToolbar: true,
subBlocks: [
{
id: 'operation',
@@ -1336,44 +1335,3 @@ export const GitHubBlock: BlockConfig<GitHubResponse> = {
],
},
}
export const GitHubV2Block: BlockConfig<GitHubResponse> = {
...GitHubBlock,
type: 'github_v2',
name: 'GitHub',
hideFromToolbar: false,
tools: {
...GitHubBlock.tools,
access: (GitHubBlock.tools?.access || []).map((toolId) => `${toolId}_v2`),
config: {
...GitHubBlock.tools?.config,
tool: (params) => {
const baseToolId = (GitHubBlock.tools?.config as any)?.tool(params)
return `${baseToolId}_v2`
},
params: (GitHubBlock.tools?.config as any)?.params,
},
},
outputs: {
data: { type: 'json', description: 'Operation result data (API-aligned)' },
// Trigger outputs (unchanged)
action: { type: 'string', description: 'The action that was performed' },
event_type: { type: 'string', description: 'Type of GitHub event' },
repository: { type: 'string', description: 'Repository full name' },
repository_name: { type: 'string', description: 'Repository name only' },
repository_owner: { type: 'string', description: 'Repository owner username' },
sender: { type: 'string', description: 'Username of the user who triggered the event' },
sender_id: { type: 'string', description: 'User ID of the sender' },
ref: { type: 'string', description: 'Git reference (for push events)' },
before: { type: 'string', description: 'SHA of the commit before the push' },
after: { type: 'string', description: 'SHA of the commit after the push' },
commits: { type: 'string', description: 'Array of commit objects (for push events)' },
pull_request: { type: 'string', description: 'Pull request object (for pull_request events)' },
issue: { type: 'string', description: 'Issue object (for issues events)' },
comment: { type: 'string', description: 'Comment object (for comment events)' },
branch: { type: 'string', description: 'Branch name extracted from ref' },
commit_message: { type: 'string', description: 'Latest commit message' },
commit_author: { type: 'string', description: 'Author of the latest commit' },
},
}

View File

@@ -1,44 +1,12 @@
import { GmailIcon } from '@/components/icons'
import type { BlockConfig } from '@/blocks/types'
import { AuthMode } from '@/blocks/types'
import { createVersionedToolSelector } from '@/blocks/utils'
import type { GmailToolResponse } from '@/tools/gmail/types'
import { getTrigger } from '@/triggers'
function selectGmailToolId(params: Record<string, any>): string {
switch (params.operation) {
case 'send_gmail':
return 'gmail_send'
case 'draft_gmail':
return 'gmail_draft'
case 'search_gmail':
return 'gmail_search'
case 'read_gmail':
return 'gmail_read'
case 'move_gmail':
return 'gmail_move'
case 'mark_read_gmail':
return 'gmail_mark_read'
case 'mark_unread_gmail':
return 'gmail_mark_unread'
case 'archive_gmail':
return 'gmail_archive'
case 'unarchive_gmail':
return 'gmail_unarchive'
case 'delete_gmail':
return 'gmail_delete'
case 'add_label_gmail':
return 'gmail_add_label'
case 'remove_label_gmail':
return 'gmail_remove_label'
default:
throw new Error(`Invalid Gmail operation: ${params.operation}`)
}
}
export const GmailBlock: BlockConfig<GmailToolResponse> = {
type: 'gmail',
name: 'Gmail (Legacy)',
name: 'Gmail',
description: 'Send, read, search, and move Gmail messages or trigger workflows from Gmail events',
authMode: AuthMode.OAuth,
longDescription:
@@ -47,7 +15,6 @@ export const GmailBlock: BlockConfig<GmailToolResponse> = {
category: 'tools',
bgColor: '#E0E0E0',
icon: GmailIcon,
hideFromToolbar: true,
triggerAllowed: true,
subBlocks: [
// Operation selector
@@ -409,7 +376,36 @@ Return ONLY the search query - no explanations, no extra text.`,
'gmail_remove_label',
],
config: {
tool: selectGmailToolId,
tool: (params) => {
switch (params.operation) {
case 'send_gmail':
return 'gmail_send'
case 'draft_gmail':
return 'gmail_draft'
case 'search_gmail':
return 'gmail_search'
case 'read_gmail':
return 'gmail_read'
case 'move_gmail':
return 'gmail_move'
case 'mark_read_gmail':
return 'gmail_mark_read'
case 'mark_unread_gmail':
return 'gmail_mark_unread'
case 'archive_gmail':
return 'gmail_archive'
case 'unarchive_gmail':
return 'gmail_unarchive'
case 'delete_gmail':
return 'gmail_delete'
case 'add_label_gmail':
return 'gmail_add_label'
case 'remove_label_gmail':
return 'gmail_remove_label'
default:
throw new Error(`Invalid Gmail operation: ${params.operation}`)
}
},
params: (params) => {
const {
credential,
@@ -543,59 +539,3 @@ Return ONLY the search query - no explanations, no extra text.`,
available: ['gmail_poller'],
},
}
export const GmailV2Block: BlockConfig<GmailToolResponse> = {
...GmailBlock,
type: 'gmail_v2',
name: 'Gmail',
hideFromToolbar: false,
tools: {
...GmailBlock.tools,
access: [
'gmail_send_v2',
'gmail_draft_v2',
'gmail_read_v2',
'gmail_search_v2',
'gmail_move_v2',
'gmail_mark_read_v2',
'gmail_mark_unread_v2',
'gmail_archive_v2',
'gmail_unarchive_v2',
'gmail_delete_v2',
'gmail_add_label_v2',
'gmail_remove_label_v2',
],
config: {
...GmailBlock.tools?.config,
tool: createVersionedToolSelector({
baseToolSelector: selectGmailToolId,
suffix: '_v2',
fallbackToolId: 'gmail_send_v2',
}),
},
},
outputs: {
// V2 tool outputs (API-aligned)
id: { type: 'string', description: 'Gmail message ID' },
threadId: { type: 'string', description: 'Gmail thread ID' },
labelIds: { type: 'array', description: 'Email label IDs' },
from: { type: 'string', description: 'Sender' },
to: { type: 'string', description: 'To' },
subject: { type: 'string', description: 'Subject' },
date: { type: 'string', description: 'Date' },
body: { type: 'string', description: 'Email body text (best-effort)' },
results: { type: 'json', description: 'Search/read summary results' },
attachments: { type: 'json', description: 'Downloaded attachments (if enabled)' },
// Trigger outputs (unchanged)
email_id: { type: 'string', description: 'Gmail message ID' },
thread_id: { type: 'string', description: 'Gmail thread ID' },
cc: { type: 'string', description: 'CC recipients (comma-separated)' },
body_text: { type: 'string', description: 'Plain text email body' },
body_html: { type: 'string', description: 'HTML email body' },
labels: { type: 'string', description: 'Email labels (comma-separated)' },
has_attachments: { type: 'boolean', description: 'Whether email has attachments' },
raw_email: { type: 'json', description: 'Complete raw email data from Gmail API (if enabled)' },
timestamp: { type: 'string', description: 'Event timestamp' },
},
}

View File

@@ -5,7 +5,7 @@ import type { GoogleCalendarResponse } from '@/tools/google_calendar/types'
export const GoogleCalendarBlock: BlockConfig<GoogleCalendarResponse> = {
type: 'google_calendar',
name: 'Google Calendar (Legacy)',
name: 'Google Calendar',
description: 'Manage Google Calendar events',
authMode: AuthMode.OAuth,
longDescription:
@@ -14,7 +14,6 @@ export const GoogleCalendarBlock: BlockConfig<GoogleCalendarResponse> = {
category: 'tools',
bgColor: '#E0E0E0',
icon: GoogleCalendarIcon,
hideFromToolbar: true,
subBlocks: [
{
id: 'operation',
@@ -386,54 +385,3 @@ Return ONLY the natural language event text - no explanations.`,
metadata: { type: 'json', description: 'Event metadata' },
},
}
export const GoogleCalendarV2Block: BlockConfig<GoogleCalendarResponse> = {
...GoogleCalendarBlock,
type: 'google_calendar_v2',
name: 'Google Calendar',
hideFromToolbar: false,
tools: {
...GoogleCalendarBlock.tools,
access: [
'google_calendar_create_v2',
'google_calendar_list_v2',
'google_calendar_get_v2',
'google_calendar_quick_add_v2',
'google_calendar_invite_v2',
],
config: {
...GoogleCalendarBlock.tools?.config,
tool: (params) => {
const operation = params.operation || 'create'
if (
operation !== 'create' &&
operation !== 'list' &&
operation !== 'get' &&
operation !== 'quick_add' &&
operation !== 'invite'
) {
throw new Error(`Invalid Google Calendar operation: ${operation}`)
}
return `google_calendar_${operation}_v2`
},
params: GoogleCalendarBlock.tools?.config?.params,
},
},
outputs: {
id: { type: 'string', description: 'Event ID' },
htmlLink: { type: 'string', description: 'Event link' },
status: { type: 'string', description: 'Event status' },
summary: { type: 'string', description: 'Event title' },
description: { type: 'string', description: 'Event description' },
location: { type: 'string', description: 'Event location' },
start: { type: 'json', description: 'Event start' },
end: { type: 'json', description: 'Event end' },
attendees: { type: 'json', description: 'Event attendees' },
creator: { type: 'json', description: 'Event creator' },
organizer: { type: 'json', description: 'Event organizer' },
events: { type: 'json', description: 'List of events (list operation)' },
nextPageToken: { type: 'string', description: 'Next page token' },
nextSyncToken: { type: 'string', description: 'Next sync token' },
timeZone: { type: 'string', description: 'Calendar time zone' },
},
}

View File

@@ -1,12 +1,10 @@
import { IntercomIcon } from '@/components/icons'
import type { BlockConfig } from '@/blocks/types'
import { AuthMode } from '@/blocks/types'
import { createVersionedToolSelector } from '@/blocks/utils'
export const IntercomBlock: BlockConfig = {
type: 'intercom',
name: 'Intercom (Legacy)',
hideFromToolbar: true,
name: 'Intercom',
description: 'Manage contacts, companies, conversations, tickets, and messages in Intercom',
longDescription:
'Integrate Intercom into the workflow. Can create, get, update, list, search, and delete contacts; create, get, and list companies; get, list, reply, and search conversations; create and get tickets; and create messages.',
@@ -939,108 +937,3 @@ Return ONLY the numeric timestamp - no explanations, no quotes, no extra text.`,
output: { type: 'json', description: 'Operation result data' },
},
}
export const IntercomV2Block: BlockConfig = {
...IntercomBlock,
type: 'intercom_v2',
name: 'Intercom',
hideFromToolbar: false,
tools: {
...IntercomBlock.tools,
access: [
'intercom_create_contact_v2',
'intercom_get_contact_v2',
'intercom_update_contact_v2',
'intercom_list_contacts_v2',
'intercom_search_contacts_v2',
'intercom_delete_contact_v2',
'intercom_create_company_v2',
'intercom_get_company_v2',
'intercom_list_companies_v2',
'intercom_get_conversation_v2',
'intercom_list_conversations_v2',
'intercom_reply_conversation_v2',
'intercom_search_conversations_v2',
'intercom_create_ticket_v2',
'intercom_get_ticket_v2',
'intercom_create_message_v2',
],
config: {
tool: createVersionedToolSelector({
baseToolSelector: (params) => {
switch (params.operation) {
case 'create_contact':
return 'intercom_create_contact'
case 'get_contact':
return 'intercom_get_contact'
case 'update_contact':
return 'intercom_update_contact'
case 'list_contacts':
return 'intercom_list_contacts'
case 'search_contacts':
return 'intercom_search_contacts'
case 'delete_contact':
return 'intercom_delete_contact'
case 'create_company':
return 'intercom_create_company'
case 'get_company':
return 'intercom_get_company'
case 'list_companies':
return 'intercom_list_companies'
case 'get_conversation':
return 'intercom_get_conversation'
case 'list_conversations':
return 'intercom_list_conversations'
case 'reply_conversation':
return 'intercom_reply_conversation'
case 'search_conversations':
return 'intercom_search_conversations'
case 'create_ticket':
return 'intercom_create_ticket'
case 'get_ticket':
return 'intercom_get_ticket'
case 'create_message':
return 'intercom_create_message'
default:
return 'intercom_create_contact'
}
},
suffix: '_v2',
fallbackToolId: 'intercom_create_contact_v2',
}),
params: IntercomBlock.tools!.config!.params,
},
},
outputs: {
contact: {
type: 'json',
description:
'Contact object with id, type, role, email, phone, name, external_id, created_at, updated_at',
},
contactId: { type: 'string', description: 'ID of the contact (for create/update operations)' },
contacts: { type: 'array', description: 'Array of contacts (for list/search operations)' },
company: { type: 'json', description: 'Company object with id, company_id, name, website' },
companyId: { type: 'string', description: 'ID of the company (for create operations)' },
companies: { type: 'array', description: 'Array of companies (for list operations)' },
conversation: { type: 'json', description: 'Conversation object with id, title, state, open' },
conversationId: {
type: 'string',
description: 'ID of the conversation (for reply operations)',
},
conversations: {
type: 'array',
description: 'Array of conversations (for list/search operations)',
},
ticket: { type: 'json', description: 'Ticket object with id, ticket_id, ticket_state' },
ticketId: { type: 'string', description: 'ID of the ticket (for create operations)' },
message: { type: 'json', description: 'Message object with id, type' },
messageId: { type: 'string', description: 'ID of the message (for create operations)' },
total_count: { type: 'number', description: 'Total count (for list/search operations)' },
pages: { type: 'json', description: 'Pagination info with page, per_page, total_pages' },
id: { type: 'string', description: 'ID of the deleted item (for delete operations)' },
deleted: {
type: 'boolean',
description: 'Whether the item was deleted (for delete operations)',
},
},
}

View File

@@ -3,11 +3,9 @@ import type { BlockConfig } from '@/blocks/types'
import { AuthMode } from '@/blocks/types'
import type { NotionResponse } from '@/tools/notion/types'
// Legacy block - hidden from toolbar
export const NotionBlock: BlockConfig<NotionResponse> = {
type: 'notion',
name: 'Notion (Legacy)',
hideFromToolbar: true,
name: 'Notion',
description: 'Manage Notion pages',
authMode: AuthMode.OAuth,
longDescription:
@@ -359,124 +357,3 @@ export const NotionBlock: BlockConfig<NotionResponse> = {
},
},
}
// V2 Block with API-aligned outputs
export const NotionV2Block: BlockConfig<any> = {
type: 'notion_v2',
name: 'Notion',
description: 'Manage Notion pages',
authMode: AuthMode.OAuth,
longDescription:
'Integrate with Notion into the workflow. Can read page, read database, create page, create database, append content, query database, and search workspace.',
docsLink: 'https://docs.sim.ai/tools/notion',
category: 'tools',
bgColor: '#181C1E',
icon: NotionIcon,
hideFromToolbar: false,
subBlocks: NotionBlock.subBlocks,
tools: {
access: [
'notion_read_v2',
'notion_read_database_v2',
'notion_write_v2',
'notion_create_page_v2',
'notion_query_database_v2',
'notion_search_v2',
'notion_create_database_v2',
],
config: {
tool: (params) => {
switch (params.operation) {
case 'notion_read':
return 'notion_read_v2'
case 'notion_read_database':
return 'notion_read_database_v2'
case 'notion_write':
return 'notion_write_v2'
case 'notion_create_page':
return 'notion_create_page_v2'
case 'notion_query_database':
return 'notion_query_database_v2'
case 'notion_search':
return 'notion_search_v2'
case 'notion_create_database':
return 'notion_create_database_v2'
default:
return 'notion_read_v2'
}
},
params: NotionBlock.tools?.config?.params,
},
},
inputs: NotionBlock.inputs,
outputs: {
// Read page outputs
content: {
type: 'string',
description: 'Page content in markdown format',
condition: { field: 'operation', value: 'notion_read' },
},
title: {
type: 'string',
description: 'Page or database title',
},
url: {
type: 'string',
description: 'Notion URL',
},
id: {
type: 'string',
description: 'Page or database ID',
condition: {
field: 'operation',
value: [
'notion_create_page',
'notion_create_database',
'notion_read_database',
'notion_update_page',
],
},
},
created_time: {
type: 'string',
description: 'Creation timestamp',
},
last_edited_time: {
type: 'string',
description: 'Last edit timestamp',
},
// Database query/search outputs
results: {
type: 'array',
description: 'Array of results from query or search',
condition: { field: 'operation', value: ['notion_query_database', 'notion_search'] },
},
has_more: {
type: 'boolean',
description: 'Whether more results are available',
condition: { field: 'operation', value: ['notion_query_database', 'notion_search'] },
},
next_cursor: {
type: 'string',
description: 'Cursor for pagination',
condition: { field: 'operation', value: ['notion_query_database', 'notion_search'] },
},
total_results: {
type: 'number',
description: 'Number of results returned',
condition: { field: 'operation', value: ['notion_query_database', 'notion_search'] },
},
// Database schema
properties: {
type: 'json',
description: 'Database properties schema',
condition: { field: 'operation', value: ['notion_read_database', 'notion_create_database'] },
},
// Write output
appended: {
type: 'boolean',
description: 'Whether content was successfully appended',
condition: { field: 'operation', value: 'notion_write' },
},
},
}

View File

@@ -250,7 +250,7 @@ Return ONLY the date/time string - no explanations, no quotes, no extra text.`,
tasks: { type: 'json', description: 'Array of task objects from bulk read operations' },
metadata: {
type: 'json',
description: 'Operation metadata with itemId, noteId, contactId, taskId, itemType',
description: 'Operation metadata including item IDs, types, and operation details',
},
success: {
type: 'boolean',

View File

@@ -15,7 +15,7 @@ import { CirclebackBlock } from '@/blocks/blocks/circleback'
import { ClayBlock } from '@/blocks/blocks/clay'
import { ConditionBlock } from '@/blocks/blocks/condition'
import { ConfluenceBlock } from '@/blocks/blocks/confluence'
import { CursorBlock, CursorV2Block } from '@/blocks/blocks/cursor'
import { CursorBlock } from '@/blocks/blocks/cursor'
import { DatadogBlock } from '@/blocks/blocks/datadog'
import { DiscordBlock } from '@/blocks/blocks/discord'
import { DropboxBlock } from '@/blocks/blocks/dropbox'
@@ -30,11 +30,11 @@ import { FirecrawlBlock } from '@/blocks/blocks/firecrawl'
import { FirefliesBlock } from '@/blocks/blocks/fireflies'
import { FunctionBlock } from '@/blocks/blocks/function'
import { GenericWebhookBlock } from '@/blocks/blocks/generic_webhook'
import { GitHubBlock, GitHubV2Block } from '@/blocks/blocks/github'
import { GitHubBlock } from '@/blocks/blocks/github'
import { GitLabBlock } from '@/blocks/blocks/gitlab'
import { GmailBlock, GmailV2Block } from '@/blocks/blocks/gmail'
import { GmailBlock } from '@/blocks/blocks/gmail'
import { GoogleSearchBlock } from '@/blocks/blocks/google'
import { GoogleCalendarBlock, GoogleCalendarV2Block } from '@/blocks/blocks/google_calendar'
import { GoogleCalendarBlock } from '@/blocks/blocks/google_calendar'
import { GoogleDocsBlock } from '@/blocks/blocks/google_docs'
import { GoogleDriveBlock } from '@/blocks/blocks/google_drive'
import { GoogleFormsBlock } from '@/blocks/blocks/google_form'
@@ -54,7 +54,7 @@ import { ImageGeneratorBlock } from '@/blocks/blocks/image_generator'
import { ImapBlock } from '@/blocks/blocks/imap'
import { IncidentioBlock } from '@/blocks/blocks/incidentio'
import { InputTriggerBlock } from '@/blocks/blocks/input_trigger'
import { IntercomBlock, IntercomV2Block } from '@/blocks/blocks/intercom'
import { IntercomBlock } from '@/blocks/blocks/intercom'
import { JinaBlock } from '@/blocks/blocks/jina'
import { JiraBlock } from '@/blocks/blocks/jira'
import { JiraServiceManagementBlock } from '@/blocks/blocks/jira_service_management'
@@ -77,7 +77,7 @@ import { MongoDBBlock } from '@/blocks/blocks/mongodb'
import { MySQLBlock } from '@/blocks/blocks/mysql'
import { Neo4jBlock } from '@/blocks/blocks/neo4j'
import { NoteBlock } from '@/blocks/blocks/note'
import { NotionBlock, NotionV2Block } from '@/blocks/blocks/notion'
import { NotionBlock } from '@/blocks/blocks/notion'
import { OneDriveBlock } from '@/blocks/blocks/onedrive'
import { OpenAIBlock } from '@/blocks/blocks/openai'
import { OutlookBlock } from '@/blocks/blocks/outlook'
@@ -165,7 +165,6 @@ export const registry: Record<string, BlockConfig> = {
condition: ConditionBlock,
confluence: ConfluenceBlock,
cursor: CursorBlock,
cursor_v2: CursorV2Block,
datadog: DatadogBlock,
discord: DiscordBlock,
dropbox: DropboxBlock,
@@ -180,16 +179,13 @@ export const registry: Record<string, BlockConfig> = {
function: FunctionBlock,
generic_webhook: GenericWebhookBlock,
github: GitHubBlock,
github_v2: GitHubV2Block,
gitlab: GitLabBlock,
gmail: GmailBlock,
gmail_v2: GmailV2Block,
grain: GrainBlock,
grafana: GrafanaBlock,
greptile: GreptileBlock,
guardrails: GuardrailsBlock,
google_calendar: GoogleCalendarBlock,
google_calendar_v2: GoogleCalendarV2Block,
google_docs: GoogleDocsBlock,
google_drive: GoogleDriveBlock,
google_forms: GoogleFormsBlock,
@@ -207,7 +203,6 @@ export const registry: Record<string, BlockConfig> = {
incidentio: IncidentioBlock,
input_trigger: InputTriggerBlock,
intercom: IntercomBlock,
intercom_v2: IntercomV2Block,
jina: JinaBlock,
jira: JiraBlock,
jira_service_management: JiraServiceManagementBlock,
@@ -231,7 +226,6 @@ export const registry: Record<string, BlockConfig> = {
neo4j: Neo4jBlock,
note: NoteBlock,
notion: NotionBlock,
notion_v2: NotionV2Block,
onedrive: OneDriveBlock,
openai: OpenAIBlock,
outlook: OutlookBlock,

View File

@@ -214,38 +214,3 @@ export const PROVIDER_CREDENTIAL_INPUTS = {
bedrockSecretKey: { type: 'string', description: 'AWS Secret Access Key for Bedrock' },
bedrockRegion: { type: 'string', description: 'AWS region for Bedrock' },
} as const
/**
* Create a versioned tool selector from an existing tool selector.
*
* This is useful for `*_v2` blocks where the operation UI remains the same, but
* the underlying tool IDs are suffixed (e.g. `cursor_launch_agent` -> `cursor_launch_agent_v2`).
*
* @example
* tools: {
* config: {
* tool: createVersionedToolSelector({
* baseToolSelector: (params) => params.operation,
* suffix: '_v2',
* fallbackToolId: 'cursor_launch_agent_v2',
* }),
* },
* }
*/
export function createVersionedToolSelector<TParams extends Record<string, any>>(args: {
baseToolSelector: (params: TParams) => string
suffix: `_${string}`
fallbackToolId: string
}): (params: TParams) => string {
const { baseToolSelector, suffix, fallbackToolId } = args
return (params: TParams) => {
try {
const baseToolId = baseToolSelector(params)
if (!baseToolId || typeof baseToolId !== 'string') return fallbackToolId
return baseToolId.endsWith(suffix) ? baseToolId : `${baseToolId}${suffix}`
} catch {
return fallbackToolId
}
}
}

View File

@@ -12,11 +12,10 @@ import { cn } from '@/lib/core/utils/cn'
const avatarVariants = cva('relative flex shrink-0 overflow-hidden rounded-full', {
variants: {
size: {
xs: 'h-6 w-6',
sm: 'h-8 w-8',
md: 'h-10 w-10',
lg: 'h-12 w-12',
xl: 'h-16 w-16',
xs: 'h-3.5 w-3.5',
sm: 'h-6 w-6',
md: 'h-8 w-8',
lg: 'h-10 w-10',
},
},
defaultVariants: {
@@ -38,11 +37,10 @@ const avatarStatusVariants = cva(
away: 'bg-[#f59e0b]',
},
size: {
xs: 'h-2 w-2',
sm: 'h-2.5 w-2.5',
md: 'h-3 w-3',
lg: 'h-3.5 w-3.5',
xl: 'h-4 w-4',
xs: 'h-1.5 w-1.5 border',
sm: 'h-2 w-2',
md: 'h-2.5 w-2.5',
lg: 'h-3 w-3',
},
},
defaultVariants: {

View File

@@ -52,6 +52,7 @@
import * as React from 'react'
import * as PopoverPrimitive from '@radix-ui/react-popover'
import { Check, ChevronLeft, ChevronRight, Search } from 'lucide-react'
import { createPortal } from 'react-dom'
import { cn } from '@/lib/core/utils/cn'
type PopoverSize = 'sm' | 'md'
@@ -166,6 +167,9 @@ interface PopoverContextValue {
colorScheme: PopoverColorScheme
searchQuery: string
setSearchQuery: (query: string) => void
/** ID of the last hovered item (for hover submenus) */
lastHoveredItem: string | null
setLastHoveredItem: (id: string | null) => void
}
const PopoverContext = React.createContext<PopoverContextValue | null>(null)
@@ -208,12 +212,24 @@ const Popover: React.FC<PopoverProps> = ({
variant = 'default',
size = 'md',
colorScheme = 'default',
open,
...props
}) => {
const [currentFolder, setCurrentFolder] = React.useState<string | null>(null)
const [folderTitle, setFolderTitle] = React.useState<string | null>(null)
const [onFolderSelect, setOnFolderSelect] = React.useState<(() => void) | null>(null)
const [searchQuery, setSearchQuery] = React.useState<string>('')
const [lastHoveredItem, setLastHoveredItem] = React.useState<string | null>(null)
React.useEffect(() => {
if (open === false) {
setCurrentFolder(null)
setFolderTitle(null)
setOnFolderSelect(null)
setSearchQuery('')
setLastHoveredItem(null)
}
}, [open])
const openFolder = React.useCallback(
(id: string, title: string, onLoad?: () => void | Promise<void>, onSelect?: () => void) => {
@@ -246,6 +262,8 @@ const Popover: React.FC<PopoverProps> = ({
colorScheme,
searchQuery,
setSearchQuery,
lastHoveredItem,
setLastHoveredItem,
}),
[
openFolder,
@@ -257,12 +275,15 @@ const Popover: React.FC<PopoverProps> = ({
size,
colorScheme,
searchQuery,
lastHoveredItem,
]
)
return (
<PopoverContext.Provider value={contextValue}>
<PopoverPrimitive.Root {...props}>{children}</PopoverPrimitive.Root>
<PopoverPrimitive.Root open={open} {...props}>
{children}
</PopoverPrimitive.Root>
</PopoverContext.Provider>
)
}
@@ -496,7 +517,17 @@ export interface PopoverItemProps extends React.HTMLAttributes<HTMLDivElement> {
*/
const PopoverItem = React.forwardRef<HTMLDivElement, PopoverItemProps>(
(
{ className, active, rootOnly, disabled, showCheck = false, children, onClick, ...props },
{
className,
active,
rootOnly,
disabled,
showCheck = false,
children,
onClick,
onMouseEnter,
...props
},
ref
) => {
const context = React.useContext(PopoverContext)
@@ -514,6 +545,12 @@ const PopoverItem = React.forwardRef<HTMLDivElement, PopoverItemProps>(
onClick?.(e)
}
const handleMouseEnter = (e: React.MouseEvent<HTMLDivElement>) => {
// Clear last hovered item to close any open hover submenus
context?.setLastHoveredItem(null)
onMouseEnter?.(e)
}
return (
<div
className={cn(
@@ -529,6 +566,7 @@ const PopoverItem = React.forwardRef<HTMLDivElement, PopoverItemProps>(
aria-selected={active}
aria-disabled={disabled}
onClick={handleClick}
onMouseEnter={handleMouseEnter}
{...props}
>
{children}
@@ -589,44 +627,150 @@ export interface PopoverFolderProps extends Omit<React.HTMLAttributes<HTMLDivEle
children?: React.ReactNode
/** Whether currently active/selected */
active?: boolean
/**
* Expand folder on hover to show submenu alongside parent
* When true, hovering shows a floating submenu; clicking still uses inline navigation
* @default false
*/
expandOnHover?: boolean
}
/**
* Expandable folder that shows nested content.
* Supports two modes:
* - Click mode (default): Replaces parent content, shows back button
* - Hover mode (expandOnHover): Shows floating submenu alongside parent
*/
const PopoverFolder = React.forwardRef<HTMLDivElement, PopoverFolderProps>(
({ className, id, title, icon, onOpen, onSelect, children, active, ...props }, ref) => {
const { openFolder, currentFolder, isInFolder, variant, size, colorScheme } =
usePopoverContext()
(
{
className,
id,
title,
icon,
onOpen,
onSelect,
children,
active,
expandOnHover = false,
...props
},
ref
) => {
const {
openFolder,
currentFolder,
isInFolder,
variant,
size,
colorScheme,
lastHoveredItem,
setLastHoveredItem,
} = usePopoverContext()
const [submenuPosition, setSubmenuPosition] = React.useState<{ top: number; left: number }>({
top: 0,
left: 0,
})
const triggerRef = React.useRef<HTMLDivElement>(null)
// Submenu is open when this folder is the last hovered item (for expandOnHover mode)
const isHoverOpen = expandOnHover && lastHoveredItem === id
// Merge refs
const mergedRef = React.useCallback(
(node: HTMLDivElement | null) => {
triggerRef.current = node
if (typeof ref === 'function') {
ref(node)
} else if (ref) {
ref.current = node
}
},
[ref]
)
// If we're in a folder and this isn't the current one, hide
if (isInFolder && currentFolder !== id) return null
// If this folder is open via click (inline mode), render children directly
if (currentFolder === id) return <>{children}</>
const handleClick = (e: React.MouseEvent) => {
e.stopPropagation()
const handleClickOpen = () => {
openFolder(id, title, onOpen, onSelect)
}
const handleClick = (e: React.MouseEvent) => {
e.stopPropagation()
if (expandOnHover) {
// In hover mode, clicking opens inline and clears hover state
setLastHoveredItem(null)
}
handleClickOpen()
}
const handleMouseEnter = () => {
if (!expandOnHover) return
// Calculate position for submenu
if (triggerRef.current) {
const rect = triggerRef.current.getBoundingClientRect()
const parentPopover = triggerRef.current.closest('[data-radix-popper-content-wrapper]')
const parentRect = parentPopover?.getBoundingClientRect()
// Position to the right of the parent popover with a small gap
setSubmenuPosition({
top: rect.top,
left: parentRect ? parentRect.right + 4 : rect.right + 4,
})
}
setLastHoveredItem(id)
onOpen?.()
}
return (
<div
ref={ref}
className={cn(
STYLES.itemBase,
STYLES.colorScheme[colorScheme].text,
STYLES.size[size].item,
getItemStateClasses(variant, colorScheme, !!active),
className
)}
role='menuitem'
aria-haspopup='true'
aria-expanded={false}
onClick={handleClick}
{...props}
>
{icon}
<span className='flex-1'>{title}</span>
<ChevronRight className={STYLES.size[size].icon} />
</div>
<>
<div
ref={mergedRef}
className={cn(
STYLES.itemBase,
STYLES.colorScheme[colorScheme].text,
STYLES.size[size].item,
getItemStateClasses(variant, colorScheme, !!active || isHoverOpen),
className
)}
role='menuitem'
aria-haspopup='true'
aria-expanded={isHoverOpen}
onClick={handleClick}
onMouseEnter={handleMouseEnter}
{...props}
>
{icon}
<span className='flex-1'>{title}</span>
<ChevronRight className={STYLES.size[size].icon} />
</div>
{/* Hover submenu - rendered as a portal to escape overflow clipping */}
{isHoverOpen &&
typeof document !== 'undefined' &&
createPortal(
<div
className={cn(
'fixed z-[10000201] min-w-[120px]',
STYLES.content,
STYLES.colorScheme[colorScheme].content,
'shadow-lg'
)}
style={{
top: submenuPosition.top,
left: submenuPosition.left,
}}
>
{children}
</div>,
document.body
)}
</>
)
}
)
@@ -665,7 +809,10 @@ const PopoverBackButton = React.forwardRef<HTMLDivElement, PopoverBackButtonProp
className
)}
role='button'
onClick={closeFolder}
onClick={(e) => {
e.stopPropagation()
closeFolder()
}}
{...props}
>
<ChevronLeft className={STYLES.size[size].icon} />

View File

@@ -166,6 +166,8 @@ export interface TagInputProps extends VariantProps<typeof tagInputVariants> {
onAdd: (value: string) => boolean
/** Callback when a tag is removed (receives value, index, and isValid) */
onRemove: (value: string, index: number, isValid: boolean) => void
/** Callback when the input value changes (useful for clearing errors) */
onInputChange?: (value: string) => void
/** Placeholder text for the input */
placeholder?: string
/** Placeholder text when there are existing tags */
@@ -207,6 +209,7 @@ const TagInput = React.forwardRef<HTMLInputElement, TagInputProps>(
items,
onAdd,
onRemove,
onInputChange,
placeholder = 'Enter values',
placeholderWithTags = 'Add another',
disabled = false,
@@ -344,10 +347,12 @@ const TagInput = React.forwardRef<HTMLInputElement, TagInputProps>(
})
if (addedCount === 0 && pastedValues.length === 1) {
setInputValue(inputValue + pastedValues[0])
const newValue = inputValue + pastedValues[0]
setInputValue(newValue)
onInputChange?.(newValue)
}
},
[onAdd, inputValue]
[onAdd, inputValue, onInputChange]
)
const handleBlur = React.useCallback(() => {
@@ -422,7 +427,10 @@ const TagInput = React.forwardRef<HTMLInputElement, TagInputProps>(
name={name}
type='text'
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
onChange={(e) => {
setInputValue(e.target.value)
onInputChange?.(e.target.value)
}}
onKeyDown={handleKeyDown}
onPaste={handlePaste}
onBlur={handleBlur}

View File

@@ -1,6 +1,7 @@
import { useEffect } from 'react'
import { createLogger } from '@sim/logger'
import { keepPreviousData, useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { getNextWorkflowColor } from '@/lib/workflows/colors'
import { buildDefaultWorkflowArtifacts } from '@/lib/workflows/defaults'
import {
createOptimisticMutationHandlers,
@@ -8,10 +9,7 @@ import {
} from '@/hooks/queries/utils/optimistic-mutation'
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
import type { WorkflowMetadata } from '@/stores/workflows/registry/types'
import {
generateCreativeWorkflowName,
getNextWorkflowColor,
} from '@/stores/workflows/registry/utils'
import { generateCreativeWorkflowName } from '@/stores/workflows/registry/utils'
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
import type { WorkflowState } from '@/stores/workflows/workflow/types'

View File

@@ -0,0 +1,75 @@
/**
* Workflow color constants and utilities.
* Centralized location for all workflow color-related functionality.
*
* Colors are aligned with the brand color scheme:
* - Purple: brand-400 (#8e4cfb)
* - Blue: brand-secondary (#33b4ff)
* - Green: brand-tertiary (#22c55e)
* - Red: text-error (#ef4444)
* - Orange: warning (#f97316)
* - Pink: (#ec4899)
*/
/**
* Full list of available workflow colors with names.
* Used for color picker and random color assignment.
* Each base color has 6 vibrant shades optimized for both light and dark themes.
*/
export const WORKFLOW_COLORS = [
// Shade 1 - all base colors (brightest)
{ color: '#c084fc', name: 'Purple 1' },
{ color: '#5ed8ff', name: 'Blue 1' },
{ color: '#4aea7f', name: 'Green 1' },
{ color: '#ff6b6b', name: 'Red 1' },
{ color: '#ff9642', name: 'Orange 1' },
{ color: '#f472b6', name: 'Pink 1' },
// Shade 2 - all base colors
{ color: '#a855f7', name: 'Purple 2' },
{ color: '#38c8ff', name: 'Blue 2' },
{ color: '#2ed96a', name: 'Green 2' },
{ color: '#ff5555', name: 'Red 2' },
{ color: '#ff8328', name: 'Orange 2' },
{ color: '#ec4899', name: 'Pink 2' },
// Shade 3 - all base colors
{ color: '#9333ea', name: 'Purple 3' },
{ color: '#33b4ff', name: 'Blue 3' },
{ color: '#22c55e', name: 'Green 3' },
{ color: '#ef4444', name: 'Red 3' },
{ color: '#f97316', name: 'Orange 3' },
{ color: '#e11d89', name: 'Pink 3' },
// Shade 4 - all base colors
{ color: '#8e4cfb', name: 'Purple 4' },
{ color: '#1e9de8', name: 'Blue 4' },
{ color: '#18b04c', name: 'Green 4' },
{ color: '#dc3535', name: 'Red 4' },
{ color: '#e56004', name: 'Orange 4' },
{ color: '#d61c7a', name: 'Pink 4' },
// Shade 5 - all base colors
{ color: '#7c3aed', name: 'Purple 5' },
{ color: '#1486d1', name: 'Blue 5' },
{ color: '#0e9b3a', name: 'Green 5' },
{ color: '#c92626', name: 'Red 5' },
{ color: '#d14d00', name: 'Orange 5' },
{ color: '#be185d', name: 'Pink 5' },
// Shade 6 - all base colors (darkest)
{ color: '#6322c9', name: 'Purple 6' },
{ color: '#0a6fb8', name: 'Blue 6' },
{ color: '#048628', name: 'Green 6' },
{ color: '#b61717', name: 'Red 6' },
{ color: '#bd3a00', name: 'Orange 6' },
{ color: '#9d174d', name: 'Pink 6' },
] as const
/**
* Generates a random color for a new workflow
* @returns A hex color string from the available workflow colors
*/
export function getNextWorkflowColor(): string {
return WORKFLOW_COLORS[Math.floor(Math.random() * WORKFLOW_COLORS.length)].color
}

View File

@@ -271,11 +271,31 @@ function resolveToolDisplay(
if (cand?.text || cand?.icon) return { text: cand.text, icon: cand.icon }
}
} catch {}
// Humanized fallback as last resort
// Humanized fallback as last resort - include state verb for proper verb-noun styling
try {
if (toolName) {
const text = toolName.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase())
return { text, icon: undefined as any }
const formattedName = toolName.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase())
// Add state verb prefix for verb-noun rendering in tool-call component
let stateVerb: string
switch (state) {
case ClientToolCallState.pending:
case ClientToolCallState.executing:
stateVerb = 'Executing'
break
case ClientToolCallState.success:
stateVerb = 'Executed'
break
case ClientToolCallState.error:
stateVerb = 'Failed'
break
case ClientToolCallState.rejected:
case ClientToolCallState.aborted:
stateVerb = 'Skipped'
break
default:
stateVerb = 'Executing'
}
return { text: `${stateVerb} ${formattedName}`, icon: undefined as any }
}
} catch {}
return undefined
@@ -572,8 +592,30 @@ function stripTodoTags(text: string): string {
*/
function deepClone<T>(obj: T): T {
try {
return JSON.parse(JSON.stringify(obj))
} catch {
const json = JSON.stringify(obj)
if (!json || json === 'undefined') {
logger.warn('[deepClone] JSON.stringify returned empty for object', {
type: typeof obj,
isArray: Array.isArray(obj),
length: Array.isArray(obj) ? obj.length : undefined,
})
return obj
}
const parsed = JSON.parse(json)
// Verify the clone worked
if (Array.isArray(obj) && (!Array.isArray(parsed) || parsed.length !== obj.length)) {
logger.warn('[deepClone] Array clone mismatch', {
originalLength: obj.length,
clonedLength: Array.isArray(parsed) ? parsed.length : 'not array',
})
}
return parsed
} catch (err) {
logger.error('[deepClone] Failed to clone object', {
error: String(err),
type: typeof obj,
isArray: Array.isArray(obj),
})
return obj
}
}
@@ -587,11 +629,18 @@ function serializeMessagesForDB(messages: CopilotMessage[]): any[] {
const result = messages
.map((msg) => {
// Deep clone the entire message to ensure all nested data is serializable
// Ensure timestamp is always a string (Zod schema requires it)
let timestamp: string = msg.timestamp
if (typeof timestamp !== 'string') {
const ts = timestamp as any
timestamp = ts instanceof Date ? ts.toISOString() : new Date().toISOString()
}
const serialized: any = {
id: msg.id,
role: msg.role,
content: msg.content || '',
timestamp: msg.timestamp,
timestamp,
}
// Deep clone contentBlocks (the main rendering data)
@@ -3151,7 +3200,7 @@ export const useCopilotStore = create<CopilotStore>()(
model: selectedModel,
}
await fetch('/api/copilot/chat/update-messages', {
const saveResponse = await fetch('/api/copilot/chat/update-messages', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
@@ -3162,6 +3211,18 @@ export const useCopilotStore = create<CopilotStore>()(
}),
})
if (!saveResponse.ok) {
const errorText = await saveResponse.text().catch(() => '')
logger.error('[Stream Done] Failed to save messages to DB', {
status: saveResponse.status,
error: errorText,
})
} else {
logger.info('[Stream Done] Successfully saved messages to DB', {
messageCount: dbMessages.length,
})
}
// Update local chat object with plan artifact and config
set({
currentChat: {
@@ -3170,7 +3231,9 @@ export const useCopilotStore = create<CopilotStore>()(
config,
},
})
} catch {}
} catch (err) {
logger.error('[Stream Done] Exception saving messages', { error: String(err) })
}
}
// Post copilot_stats record (input/output tokens can be null for now)

View File

@@ -3,6 +3,7 @@ import { create } from 'zustand'
import { devtools } from 'zustand/middleware'
import { withOptimisticUpdate } from '@/lib/core/utils/optimistic-update'
import { DEFAULT_DUPLICATE_OFFSET } from '@/lib/workflows/autolayout/constants'
import { getNextWorkflowColor } from '@/lib/workflows/colors'
import { buildDefaultWorkflowArtifacts } from '@/lib/workflows/defaults'
import { useVariablesStore } from '@/stores/panel/variables/store'
import type {
@@ -11,7 +12,6 @@ import type {
WorkflowMetadata,
WorkflowRegistry,
} from '@/stores/workflows/registry/types'
import { getNextWorkflowColor } from '@/stores/workflows/registry/utils'
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
import { getUniqueBlockName, regenerateBlockIds } from '@/stores/workflows/utils'
import { useWorkflowStore } from '@/stores/workflows/workflow/store'

View File

@@ -1,321 +1,410 @@
// Available workflow colors
export const WORKFLOW_COLORS = [
// Blues - vibrant blue tones
'#3972F6', // Blue (original)
'#2E5BF5', // Deeper Blue
'#1E4BF4', // Royal Blue
'#0D3BF3', // Deep Royal Blue
// Pinks/Magentas - vibrant pink and magenta tones
'#F639DD', // Pink/Magenta (original)
'#F529CF', // Deep Magenta
'#F749E7', // Light Magenta
'#F419C1', // Hot Pink
// Oranges/Yellows - vibrant orange and yellow tones
'#F6B539', // Orange/Yellow (original)
'#F5A529', // Deep Orange
'#F49519', // Burnt Orange
'#F38509', // Deep Burnt Orange
// Purples - vibrant purple tones
'#8139F6', // Purple (original)
'#7129F5', // Deep Purple
'#6119F4', // Royal Purple
'#5109F3', // Deep Royal Purple
// Greens - vibrant green tones
'#39B54A', // Green (original)
'#29A53A', // Deep Green
'#19952A', // Forest Green
'#09851A', // Deep Forest Green
// Teals/Cyans - vibrant teal and cyan tones
'#39B5AB', // Teal (original)
'#29A59B', // Deep Teal
'#19958B', // Dark Teal
'#09857B', // Deep Dark Teal
// Reds/Red-Oranges - vibrant red and red-orange tones
'#F66839', // Red/Orange (original)
'#F55829', // Deep Red-Orange
'#F44819', // Burnt Red
'#F33809', // Deep Burnt Red
// Additional vibrant colors for variety
// Corals - warm coral tones
'#F6397A', // Coral
'#F5296A', // Deep Coral
'#F7498A', // Light Coral
// Crimsons - deep red tones
'#DC143C', // Crimson
'#CC042C', // Deep Crimson
'#EC243C', // Light Crimson
'#BC003C', // Dark Crimson
'#FC343C', // Bright Crimson
// Mint - fresh green tones
'#00FF7F', // Mint Green
'#00EF6F', // Deep Mint
'#00DF5F', // Dark Mint
// Slate - blue-gray tones
'#6A5ACD', // Slate Blue
'#5A4ABD', // Deep Slate
'#4A3AAD', // Dark Slate
// Amber - warm orange-yellow tones
'#FFBF00', // Amber
'#EFAF00', // Deep Amber
'#DF9F00', // Dark Amber
]
// Generates a random color for a new workflow
export function getNextWorkflowColor(): string {
// Simply return a random color from the available colors
return WORKFLOW_COLORS[Math.floor(Math.random() * WORKFLOW_COLORS.length)]
}
// Adjectives and nouns for creative workflow names
// Cosmos-themed adjectives and nouns for creative workflow names (max 9 chars each)
const ADJECTIVES = [
'Blazing',
'Crystal',
'Golden',
'Silver',
'Mystic',
'Cosmic',
'Electric',
'Frozen',
'Burning',
'Shining',
'Dancing',
'Flying',
'Roaring',
'Whispering',
'Glowing',
'Sparkling',
'Thunder',
'Lightning',
'Storm',
'Ocean',
'Mountain',
'Forest',
'Desert',
'Arctic',
'Tropical',
'Midnight',
'Dawn',
'Sunset',
'Rainbow',
'Diamond',
'Ruby',
'Emerald',
'Sapphire',
'Pearl',
'Jade',
'Amber',
'Coral',
'Ivory',
'Obsidian',
'Marble',
'Velvet',
'Silk',
'Satin',
'Linen',
'Cotton',
'Wool',
'Cashmere',
'Denim',
'Neon',
'Pastel',
'Vibrant',
'Muted',
'Bold',
'Subtle',
'Bright',
'Dark',
'Ancient',
'Modern',
'Eternal',
'Swift',
// Light & Luminosity
'Radiant',
'Quantum',
'Luminous',
'Blazing',
'Glowing',
'Bright',
'Gleaming',
'Shining',
'Lustrous',
'Flaring',
'Vivid',
'Dazzling',
'Beaming',
'Brilliant',
'Lit',
'Ablaze',
// Celestial Descriptors
'Stellar',
'Cosmic',
'Astral',
'Galactic',
'Nebular',
'Orbital',
'Lunar',
'Solar',
'Starlit',
'Heavenly',
'Celestial',
'Ethereal',
'Phantom',
'Shadow',
'Sidereal',
'Planetary',
'Starry',
'Spacial',
// Scale & Magnitude
'Infinite',
'Vast',
'Boundless',
'Immense',
'Colossal',
'Titanic',
'Massive',
'Grand',
'Supreme',
'Ultimate',
'Epic',
'Enormous',
'Gigantic',
'Limitless',
'Total',
// Temporal
'Eternal',
'Ancient',
'Timeless',
'Enduring',
'Ageless',
'Immortal',
'Primal',
'Nascent',
'First',
'Elder',
'Lasting',
'Undying',
'Perpetual',
'Final',
'Prime',
// Movement & Energy
'Sidbuck',
'Swift',
'Drifting',
'Spinning',
'Surging',
'Pulsing',
'Soaring',
'Racing',
'Falling',
'Rising',
'Circling',
'Streaking',
'Hurtling',
'Floating',
'Orbiting',
'Spiraling',
// Colors of Space
'Crimson',
'Azure',
'Violet',
'Scarlet',
'Magenta',
'Turquoise',
'Indigo',
'Jade',
'Noble',
'Regal',
'Imperial',
'Royal',
'Supreme',
'Prime',
'Elite',
'Ultra',
'Mega',
'Hyper',
'Super',
'Neo',
'Cyber',
'Digital',
'Virtual',
'Sonic',
'Amber',
'Sapphire',
'Obsidian',
'Silver',
'Golden',
'Scarlet',
'Cobalt',
'Emerald',
'Ruby',
'Onyx',
'Ivory',
// Physical Properties
'Magnetic',
'Quantum',
'Thermal',
'Photonic',
'Ionic',
'Plasma',
'Spectral',
'Charged',
'Polar',
'Dense',
'Atomic',
'Nuclear',
'Laser',
'Plasma',
'Magnetic',
'Electric',
'Kinetic',
'Static',
// Atmosphere & Mystery
'Ethereal',
'Mystic',
'Phantom',
'Shadow',
'Silent',
'Distant',
'Hidden',
'Veiled',
'Fading',
'Arcane',
'Cryptic',
'Obscure',
'Dim',
'Dusky',
'Shrouded',
// Temperature & State
'Frozen',
'Burning',
'Molten',
'Volatile',
'Icy',
'Fiery',
'Cool',
'Warm',
'Cold',
'Hot',
'Searing',
'Frigid',
'Scalding',
'Chilled',
'Heated',
// Power & Force
'Mighty',
'Fierce',
'Raging',
'Wild',
'Serene',
'Tranquil',
'Harmonic',
'Resonant',
'Steady',
'Bold',
'Potent',
'Violent',
'Calm',
'Furious',
'Forceful',
// Texture & Form
'Smooth',
'Jagged',
'Fractured',
'Solid',
'Hollow',
'Curved',
'Sharp',
'Fluid',
'Rigid',
'Warped',
// Rare & Precious
'Noble',
'Pure',
'Rare',
'Pristine',
'Flawless',
'Unique',
'Exotic',
'Sacred',
'Divine',
'Hallowed',
]
const NOUNS = [
'Phoenix',
'Dragon',
'Eagle',
'Wolf',
'Lion',
'Tiger',
'Panther',
'Falcon',
'Hawk',
'Raven',
'Swan',
'Dove',
'Butterfly',
'Firefly',
'Dragonfly',
'Hummingbird',
// Stars & Stellar Objects
'Star',
'Sun',
'Pulsar',
'Quasar',
'Magnetar',
'Nova',
'Supernova',
'Hypernova',
'Neutron',
'Dwarf',
'Giant',
'Protostar',
'Blazar',
'Cepheid',
'Binary',
// Galaxies & Clusters
'Galaxy',
'Nebula',
'Cluster',
'Void',
'Filament',
'Halo',
'Bulge',
'Spiral',
'Ellipse',
'Arm',
'Disk',
'Shell',
'Remnant',
'Cloud',
'Dust',
// Planets & Moons
'Planet',
'Moon',
'World',
'Exoplanet',
'Jovian',
'Titan',
'Europa',
'Io',
'Callisto',
'Ganymede',
'Triton',
'Phobos',
'Deimos',
'Enceladus',
'Charon',
// Small Bodies
'Comet',
'Meteor',
'Star',
'Moon',
'Sun',
'Planet',
'Asteroid',
'Constellation',
'Aurora',
'Meteorite',
'Bolide',
'Fireball',
'Iceball',
'Plutino',
'Centaur',
'Trojan',
'Shard',
'Fragment',
'Debris',
'Rock',
'Ice',
// Constellations & Myths
'Orion',
'Andromeda',
'Perseus',
'Pegasus',
'Phoenix',
'Draco',
'Cygnus',
'Aquila',
'Lyra',
'Vega',
'Centaurus',
'Hydra',
'Sirius',
'Polaris',
'Altair',
// Celestial Phenomena
'Eclipse',
'Solstice',
'Equinox',
'Horizon',
'Zenith',
'Castle',
'Tower',
'Bridge',
'Garden',
'Fountain',
'Palace',
'Temple',
'Cathedral',
'Lighthouse',
'Windmill',
'Waterfall',
'Canyon',
'Valley',
'Peak',
'Ridge',
'Cliff',
'Ocean',
'River',
'Lake',
'Stream',
'Pond',
'Bay',
'Cove',
'Harbor',
'Island',
'Peninsula',
'Archipelago',
'Atoll',
'Reef',
'Lagoon',
'Fjord',
'Delta',
'Cake',
'Cookie',
'Muffin',
'Cupcake',
'Pie',
'Tart',
'Brownie',
'Donut',
'Pancake',
'Waffle',
'Croissant',
'Bagel',
'Pretzel',
'Biscuit',
'Scone',
'Crumpet',
'Thunder',
'Blizzard',
'Tornado',
'Hurricane',
'Tsunami',
'Volcano',
'Glacier',
'Avalanche',
'Aurora',
'Corona',
'Flare',
'Storm',
'Vortex',
'Tempest',
'Maelstrom',
'Whirlwind',
'Cyclone',
'Typhoon',
'Monsoon',
'Anvil',
'Hammer',
'Forge',
'Blade',
'Sword',
'Shield',
'Arrow',
'Spear',
'Crown',
'Throne',
'Scepter',
'Orb',
'Gem',
'Crystal',
'Prism',
'Spectrum',
'Beacon',
'Signal',
'Jet',
'Burst',
'Pulse',
'Wave',
'Surge',
'Tide',
'Ripple',
'Shimmer',
'Glow',
'Flash',
'Spark',
// Cosmic Structures
'Horizon',
'Zenith',
'Nadir',
'Apex',
'Meridian',
'Equinox',
'Solstice',
'Transit',
'Aphelion',
'Orbit',
'Axis',
'Pole',
'Equator',
'Limb',
'Arc',
// Space & Dimensions
'Cosmos',
'Universe',
'Dimension',
'Realm',
'Expanse',
'Infinity',
'Continuum',
'Manifold',
'Abyss',
'Ether',
'Vacuum',
'Space',
'Fabric',
'Plane',
'Domain',
// Energy & Particles
'Photon',
'Neutrino',
'Proton',
'Electron',
'Positron',
'Quark',
'Boson',
'Fermion',
'Tachyon',
'Graviton',
'Meson',
'Gluon',
'Lepton',
'Muon',
'Pion',
// Regions & Zones
'Sector',
'Quadrant',
'Zone',
'Belt',
'Ring',
'Field',
'Stream',
'Current',
'Flow',
'Circuit',
'Node',
'Core',
'Matrix',
'Network',
'System',
'Engine',
'Reactor',
'Generator',
'Dynamo',
'Catalyst',
'Nexus',
'Portal',
'Wake',
'Region',
'Frontier',
'Border',
'Edge',
'Margin',
'Rim',
// Navigation & Discovery
'Beacon',
'Signal',
'Probe',
'Voyager',
'Pioneer',
'Seeker',
'Wanderer',
'Nomad',
'Drifter',
'Scout',
'Explorer',
'Ranger',
'Surveyor',
'Sentinel',
'Watcher',
// Portals & Passages
'Gateway',
'Passage',
'Portal',
'Nexus',
'Bridge',
'Conduit',
'Channel',
'Passage',
'Rift',
'Warp',
'Fold',
'Tunnel',
'Crossing',
'Link',
'Path',
'Route',
// Core & Systems
'Core',
'Matrix',
'Lattice',
'Network',
'Circuit',
'Array',
'Reactor',
'Engine',
'Forge',
'Crucible',
'Hub',
'Node',
'Kernel',
'Center',
'Heart',
// Cosmic Objects
'Crater',
'Rift',
'Chasm',
'Canyon',
'Peak',
'Ridge',
'Basin',
'Plateau',
'Valley',
'Trench',
]
/**

View File

@@ -56,9 +56,11 @@ export const apolloAccountBulkCreateTool: ToolConfig<
output: {
created_accounts: data.accounts || data.created_accounts || [],
failed_accounts: data.failed_accounts || [],
total_submitted: data.accounts?.length || 0,
created: data.created_accounts?.length || data.accounts?.length || 0,
failed: data.failed_accounts?.length || 0,
metadata: {
total_submitted: data.accounts?.length || 0,
created: data.created_accounts?.length || data.accounts?.length || 0,
failed: data.failed_accounts?.length || 0,
},
},
}
},
@@ -72,17 +74,9 @@ export const apolloAccountBulkCreateTool: ToolConfig<
type: 'json',
description: 'Array of accounts that failed to create',
},
total_submitted: {
type: 'number',
description: 'Total number of accounts submitted',
},
created: {
type: 'number',
description: 'Number of accounts successfully created',
},
failed: {
type: 'number',
description: 'Number of accounts that failed to create',
metadata: {
type: 'json',
description: 'Bulk creation metadata including counts of created and failed accounts',
},
},
}

View File

@@ -56,9 +56,11 @@ export const apolloAccountBulkUpdateTool: ToolConfig<
output: {
updated_accounts: data.accounts || data.updated_accounts || [],
failed_accounts: data.failed_accounts || [],
total_submitted: data.accounts?.length || 0,
updated: data.updated_accounts?.length || data.accounts?.length || 0,
failed: data.failed_accounts?.length || 0,
metadata: {
total_submitted: data.accounts?.length || 0,
updated: data.updated_accounts?.length || data.accounts?.length || 0,
failed: data.failed_accounts?.length || 0,
},
},
}
},
@@ -72,17 +74,9 @@ export const apolloAccountBulkUpdateTool: ToolConfig<
type: 'json',
description: 'Array of accounts that failed to update',
},
total_submitted: {
type: 'number',
description: 'Total number of accounts submitted',
},
updated: {
type: 'number',
description: 'Number of accounts successfully updated',
},
failed: {
type: 'number',
description: 'Number of accounts that failed to update',
metadata: {
type: 'json',
description: 'Bulk update metadata including counts of updated and failed accounts',
},
},
}

View File

@@ -72,13 +72,15 @@ export const apolloAccountCreateTool: ToolConfig<
success: true,
output: {
account: data.account || {},
created: !!data.account,
metadata: {
created: !!data.account,
},
},
}
},
outputs: {
account: { type: 'json', description: 'Created account data from Apollo' },
created: { type: 'boolean', description: 'Whether the account was successfully created' },
metadata: { type: 'json', description: 'Creation metadata including created status' },
},
}

View File

@@ -84,17 +84,20 @@ export const apolloAccountSearchTool: ToolConfig<
success: true,
output: {
accounts: data.accounts || [],
page: data.pagination?.page || 1,
per_page: data.pagination?.per_page || 25,
total_entries: data.pagination?.total_entries || 0,
metadata: {
page: data.pagination?.page || 1,
per_page: data.pagination?.per_page || 25,
total_entries: data.pagination?.total_entries || 0,
},
},
}
},
outputs: {
accounts: { type: 'json', description: 'Array of accounts matching the search criteria' },
page: { type: 'number', description: 'Current page number' },
per_page: { type: 'number', description: 'Results per page' },
total_entries: { type: 'number', description: 'Total matching entries' },
metadata: {
type: 'json',
description: 'Pagination information including page, per_page, and total_entries',
},
},
}

View File

@@ -80,13 +80,15 @@ export const apolloAccountUpdateTool: ToolConfig<
success: true,
output: {
account: data.account || {},
updated: !!data.account,
metadata: {
updated: !!data.account,
},
},
}
},
outputs: {
account: { type: 'json', description: 'Updated account data from Apollo' },
updated: { type: 'boolean', description: 'Whether the account was successfully updated' },
metadata: { type: 'json', description: 'Update metadata including updated status' },
},
}

View File

@@ -69,9 +69,11 @@ export const apolloContactBulkCreateTool: ToolConfig<
output: {
created_contacts: data.contacts || data.created_contacts || [],
existing_contacts: data.existing_contacts || [],
total_submitted: data.contacts?.length || 0,
created: data.created_contacts?.length || data.contacts?.length || 0,
existing: data.existing_contacts?.length || 0,
metadata: {
total_submitted: data.contacts?.length || 0,
created: data.created_contacts?.length || data.contacts?.length || 0,
existing: data.existing_contacts?.length || 0,
},
},
}
},
@@ -85,17 +87,9 @@ export const apolloContactBulkCreateTool: ToolConfig<
type: 'json',
description: 'Array of existing contacts (when deduplication is enabled)',
},
total_submitted: {
type: 'number',
description: 'Total number of contacts submitted',
},
created: {
type: 'number',
description: 'Number of contacts successfully created',
},
existing: {
type: 'number',
description: 'Number of existing contacts found',
metadata: {
type: 'json',
description: 'Bulk creation metadata including counts of created and existing contacts',
},
},
}

View File

@@ -56,9 +56,11 @@ export const apolloContactBulkUpdateTool: ToolConfig<
output: {
updated_contacts: data.contacts || data.updated_contacts || [],
failed_contacts: data.failed_contacts || [],
total_submitted: data.contacts?.length || 0,
updated: data.updated_contacts?.length || data.contacts?.length || 0,
failed: data.failed_contacts?.length || 0,
metadata: {
total_submitted: data.contacts?.length || 0,
updated: data.updated_contacts?.length || data.contacts?.length || 0,
failed: data.failed_contacts?.length || 0,
},
},
}
},
@@ -72,17 +74,9 @@ export const apolloContactBulkUpdateTool: ToolConfig<
type: 'json',
description: 'Array of contacts that failed to update',
},
total_submitted: {
type: 'number',
description: 'Total number of contacts submitted',
},
updated: {
type: 'number',
description: 'Number of contacts successfully updated',
},
failed: {
type: 'number',
description: 'Number of contacts that failed to update',
metadata: {
type: 'json',
description: 'Bulk update metadata including counts of updated and failed contacts',
},
},
}

View File

@@ -88,13 +88,15 @@ export const apolloContactCreateTool: ToolConfig<
success: true,
output: {
contact: data.contact || {},
created: !!data.contact,
metadata: {
created: !!data.contact,
},
},
}
},
outputs: {
contact: { type: 'json', description: 'Created contact data from Apollo' },
created: { type: 'boolean', description: 'Whether the contact was successfully created' },
metadata: { type: 'json', description: 'Creation metadata including created status' },
},
}

View File

@@ -76,17 +76,20 @@ export const apolloContactSearchTool: ToolConfig<
success: true,
output: {
contacts: data.contacts || [],
page: data.pagination?.page || 1,
per_page: data.pagination?.per_page || 25,
total_entries: data.pagination?.total_entries || 0,
metadata: {
page: data.pagination?.page || 1,
per_page: data.pagination?.per_page || 25,
total_entries: data.pagination?.total_entries || 0,
},
},
}
},
outputs: {
contacts: { type: 'json', description: 'Array of contacts matching the search criteria' },
page: { type: 'number', description: 'Current page number' },
per_page: { type: 'number', description: 'Results per page' },
total_entries: { type: 'number', description: 'Total matching entries' },
metadata: {
type: 'json',
description: 'Pagination information including page, per_page, and total_entries',
},
},
}

View File

@@ -94,13 +94,15 @@ export const apolloContactUpdateTool: ToolConfig<
success: true,
output: {
contact: data.contact || {},
updated: !!data.contact,
metadata: {
updated: !!data.contact,
},
},
}
},
outputs: {
contact: { type: 'json', description: 'Updated contact data from Apollo' },
updated: { type: 'boolean', description: 'Whether the contact was successfully updated' },
metadata: { type: 'json', description: 'Update metadata including updated status' },
},
}

View File

@@ -41,13 +41,15 @@ export const apolloEmailAccountsTool: ToolConfig<
success: true,
output: {
email_accounts: data.email_accounts || [],
total: data.email_accounts?.length || 0,
metadata: {
total: data.email_accounts?.length || 0,
},
},
}
},
outputs: {
email_accounts: { type: 'json', description: 'Array of team email accounts linked in Apollo' },
total: { type: 'number', description: 'Total count of email accounts' },
metadata: { type: 'json', description: 'Metadata including total count of email accounts' },
},
}

View File

@@ -98,13 +98,15 @@ export const apolloOpportunityCreateTool: ToolConfig<
success: true,
output: {
opportunity: data.opportunity || {},
created: !!data.opportunity,
metadata: {
created: !!data.opportunity,
},
},
}
},
outputs: {
opportunity: { type: 'json', description: 'Created opportunity data from Apollo' },
created: { type: 'boolean', description: 'Whether the opportunity was successfully created' },
metadata: { type: 'json', description: 'Creation metadata including created status' },
},
}

View File

@@ -48,13 +48,15 @@ export const apolloOpportunityGetTool: ToolConfig<
success: true,
output: {
opportunity: data.opportunity || {},
found: !!data.opportunity,
metadata: {
found: !!data.opportunity,
},
},
}
},
outputs: {
opportunity: { type: 'json', description: 'Complete opportunity data from Apollo' },
found: { type: 'boolean', description: 'Whether the opportunity was found' },
metadata: { type: 'json', description: 'Retrieval metadata including found status' },
},
}

View File

@@ -91,9 +91,11 @@ export const apolloOpportunitySearchTool: ToolConfig<
success: true,
output: {
opportunities: data.opportunities || [],
page: data.pagination?.page || 1,
per_page: data.pagination?.per_page || 25,
total_entries: data.pagination?.total_entries || 0,
metadata: {
page: data.pagination?.page || 1,
per_page: data.pagination?.per_page || 25,
total_entries: data.pagination?.total_entries || 0,
},
},
}
},
@@ -103,8 +105,9 @@ export const apolloOpportunitySearchTool: ToolConfig<
type: 'json',
description: 'Array of opportunities matching the search criteria',
},
page: { type: 'number', description: 'Current page number' },
per_page: { type: 'number', description: 'Results per page' },
total_entries: { type: 'number', description: 'Total matching entries' },
metadata: {
type: 'json',
description: 'Pagination information including page, per_page, and total_entries',
},
},
}

View File

@@ -97,13 +97,15 @@ export const apolloOpportunityUpdateTool: ToolConfig<
success: true,
output: {
opportunity: data.opportunity || {},
updated: !!data.opportunity,
metadata: {
updated: !!data.opportunity,
},
},
}
},
outputs: {
opportunity: { type: 'json', description: 'Updated opportunity data from Apollo' },
updated: { type: 'boolean', description: 'Whether the opportunity was successfully updated' },
metadata: { type: 'json', description: 'Update metadata including updated status' },
},
}

View File

@@ -53,15 +53,19 @@ export const apolloOrganizationBulkEnrichTool: ToolConfig<
success: true,
output: {
organizations: data.matches || [],
total: data.matches?.length || 0,
enriched: data.matches?.filter((o: any) => o).length || 0,
metadata: {
total: data.matches?.length || 0,
enriched: data.matches?.filter((o: any) => o).length || 0,
},
},
}
},
outputs: {
organizations: { type: 'json', description: 'Array of enriched organization data' },
total: { type: 'number', description: 'Total number of organizations processed' },
enriched: { type: 'number', description: 'Number of organizations successfully enriched' },
metadata: {
type: 'json',
description: 'Bulk enrichment metadata including total and enriched counts',
},
},
}

View File

@@ -71,16 +71,15 @@ export const apolloOrganizationEnrichTool: ToolConfig<
success: true,
output: {
organization: data.organization || {},
enriched: !!data.organization,
metadata: {
enriched: !!data.organization,
},
},
}
},
outputs: {
organization: { type: 'json', description: 'Enriched organization data from Apollo' },
enriched: {
type: 'boolean',
description: 'Whether the organization was successfully enriched',
},
metadata: { type: 'json', description: 'Enrichment metadata including enriched status' },
},
}

View File

@@ -101,9 +101,11 @@ export const apolloOrganizationSearchTool: ToolConfig<
success: true,
output: {
organizations: data.organizations || [],
page: data.pagination?.page || 1,
per_page: data.pagination?.per_page || 25,
total_entries: data.pagination?.total_entries || 0,
metadata: {
page: data.pagination?.page || 1,
per_page: data.pagination?.per_page || 25,
total_entries: data.pagination?.total_entries || 0,
},
},
}
},
@@ -113,8 +115,9 @@ export const apolloOrganizationSearchTool: ToolConfig<
type: 'json',
description: 'Array of organizations matching the search criteria',
},
page: { type: 'number', description: 'Current page number' },
per_page: { type: 'number', description: 'Results per page' },
total_entries: { type: 'number', description: 'Total matching entries' },
metadata: {
type: 'json',
description: 'Pagination information including page, per_page, and total_entries',
},
},
}

View File

@@ -67,15 +67,19 @@ export const apolloPeopleBulkEnrichTool: ToolConfig<
success: true,
output: {
people: data.matches || [],
total: data.matches?.length || 0,
enriched: data.matches?.filter((p: any) => p).length || 0,
metadata: {
total: data.matches?.length || 0,
enriched: data.matches?.filter((p: any) => p).length || 0,
},
},
}
},
outputs: {
people: { type: 'json', description: 'Array of enriched people data' },
total: { type: 'number', description: 'Total number of people processed' },
enriched: { type: 'number', description: 'Number of people successfully enriched' },
metadata: {
type: 'json',
description: 'Bulk enrichment metadata including total and enriched counts',
},
},
}

View File

@@ -107,13 +107,15 @@ export const apolloPeopleEnrichTool: ToolConfig<
success: true,
output: {
person: data.person || {},
enriched: !!data.person,
metadata: {
enriched: !!data.person,
},
},
}
},
outputs: {
person: { type: 'json', description: 'Enriched person data from Apollo' },
enriched: { type: 'boolean', description: 'Whether the person was successfully enriched' },
metadata: { type: 'json', description: 'Enrichment metadata including enriched status' },
},
}

View File

@@ -107,17 +107,20 @@ export const apolloPeopleSearchTool: ToolConfig<
success: true,
output: {
people: data.people || [],
page: data.pagination?.page || 1,
per_page: data.pagination?.per_page || 25,
total_entries: data.pagination?.total_entries || 0,
metadata: {
page: data.pagination?.page || 1,
per_page: data.pagination?.per_page || 25,
total_entries: data.pagination?.total_entries || 0,
},
},
}
},
outputs: {
people: { type: 'json', description: 'Array of people matching the search criteria' },
page: { type: 'number', description: 'Current page number' },
per_page: { type: 'number', description: 'Results per page' },
total_entries: { type: 'number', description: 'Total matching entries' },
metadata: {
type: 'json',
description: 'Pagination information including page, per_page, and total_entries',
},
},
}

View File

@@ -81,15 +81,19 @@ export const apolloSequenceAddContactsTool: ToolConfig<
success: true,
output: {
contacts_added: data.contacts || params?.contact_ids || [],
sequence_id: params?.sequence_id || '',
total_added: data.contacts?.length || params?.contact_ids?.length || 0,
metadata: {
sequence_id: params?.sequence_id || '',
total_added: data.contacts?.length || params?.contact_ids?.length || 0,
},
},
}
},
outputs: {
contacts_added: { type: 'json', description: 'Array of contact IDs added to the sequence' },
sequence_id: { type: 'string', description: 'ID of the sequence contacts were added to' },
total_added: { type: 'number', description: 'Total number of contacts added' },
metadata: {
type: 'json',
description: 'Sequence metadata including sequence_id and total_added count',
},
},
}

View File

@@ -74,9 +74,11 @@ export const apolloSequenceSearchTool: ToolConfig<
success: true,
output: {
sequences: data.emailer_campaigns || [],
page: data.pagination?.page || 1,
per_page: data.pagination?.per_page || 25,
total_entries: data.pagination?.total_entries || 0,
metadata: {
page: data.pagination?.page || 1,
per_page: data.pagination?.per_page || 25,
total_entries: data.pagination?.total_entries || 0,
},
},
}
},
@@ -86,8 +88,9 @@ export const apolloSequenceSearchTool: ToolConfig<
type: 'json',
description: 'Array of sequences/campaigns matching the search criteria',
},
page: { type: 'number', description: 'Current page number' },
per_page: { type: 'number', description: 'Results per page' },
total_entries: { type: 'number', description: 'Total matching entries' },
metadata: {
type: 'json',
description: 'Pagination information including page, per_page, and total_entries',
},
},
}

View File

@@ -89,13 +89,15 @@ export const apolloTaskCreateTool: ToolConfig<ApolloTaskCreateParams, ApolloTask
created: true,
message: 'Task created successfully. Apollo API does not return task details.',
},
created: data === true || !!data.task,
metadata: {
created: data === true || !!data.task,
},
},
}
},
outputs: {
task: { type: 'json', description: 'Created task data from Apollo' },
created: { type: 'boolean', description: 'Whether the task was successfully created' },
metadata: { type: 'json', description: 'Creation metadata including created status' },
},
}

View File

@@ -78,17 +78,20 @@ export const apolloTaskSearchTool: ToolConfig<ApolloTaskSearchParams, ApolloTask
success: true,
output: {
tasks: data.tasks || [],
page: data.pagination?.page || 1,
per_page: data.pagination?.per_page || 25,
total_entries: data.pagination?.total_entries || 0,
metadata: {
page: data.pagination?.page || 1,
per_page: data.pagination?.per_page || 25,
total_entries: data.pagination?.total_entries || 0,
},
},
}
},
outputs: {
tasks: { type: 'json', description: 'Array of tasks matching the search criteria' },
page: { type: 'number', description: 'Current page number' },
per_page: { type: 'number', description: 'Results per page' },
total_entries: { type: 'number', description: 'Total matching entries' },
metadata: {
type: 'json',
description: 'Pagination information including page, per_page, and total_entries',
},
},
}

View File

@@ -89,9 +89,11 @@ export interface ApolloPeopleSearchParams extends ApolloBaseParams {
export interface ApolloPeopleSearchResponse extends ToolResponse {
output: {
people: ApolloPerson[]
page: number
per_page: number
total_entries: number
metadata: {
page: number
per_page: number
total_entries: number
}
}
}
@@ -110,7 +112,9 @@ export interface ApolloPeopleEnrichParams extends ApolloBaseParams {
export interface ApolloPeopleEnrichResponse extends ToolResponse {
output: {
person: ApolloPerson
enriched: boolean
metadata: {
enriched: boolean
}
}
}
@@ -130,8 +134,10 @@ export interface ApolloPeopleBulkEnrichParams extends ApolloBaseParams {
export interface ApolloPeopleBulkEnrichResponse extends ToolResponse {
output: {
people: ApolloPerson[]
total: number
enriched: number
metadata: {
total: number
enriched: number
}
}
}
@@ -148,9 +154,11 @@ export interface ApolloOrganizationSearchParams extends ApolloBaseParams {
export interface ApolloOrganizationSearchResponse extends ToolResponse {
output: {
organizations: ApolloOrganization[]
page: number
per_page: number
total_entries: number
metadata: {
page: number
per_page: number
total_entries: number
}
}
}
@@ -163,7 +171,9 @@ export interface ApolloOrganizationEnrichParams extends ApolloBaseParams {
export interface ApolloOrganizationEnrichResponse extends ToolResponse {
output: {
organization: ApolloOrganization
enriched: boolean
metadata: {
enriched: boolean
}
}
}
@@ -178,8 +188,10 @@ export interface ApolloOrganizationBulkEnrichParams extends ApolloBaseParams {
export interface ApolloOrganizationBulkEnrichResponse extends ToolResponse {
output: {
organizations: ApolloOrganization[]
total: number
enriched: number
metadata: {
total: number
enriched: number
}
}
}
@@ -196,7 +208,9 @@ export interface ApolloContactCreateParams extends ApolloBaseParams {
export interface ApolloContactCreateResponse extends ToolResponse {
output: {
contact: ApolloContact
created: boolean
metadata: {
created: boolean
}
}
}
@@ -214,7 +228,9 @@ export interface ApolloContactUpdateParams extends ApolloBaseParams {
export interface ApolloContactUpdateResponse extends ToolResponse {
output: {
contact: ApolloContact
updated: boolean
metadata: {
updated: boolean
}
}
}
@@ -235,9 +251,11 @@ export interface ApolloContactBulkCreateResponse extends ToolResponse {
output: {
created_contacts: ApolloContact[]
existing_contacts: ApolloContact[]
total_submitted: number
created: number
existing: number
metadata: {
total_submitted: number
created: number
existing: number
}
}
}
@@ -258,9 +276,11 @@ export interface ApolloContactBulkUpdateResponse extends ToolResponse {
output: {
updated_contacts: ApolloContact[]
failed_contacts: Array<{ id: string; error: string }>
total_submitted: number
updated: number
failed: number
metadata: {
total_submitted: number
updated: number
failed: number
}
}
}
@@ -275,9 +295,11 @@ export interface ApolloContactSearchParams extends ApolloBaseParams {
export interface ApolloContactSearchResponse extends ToolResponse {
output: {
contacts: ApolloContact[]
page: number
per_page: number
total_entries: number
metadata: {
page: number
per_page: number
total_entries: number
}
}
}
@@ -292,7 +314,9 @@ export interface ApolloAccountCreateParams extends ApolloBaseParams {
export interface ApolloAccountCreateResponse extends ToolResponse {
output: {
account: ApolloAccount
created: boolean
metadata: {
created: boolean
}
}
}
@@ -308,7 +332,9 @@ export interface ApolloAccountUpdateParams extends ApolloBaseParams {
export interface ApolloAccountUpdateResponse extends ToolResponse {
output: {
account: ApolloAccount
updated: boolean
metadata: {
updated: boolean
}
}
}
@@ -324,9 +350,11 @@ export interface ApolloAccountSearchParams extends ApolloBaseParams {
export interface ApolloAccountSearchResponse extends ToolResponse {
output: {
accounts: ApolloAccount[]
page: number
per_page: number
total_entries: number
metadata: {
page: number
per_page: number
total_entries: number
}
}
}
@@ -344,9 +372,11 @@ export interface ApolloAccountBulkCreateResponse extends ToolResponse {
output: {
created_accounts: ApolloAccount[]
failed_accounts: Array<{ name: string; error: string }>
total_submitted: number
created: number
failed: number
metadata: {
total_submitted: number
created: number
failed: number
}
}
}
@@ -365,9 +395,11 @@ export interface ApolloAccountBulkUpdateResponse extends ToolResponse {
output: {
updated_accounts: ApolloAccount[]
failed_accounts: Array<{ id: string; error: string }>
total_submitted: number
updated: number
failed: number
metadata: {
total_submitted: number
updated: number
failed: number
}
}
}
@@ -382,8 +414,10 @@ export interface ApolloSequenceAddContactsParams extends ApolloBaseParams {
export interface ApolloSequenceAddContactsResponse extends ToolResponse {
output: {
contacts_added: string[]
sequence_id: string
total_added: number
metadata: {
sequence_id: string
total_added: number
}
}
}
@@ -400,7 +434,9 @@ export interface ApolloTaskCreateParams extends ApolloBaseParams {
export interface ApolloTaskCreateResponse extends ToolResponse {
output: {
task: ApolloTask
created: boolean
metadata: {
created: boolean
}
}
}
@@ -416,9 +452,11 @@ export interface ApolloTaskSearchParams extends ApolloBaseParams {
export interface ApolloTaskSearchResponse extends ToolResponse {
output: {
tasks: ApolloTask[]
page: number
per_page: number
total_entries: number
metadata: {
page: number
per_page: number
total_entries: number
}
}
}
@@ -432,7 +470,9 @@ export interface ApolloEmailAccountsResponse extends ToolResponse {
email: string
active: boolean
}>
total: number
metadata: {
total: number
}
}
}
@@ -450,7 +490,9 @@ export interface ApolloOpportunityCreateParams extends ApolloBaseParams {
export interface ApolloOpportunityCreateResponse extends ToolResponse {
output: {
opportunity: ApolloOpportunity
created: boolean
metadata: {
created: boolean
}
}
}
@@ -467,9 +509,11 @@ export interface ApolloOpportunitySearchParams extends ApolloBaseParams {
export interface ApolloOpportunitySearchResponse extends ToolResponse {
output: {
opportunities: ApolloOpportunity[]
page: number
per_page: number
total_entries: number
metadata: {
page: number
per_page: number
total_entries: number
}
}
}
@@ -481,7 +525,9 @@ export interface ApolloOpportunityGetParams extends ApolloBaseParams {
export interface ApolloOpportunityGetResponse extends ToolResponse {
output: {
opportunity: ApolloOpportunity
found: boolean
metadata: {
found: boolean
}
}
}
@@ -499,7 +545,9 @@ export interface ApolloOpportunityUpdateParams extends ApolloBaseParams {
export interface ApolloOpportunityUpdateResponse extends ToolResponse {
output: {
opportunity: ApolloOpportunity
updated: boolean
metadata: {
updated: boolean
}
}
}
@@ -527,9 +575,11 @@ export interface ApolloSequenceSearchParams extends ApolloBaseParams {
export interface ApolloSequenceSearchResponse extends ToolResponse {
output: {
sequences: ApolloSequence[]
page: number
per_page: number
total_entries: number
metadata: {
page: number
per_page: number
total_entries: number
}
}
}

View File

@@ -1,7 +1,12 @@
import type { AddFollowupParams, AddFollowupResponse } from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const addFollowupBase = {
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',
params: {
apiKey: {
type: 'string',
@@ -28,15 +33,15 @@ const addFollowupBase = {
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}/followup`,
url: (params) => `https://api.cursor.com/v0/agents/${params.agentId}/followup`,
method: 'POST',
headers: (params: AddFollowupParams) => ({
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`,
}),
body: (params: AddFollowupParams) => {
body: (params) => {
const body: Record<string, any> = {
prompt: {
text: params.followupPromptText,
@@ -54,15 +59,6 @@ const addFollowupBase = {
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()
@@ -91,32 +87,3 @@ export const addFollowupTool: ToolConfig<AddFollowupParams, AddFollowupResponse>
},
},
}
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' },
},
}

View File

@@ -1,7 +1,12 @@
import type { DeleteAgentParams, DeleteAgentResponse } from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const deleteAgentBase = {
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',
params: {
apiKey: {
type: 'string',
@@ -16,22 +21,14 @@ const deleteAgentBase = {
description: 'Unique identifier for the cloud agent (e.g., bc_abc123)',
},
},
request: {
url: (params: DeleteAgentParams) => `https://api.cursor.com/v0/agents/${params.agentId}`,
url: (params) => `https://api.cursor.com/v0/agents/${params.agentId}`,
method: 'DELETE',
headers: (params: DeleteAgentParams) => ({
headers: (params) => ({
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()
@@ -60,31 +57,3 @@ export const deleteAgentTool: ToolConfig<DeleteAgentParams, DeleteAgentResponse>
},
},
}
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' },
},
}

View File

@@ -1,7 +1,12 @@
import type { GetAgentParams, GetAgentResponse } from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const getAgentBase = {
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',
params: {
apiKey: {
type: 'string',
@@ -16,22 +21,14 @@ const getAgentBase = {
description: 'Unique identifier for the cloud agent (e.g., bc_abc123)',
},
},
request: {
url: (params: GetAgentParams) => `https://api.cursor.com/v0/agents/${params.agentId}`,
url: (params) => `https://api.cursor.com/v0/agents/${params.agentId}`,
method: 'GET',
headers: (params: GetAgentParams) => ({
headers: (params) => ({
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()
@@ -62,50 +59,3 @@ export const getAgentTool: ToolConfig<GetAgentParams, GetAgentResponse> = {
},
},
}
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,
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' },
},
}

View File

@@ -1,7 +1,13 @@
import type { GetConversationParams, GetConversationResponse } from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const getConversationBase = {
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',
params: {
apiKey: {
type: 'string',
@@ -16,24 +22,14 @@ const getConversationBase = {
description: 'Unique identifier for the cloud agent (e.g., bc_abc123)',
},
},
request: {
url: (params: GetConversationParams) =>
`https://api.cursor.com/v0/agents/${params.agentId}/conversation`,
url: (params) => `https://api.cursor.com/v0/agents/${params.agentId}/conversation`,
method: 'GET',
headers: (params: GetConversationParams) => ({
headers: (params) => ({
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()
@@ -65,35 +61,3 @@ export const getConversationTool: ToolConfig<GetConversationParams, GetConversat
},
},
}
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' },
},
}

View File

@@ -1,10 +1,10 @@
import { addFollowupTool, addFollowupV2Tool } from '@/tools/cursor/add_followup'
import { deleteAgentTool, deleteAgentV2Tool } from '@/tools/cursor/delete_agent'
import { getAgentTool, getAgentV2Tool } from '@/tools/cursor/get_agent'
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 { stopAgentTool, stopAgentV2Tool } from '@/tools/cursor/stop_agent'
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
@@ -13,11 +13,3 @@ export const cursorLaunchAgentTool = launchAgentTool
export const cursorAddFollowupTool = addFollowupTool
export const cursorStopAgentTool = stopAgentTool
export const cursorDeleteAgentTool = deleteAgentTool
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

View File

@@ -1,7 +1,13 @@
import type { LaunchAgentParams, LaunchAgentResponse } from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const launchAgentBase = {
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',
params: {
apiKey: {
type: 'string',
@@ -64,14 +70,15 @@ const launchAgentBase = {
description: 'Skip requesting reviewers on the PR',
},
},
request: {
url: () => 'https://api.cursor.com/v0/agents',
method: 'POST',
headers: (params: LaunchAgentParams) => ({
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Basic ${Buffer.from(`${params.apiKey}:`).toString('base64')}`,
}),
body: (params: LaunchAgentParams) => {
body: (params) => {
const body: Record<string, any> = {
source: {
repository: params.repository,
@@ -112,16 +119,6 @@ const launchAgentBase = {
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()
@@ -151,36 +148,3 @@ export const launchAgentTool: ToolConfig<LaunchAgentParams, LaunchAgentResponse>
},
},
}
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' },
},
}

View File

@@ -1,7 +1,12 @@
import type { ListAgentsParams, ListAgentsResponse } from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const listAgentsBase = {
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',
params: {
apiKey: {
type: 'string',
@@ -22,27 +27,19 @@ const listAgentsBase = {
description: 'Pagination cursor from previous response',
},
},
request: {
url: (params: ListAgentsParams) => {
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: ListAgentsParams) => ({
headers: (params) => ({
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()
@@ -78,35 +75,3 @@ export const listAgentsTool: ToolConfig<ListAgentsParams, ListAgentsResponse> =
},
},
}
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,
},
}
},
outputs: {
agents: { type: 'array', description: 'Array of agent objects' },
nextCursor: { type: 'string', description: 'Pagination cursor for next page', optional: true },
},
}

View File

@@ -1,7 +1,12 @@
import type { StopAgentParams, StopAgentResponse } from '@/tools/cursor/types'
import type { ToolConfig } from '@/tools/types'
const stopAgentBase = {
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',
params: {
apiKey: {
type: 'string',
@@ -16,22 +21,14 @@ const stopAgentBase = {
description: 'Unique identifier for the cloud agent (e.g., bc_abc123)',
},
},
request: {
url: (params: StopAgentParams) => `https://api.cursor.com/v0/agents/${params.agentId}/stop`,
url: (params) => `https://api.cursor.com/v0/agents/${params.agentId}/stop`,
method: 'POST',
headers: (params: StopAgentParams) => ({
headers: (params) => ({
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()
@@ -60,31 +57,3 @@ export const stopAgentTool: ToolConfig<StopAgentParams, StopAgentResponse> = {
},
},
}
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' },
},
}

View File

@@ -106,46 +106,3 @@ URL: ${issue.html_url}`
},
},
}
export const addAssigneesV2Tool: ToolConfig<AddAssigneesParams, any> = {
id: 'github_add_assignees_v2',
name: addAssigneesTool.name,
description: addAssigneesTool.description,
version: '2.0.0',
params: addAssigneesTool.params,
request: addAssigneesTool.request,
transformResponse: async (response: Response) => {
const issue = await response.json()
return {
success: true,
output: {
id: issue.id,
number: issue.number,
title: issue.title,
state: issue.state,
html_url: issue.html_url,
body: issue.body,
user: issue.user,
labels: issue.labels,
assignees: issue.assignees,
created_at: issue.created_at,
updated_at: issue.updated_at,
},
}
},
outputs: {
id: { type: 'number', description: 'Issue ID' },
number: { type: 'number', description: 'Issue number' },
title: { type: 'string', description: 'Issue title' },
state: { type: 'string', description: 'Issue state' },
html_url: { type: 'string', description: 'GitHub web URL' },
body: { type: 'string', description: 'Issue body' },
user: { type: 'json', description: 'Issue creator' },
labels: { type: 'array', description: 'Array of label objects' },
assignees: { type: 'array', description: 'Array of assignee objects' },
created_at: { type: 'string', description: 'Creation timestamp' },
updated_at: { type: 'string', description: 'Last update timestamp' },
},
}

View File

@@ -94,40 +94,3 @@ All labels on issue: ${labels.join(', ')}`
},
},
}
export const addLabelsV2Tool: ToolConfig<AddLabelsParams, any> = {
id: 'github_add_labels_v2',
name: addLabelsTool.name,
description: addLabelsTool.description,
version: '2.0.0',
params: addLabelsTool.params,
request: addLabelsTool.request,
transformResponse: async (response: Response) => {
const labels = await response.json()
return {
success: true,
output: {
items: labels,
count: labels.length,
},
}
},
outputs: {
items: {
type: 'array',
description: 'Array of label objects on the issue',
items: {
type: 'object',
properties: {
id: { type: 'number', description: 'Label ID' },
name: { type: 'string', description: 'Label name' },
color: { type: 'string', description: 'Label color' },
description: { type: 'string', description: 'Label description' },
},
},
},
count: { type: 'number', description: 'Number of labels' },
},
}

Some files were not shown because too many files have changed in this diff Show More