mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-06 03:00:16 -04:00
improvement(attio): validate integration, fix event bug, add missing tool and triggers (#3872)
* improvement(attio): validate integration, fix event bug, add missing tool and triggers * fix(attio): wire new trigger extractors into dispatcher, trim targetUrl Add extractAttioListData and extractAttioWorkspaceMemberData dispatch branches in utils.server.ts so the four new triggers return correct outputs instead of falling through to generic extraction. Also add missing .trim() on targetUrl in update_webhook. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -359,6 +359,35 @@ List tasks in Attio, optionally filtered by record, assignee, or completion stat
|
||||
| ↳ `createdAt` | string | When the task was created |
|
||||
| `count` | number | Number of tasks returned |
|
||||
|
||||
### `attio_get_task`
|
||||
|
||||
Get a single task by ID from Attio
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `taskId` | string | Yes | The ID of the task to retrieve |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `taskId` | string | The task ID |
|
||||
| `content` | string | The task content |
|
||||
| `deadlineAt` | string | The task deadline |
|
||||
| `isCompleted` | boolean | Whether the task is completed |
|
||||
| `linkedRecords` | array | Records linked to this task |
|
||||
| ↳ `targetObjectId` | string | The linked object ID |
|
||||
| ↳ `targetRecordId` | string | The linked record ID |
|
||||
| `assignees` | array | Task assignees |
|
||||
| ↳ `type` | string | The assignee actor type \(e.g. workspace-member\) |
|
||||
| ↳ `id` | string | The assignee actor ID |
|
||||
| `createdByActor` | object | The actor who created this task |
|
||||
| ↳ `type` | string | The actor type \(e.g. workspace-member, api-token, system\) |
|
||||
| ↳ `id` | string | The actor ID |
|
||||
| `createdAt` | string | When the task was created |
|
||||
|
||||
### `attio_create_task`
|
||||
|
||||
Create a task in Attio
|
||||
@@ -1012,8 +1041,8 @@ Update a webhook in Attio (target URL and/or subscriptions)
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `webhookId` | string | Yes | The webhook ID to update |
|
||||
| `targetUrl` | string | Yes | HTTPS target URL for webhook delivery |
|
||||
| `subscriptions` | string | Yes | JSON array of subscriptions, e.g. \[\{"event_type":"note.created"\}\] |
|
||||
| `targetUrl` | string | No | HTTPS target URL for webhook delivery |
|
||||
| `subscriptions` | string | No | JSON array of subscriptions, e.g. \[\{"event_type":"note.created"\}\] |
|
||||
|
||||
#### Output
|
||||
|
||||
|
||||
@@ -926,6 +926,10 @@
|
||||
"name": "List Tasks",
|
||||
"description": "List tasks in Attio, optionally filtered by record, assignee, or completion status"
|
||||
},
|
||||
{
|
||||
"name": "Get Task",
|
||||
"description": "Get a single task by ID from Attio"
|
||||
},
|
||||
{
|
||||
"name": "Create Task",
|
||||
"description": "Create a task in Attio"
|
||||
@@ -1039,7 +1043,7 @@
|
||||
"description": "Delete a webhook from Attio"
|
||||
}
|
||||
],
|
||||
"operationCount": 40,
|
||||
"operationCount": 41,
|
||||
"triggers": [
|
||||
{
|
||||
"id": "attio_record_created",
|
||||
@@ -1126,13 +1130,33 @@
|
||||
"name": "Attio List Entry Deleted",
|
||||
"description": "Trigger workflow when a list entry is deleted in Attio"
|
||||
},
|
||||
{
|
||||
"id": "attio_list_created",
|
||||
"name": "Attio List Created",
|
||||
"description": "Trigger workflow when a list is created in Attio"
|
||||
},
|
||||
{
|
||||
"id": "attio_list_updated",
|
||||
"name": "Attio List Updated",
|
||||
"description": "Trigger workflow when a list is updated in Attio"
|
||||
},
|
||||
{
|
||||
"id": "attio_list_deleted",
|
||||
"name": "Attio List Deleted",
|
||||
"description": "Trigger workflow when a list is deleted in Attio"
|
||||
},
|
||||
{
|
||||
"id": "attio_workspace_member_created",
|
||||
"name": "Attio Workspace Member Created",
|
||||
"description": "Trigger workflow when a new member is added to the Attio workspace"
|
||||
},
|
||||
{
|
||||
"id": "attio_webhook",
|
||||
"name": "Attio Webhook (All Events)",
|
||||
"description": "Trigger workflow on any Attio webhook event"
|
||||
}
|
||||
],
|
||||
"triggerCount": 18,
|
||||
"triggerCount": 22,
|
||||
"authType": "oauth",
|
||||
"category": "tools",
|
||||
"integrationType": "crm",
|
||||
|
||||
@@ -36,6 +36,7 @@ export const AttioBlock: BlockConfig<AttioResponse> = {
|
||||
{ label: 'Create Note', id: 'create_note' },
|
||||
{ label: 'Delete Note', id: 'delete_note' },
|
||||
{ label: 'List Tasks', id: 'list_tasks' },
|
||||
{ label: 'Get Task', id: 'get_task' },
|
||||
{ label: 'Create Task', id: 'create_task' },
|
||||
{ label: 'Update Task', id: 'update_task' },
|
||||
{ label: 'Delete Task', id: 'delete_task' },
|
||||
@@ -490,8 +491,8 @@ Return ONLY the JSON array. No explanations, no markdown, no extra text.
|
||||
title: 'Task ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'Enter the task ID',
|
||||
condition: { field: 'operation', value: ['update_task', 'delete_task'] },
|
||||
required: { field: 'operation', value: ['update_task', 'delete_task'] },
|
||||
condition: { field: 'operation', value: ['get_task', 'update_task', 'delete_task'] },
|
||||
required: { field: 'operation', value: ['get_task', 'update_task', 'delete_task'] },
|
||||
},
|
||||
{
|
||||
id: 'taskFilterObject',
|
||||
@@ -944,7 +945,7 @@ YYYY-MM-DDTHH:mm:ss.SSSZ
|
||||
type: 'short-input',
|
||||
placeholder: 'https://example.com/webhook',
|
||||
condition: { field: 'operation', value: ['create_webhook', 'update_webhook'] },
|
||||
required: { field: 'operation', value: ['create_webhook', 'update_webhook'] },
|
||||
required: { field: 'operation', value: 'create_webhook' },
|
||||
},
|
||||
{
|
||||
id: 'webhookSubscriptions',
|
||||
@@ -952,7 +953,7 @@ YYYY-MM-DDTHH:mm:ss.SSSZ
|
||||
type: 'code',
|
||||
placeholder: '[{"event_type":"record.created","filter":{"object_id":"..."}}]',
|
||||
condition: { field: 'operation', value: ['create_webhook', 'update_webhook'] },
|
||||
required: { field: 'operation', value: ['create_webhook', 'update_webhook'] },
|
||||
required: { field: 'operation', value: 'create_webhook' },
|
||||
wandConfig: {
|
||||
enabled: true,
|
||||
maintainHistory: true,
|
||||
@@ -1040,6 +1041,10 @@ workspace-member.created
|
||||
...getTrigger('attio_list_entry_created').subBlocks,
|
||||
...getTrigger('attio_list_entry_updated').subBlocks,
|
||||
...getTrigger('attio_list_entry_deleted').subBlocks,
|
||||
...getTrigger('attio_list_created').subBlocks,
|
||||
...getTrigger('attio_list_updated').subBlocks,
|
||||
...getTrigger('attio_list_deleted').subBlocks,
|
||||
...getTrigger('attio_workspace_member_created').subBlocks,
|
||||
...getTrigger('attio_webhook').subBlocks,
|
||||
],
|
||||
|
||||
@@ -1063,6 +1068,10 @@ workspace-member.created
|
||||
'attio_list_entry_created',
|
||||
'attio_list_entry_updated',
|
||||
'attio_list_entry_deleted',
|
||||
'attio_list_created',
|
||||
'attio_list_updated',
|
||||
'attio_list_deleted',
|
||||
'attio_workspace_member_created',
|
||||
'attio_webhook',
|
||||
],
|
||||
},
|
||||
@@ -1081,6 +1090,7 @@ workspace-member.created
|
||||
'attio_create_note',
|
||||
'attio_delete_note',
|
||||
'attio_list_tasks',
|
||||
'attio_get_task',
|
||||
'attio_create_task',
|
||||
'attio_update_task',
|
||||
'attio_delete_task',
|
||||
|
||||
@@ -1311,6 +1311,8 @@ export async function formatWebhookInput(
|
||||
extractAttioCommentData,
|
||||
extractAttioListEntryData,
|
||||
extractAttioListEntryUpdatedData,
|
||||
extractAttioListData,
|
||||
extractAttioWorkspaceMemberData,
|
||||
extractAttioGenericData,
|
||||
} = await import('@/triggers/attio/utils')
|
||||
|
||||
@@ -1341,6 +1343,16 @@ export async function formatWebhookInput(
|
||||
if (triggerId === 'attio_list_entry_created' || triggerId === 'attio_list_entry_deleted') {
|
||||
return extractAttioListEntryData(body)
|
||||
}
|
||||
if (
|
||||
triggerId === 'attio_list_created' ||
|
||||
triggerId === 'attio_list_updated' ||
|
||||
triggerId === 'attio_list_deleted'
|
||||
) {
|
||||
return extractAttioListData(body)
|
||||
}
|
||||
if (triggerId === 'attio_workspace_member_created') {
|
||||
return extractAttioWorkspaceMemberData(body)
|
||||
}
|
||||
return extractAttioGenericData(body)
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ export const attioAssertRecordTool: ToolConfig<AttioAssertRecordParams, AttioAss
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://api.attio.com/v2/objects/${params.objectType}/records?matching_attribute=${params.matchingAttribute}`,
|
||||
`https://api.attio.com/v2/objects/${params.objectType.trim()}/records?matching_attribute=${params.matchingAttribute.trim()}`,
|
||||
method: 'PUT',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -53,7 +53,7 @@ export const attioCreateListEntryTool: ToolConfig<
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.attio.com/v2/lists/${params.list}/entries`,
|
||||
url: (params) => `https://api.attio.com/v2/lists/${params.list.trim()}/entries`,
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -39,7 +39,7 @@ export const attioCreateRecordTool: ToolConfig<AttioCreateRecordParams, AttioCre
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.attio.com/v2/objects/${params.objectType}/records`,
|
||||
url: (params) => `https://api.attio.com/v2/objects/${params.objectType.trim()}/records`,
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -34,7 +34,7 @@ export const attioDeleteCommentTool: ToolConfig<
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.attio.com/v2/comments/${params.commentId}`,
|
||||
url: (params) => `https://api.attio.com/v2/comments/${params.commentId.trim()}`,
|
||||
method: 'DELETE',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -40,7 +40,8 @@ export const attioDeleteListEntryTool: ToolConfig<
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.attio.com/v2/lists/${params.list}/entries/${params.entryId}`,
|
||||
url: (params) =>
|
||||
`https://api.attio.com/v2/lists/${params.list.trim()}/entries/${params.entryId.trim()}`,
|
||||
method: 'DELETE',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -31,7 +31,7 @@ export const attioDeleteNoteTool: ToolConfig<AttioDeleteNoteParams, AttioDeleteN
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.attio.com/v2/notes/${params.noteId}`,
|
||||
url: (params) => `https://api.attio.com/v2/notes/${params.noteId.trim()}`,
|
||||
method: 'DELETE',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -39,7 +39,7 @@ export const attioDeleteRecordTool: ToolConfig<AttioDeleteRecordParams, AttioDel
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://api.attio.com/v2/objects/${params.objectType}/records/${params.recordId}`,
|
||||
`https://api.attio.com/v2/objects/${params.objectType.trim()}/records/${params.recordId.trim()}`,
|
||||
method: 'DELETE',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -31,7 +31,7 @@ export const attioDeleteTaskTool: ToolConfig<AttioDeleteTaskParams, AttioDeleteT
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.attio.com/v2/tasks/${params.taskId}`,
|
||||
url: (params) => `https://api.attio.com/v2/tasks/${params.taskId.trim()}`,
|
||||
method: 'DELETE',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -34,7 +34,7 @@ export const attioDeleteWebhookTool: ToolConfig<
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.attio.com/v2/webhooks/${params.webhookId}`,
|
||||
url: (params) => `https://api.attio.com/v2/webhooks/${params.webhookId.trim()}`,
|
||||
method: 'DELETE',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -32,7 +32,7 @@ export const attioGetCommentTool: ToolConfig<AttioGetCommentParams, AttioGetComm
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.attio.com/v2/comments/${params.commentId}`,
|
||||
url: (params) => `https://api.attio.com/v2/comments/${params.commentId.trim()}`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -32,7 +32,7 @@ export const attioGetListTool: ToolConfig<AttioGetListParams, AttioGetListRespon
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.attio.com/v2/lists/${params.list}`,
|
||||
url: (params) => `https://api.attio.com/v2/lists/${params.list.trim()}`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -39,7 +39,8 @@ export const attioGetListEntryTool: ToolConfig<AttioGetListEntryParams, AttioGet
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.attio.com/v2/lists/${params.list}/entries/${params.entryId}`,
|
||||
url: (params) =>
|
||||
`https://api.attio.com/v2/lists/${params.list.trim()}/entries/${params.entryId.trim()}`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -32,7 +32,7 @@ export const attioGetMemberTool: ToolConfig<AttioGetMemberParams, AttioGetMember
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.attio.com/v2/workspace_members/${params.memberId}`,
|
||||
url: (params) => `https://api.attio.com/v2/workspace_members/${params.memberId.trim()}`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -32,7 +32,7 @@ export const attioGetNoteTool: ToolConfig<AttioGetNoteParams, AttioGetNoteRespon
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.attio.com/v2/notes/${params.noteId}`,
|
||||
url: (params) => `https://api.attio.com/v2/notes/${params.noteId.trim()}`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -32,7 +32,7 @@ export const attioGetObjectTool: ToolConfig<AttioGetObjectParams, AttioGetObject
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.attio.com/v2/objects/${params.object}`,
|
||||
url: (params) => `https://api.attio.com/v2/objects/${params.object.trim()}`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -39,7 +39,7 @@ export const attioGetRecordTool: ToolConfig<AttioGetRecordParams, AttioGetRecord
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://api.attio.com/v2/objects/${params.objectType}/records/${params.recordId}`,
|
||||
`https://api.attio.com/v2/objects/${params.objectType.trim()}/records/${params.recordId.trim()}`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
78
apps/sim/tools/attio/get_task.ts
Normal file
78
apps/sim/tools/attio/get_task.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
import type { AttioGetTaskParams, AttioGetTaskResponse } from './types'
|
||||
import { TASK_OUTPUT_PROPERTIES } from './types'
|
||||
|
||||
const logger = createLogger('AttioGetTask')
|
||||
|
||||
export const attioGetTaskTool: ToolConfig<AttioGetTaskParams, AttioGetTaskResponse> = {
|
||||
id: 'attio_get_task',
|
||||
name: 'Attio Get Task',
|
||||
description: 'Get a single task by ID from Attio',
|
||||
version: '1.0.0',
|
||||
|
||||
oauth: {
|
||||
required: true,
|
||||
provider: 'attio',
|
||||
},
|
||||
|
||||
params: {
|
||||
accessToken: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'hidden',
|
||||
description: 'The OAuth access token for the Attio API',
|
||||
},
|
||||
taskId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'The ID of the task to retrieve',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.attio.com/v2/tasks/${params.taskId.trim()}`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response) => {
|
||||
const data = await response.json()
|
||||
if (!response.ok) {
|
||||
logger.error('Attio API request failed', { data, status: response.status })
|
||||
throw new Error(data.message || 'Failed to get task')
|
||||
}
|
||||
const task = data.data
|
||||
const linkedRecords = (task.linked_records ?? []).map(
|
||||
(r: { target_object_id?: string; target_record_id?: string }) => ({
|
||||
targetObjectId: r.target_object_id ?? null,
|
||||
targetRecordId: r.target_record_id ?? null,
|
||||
})
|
||||
)
|
||||
const assignees = (task.assignees ?? []).map(
|
||||
(a: { referenced_actor_type?: string; referenced_actor_id?: string }) => ({
|
||||
type: a.referenced_actor_type ?? null,
|
||||
id: a.referenced_actor_id ?? null,
|
||||
})
|
||||
)
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
taskId: task.id?.task_id ?? null,
|
||||
content: task.content_plaintext ?? null,
|
||||
deadlineAt: task.deadline_at ?? null,
|
||||
isCompleted: task.is_completed ?? false,
|
||||
linkedRecords,
|
||||
assignees,
|
||||
createdByActor: task.created_by_actor ?? null,
|
||||
createdAt: task.created_at ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: TASK_OUTPUT_PROPERTIES,
|
||||
}
|
||||
@@ -32,7 +32,7 @@ export const attioGetThreadTool: ToolConfig<AttioGetThreadParams, AttioGetThread
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.attio.com/v2/threads/${params.threadId}`,
|
||||
url: (params) => `https://api.attio.com/v2/threads/${params.threadId.trim()}`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -32,7 +32,7 @@ export const attioGetWebhookTool: ToolConfig<AttioGetWebhookParams, AttioGetWebh
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.attio.com/v2/webhooks/${params.webhookId}`,
|
||||
url: (params) => `https://api.attio.com/v2/webhooks/${params.webhookId.trim()}`,
|
||||
method: 'GET',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -20,6 +20,7 @@ export { attioGetMemberTool } from './get_member'
|
||||
export { attioGetNoteTool } from './get_note'
|
||||
export { attioGetObjectTool } from './get_object'
|
||||
export { attioGetRecordTool } from './get_record'
|
||||
export { attioGetTaskTool } from './get_task'
|
||||
export { attioGetThreadTool } from './get_thread'
|
||||
export { attioGetWebhookTool } from './get_webhook'
|
||||
export { attioListListsTool } from './list_lists'
|
||||
|
||||
@@ -56,7 +56,7 @@ export const attioListRecordsTool: ToolConfig<AttioListRecordsParams, AttioListR
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.attio.com/v2/objects/${params.objectType}/records/query`,
|
||||
url: (params) => `https://api.attio.com/v2/objects/${params.objectType.trim()}/records/query`,
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -60,7 +60,7 @@ export const attioQueryListEntriesTool: ToolConfig<
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.attio.com/v2/lists/${params.list}/entries/query`,
|
||||
url: (params) => `https://api.attio.com/v2/lists/${params.list.trim()}/entries/query`,
|
||||
method: 'POST',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -529,6 +529,26 @@ export interface AttioUpdateTaskResponse extends ToolResponse {
|
||||
}
|
||||
}
|
||||
|
||||
/** Params for getting a single task */
|
||||
export interface AttioGetTaskParams {
|
||||
accessToken: string
|
||||
taskId: string
|
||||
}
|
||||
|
||||
/** Response for getting a single task */
|
||||
export interface AttioGetTaskResponse extends ToolResponse {
|
||||
output: {
|
||||
taskId: string | null
|
||||
content: string | null
|
||||
deadlineAt: string | null
|
||||
isCompleted: boolean
|
||||
linkedRecords: Array<{ targetObjectId: string | null; targetRecordId: string | null }>
|
||||
assignees: Array<{ type: string | null; id: string | null }>
|
||||
createdByActor: unknown
|
||||
createdAt: string | null
|
||||
}
|
||||
}
|
||||
|
||||
/** Response for deleting a task */
|
||||
export interface AttioDeleteTaskResponse extends ToolResponse {
|
||||
output: {
|
||||
@@ -1093,6 +1113,7 @@ export type AttioResponse =
|
||||
| AttioListTasksResponse
|
||||
| AttioCreateTaskResponse
|
||||
| AttioUpdateTaskResponse
|
||||
| AttioGetTaskResponse
|
||||
| AttioDeleteTaskResponse
|
||||
| AttioListObjectsResponse
|
||||
| AttioGetObjectResponse
|
||||
|
||||
@@ -58,7 +58,7 @@ export const attioUpdateListTool: ToolConfig<AttioUpdateListParams, AttioUpdateL
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.attio.com/v2/lists/${params.list}`,
|
||||
url: (params) => `https://api.attio.com/v2/lists/${params.list.trim()}`,
|
||||
method: 'PATCH',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -47,7 +47,8 @@ export const attioUpdateListEntryTool: ToolConfig<
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.attio.com/v2/lists/${params.list}/entries/${params.entryId}`,
|
||||
url: (params) =>
|
||||
`https://api.attio.com/v2/lists/${params.list.trim()}/entries/${params.entryId.trim()}`,
|
||||
method: 'PATCH',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -51,7 +51,7 @@ export const attioUpdateObjectTool: ToolConfig<AttioUpdateObjectParams, AttioUpd
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.attio.com/v2/objects/${params.object}`,
|
||||
url: (params) => `https://api.attio.com/v2/objects/${params.object.trim()}`,
|
||||
method: 'PATCH',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -46,7 +46,7 @@ export const attioUpdateRecordTool: ToolConfig<AttioUpdateRecordParams, AttioUpd
|
||||
|
||||
request: {
|
||||
url: (params) =>
|
||||
`https://api.attio.com/v2/objects/${params.objectType}/records/${params.recordId}`,
|
||||
`https://api.attio.com/v2/objects/${params.objectType.trim()}/records/${params.recordId.trim()}`,
|
||||
method: 'PATCH',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -56,7 +56,7 @@ export const attioUpdateTaskTool: ToolConfig<AttioUpdateTaskParams, AttioUpdateT
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.attio.com/v2/tasks/${params.taskId}`,
|
||||
url: (params) => `https://api.attio.com/v2/tasks/${params.taskId.trim()}`,
|
||||
method: 'PATCH',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
|
||||
@@ -34,41 +34,38 @@ export const attioUpdateWebhookTool: ToolConfig<
|
||||
},
|
||||
targetUrl: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'HTTPS target URL for webhook delivery',
|
||||
},
|
||||
subscriptions: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'JSON array of subscriptions, e.g. [{"event_type":"note.created"}]',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => `https://api.attio.com/v2/webhooks/${params.webhookId}`,
|
||||
url: (params) => `https://api.attio.com/v2/webhooks/${params.webhookId.trim()}`,
|
||||
method: 'PATCH',
|
||||
headers: (params) => ({
|
||||
Authorization: `Bearer ${params.accessToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
body: (params) => {
|
||||
let subscriptions: unknown = []
|
||||
const data: Record<string, unknown> = {}
|
||||
if (params.targetUrl) data.target_url = params.targetUrl.trim()
|
||||
if (params.subscriptions) {
|
||||
try {
|
||||
subscriptions =
|
||||
data.subscriptions =
|
||||
typeof params.subscriptions === 'string'
|
||||
? JSON.parse(params.subscriptions)
|
||||
: params.subscriptions
|
||||
} catch {
|
||||
subscriptions = []
|
||||
data.subscriptions = []
|
||||
}
|
||||
}
|
||||
const data: Record<string, unknown> = {
|
||||
target_url: params.targetUrl,
|
||||
subscriptions,
|
||||
}
|
||||
return { data }
|
||||
},
|
||||
},
|
||||
|
||||
@@ -149,6 +149,7 @@ import {
|
||||
attioGetNoteTool,
|
||||
attioGetObjectTool,
|
||||
attioGetRecordTool,
|
||||
attioGetTaskTool,
|
||||
attioGetThreadTool,
|
||||
attioGetWebhookTool,
|
||||
attioListListsTool,
|
||||
@@ -3970,6 +3971,7 @@ export const tools: Record<string, ToolConfig> = {
|
||||
attio_get_note: attioGetNoteTool,
|
||||
attio_get_object: attioGetObjectTool,
|
||||
attio_get_record: attioGetRecordTool,
|
||||
attio_get_task: attioGetTaskTool,
|
||||
attio_get_thread: attioGetThreadTool,
|
||||
attio_get_webhook: attioGetWebhookTool,
|
||||
attio_list_lists: attioListListsTool,
|
||||
|
||||
@@ -2,9 +2,12 @@ export { attioCommentCreatedTrigger } from './comment_created'
|
||||
export { attioCommentDeletedTrigger } from './comment_deleted'
|
||||
export { attioCommentResolvedTrigger } from './comment_resolved'
|
||||
export { attioCommentUnresolvedTrigger } from './comment_unresolved'
|
||||
export { attioListCreatedTrigger } from './list_created'
|
||||
export { attioListDeletedTrigger } from './list_deleted'
|
||||
export { attioListEntryCreatedTrigger } from './list_entry_created'
|
||||
export { attioListEntryDeletedTrigger } from './list_entry_deleted'
|
||||
export { attioListEntryUpdatedTrigger } from './list_entry_updated'
|
||||
export { attioListUpdatedTrigger } from './list_updated'
|
||||
export { attioNoteCreatedTrigger } from './note_created'
|
||||
export { attioNoteDeletedTrigger } from './note_deleted'
|
||||
export { attioNoteUpdatedTrigger } from './note_updated'
|
||||
@@ -16,3 +19,4 @@ export { attioTaskCreatedTrigger } from './task_created'
|
||||
export { attioTaskDeletedTrigger } from './task_deleted'
|
||||
export { attioTaskUpdatedTrigger } from './task_updated'
|
||||
export { attioWebhookTrigger } from './webhook'
|
||||
export { attioWorkspaceMemberCreatedTrigger } from './workspace_member_created'
|
||||
|
||||
29
apps/sim/triggers/attio/list_created.ts
Normal file
29
apps/sim/triggers/attio/list_created.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildListOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio List Created Trigger
|
||||
*
|
||||
* Triggers when a list is created in Attio.
|
||||
*/
|
||||
export const attioListCreatedTrigger: TriggerConfig = {
|
||||
id: 'attio_list_created',
|
||||
name: 'Attio List Created',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a list is created in Attio',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_list_created'),
|
||||
|
||||
outputs: buildListOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
29
apps/sim/triggers/attio/list_deleted.ts
Normal file
29
apps/sim/triggers/attio/list_deleted.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildListOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio List Deleted Trigger
|
||||
*
|
||||
* Triggers when a list is deleted in Attio.
|
||||
*/
|
||||
export const attioListDeletedTrigger: TriggerConfig = {
|
||||
id: 'attio_list_deleted',
|
||||
name: 'Attio List Deleted',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a list is deleted in Attio',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_list_deleted'),
|
||||
|
||||
outputs: buildListOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
29
apps/sim/triggers/attio/list_updated.ts
Normal file
29
apps/sim/triggers/attio/list_updated.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildListOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio List Updated Trigger
|
||||
*
|
||||
* Triggers when a list is updated in Attio.
|
||||
*/
|
||||
export const attioListUpdatedTrigger: TriggerConfig = {
|
||||
id: 'attio_list_updated',
|
||||
name: 'Attio List Updated',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a list is updated in Attio',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_list_updated'),
|
||||
|
||||
outputs: buildListOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -19,6 +19,10 @@ export const attioTriggerOptions = [
|
||||
{ label: 'List Entry Created', id: 'attio_list_entry_created' },
|
||||
{ label: 'List Entry Updated', id: 'attio_list_entry_updated' },
|
||||
{ label: 'List Entry Deleted', id: 'attio_list_entry_deleted' },
|
||||
{ label: 'List Created', id: 'attio_list_created' },
|
||||
{ label: 'List Updated', id: 'attio_list_updated' },
|
||||
{ label: 'List Deleted', id: 'attio_list_deleted' },
|
||||
{ label: 'Workspace Member Created', id: 'attio_workspace_member_created' },
|
||||
{ label: 'Generic Webhook (All Events)', id: 'attio_webhook' },
|
||||
]
|
||||
|
||||
@@ -235,6 +239,42 @@ export function buildCommentOutputs(): Record<string, TriggerOutput> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List event outputs.
|
||||
*/
|
||||
function buildListIdOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
workspaceId: { type: 'string', description: 'The workspace ID' },
|
||||
listId: { type: 'string', description: 'The list ID' },
|
||||
}
|
||||
}
|
||||
|
||||
/** List created/updated/deleted outputs. */
|
||||
export function buildListOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...buildBaseWebhookOutputs(),
|
||||
...buildListIdOutputs(),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Workspace member event outputs.
|
||||
*/
|
||||
function buildWorkspaceMemberIdOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
workspaceId: { type: 'string', description: 'The workspace ID' },
|
||||
workspaceMemberId: { type: 'string', description: 'The workspace member ID' },
|
||||
}
|
||||
}
|
||||
|
||||
/** Workspace member outputs. */
|
||||
export function buildWorkspaceMemberOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
...buildBaseWebhookOutputs(),
|
||||
...buildWorkspaceMemberIdOutputs(),
|
||||
}
|
||||
}
|
||||
|
||||
/** List entry created/deleted outputs. */
|
||||
export function buildListEntryOutputs(): Record<string, TriggerOutput> {
|
||||
return {
|
||||
@@ -276,7 +316,7 @@ export const TRIGGER_EVENT_MAP: Record<string, string[]> = {
|
||||
attio_record_deleted: ['record.deleted'],
|
||||
attio_record_merged: ['record.merged'],
|
||||
attio_note_created: ['note.created'],
|
||||
attio_note_updated: ['note.updated', 'note.content-updated'],
|
||||
attio_note_updated: ['note.updated', 'note-content.updated'],
|
||||
attio_note_deleted: ['note.deleted'],
|
||||
attio_task_created: ['task.created'],
|
||||
attio_task_updated: ['task.updated'],
|
||||
@@ -288,6 +328,10 @@ export const TRIGGER_EVENT_MAP: Record<string, string[]> = {
|
||||
attio_list_entry_created: ['list-entry.created'],
|
||||
attio_list_entry_updated: ['list-entry.updated'],
|
||||
attio_list_entry_deleted: ['list-entry.deleted'],
|
||||
attio_list_created: ['list.created'],
|
||||
attio_list_updated: ['list.updated'],
|
||||
attio_list_deleted: ['list.deleted'],
|
||||
attio_workspace_member_created: ['workspace-member.created'],
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -445,6 +489,35 @@ export function extractAttioListEntryUpdatedData(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts formatted data from an Attio list event payload.
|
||||
* Used for list.created, list.updated, list.deleted triggers.
|
||||
*/
|
||||
export function extractAttioListData(body: Record<string, unknown>): Record<string, unknown> {
|
||||
const event = getAttioEvent(body) ?? {}
|
||||
const id = (event.id as Record<string, unknown>) ?? {}
|
||||
return {
|
||||
eventType: event.event_type ?? null,
|
||||
workspaceId: id.workspace_id ?? null,
|
||||
listId: id.list_id ?? null,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts formatted data from an Attio workspace-member.created event payload.
|
||||
*/
|
||||
export function extractAttioWorkspaceMemberData(
|
||||
body: Record<string, unknown>
|
||||
): Record<string, unknown> {
|
||||
const event = getAttioEvent(body) ?? {}
|
||||
const id = (event.id as Record<string, unknown>) ?? {}
|
||||
return {
|
||||
eventType: event.event_type ?? null,
|
||||
workspaceId: id.workspace_id ?? null,
|
||||
workspaceMemberId: id.workspace_member_id ?? null,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts formatted data from a generic Attio webhook payload.
|
||||
* Passes through the first event with camelCase field mapping.
|
||||
|
||||
29
apps/sim/triggers/attio/workspace_member_created.ts
Normal file
29
apps/sim/triggers/attio/workspace_member_created.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { AttioIcon } from '@/components/icons'
|
||||
import { buildAttioTriggerSubBlocks, buildWorkspaceMemberOutputs } from '@/triggers/attio/utils'
|
||||
import type { TriggerConfig } from '@/triggers/types'
|
||||
|
||||
/**
|
||||
* Attio Workspace Member Created Trigger
|
||||
*
|
||||
* Triggers when a new member is added to the Attio workspace.
|
||||
*/
|
||||
export const attioWorkspaceMemberCreatedTrigger: TriggerConfig = {
|
||||
id: 'attio_workspace_member_created',
|
||||
name: 'Attio Workspace Member Created',
|
||||
provider: 'attio',
|
||||
description: 'Trigger workflow when a new member is added to the Attio workspace',
|
||||
version: '1.0.0',
|
||||
icon: AttioIcon,
|
||||
|
||||
subBlocks: buildAttioTriggerSubBlocks('attio_workspace_member_created'),
|
||||
|
||||
outputs: buildWorkspaceMemberOutputs(),
|
||||
|
||||
webhook: {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Attio-Signature': 'hmac-sha256-signature',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -12,9 +12,12 @@ import {
|
||||
attioCommentDeletedTrigger,
|
||||
attioCommentResolvedTrigger,
|
||||
attioCommentUnresolvedTrigger,
|
||||
attioListCreatedTrigger,
|
||||
attioListDeletedTrigger,
|
||||
attioListEntryCreatedTrigger,
|
||||
attioListEntryDeletedTrigger,
|
||||
attioListEntryUpdatedTrigger,
|
||||
attioListUpdatedTrigger,
|
||||
attioNoteCreatedTrigger,
|
||||
attioNoteDeletedTrigger,
|
||||
attioNoteUpdatedTrigger,
|
||||
@@ -26,6 +29,7 @@ import {
|
||||
attioTaskDeletedTrigger,
|
||||
attioTaskUpdatedTrigger,
|
||||
attioWebhookTrigger,
|
||||
attioWorkspaceMemberCreatedTrigger,
|
||||
} from '@/triggers/attio'
|
||||
import {
|
||||
calcomBookingCancelledTrigger,
|
||||
@@ -200,6 +204,10 @@ export const TRIGGER_REGISTRY: TriggerRegistry = {
|
||||
attio_list_entry_created: attioListEntryCreatedTrigger,
|
||||
attio_list_entry_updated: attioListEntryUpdatedTrigger,
|
||||
attio_list_entry_deleted: attioListEntryDeletedTrigger,
|
||||
attio_list_created: attioListCreatedTrigger,
|
||||
attio_list_updated: attioListUpdatedTrigger,
|
||||
attio_list_deleted: attioListDeletedTrigger,
|
||||
attio_workspace_member_created: attioWorkspaceMemberCreatedTrigger,
|
||||
calendly_webhook: calendlyWebhookTrigger,
|
||||
calendly_invitee_created: calendlyInviteeCreatedTrigger,
|
||||
calendly_invitee_canceled: calendlyInviteeCanceledTrigger,
|
||||
|
||||
Reference in New Issue
Block a user