feat(tools): added guesty tools/block

This commit is contained in:
Waleed Latif
2025-03-09 13:17:26 -07:00
parent fd510d582e
commit 163cc9bf53
7 changed files with 307 additions and 0 deletions

99
blocks/blocks/guesty.ts Normal file
View 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',
},
},
},
}

View File

@@ -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,

View File

@@ -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
View 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
View File

@@ -0,0 +1,4 @@
import { guestyGuestTool } from './guest'
import { guestyReservationTool } from './reservation'
export { guestyGuestTool, guestyReservationTool }

View 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
},
}

View File

@@ -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