mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-06 03:00:16 -04:00
* improvement(oauth): centralize scopes and remove dead scope evaluation code Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(oauth): fix stale scope-descriptions.ts references and add test coverage Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
274 lines
9.0 KiB
TypeScript
274 lines
9.0 KiB
TypeScript
import { WealthboxIcon } from '@/components/icons'
|
|
import { getScopesForService } from '@/lib/oauth/utils'
|
|
import type { BlockConfig } from '@/blocks/types'
|
|
import { AuthMode } from '@/blocks/types'
|
|
import type { WealthboxResponse } from '@/tools/wealthbox/types'
|
|
|
|
export const WealthboxBlock: BlockConfig<WealthboxResponse> = {
|
|
type: 'wealthbox',
|
|
name: 'Wealthbox',
|
|
description: 'Interact with Wealthbox',
|
|
authMode: AuthMode.OAuth,
|
|
longDescription:
|
|
'Integrate Wealthbox into the workflow. Can read and write notes, read and write contacts, and read and write tasks.',
|
|
docsLink: 'https://docs.sim.ai/tools/wealthbox',
|
|
category: 'tools',
|
|
bgColor: '#E0E0E0',
|
|
icon: WealthboxIcon,
|
|
subBlocks: [
|
|
{
|
|
id: 'operation',
|
|
title: 'Operation',
|
|
type: 'dropdown',
|
|
options: [
|
|
{ label: 'Read Note', id: 'read_note' },
|
|
{ label: 'Write Note', id: 'write_note' },
|
|
{ label: 'Read Contact', id: 'read_contact' },
|
|
{ label: 'Write Contact', id: 'write_contact' },
|
|
{ label: 'Read Task', id: 'read_task' },
|
|
{ label: 'Write Task', id: 'write_task' },
|
|
],
|
|
value: () => 'read_note',
|
|
},
|
|
{
|
|
id: 'credential',
|
|
title: 'Wealthbox Account',
|
|
type: 'oauth-input',
|
|
canonicalParamId: 'oauthCredential',
|
|
mode: 'basic',
|
|
serviceId: 'wealthbox',
|
|
requiredScopes: getScopesForService('wealthbox'),
|
|
placeholder: 'Select Wealthbox account',
|
|
required: true,
|
|
},
|
|
{
|
|
id: 'manualCredential',
|
|
title: 'Wealthbox Account',
|
|
type: 'short-input',
|
|
canonicalParamId: 'oauthCredential',
|
|
mode: 'advanced',
|
|
placeholder: 'Enter credential ID',
|
|
required: true,
|
|
},
|
|
{
|
|
id: 'noteId',
|
|
title: 'Note ID',
|
|
type: 'short-input',
|
|
placeholder: 'Enter Note ID (optional)',
|
|
condition: { field: 'operation', value: ['read_note'] },
|
|
},
|
|
{
|
|
id: 'contactId',
|
|
title: 'Select Contact',
|
|
type: 'file-selector',
|
|
serviceId: 'wealthbox',
|
|
selectorKey: 'wealthbox.contacts',
|
|
requiredScopes: getScopesForService('wealthbox'),
|
|
placeholder: 'Enter Contact ID',
|
|
mode: 'basic',
|
|
canonicalParamId: 'contactId',
|
|
condition: { field: 'operation', value: ['read_contact', 'write_task', 'write_note'] },
|
|
},
|
|
{
|
|
id: 'manualContactId',
|
|
title: 'Contact ID',
|
|
type: 'short-input',
|
|
canonicalParamId: 'contactId',
|
|
placeholder: 'Enter Contact ID',
|
|
mode: 'advanced',
|
|
condition: { field: 'operation', value: ['read_contact', 'write_task', 'write_note'] },
|
|
},
|
|
{
|
|
id: 'taskId',
|
|
title: 'Task ID',
|
|
type: 'short-input',
|
|
placeholder: 'Enter Task ID',
|
|
condition: { field: 'operation', value: ['read_task'] },
|
|
},
|
|
{
|
|
id: 'title',
|
|
title: 'Title',
|
|
type: 'short-input',
|
|
placeholder: 'Enter Title',
|
|
condition: { field: 'operation', value: ['write_task'] },
|
|
required: true,
|
|
},
|
|
{
|
|
id: 'dueDate',
|
|
title: 'Due Date',
|
|
type: 'short-input',
|
|
placeholder: 'Enter due date (e.g., 2015-05-24 11:00 AM -0400)',
|
|
condition: { field: 'operation', value: ['write_task'] },
|
|
required: true,
|
|
wandConfig: {
|
|
enabled: true,
|
|
prompt: `Generate a date/time string based on the user's description.
|
|
The format should be: YYYY-MM-DD HH:MM AM/PM ZZZZ (e.g., 2015-05-24 11:00 AM -0400).
|
|
Examples:
|
|
- "tomorrow at 2pm" -> Calculate tomorrow's date at 02:00 PM with local timezone offset
|
|
- "next Monday at 9am" -> Calculate next Monday at 09:00 AM with local timezone offset
|
|
- "in 3 days at noon" -> Calculate 3 days from now at 12:00 PM with local timezone offset
|
|
|
|
Return ONLY the date/time string - no explanations, no quotes, no extra text.`,
|
|
placeholder: 'Describe the due date (e.g., "tomorrow at 2pm", "next Friday morning")...',
|
|
generationType: 'timestamp',
|
|
},
|
|
},
|
|
{
|
|
id: 'firstName',
|
|
title: 'First Name',
|
|
type: 'short-input',
|
|
placeholder: 'Enter First Name',
|
|
condition: { field: 'operation', value: ['write_contact'] },
|
|
required: true,
|
|
},
|
|
{
|
|
id: 'lastName',
|
|
title: 'Last Name',
|
|
type: 'short-input',
|
|
placeholder: 'Enter Last Name',
|
|
condition: { field: 'operation', value: ['write_contact'] },
|
|
required: true,
|
|
},
|
|
{
|
|
id: 'emailAddress',
|
|
title: 'Email Address',
|
|
type: 'short-input',
|
|
placeholder: 'Enter Email Address',
|
|
condition: { field: 'operation', value: ['write_contact'] },
|
|
},
|
|
{
|
|
id: 'content',
|
|
title: 'Content',
|
|
type: 'long-input',
|
|
placeholder: 'Enter Content',
|
|
condition: { field: 'operation', value: ['write_note', 'write_event', 'write_task'] },
|
|
required: true,
|
|
},
|
|
{
|
|
id: 'backgroundInformation',
|
|
title: 'Background Information',
|
|
type: 'long-input',
|
|
placeholder: 'Enter Background Information',
|
|
condition: { field: 'operation', value: ['write_contact'] },
|
|
},
|
|
],
|
|
tools: {
|
|
access: [
|
|
'wealthbox_read_note',
|
|
'wealthbox_write_note',
|
|
'wealthbox_read_contact',
|
|
'wealthbox_write_contact',
|
|
'wealthbox_read_task',
|
|
'wealthbox_write_task',
|
|
],
|
|
config: {
|
|
tool: (params) => {
|
|
switch (params.operation) {
|
|
case 'read_note':
|
|
return 'wealthbox_read_note'
|
|
case 'write_note':
|
|
return 'wealthbox_write_note'
|
|
case 'read_contact':
|
|
return 'wealthbox_read_contact'
|
|
case 'write_contact':
|
|
return 'wealthbox_write_contact'
|
|
case 'read_task':
|
|
return 'wealthbox_read_task'
|
|
case 'write_task':
|
|
return 'wealthbox_write_task'
|
|
default:
|
|
throw new Error(`Unknown operation: ${params.operation}`)
|
|
}
|
|
},
|
|
params: (params) => {
|
|
const { oauthCredential, operation, contactId, taskId, ...rest } = params
|
|
|
|
// contactId is the canonical param for both basic (file-selector) and advanced (manualContactId) modes
|
|
const effectiveContactId = contactId ? String(contactId).trim() : ''
|
|
|
|
const baseParams = {
|
|
...rest,
|
|
credential: oauthCredential,
|
|
}
|
|
|
|
if (operation === 'read_note' || operation === 'write_note') {
|
|
return {
|
|
...baseParams,
|
|
noteId: params.noteId,
|
|
contactId: effectiveContactId,
|
|
}
|
|
}
|
|
if (operation === 'read_contact') {
|
|
if (!effectiveContactId) {
|
|
throw new Error('Contact ID is required for contact operations')
|
|
}
|
|
return {
|
|
...baseParams,
|
|
contactId: effectiveContactId,
|
|
}
|
|
}
|
|
if (operation === 'read_task') {
|
|
if (!taskId?.trim()) {
|
|
throw new Error('Task ID is required for task operations')
|
|
}
|
|
return {
|
|
...baseParams,
|
|
taskId: taskId.trim(),
|
|
}
|
|
}
|
|
if (operation === 'write_task' || operation === 'write_note') {
|
|
if (!contactId?.trim()) {
|
|
throw new Error('Contact ID is required for this operation')
|
|
}
|
|
return {
|
|
...baseParams,
|
|
contactId: contactId.trim(),
|
|
}
|
|
}
|
|
|
|
return baseParams
|
|
},
|
|
},
|
|
},
|
|
inputs: {
|
|
operation: { type: 'string', description: 'Operation to perform' },
|
|
oauthCredential: { type: 'string', description: 'Wealthbox access token' },
|
|
noteId: { type: 'string', description: 'Note identifier' },
|
|
contactId: { type: 'string', description: 'Contact identifier' },
|
|
taskId: { type: 'string', description: 'Task identifier' },
|
|
content: { type: 'string', description: 'Content text' },
|
|
firstName: { type: 'string', description: 'First name' },
|
|
lastName: { type: 'string', description: 'Last name' },
|
|
emailAddress: { type: 'string', description: 'Email address' },
|
|
backgroundInformation: { type: 'string', description: 'Background information' },
|
|
title: { type: 'string', description: 'Task title' },
|
|
dueDate: { type: 'string', description: 'Due date' },
|
|
},
|
|
outputs: {
|
|
note: {
|
|
type: 'json',
|
|
description: 'Single note object with ID, content, creator, and linked contacts',
|
|
},
|
|
notes: { type: 'json', description: 'Array of note objects from bulk read operations' },
|
|
contact: {
|
|
type: 'json',
|
|
description: 'Single contact object with name, email, phone, and background info',
|
|
},
|
|
contacts: { type: 'json', description: 'Array of contact objects from bulk read operations' },
|
|
task: {
|
|
type: 'json',
|
|
description: 'Single task object with name, due date, description, and priority',
|
|
},
|
|
tasks: { type: 'json', description: 'Array of task objects from bulk read operations' },
|
|
metadata: {
|
|
type: 'json',
|
|
description: 'Operation metadata with itemId, noteId, contactId, taskId, itemType',
|
|
},
|
|
success: {
|
|
type: 'boolean',
|
|
description: 'Boolean indicating whether the operation completed successfully',
|
|
},
|
|
},
|
|
}
|