mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-22 21:38:05 -05:00
feat(tools): added guesty tools/block
This commit is contained in:
99
blocks/blocks/guesty.ts
Normal file
99
blocks/blocks/guesty.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import { GuestyIcon } from '@/components/icons'
|
||||
import { GuestyGuestResponse } from '@/tools/guesty/guest'
|
||||
import { GuestyReservationResponse } from '@/tools/guesty/reservation'
|
||||
import { BlockConfig } from '../types'
|
||||
|
||||
export const GuestyBlock: BlockConfig<GuestyReservationResponse | GuestyGuestResponse> = {
|
||||
type: 'guesty',
|
||||
name: 'Guesty',
|
||||
description: 'Interact with Guesty property management system',
|
||||
longDescription:
|
||||
'Access Guesty property management data including reservations and guest information. Retrieve reservation details by ID or search for guests by phone number.',
|
||||
category: 'tools',
|
||||
bgColor: '#0051F8', // Guesty brand color
|
||||
icon: GuestyIcon,
|
||||
subBlocks: [
|
||||
{
|
||||
id: 'action',
|
||||
title: 'Action',
|
||||
type: 'dropdown',
|
||||
layout: 'full',
|
||||
options: [
|
||||
{ label: 'Get Reservation', id: 'reservation' },
|
||||
{ label: 'Search Guest', id: 'guest' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'reservationId',
|
||||
title: 'Reservation ID',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Enter reservation ID',
|
||||
condition: {
|
||||
field: 'action',
|
||||
value: 'reservation',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'phoneNumber',
|
||||
title: 'Phone Number',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Enter phone number',
|
||||
condition: {
|
||||
field: 'action',
|
||||
value: 'guest',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'apiKey',
|
||||
title: 'API Key',
|
||||
type: 'short-input',
|
||||
layout: 'full',
|
||||
placeholder: 'Enter your Guesty API key',
|
||||
password: true,
|
||||
connectionDroppable: false,
|
||||
},
|
||||
],
|
||||
tools: {
|
||||
access: ['guesty_reservation', 'guesty_guest'],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
return params.action === 'reservation' ? 'guesty_reservation' : 'guesty_guest'
|
||||
},
|
||||
params: (params) => {
|
||||
if (params.action === 'reservation') {
|
||||
return {
|
||||
apiKey: params.apiKey,
|
||||
reservationId: params.reservationId,
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
apiKey: params.apiKey,
|
||||
phoneNumber: params.phoneNumber,
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
inputs: {
|
||||
action: { type: 'string', required: true },
|
||||
apiKey: { type: 'string', required: true },
|
||||
reservationId: { type: 'string', required: false },
|
||||
phoneNumber: { type: 'string', required: false },
|
||||
},
|
||||
outputs: {
|
||||
response: {
|
||||
type: {
|
||||
id: 'string',
|
||||
guest: 'json',
|
||||
checkIn: 'string',
|
||||
checkOut: 'string',
|
||||
status: 'string',
|
||||
listing: 'json',
|
||||
money: 'json',
|
||||
guests: 'json',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import { FirecrawlBlock } from './blocks/firecrawl'
|
||||
import { FunctionBlock } from './blocks/function'
|
||||
import { GitHubBlock } from './blocks/github'
|
||||
import { GmailBlock } from './blocks/gmail'
|
||||
import { GuestyBlock } from './blocks/guesty'
|
||||
import { JinaBlock } from './blocks/jina'
|
||||
import { NotionBlock } from './blocks/notion'
|
||||
import { OpenAIBlock } from './blocks/openai'
|
||||
@@ -34,6 +35,7 @@ export {
|
||||
FunctionBlock,
|
||||
CrewAIVisionBlock,
|
||||
FirecrawlBlock,
|
||||
GuestyBlock,
|
||||
JinaBlock,
|
||||
TranslateBlock,
|
||||
SlackBlock,
|
||||
@@ -71,6 +73,7 @@ const blocks: Record<string, BlockConfig> = {
|
||||
gmail: GmailBlock,
|
||||
google_drive: GoogleDriveBlock,
|
||||
google_sheets: GoogleSheetsBlock,
|
||||
guesty: GuestyBlock,
|
||||
jina: JinaBlock,
|
||||
notion: NotionBlock,
|
||||
openai: OpenAIBlock,
|
||||
|
||||
@@ -1680,3 +1680,21 @@ export function StripeIcon(props: SVGProps<SVGSVGElement>) {
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function GuestyIcon(props: SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
{...props}
|
||||
width="101"
|
||||
height="100"
|
||||
viewBox="0 0 101 100"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M56.6019 2.6685C53.2445 0.339792 48.8025 0.308905 45.413 2.5907L44.1323 3.45286C44.1309 3.45379 44.1296 3.45471 44.1282 3.45564L5.37916 29.5416C5.37801 29.5424 5.37687 29.5431 5.37572 29.5439L4.37839 30.2153C1.64126 32.058 0 35.1414 0 38.441V90.0841C0 95.5599 4.4395 100 9.91593 100H67.4737C72.9501 100 77.389 95.5605 77.389 90.0841V49.6765C77.389 46.3038 75.675 43.1622 72.8385 41.3373L56.3027 30.6989C53.0908 28.6325 48.9777 28.5944 45.728 30.6009L28.3986 41.301C25.4732 43.1073 23.6922 46.3001 23.6922 49.7382V75.553H33.3248V51.0025C33.3248 50.1189 33.7823 49.2983 34.5337 48.8337L34.535 48.8329L49.5731 39.5476C50.408 39.0322 51.4645 39.0414 52.29 39.5714L66.5886 48.7705C67.3167 49.24 67.7564 50.0471 67.7564 50.9134V87.8176C67.7564 89.2256 66.6152 90.3674 65.2072 90.3674H12.1824C10.7742 90.3674 9.63262 89.2256 9.63262 87.8176V39.6474C9.63262 38.7995 10.0541 38.0071 10.7571 37.5331L49.5075 11.4463C50.3783 10.8601 51.5192 10.8675 52.3822 11.4646L89.8995 37.4867C89.9007 37.4877 89.9024 37.4886 89.9035 37.4896C90.588 37.9663 90.9959 38.7476 90.9959 39.5819V100H100.629V38.3956C100.629 35.1448 99.0352 32.1005 96.3641 30.2478L95.3969 29.5767C95.3941 29.575 95.3918 29.5733 95.3895 29.5717L56.6019 2.6685Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
84
tools/guesty/guest.ts
Normal file
84
tools/guesty/guest.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { ToolConfig, ToolResponse } from '../types'
|
||||
|
||||
export interface GuestyGuestParams {
|
||||
apiKey: string
|
||||
phoneNumber: string
|
||||
}
|
||||
|
||||
export interface GuestyGuestResponse extends ToolResponse {
|
||||
output: {
|
||||
guests: Array<{
|
||||
id: string
|
||||
fullName: string
|
||||
email: string
|
||||
phone: string
|
||||
address: string
|
||||
city: string
|
||||
country: string
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export const guestyGuestTool: ToolConfig<GuestyGuestParams, GuestyGuestResponse> = {
|
||||
id: 'guesty_guest',
|
||||
name: 'Guesty Guest',
|
||||
description: 'Search for guests in Guesty by phone number',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
requiredForToolCall: true,
|
||||
description: 'Your Guesty API token',
|
||||
},
|
||||
phoneNumber: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'The phone number to search for',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://open-api.guesty.com/v1/guests',
|
||||
method: 'GET',
|
||||
headers: (params: GuestyGuestParams) => ({
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
}),
|
||||
body: (params: GuestyGuestParams) => ({
|
||||
filters: {
|
||||
phone: params.phoneNumber,
|
||||
},
|
||||
fields: 'fullName,email,phone,address,city,country',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.message || 'Failed to search for guests in Guesty')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
guests: data.results.map((guest: any) => ({
|
||||
id: guest.id,
|
||||
fullName: guest.fullName || 'N/A',
|
||||
email: guest.email || 'N/A',
|
||||
phone: guest.phone || 'N/A',
|
||||
address: guest.address || 'N/A',
|
||||
city: guest.city || 'N/A',
|
||||
country: guest.country || 'N/A',
|
||||
})),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
transformError: (error: any) => {
|
||||
const message = error.message || 'Failed to search for guests in Guesty'
|
||||
return message
|
||||
},
|
||||
}
|
||||
4
tools/guesty/index.ts
Normal file
4
tools/guesty/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { guestyGuestTool } from './guest'
|
||||
import { guestyReservationTool } from './reservation'
|
||||
|
||||
export { guestyGuestTool, guestyReservationTool }
|
||||
96
tools/guesty/reservation.ts
Normal file
96
tools/guesty/reservation.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import { ToolConfig, ToolResponse } from '../types'
|
||||
|
||||
export interface GuestyReservationParams {
|
||||
apiKey: string
|
||||
reservationId: string
|
||||
}
|
||||
|
||||
export interface GuestyReservationResponse extends ToolResponse {
|
||||
output: {
|
||||
id: string
|
||||
guest: {
|
||||
fullName: string
|
||||
email: string
|
||||
phone: string
|
||||
}
|
||||
checkIn: string
|
||||
checkOut: string
|
||||
status: string
|
||||
listing: {
|
||||
id: string
|
||||
title: string
|
||||
}
|
||||
money: {
|
||||
totalPaid: number
|
||||
currency: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const guestyReservationTool: ToolConfig<GuestyReservationParams, GuestyReservationResponse> =
|
||||
{
|
||||
id: 'guesty_reservation',
|
||||
name: 'Guesty Reservation',
|
||||
description: 'Fetch reservation details from Guesty by reservation ID',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
requiredForToolCall: true,
|
||||
description: 'Your Guesty API token',
|
||||
},
|
||||
reservationId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'The ID of the reservation to fetch',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: GuestyReservationParams) =>
|
||||
`https://open-api.guesty.com/v1/reservations/${params.reservationId}`,
|
||||
method: 'GET',
|
||||
headers: (params: GuestyReservationParams) => ({
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${params.apiKey}`,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.message || 'Failed to fetch reservation from Guesty')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
id: data.id,
|
||||
guest: {
|
||||
fullName: data.guest?.fullName || 'N/A',
|
||||
email: data.guest?.email || 'N/A',
|
||||
phone: data.guest?.phone || 'N/A',
|
||||
},
|
||||
checkIn: data.checkIn || 'N/A',
|
||||
checkOut: data.checkOut || 'N/A',
|
||||
status: data.status || 'N/A',
|
||||
listing: {
|
||||
id: data.listing?.id || 'N/A',
|
||||
title: data.listing?.title || 'N/A',
|
||||
},
|
||||
money: {
|
||||
totalPaid: data.money?.totalPaid || 0,
|
||||
currency: data.money?.currency || 'USD',
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
transformError: (error: any) => {
|
||||
const message = error.message || 'Failed to fetch reservation from Guesty'
|
||||
return message
|
||||
},
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import { commentTool } from './github/comment'
|
||||
import { prTool } from './github/pr'
|
||||
import { repoInfoTool } from './github/repo'
|
||||
import { gmailReadTool, gmailSearchTool, gmailSendTool } from './gmail'
|
||||
import { guestyGuestTool, guestyReservationTool } from './guesty'
|
||||
import { requestTool as httpRequest } from './http/request'
|
||||
import { contactsTool as hubspotContacts } from './hubspot/contacts'
|
||||
import { readUrlTool } from './jina/reader'
|
||||
@@ -82,6 +83,8 @@ export const tools: Record<string, ToolConfig> = {
|
||||
google_sheets_read: sheetsReadTool,
|
||||
google_sheets_write: sheetsWriteTool,
|
||||
google_sheets_update: sheetsUpdateTool,
|
||||
guesty_reservation: guestyReservationTool,
|
||||
guesty_guest: guestyGuestTool,
|
||||
}
|
||||
|
||||
// Get a tool by its ID
|
||||
|
||||
Reference in New Issue
Block a user