chore: import upstream snapshot with attribution
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
import type {
|
||||
InstantlyActivateCampaignParams,
|
||||
InstantlyCampaignActionResponse,
|
||||
} from '@/tools/instantly/types'
|
||||
import {
|
||||
campaignActionOutputs,
|
||||
getMessage,
|
||||
instantlyBaseParamFields,
|
||||
instantlyHeaders,
|
||||
instantlyUrl,
|
||||
mapCampaign,
|
||||
parseInstantlyResponse,
|
||||
} from '@/tools/instantly/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const activateCampaignTool: ToolConfig<
|
||||
InstantlyActivateCampaignParams,
|
||||
InstantlyCampaignActionResponse
|
||||
> = {
|
||||
id: 'instantly_activate_campaign',
|
||||
name: 'Instantly Activate Campaign',
|
||||
description: 'Activates, starts, or resumes an Instantly V2 campaign.',
|
||||
version: '1.0.0',
|
||||
params: {
|
||||
...instantlyBaseParamFields,
|
||||
campaignId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Campaign ID',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: (params) => instantlyUrl(`/api/v2/campaigns/${params.campaignId.trim()}/activate`),
|
||||
method: 'POST',
|
||||
headers: instantlyHeaders,
|
||||
},
|
||||
transformResponse: async (response) => {
|
||||
const data = await parseInstantlyResponse(response)
|
||||
const campaign = mapCampaign(data)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
campaign,
|
||||
id: campaign.id,
|
||||
name: campaign.name,
|
||||
status: campaign.status,
|
||||
message: getMessage(data),
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: campaignActionOutputs,
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
import type {
|
||||
InstantlyCampaignResponse,
|
||||
InstantlyCreateCampaignParams,
|
||||
} from '@/tools/instantly/types'
|
||||
import {
|
||||
campaignOutputs,
|
||||
compactBody,
|
||||
instantlyBaseParamFields,
|
||||
instantlyHeaders,
|
||||
instantlyUrl,
|
||||
mapCampaign,
|
||||
parseInstantlyResponse,
|
||||
} from '@/tools/instantly/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const createCampaignTool: ToolConfig<
|
||||
InstantlyCreateCampaignParams,
|
||||
InstantlyCampaignResponse
|
||||
> = {
|
||||
id: 'instantly_create_campaign',
|
||||
name: 'Instantly Create Campaign',
|
||||
description: 'Creates an Instantly V2 campaign using the documented campaign schedule schema.',
|
||||
version: '1.0.0',
|
||||
params: {
|
||||
...instantlyBaseParamFields,
|
||||
name: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Campaign name',
|
||||
},
|
||||
campaign_schedule: {
|
||||
type: 'json',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Campaign schedule object with schedules array',
|
||||
},
|
||||
sequences: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Campaign sequence definitions',
|
||||
items: { type: 'object', description: 'Sequence object' },
|
||||
},
|
||||
email_list: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sending email accounts',
|
||||
items: { type: 'string', description: 'Email address' },
|
||||
},
|
||||
daily_limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Daily sending limit',
|
||||
},
|
||||
daily_max_leads: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Daily maximum new leads to contact',
|
||||
},
|
||||
open_tracking: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether to track opens',
|
||||
},
|
||||
stop_on_reply: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether to stop the campaign on reply',
|
||||
},
|
||||
link_tracking: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether to track links',
|
||||
},
|
||||
text_only: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether the campaign is text only',
|
||||
},
|
||||
email_gap: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Gap between emails in minutes',
|
||||
},
|
||||
pl_value: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Value of every positive lead',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: () => instantlyUrl('/api/v2/campaigns'),
|
||||
method: 'POST',
|
||||
headers: instantlyHeaders,
|
||||
body: (params) =>
|
||||
compactBody({
|
||||
name: params.name,
|
||||
campaign_schedule: params.campaign_schedule,
|
||||
sequences: params.sequences,
|
||||
pl_value: params.pl_value,
|
||||
email_gap: params.email_gap,
|
||||
text_only: params.text_only,
|
||||
email_list: params.email_list,
|
||||
daily_limit: params.daily_limit,
|
||||
stop_on_reply: params.stop_on_reply,
|
||||
link_tracking: params.link_tracking,
|
||||
open_tracking: params.open_tracking,
|
||||
daily_max_leads: params.daily_max_leads,
|
||||
}),
|
||||
},
|
||||
transformResponse: async (response) => {
|
||||
const data = await parseInstantlyResponse(response)
|
||||
const campaign = mapCampaign(data)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
campaign,
|
||||
id: campaign.id,
|
||||
name: campaign.name,
|
||||
status: campaign.status,
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: campaignOutputs,
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
import type { InstantlyCreateLeadParams, InstantlyLeadResponse } from '@/tools/instantly/types'
|
||||
import {
|
||||
compactBody,
|
||||
instantlyBaseParamFields,
|
||||
instantlyHeaders,
|
||||
instantlyUrl,
|
||||
leadOutputs,
|
||||
mapLead,
|
||||
parseInstantlyResponse,
|
||||
} from '@/tools/instantly/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const createLeadTool: ToolConfig<InstantlyCreateLeadParams, InstantlyLeadResponse> = {
|
||||
id: 'instantly_create_lead',
|
||||
name: 'Instantly Create Lead',
|
||||
description: 'Creates an Instantly V2 lead in a campaign or lead list.',
|
||||
version: '1.0.0',
|
||||
params: {
|
||||
...instantlyBaseParamFields,
|
||||
campaign: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Campaign ID associated with the lead',
|
||||
},
|
||||
list_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead list ID associated with the lead',
|
||||
},
|
||||
email: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead email address. Required when adding to a campaign.',
|
||||
},
|
||||
first_name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead first name',
|
||||
},
|
||||
last_name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead last name',
|
||||
},
|
||||
company_name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead company name',
|
||||
},
|
||||
job_title: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead job title',
|
||||
},
|
||||
phone: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead phone number',
|
||||
},
|
||||
website: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead website',
|
||||
},
|
||||
personalization: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead personalization text',
|
||||
},
|
||||
lt_interest_status: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead interest status value',
|
||||
},
|
||||
pl_value_lead: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Potential value of the lead',
|
||||
},
|
||||
assigned_to: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Organization user ID assigned to the lead',
|
||||
},
|
||||
skip_if_in_workspace: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Skip if the lead already exists in the workspace',
|
||||
},
|
||||
skip_if_in_campaign: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Skip if the lead already exists in the campaign',
|
||||
},
|
||||
skip_if_in_list: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Skip if the lead already exists in the list',
|
||||
},
|
||||
blocklist_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Blocklist ID to check for the lead',
|
||||
},
|
||||
verify_leads_for_lead_finder: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether to verify leads imported from Lead Finder',
|
||||
},
|
||||
verify_leads_on_import: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether to verify leads on import',
|
||||
},
|
||||
custom_variables: {
|
||||
type: 'json',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Custom variable object with string, number, boolean, or null values',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: () => instantlyUrl('/api/v2/leads'),
|
||||
method: 'POST',
|
||||
headers: instantlyHeaders,
|
||||
body: (params) =>
|
||||
compactBody({
|
||||
campaign: params.campaign,
|
||||
list_id: params.list_id,
|
||||
email: params.email,
|
||||
first_name: params.first_name,
|
||||
last_name: params.last_name,
|
||||
company_name: params.company_name,
|
||||
job_title: params.job_title,
|
||||
phone: params.phone,
|
||||
website: params.website,
|
||||
personalization: params.personalization,
|
||||
lt_interest_status: params.lt_interest_status,
|
||||
pl_value_lead: params.pl_value_lead,
|
||||
assigned_to: params.assigned_to,
|
||||
skip_if_in_workspace: params.skip_if_in_workspace,
|
||||
skip_if_in_campaign: params.skip_if_in_campaign,
|
||||
skip_if_in_list: params.skip_if_in_list,
|
||||
blocklist_id: params.blocklist_id,
|
||||
verify_leads_for_lead_finder: params.verify_leads_for_lead_finder,
|
||||
verify_leads_on_import: params.verify_leads_on_import,
|
||||
custom_variables: params.custom_variables,
|
||||
}),
|
||||
},
|
||||
transformResponse: async (response) => {
|
||||
const data = await parseInstantlyResponse(response)
|
||||
const lead = mapLead(data)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
lead,
|
||||
id: lead.id,
|
||||
email_address: lead.email,
|
||||
first_name: lead.first_name,
|
||||
last_name: lead.last_name,
|
||||
campaign: lead.campaign,
|
||||
status: lead.status,
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: leadOutputs,
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
import type {
|
||||
InstantlyCreateLeadListParams,
|
||||
InstantlyLeadListResponse,
|
||||
} from '@/tools/instantly/types'
|
||||
import {
|
||||
compactBody,
|
||||
instantlyBaseParamFields,
|
||||
instantlyHeaders,
|
||||
instantlyUrl,
|
||||
leadListOutputs,
|
||||
mapLeadList,
|
||||
parseInstantlyResponse,
|
||||
} from '@/tools/instantly/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const createLeadListTool: ToolConfig<
|
||||
InstantlyCreateLeadListParams,
|
||||
InstantlyLeadListResponse
|
||||
> = {
|
||||
id: 'instantly_create_lead_list',
|
||||
name: 'Instantly Create Lead List',
|
||||
description: 'Creates an Instantly V2 lead list.',
|
||||
version: '1.0.0',
|
||||
params: {
|
||||
...instantlyBaseParamFields,
|
||||
name: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead list name',
|
||||
},
|
||||
has_enrichment_task: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether this list runs enrichment for every added lead',
|
||||
},
|
||||
owned_by: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'User ID of the lead list owner',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: () => instantlyUrl('/api/v2/lead-lists'),
|
||||
method: 'POST',
|
||||
headers: instantlyHeaders,
|
||||
body: (params) =>
|
||||
compactBody({
|
||||
name: params.name,
|
||||
has_enrichment_task: params.has_enrichment_task,
|
||||
owned_by: params.owned_by,
|
||||
}),
|
||||
},
|
||||
transformResponse: async (response) => {
|
||||
const data = await parseInstantlyResponse(response)
|
||||
const leadList = mapLeadList(data)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
lead_list: leadList,
|
||||
id: leadList.id,
|
||||
name: leadList.name,
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: leadListOutputs,
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import type {
|
||||
InstantlyCampaignActionResponse,
|
||||
InstantlyDeleteCampaignParams,
|
||||
} from '@/tools/instantly/types'
|
||||
import {
|
||||
campaignActionOutputs,
|
||||
getMessage,
|
||||
instantlyBaseParamFields,
|
||||
instantlyHeaders,
|
||||
instantlyUrl,
|
||||
mapCampaign,
|
||||
parseInstantlyResponse,
|
||||
} from '@/tools/instantly/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const deleteCampaignTool: ToolConfig<
|
||||
InstantlyDeleteCampaignParams,
|
||||
InstantlyCampaignActionResponse
|
||||
> = {
|
||||
id: 'instantly_delete_campaign',
|
||||
name: 'Instantly Delete Campaign',
|
||||
description: 'Permanently deletes an Instantly V2 campaign.',
|
||||
version: '1.0.0',
|
||||
params: {
|
||||
...instantlyBaseParamFields,
|
||||
campaignId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Campaign ID',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: (params) => instantlyUrl(`/api/v2/campaigns/${params.campaignId.trim()}`),
|
||||
method: 'DELETE',
|
||||
headers: instantlyHeaders,
|
||||
},
|
||||
transformResponse: async (response) => {
|
||||
const data = await parseInstantlyResponse(response)
|
||||
const campaign = mapCampaign(data)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
campaign,
|
||||
id: campaign.id,
|
||||
name: campaign.name,
|
||||
status: campaign.status,
|
||||
message: getMessage(data),
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: campaignActionOutputs,
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import type {
|
||||
InstantlyDeleteLeadsParams,
|
||||
InstantlyDeleteLeadsResponse,
|
||||
} from '@/tools/instantly/types'
|
||||
import {
|
||||
asRecord,
|
||||
compactBody,
|
||||
instantlyBaseParamFields,
|
||||
instantlyHeaders,
|
||||
instantlyUrl,
|
||||
parseInstantlyResponse,
|
||||
} from '@/tools/instantly/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const deleteLeadsTool: ToolConfig<InstantlyDeleteLeadsParams, InstantlyDeleteLeadsResponse> =
|
||||
{
|
||||
id: 'instantly_delete_leads',
|
||||
name: 'Instantly Delete Leads',
|
||||
description: 'Deletes Instantly V2 leads in bulk from a campaign or lead list.',
|
||||
version: '1.0.0',
|
||||
params: {
|
||||
...instantlyBaseParamFields,
|
||||
campaign_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Campaign ID to delete leads from. Required if list_id is not provided.',
|
||||
},
|
||||
list_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead list ID to delete leads from. Required if campaign_id is not provided.',
|
||||
},
|
||||
status: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Optional lead status filter',
|
||||
},
|
||||
ids: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Specific lead IDs to delete',
|
||||
items: { type: 'string', description: 'Lead ID' },
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Maximum number of matching leads to delete, up to 10000',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: () => instantlyUrl('/api/v2/leads'),
|
||||
method: 'DELETE',
|
||||
headers: instantlyHeaders,
|
||||
body: (params) =>
|
||||
compactBody({
|
||||
campaign_id: params.campaign_id,
|
||||
list_id: params.list_id,
|
||||
status: params.status,
|
||||
ids: params.ids,
|
||||
limit: params.limit,
|
||||
}),
|
||||
},
|
||||
transformResponse: async (response) => {
|
||||
const data = await parseInstantlyResponse(response)
|
||||
const result = asRecord(data)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
count: typeof result.count === 'number' ? result.count : null,
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
count: { type: 'number', description: 'Number of leads deleted', optional: true },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import type { InstantlyGetLeadParams, InstantlyLeadResponse } from '@/tools/instantly/types'
|
||||
import {
|
||||
instantlyBaseParamFields,
|
||||
instantlyHeaders,
|
||||
instantlyUrl,
|
||||
leadOutputs,
|
||||
mapLead,
|
||||
parseInstantlyResponse,
|
||||
} from '@/tools/instantly/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const getLeadTool: ToolConfig<InstantlyGetLeadParams, InstantlyLeadResponse> = {
|
||||
id: 'instantly_get_lead',
|
||||
name: 'Instantly Get Lead',
|
||||
description: 'Retrieves an Instantly V2 lead by ID.',
|
||||
version: '1.0.0',
|
||||
params: {
|
||||
...instantlyBaseParamFields,
|
||||
leadId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead ID',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: (params) => instantlyUrl(`/api/v2/leads/${params.leadId.trim()}`),
|
||||
method: 'GET',
|
||||
headers: instantlyHeaders,
|
||||
},
|
||||
transformResponse: async (response) => {
|
||||
const data = await parseInstantlyResponse(response)
|
||||
const lead = mapLead(data)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
lead,
|
||||
id: lead.id,
|
||||
email_address: lead.email,
|
||||
first_name: lead.first_name,
|
||||
last_name: lead.last_name,
|
||||
campaign: lead.campaign,
|
||||
status: lead.status,
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: leadOutputs,
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
export { activateCampaignTool as instantlyActivateCampaignTool } from '@/tools/instantly/activate_campaign'
|
||||
export { createCampaignTool as instantlyCreateCampaignTool } from '@/tools/instantly/create_campaign'
|
||||
export { createLeadTool as instantlyCreateLeadTool } from '@/tools/instantly/create_lead'
|
||||
export { createLeadListTool as instantlyCreateLeadListTool } from '@/tools/instantly/create_lead_list'
|
||||
export { deleteCampaignTool as instantlyDeleteCampaignTool } from '@/tools/instantly/delete_campaign'
|
||||
export { deleteLeadsTool as instantlyDeleteLeadsTool } from '@/tools/instantly/delete_leads'
|
||||
export { getLeadTool as instantlyGetLeadTool } from '@/tools/instantly/get_lead'
|
||||
export { listCampaignsTool as instantlyListCampaignsTool } from '@/tools/instantly/list_campaigns'
|
||||
export { listEmailsTool as instantlyListEmailsTool } from '@/tools/instantly/list_emails'
|
||||
export { listLeadListsTool as instantlyListLeadListsTool } from '@/tools/instantly/list_lead_lists'
|
||||
export { listLeadsTool as instantlyListLeadsTool } from '@/tools/instantly/list_leads'
|
||||
export { patchCampaignTool as instantlyPatchCampaignTool } from '@/tools/instantly/patch_campaign'
|
||||
export { patchLeadTool as instantlyPatchLeadTool } from '@/tools/instantly/patch_lead'
|
||||
export { pauseCampaignTool as instantlyPauseCampaignTool } from '@/tools/instantly/pause_campaign'
|
||||
export { replyToEmailTool as instantlyReplyToEmailTool } from '@/tools/instantly/reply_to_email'
|
||||
export * from '@/tools/instantly/types'
|
||||
export { updateLeadInterestStatusTool as instantlyUpdateLeadInterestStatusTool } from '@/tools/instantly/update_lead_interest_status'
|
||||
@@ -0,0 +1,91 @@
|
||||
import type {
|
||||
InstantlyListCampaignsParams,
|
||||
InstantlyListCampaignsResponse,
|
||||
} from '@/tools/instantly/types'
|
||||
import {
|
||||
campaignsListOutputs,
|
||||
getItems,
|
||||
getNextStartingAfter,
|
||||
instantlyBaseParamFields,
|
||||
instantlyHeaders,
|
||||
instantlyUrl,
|
||||
mapCampaign,
|
||||
parseInstantlyResponse,
|
||||
} from '@/tools/instantly/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const listCampaignsTool: ToolConfig<
|
||||
InstantlyListCampaignsParams,
|
||||
InstantlyListCampaignsResponse
|
||||
> = {
|
||||
id: 'instantly_list_campaigns',
|
||||
name: 'Instantly List Campaigns',
|
||||
description: 'Retrieves Instantly V2 campaigns with search, status, tag, and pagination filters.',
|
||||
version: '1.0.0',
|
||||
params: {
|
||||
...instantlyBaseParamFields,
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Number of campaigns to return, from 1 to 100',
|
||||
},
|
||||
starting_after: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Pagination cursor from next_starting_after',
|
||||
},
|
||||
search: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Search by campaign name',
|
||||
},
|
||||
tag_ids: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated campaign tag IDs',
|
||||
},
|
||||
ai_sales_agent_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter campaigns by AI Sales Agent ID',
|
||||
},
|
||||
status: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Campaign status enum value',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: (params) =>
|
||||
instantlyUrl('/api/v2/campaigns', {
|
||||
limit: params.limit,
|
||||
starting_after: params.starting_after,
|
||||
search: params.search,
|
||||
tag_ids: params.tag_ids,
|
||||
ai_sales_agent_id: params.ai_sales_agent_id,
|
||||
status: params.status,
|
||||
}),
|
||||
method: 'GET',
|
||||
headers: instantlyHeaders,
|
||||
},
|
||||
transformResponse: async (response) => {
|
||||
const data = await parseInstantlyResponse(response)
|
||||
const campaigns = getItems(data).map(mapCampaign)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
campaigns,
|
||||
count: campaigns.length,
|
||||
next_starting_after: getNextStartingAfter(data),
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: campaignsListOutputs,
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
import type {
|
||||
InstantlyListEmailsParams,
|
||||
InstantlyListEmailsResponse,
|
||||
} from '@/tools/instantly/types'
|
||||
import {
|
||||
emailsListOutputs,
|
||||
getItems,
|
||||
getNextStartingAfter,
|
||||
instantlyBaseParamFields,
|
||||
instantlyHeaders,
|
||||
instantlyUrl,
|
||||
mapEmail,
|
||||
parseInstantlyResponse,
|
||||
} from '@/tools/instantly/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const listEmailsTool: ToolConfig<InstantlyListEmailsParams, InstantlyListEmailsResponse> = {
|
||||
id: 'instantly_list_emails',
|
||||
name: 'Instantly List Emails',
|
||||
description: 'Retrieves Instantly V2 Unibox emails with search and pagination filters.',
|
||||
version: '1.0.0',
|
||||
params: {
|
||||
...instantlyBaseParamFields,
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Number of emails to return, from 1 to 100',
|
||||
},
|
||||
starting_after: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Pagination cursor from next_starting_after',
|
||||
},
|
||||
search: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Search query, email address, or thread:<thread-id>',
|
||||
},
|
||||
campaign_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Campaign ID filter',
|
||||
},
|
||||
list_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead list ID filter',
|
||||
},
|
||||
i_status: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Email interest status filter',
|
||||
},
|
||||
eaccount: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sending email account filter',
|
||||
},
|
||||
lead: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead email address filter',
|
||||
},
|
||||
is_unread: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Unread status filter',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: (params) =>
|
||||
instantlyUrl('/api/v2/emails', {
|
||||
limit: params.limit,
|
||||
starting_after: params.starting_after,
|
||||
search: params.search,
|
||||
campaign_id: params.campaign_id,
|
||||
list_id: params.list_id,
|
||||
i_status: params.i_status,
|
||||
eaccount: params.eaccount,
|
||||
lead: params.lead,
|
||||
is_unread: params.is_unread,
|
||||
}),
|
||||
method: 'GET',
|
||||
headers: instantlyHeaders,
|
||||
},
|
||||
transformResponse: async (response) => {
|
||||
const data = await parseInstantlyResponse(response)
|
||||
const emails = getItems(data).map(mapEmail)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
emails,
|
||||
count: emails.length,
|
||||
next_starting_after: getNextStartingAfter(data),
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: emailsListOutputs,
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
import type {
|
||||
InstantlyListLeadListsParams,
|
||||
InstantlyListLeadListsResponse,
|
||||
} from '@/tools/instantly/types'
|
||||
import {
|
||||
getItems,
|
||||
getNextStartingAfter,
|
||||
instantlyBaseParamFields,
|
||||
instantlyHeaders,
|
||||
instantlyUrl,
|
||||
leadListsListOutputs,
|
||||
mapLeadList,
|
||||
parseInstantlyResponse,
|
||||
} from '@/tools/instantly/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const listLeadListsTool: ToolConfig<
|
||||
InstantlyListLeadListsParams,
|
||||
InstantlyListLeadListsResponse
|
||||
> = {
|
||||
id: 'instantly_list_lead_lists',
|
||||
name: 'Instantly List Lead Lists',
|
||||
description: 'Retrieves Instantly V2 lead lists with search and pagination filters.',
|
||||
version: '1.0.0',
|
||||
params: {
|
||||
...instantlyBaseParamFields,
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Number of lead lists to return, from 1 to 100',
|
||||
},
|
||||
starting_after: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Starting-after timestamp cursor',
|
||||
},
|
||||
has_enrichment_task: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter by enrichment task setting',
|
||||
},
|
||||
search: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Search query to filter lead lists by name',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: (params) =>
|
||||
instantlyUrl('/api/v2/lead-lists', {
|
||||
limit: params.limit,
|
||||
starting_after: params.starting_after,
|
||||
has_enrichment_task: params.has_enrichment_task,
|
||||
search: params.search,
|
||||
}),
|
||||
method: 'GET',
|
||||
headers: instantlyHeaders,
|
||||
},
|
||||
transformResponse: async (response) => {
|
||||
const data = await parseInstantlyResponse(response)
|
||||
const leadLists = getItems(data).map(mapLeadList)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
lead_lists: leadLists,
|
||||
count: leadLists.length,
|
||||
next_starting_after: getNextStartingAfter(data),
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: leadListsListOutputs,
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
import type { InstantlyListLeadsParams, InstantlyListLeadsResponse } from '@/tools/instantly/types'
|
||||
import {
|
||||
compactBody,
|
||||
getItems,
|
||||
getNextStartingAfter,
|
||||
instantlyBaseParamFields,
|
||||
instantlyHeaders,
|
||||
instantlyUrl,
|
||||
leadsListOutputs,
|
||||
mapLead,
|
||||
parseInstantlyResponse,
|
||||
} from '@/tools/instantly/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const listLeadsTool: ToolConfig<InstantlyListLeadsParams, InstantlyListLeadsResponse> = {
|
||||
id: 'instantly_list_leads',
|
||||
name: 'Instantly List Leads',
|
||||
description: 'Retrieves Instantly V2 leads with search, campaign, list, and pagination filters.',
|
||||
version: '1.0.0',
|
||||
params: {
|
||||
...instantlyBaseParamFields,
|
||||
search: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Search by first name, last name, or email',
|
||||
},
|
||||
filter: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Instantly lead filter value, such as FILTER_VAL_CONTACTED or FILTER_VAL_ACTIVE',
|
||||
},
|
||||
campaign: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Campaign ID to filter leads',
|
||||
},
|
||||
list_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead list ID to filter leads',
|
||||
},
|
||||
in_campaign: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether the lead is in a campaign',
|
||||
},
|
||||
in_list: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether the lead is in a list',
|
||||
},
|
||||
ids: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead IDs to include',
|
||||
items: { type: 'string', description: 'Lead ID' },
|
||||
},
|
||||
excluded_ids: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead IDs to exclude',
|
||||
items: { type: 'string', description: 'Lead ID' },
|
||||
},
|
||||
organization_user_ids: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Organization user IDs to filter leads',
|
||||
items: { type: 'string', description: 'Organization user ID' },
|
||||
},
|
||||
smart_view_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Smart view ID to filter leads',
|
||||
},
|
||||
contacts: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead email addresses to include',
|
||||
items: { type: 'string', description: 'Email address' },
|
||||
},
|
||||
limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Number of leads to return, from 1 to 100',
|
||||
},
|
||||
starting_after: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Forward pagination cursor from next_starting_after',
|
||||
},
|
||||
distinct_contacts: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether to return distinct contacts',
|
||||
},
|
||||
is_website_visitor: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether the lead is a website visitor',
|
||||
},
|
||||
enrichment_status: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Enrichment status filter',
|
||||
},
|
||||
esg_code: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Email security gateway code filter',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: () => instantlyUrl('/api/v2/leads/list'),
|
||||
method: 'POST',
|
||||
headers: instantlyHeaders,
|
||||
body: (params) =>
|
||||
compactBody({
|
||||
search: params.search,
|
||||
filter: params.filter,
|
||||
campaign: params.campaign,
|
||||
list_id: params.list_id,
|
||||
in_campaign: params.in_campaign,
|
||||
in_list: params.in_list,
|
||||
ids: params.ids,
|
||||
excluded_ids: params.excluded_ids,
|
||||
contacts: params.contacts,
|
||||
limit: params.limit,
|
||||
starting_after: params.starting_after,
|
||||
organization_user_ids: params.organization_user_ids,
|
||||
smart_view_id: params.smart_view_id,
|
||||
is_website_visitor: params.is_website_visitor,
|
||||
distinct_contacts: params.distinct_contacts,
|
||||
enrichment_status: params.enrichment_status,
|
||||
esg_code: params.esg_code,
|
||||
}),
|
||||
},
|
||||
transformResponse: async (response) => {
|
||||
const data = await parseInstantlyResponse(response)
|
||||
const leads = getItems(data).map(mapLead)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
leads,
|
||||
count: leads.length,
|
||||
next_starting_after: getNextStartingAfter(data),
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: leadsListOutputs,
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
import type {
|
||||
InstantlyCampaignResponse,
|
||||
InstantlyPatchCampaignParams,
|
||||
} from '@/tools/instantly/types'
|
||||
import {
|
||||
campaignOutputs,
|
||||
compactBody,
|
||||
instantlyBaseParamFields,
|
||||
instantlyHeaders,
|
||||
instantlyUrl,
|
||||
mapCampaign,
|
||||
parseInstantlyResponse,
|
||||
} from '@/tools/instantly/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const patchCampaignTool: ToolConfig<
|
||||
InstantlyPatchCampaignParams,
|
||||
InstantlyCampaignResponse
|
||||
> = {
|
||||
id: 'instantly_patch_campaign',
|
||||
name: 'Instantly Patch Campaign',
|
||||
description: 'Updates documented Instantly V2 campaign fields.',
|
||||
version: '1.0.0',
|
||||
params: {
|
||||
...instantlyBaseParamFields,
|
||||
campaignId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Campaign ID',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Campaign name',
|
||||
},
|
||||
campaign_schedule: {
|
||||
type: 'json',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Campaign schedule object with schedules array',
|
||||
},
|
||||
sequences: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Campaign sequence definitions',
|
||||
items: { type: 'object', description: 'Sequence object' },
|
||||
},
|
||||
email_list: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sending email accounts',
|
||||
items: { type: 'string', description: 'Email address' },
|
||||
},
|
||||
daily_limit: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Daily sending limit',
|
||||
},
|
||||
daily_max_leads: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Daily maximum new leads to contact',
|
||||
},
|
||||
open_tracking: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether to track opens',
|
||||
},
|
||||
stop_on_reply: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether to stop the campaign on reply',
|
||||
},
|
||||
link_tracking: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether to track links',
|
||||
},
|
||||
text_only: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether the campaign is text only',
|
||||
},
|
||||
email_gap: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Gap between emails in minutes',
|
||||
},
|
||||
pl_value: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Value of every positive lead',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: (params) => instantlyUrl(`/api/v2/campaigns/${params.campaignId.trim()}`),
|
||||
method: 'PATCH',
|
||||
headers: instantlyHeaders,
|
||||
body: (params) =>
|
||||
compactBody({
|
||||
name: params.name,
|
||||
campaign_schedule: params.campaign_schedule,
|
||||
sequences: params.sequences,
|
||||
pl_value: params.pl_value,
|
||||
email_gap: params.email_gap,
|
||||
text_only: params.text_only,
|
||||
email_list: params.email_list,
|
||||
daily_limit: params.daily_limit,
|
||||
stop_on_reply: params.stop_on_reply,
|
||||
link_tracking: params.link_tracking,
|
||||
open_tracking: params.open_tracking,
|
||||
daily_max_leads: params.daily_max_leads,
|
||||
}),
|
||||
},
|
||||
transformResponse: async (response) => {
|
||||
const data = await parseInstantlyResponse(response)
|
||||
const campaign = mapCampaign(data)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
campaign,
|
||||
id: campaign.id,
|
||||
name: campaign.name,
|
||||
status: campaign.status,
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: campaignOutputs,
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
import type { InstantlyLeadResponse, InstantlyPatchLeadParams } from '@/tools/instantly/types'
|
||||
import {
|
||||
compactBody,
|
||||
instantlyBaseParamFields,
|
||||
instantlyHeaders,
|
||||
instantlyUrl,
|
||||
leadOutputs,
|
||||
mapLead,
|
||||
parseInstantlyResponse,
|
||||
} from '@/tools/instantly/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const patchLeadTool: ToolConfig<InstantlyPatchLeadParams, InstantlyLeadResponse> = {
|
||||
id: 'instantly_patch_lead',
|
||||
name: 'Instantly Patch Lead',
|
||||
description: 'Updates fields on an existing Instantly V2 lead.',
|
||||
version: '1.0.0',
|
||||
params: {
|
||||
...instantlyBaseParamFields,
|
||||
leadId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead ID',
|
||||
},
|
||||
first_name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead first name',
|
||||
},
|
||||
last_name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead last name',
|
||||
},
|
||||
company_name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead company name',
|
||||
},
|
||||
job_title: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead job title',
|
||||
},
|
||||
phone: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead phone number',
|
||||
},
|
||||
website: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead website',
|
||||
},
|
||||
personalization: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead personalization text',
|
||||
},
|
||||
lt_interest_status: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead interest status value',
|
||||
},
|
||||
pl_value_lead: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Potential value of the lead',
|
||||
},
|
||||
assigned_to: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'ID of the user assigned to the lead',
|
||||
},
|
||||
custom_variables: {
|
||||
type: 'json',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Custom variable object with string, number, boolean, or null values',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: (params) => instantlyUrl(`/api/v2/leads/${params.leadId.trim()}`),
|
||||
method: 'PATCH',
|
||||
headers: instantlyHeaders,
|
||||
body: (params) => {
|
||||
const body = compactBody({
|
||||
first_name: params.first_name,
|
||||
last_name: params.last_name,
|
||||
company_name: params.company_name,
|
||||
job_title: params.job_title,
|
||||
phone: params.phone,
|
||||
website: params.website,
|
||||
personalization: params.personalization,
|
||||
lt_interest_status: params.lt_interest_status,
|
||||
pl_value_lead: params.pl_value_lead,
|
||||
assigned_to: params.assigned_to,
|
||||
custom_variables: params.custom_variables,
|
||||
})
|
||||
|
||||
if (Object.keys(body).length === 0) {
|
||||
throw new Error('Provide at least one field to update')
|
||||
}
|
||||
|
||||
return body
|
||||
},
|
||||
},
|
||||
transformResponse: async (response) => {
|
||||
const data = await parseInstantlyResponse(response)
|
||||
const lead = mapLead(data)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
lead,
|
||||
id: lead.id,
|
||||
email_address: lead.email,
|
||||
first_name: lead.first_name,
|
||||
last_name: lead.last_name,
|
||||
campaign: lead.campaign,
|
||||
status: lead.status,
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: leadOutputs,
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import type {
|
||||
InstantlyCampaignActionResponse,
|
||||
InstantlyPauseCampaignParams,
|
||||
} from '@/tools/instantly/types'
|
||||
import {
|
||||
campaignActionOutputs,
|
||||
getMessage,
|
||||
instantlyBaseParamFields,
|
||||
instantlyHeaders,
|
||||
instantlyUrl,
|
||||
mapCampaign,
|
||||
parseInstantlyResponse,
|
||||
} from '@/tools/instantly/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const pauseCampaignTool: ToolConfig<
|
||||
InstantlyPauseCampaignParams,
|
||||
InstantlyCampaignActionResponse
|
||||
> = {
|
||||
id: 'instantly_pause_campaign',
|
||||
name: 'Instantly Pause Campaign',
|
||||
description: 'Pauses a running Instantly V2 campaign, stopping further email sends.',
|
||||
version: '1.0.0',
|
||||
params: {
|
||||
...instantlyBaseParamFields,
|
||||
campaignId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Campaign ID',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: (params) => instantlyUrl(`/api/v2/campaigns/${params.campaignId.trim()}/pause`),
|
||||
method: 'POST',
|
||||
headers: instantlyHeaders,
|
||||
},
|
||||
transformResponse: async (response) => {
|
||||
const data = await parseInstantlyResponse(response)
|
||||
const campaign = mapCampaign(data)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
campaign,
|
||||
id: campaign.id,
|
||||
name: campaign.name,
|
||||
status: campaign.status,
|
||||
message: getMessage(data),
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: campaignActionOutputs,
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
import type { InstantlyEmailResponse, InstantlyReplyToEmailParams } from '@/tools/instantly/types'
|
||||
import {
|
||||
compactBody,
|
||||
emailOutputs,
|
||||
instantlyBaseParamFields,
|
||||
instantlyHeaders,
|
||||
instantlyUrl,
|
||||
mapEmail,
|
||||
parseInstantlyResponse,
|
||||
} from '@/tools/instantly/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const replyToEmailTool: ToolConfig<InstantlyReplyToEmailParams, InstantlyEmailResponse> = {
|
||||
id: 'instantly_reply_to_email',
|
||||
name: 'Instantly Reply To Email',
|
||||
description: 'Sends an Instantly V2 reply to an existing Unibox email.',
|
||||
version: '1.0.0',
|
||||
params: {
|
||||
...instantlyBaseParamFields,
|
||||
eaccount: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Connected email account used to send the reply',
|
||||
},
|
||||
reply_to_uuid: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Email ID to reply to',
|
||||
},
|
||||
subject: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Reply subject',
|
||||
},
|
||||
body: {
|
||||
type: 'json',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Reply body object with text and/or html',
|
||||
},
|
||||
cc_address_email_list: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated CC email addresses',
|
||||
},
|
||||
bcc_address_email_list: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Comma-separated BCC email addresses',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: () => instantlyUrl('/api/v2/emails/reply'),
|
||||
method: 'POST',
|
||||
headers: instantlyHeaders,
|
||||
body: (params) =>
|
||||
compactBody({
|
||||
eaccount: params.eaccount,
|
||||
reply_to_uuid: params.reply_to_uuid,
|
||||
subject: params.subject,
|
||||
body: params.body,
|
||||
cc_address_email_list: params.cc_address_email_list,
|
||||
bcc_address_email_list: params.bcc_address_email_list,
|
||||
}),
|
||||
},
|
||||
transformResponse: async (response) => {
|
||||
const data = await parseInstantlyResponse(response)
|
||||
const email = mapEmail(data)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
email,
|
||||
id: email.id,
|
||||
subject: email.subject,
|
||||
thread_id: email.thread_id,
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: emailOutputs,
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
import type { ToolResponse } from '@/tools/types'
|
||||
|
||||
export type InstantlyScalar = string | number | boolean | null
|
||||
|
||||
export interface InstantlyBaseParams {
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
export interface InstantlyLead {
|
||||
id: string | null
|
||||
timestamp_created: string | null
|
||||
timestamp_updated: string | null
|
||||
organization: string | null
|
||||
campaign: string | null
|
||||
status: number | null
|
||||
email: string | null
|
||||
personalization: string | null
|
||||
website: string | null
|
||||
last_name: string | null
|
||||
first_name: string | null
|
||||
company_name: string | null
|
||||
job_title: string | null
|
||||
phone: string | null
|
||||
email_open_count: number | null
|
||||
email_reply_count: number | null
|
||||
email_click_count: number | null
|
||||
company_domain: string | null
|
||||
payload: Record<string, unknown> | null
|
||||
lt_interest_status: number | null
|
||||
}
|
||||
|
||||
export interface InstantlyCampaign {
|
||||
id: string | null
|
||||
name: string | null
|
||||
pl_value: number | null
|
||||
status: number | null
|
||||
is_evergreen: boolean | null
|
||||
timestamp_created: string | null
|
||||
timestamp_updated: string | null
|
||||
email_gap: number | null
|
||||
daily_limit: number | null
|
||||
daily_max_leads: number | null
|
||||
open_tracking: boolean | null
|
||||
stop_on_reply: boolean | null
|
||||
sequences: unknown[]
|
||||
campaign_schedule: Record<string, unknown> | null
|
||||
}
|
||||
|
||||
export interface InstantlyEmail {
|
||||
id: string | null
|
||||
timestamp_created: string | null
|
||||
timestamp_email: string | null
|
||||
message_id: string | null
|
||||
subject: string | null
|
||||
from_address_email: string | null
|
||||
to_address_email_list: string | null
|
||||
cc_address_email_list: string | null
|
||||
bcc_address_email_list: string | null
|
||||
reply_to: string | null
|
||||
body: {
|
||||
text: string | null
|
||||
html: string | null
|
||||
}
|
||||
organization_id: string | null
|
||||
campaign_id: string | null
|
||||
subsequence_id: string | null
|
||||
list_id: string | null
|
||||
lead: string | null
|
||||
lead_id: string | null
|
||||
eaccount: string | null
|
||||
ue_type: number | null
|
||||
is_unread: number | null
|
||||
is_auto_reply: number | null
|
||||
i_status: number | null
|
||||
thread_id: string | null
|
||||
content_preview: string | null
|
||||
}
|
||||
|
||||
export interface InstantlyLeadList {
|
||||
id: string | null
|
||||
organization_id: string | null
|
||||
has_enrichment_task: boolean | null
|
||||
owned_by: string | null
|
||||
name: string | null
|
||||
timestamp_created: string | null
|
||||
}
|
||||
|
||||
export interface InstantlyListLeadsParams extends InstantlyBaseParams {
|
||||
search?: string
|
||||
filter?: string
|
||||
campaign?: string
|
||||
list_id?: string
|
||||
in_campaign?: boolean
|
||||
in_list?: boolean
|
||||
ids?: string[]
|
||||
excluded_ids?: string[]
|
||||
contacts?: string[]
|
||||
limit?: number
|
||||
starting_after?: string
|
||||
organization_user_ids?: string[]
|
||||
smart_view_id?: string
|
||||
is_website_visitor?: boolean
|
||||
distinct_contacts?: boolean
|
||||
enrichment_status?: number
|
||||
esg_code?: string
|
||||
}
|
||||
|
||||
export interface InstantlyGetLeadParams extends InstantlyBaseParams {
|
||||
leadId: string
|
||||
}
|
||||
|
||||
export interface InstantlyPatchLeadParams extends InstantlyBaseParams {
|
||||
leadId: string
|
||||
personalization?: string | null
|
||||
website?: string | null
|
||||
last_name?: string | null
|
||||
first_name?: string | null
|
||||
company_name?: string | null
|
||||
job_title?: string | null
|
||||
phone?: string | null
|
||||
lt_interest_status?: number
|
||||
pl_value_lead?: string | null
|
||||
assigned_to?: string | null
|
||||
custom_variables?: Record<string, InstantlyScalar>
|
||||
}
|
||||
|
||||
export interface InstantlyCreateLeadParams extends InstantlyBaseParams {
|
||||
campaign?: string | null
|
||||
email?: string | null
|
||||
personalization?: string | null
|
||||
website?: string | null
|
||||
last_name?: string | null
|
||||
first_name?: string | null
|
||||
company_name?: string | null
|
||||
job_title?: string | null
|
||||
phone?: string | null
|
||||
lt_interest_status?: number
|
||||
pl_value_lead?: string | null
|
||||
list_id?: string | null
|
||||
assigned_to?: string | null
|
||||
skip_if_in_workspace?: boolean
|
||||
skip_if_in_campaign?: boolean
|
||||
skip_if_in_list?: boolean
|
||||
blocklist_id?: string
|
||||
verify_leads_for_lead_finder?: boolean
|
||||
verify_leads_on_import?: boolean
|
||||
custom_variables?: Record<string, InstantlyScalar>
|
||||
}
|
||||
|
||||
export interface InstantlyDeleteLeadsParams extends InstantlyBaseParams {
|
||||
campaign_id?: string
|
||||
list_id?: string
|
||||
status?: number
|
||||
ids?: string[]
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export interface InstantlyUpdateLeadInterestStatusParams extends InstantlyBaseParams {
|
||||
lead_email: string
|
||||
interest_value?: number | null
|
||||
campaign_id?: string
|
||||
ai_interest_value?: number
|
||||
disable_auto_interest?: boolean
|
||||
list_id?: string
|
||||
}
|
||||
|
||||
export interface InstantlyListCampaignsParams extends InstantlyBaseParams {
|
||||
limit?: number
|
||||
starting_after?: string
|
||||
search?: string
|
||||
tag_ids?: string
|
||||
ai_sales_agent_id?: string
|
||||
status?: number
|
||||
}
|
||||
|
||||
export interface InstantlyCreateCampaignParams extends InstantlyBaseParams {
|
||||
name: string
|
||||
campaign_schedule: Record<string, unknown>
|
||||
sequences?: unknown[]
|
||||
pl_value?: number | null
|
||||
email_gap?: number | null
|
||||
text_only?: boolean | null
|
||||
email_list?: string[]
|
||||
daily_limit?: number | null
|
||||
stop_on_reply?: boolean | null
|
||||
link_tracking?: boolean | null
|
||||
open_tracking?: boolean
|
||||
daily_max_leads?: number | null
|
||||
}
|
||||
|
||||
export interface InstantlyPatchCampaignParams extends Partial<InstantlyCreateCampaignParams> {
|
||||
apiKey: string
|
||||
campaignId: string
|
||||
}
|
||||
|
||||
export interface InstantlyActivateCampaignParams extends InstantlyBaseParams {
|
||||
campaignId: string
|
||||
}
|
||||
|
||||
export interface InstantlyPauseCampaignParams extends InstantlyBaseParams {
|
||||
campaignId: string
|
||||
}
|
||||
|
||||
export interface InstantlyDeleteCampaignParams extends InstantlyBaseParams {
|
||||
campaignId: string
|
||||
}
|
||||
|
||||
export interface InstantlyListEmailsParams extends InstantlyBaseParams {
|
||||
limit?: number
|
||||
starting_after?: string
|
||||
search?: string
|
||||
campaign_id?: string
|
||||
list_id?: string
|
||||
i_status?: number
|
||||
eaccount?: string
|
||||
lead?: string
|
||||
is_unread?: boolean
|
||||
}
|
||||
|
||||
export interface InstantlyReplyToEmailParams extends InstantlyBaseParams {
|
||||
eaccount: string
|
||||
reply_to_uuid: string
|
||||
subject: string
|
||||
body: {
|
||||
text?: string
|
||||
html?: string
|
||||
}
|
||||
cc_address_email_list?: string
|
||||
bcc_address_email_list?: string
|
||||
}
|
||||
|
||||
export interface InstantlyListLeadListsParams extends InstantlyBaseParams {
|
||||
limit?: number
|
||||
starting_after?: string
|
||||
has_enrichment_task?: boolean
|
||||
search?: string
|
||||
}
|
||||
|
||||
export interface InstantlyCreateLeadListParams extends InstantlyBaseParams {
|
||||
name: string
|
||||
has_enrichment_task?: boolean | null
|
||||
owned_by?: string | null
|
||||
}
|
||||
|
||||
export interface InstantlyListLeadsResponse extends ToolResponse {
|
||||
output: {
|
||||
leads: InstantlyLead[]
|
||||
count: number
|
||||
next_starting_after: string | null
|
||||
}
|
||||
}
|
||||
|
||||
export interface InstantlyLeadResponse extends ToolResponse {
|
||||
output: {
|
||||
lead: InstantlyLead
|
||||
id: string | null
|
||||
email_address: string | null
|
||||
first_name: string | null
|
||||
last_name: string | null
|
||||
campaign: string | null
|
||||
status: number | null
|
||||
}
|
||||
}
|
||||
|
||||
export interface InstantlyDeleteLeadsResponse extends ToolResponse {
|
||||
output: {
|
||||
count: number | null
|
||||
}
|
||||
}
|
||||
|
||||
export interface InstantlyUpdateLeadInterestStatusResponse extends ToolResponse {
|
||||
output: {
|
||||
message: string | null
|
||||
}
|
||||
}
|
||||
|
||||
export interface InstantlyListCampaignsResponse extends ToolResponse {
|
||||
output: {
|
||||
campaigns: InstantlyCampaign[]
|
||||
count: number
|
||||
next_starting_after: string | null
|
||||
}
|
||||
}
|
||||
|
||||
export interface InstantlyCampaignResponse extends ToolResponse {
|
||||
output: {
|
||||
campaign: InstantlyCampaign
|
||||
id: string | null
|
||||
name: string | null
|
||||
status: number | null
|
||||
}
|
||||
}
|
||||
|
||||
export interface InstantlyCampaignActionResponse extends ToolResponse {
|
||||
output: {
|
||||
campaign: InstantlyCampaign
|
||||
id: string | null
|
||||
name: string | null
|
||||
status: number | null
|
||||
message: string | null
|
||||
}
|
||||
}
|
||||
|
||||
export interface InstantlyListEmailsResponse extends ToolResponse {
|
||||
output: {
|
||||
emails: InstantlyEmail[]
|
||||
count: number
|
||||
next_starting_after: string | null
|
||||
}
|
||||
}
|
||||
|
||||
export interface InstantlyEmailResponse extends ToolResponse {
|
||||
output: {
|
||||
email: InstantlyEmail
|
||||
id: string | null
|
||||
subject: string | null
|
||||
thread_id: string | null
|
||||
}
|
||||
}
|
||||
|
||||
export interface InstantlyListLeadListsResponse extends ToolResponse {
|
||||
output: {
|
||||
lead_lists: InstantlyLeadList[]
|
||||
count: number
|
||||
next_starting_after: string | null
|
||||
}
|
||||
}
|
||||
|
||||
export interface InstantlyLeadListResponse extends ToolResponse {
|
||||
output: {
|
||||
lead_list: InstantlyLeadList
|
||||
id: string | null
|
||||
name: string | null
|
||||
}
|
||||
}
|
||||
|
||||
export type InstantlyResponse =
|
||||
| InstantlyListLeadsResponse
|
||||
| InstantlyLeadResponse
|
||||
| InstantlyDeleteLeadsResponse
|
||||
| InstantlyUpdateLeadInterestStatusResponse
|
||||
| InstantlyListCampaignsResponse
|
||||
| InstantlyCampaignResponse
|
||||
| InstantlyCampaignActionResponse
|
||||
| InstantlyListEmailsResponse
|
||||
| InstantlyEmailResponse
|
||||
| InstantlyListLeadListsResponse
|
||||
| InstantlyLeadListResponse
|
||||
@@ -0,0 +1,99 @@
|
||||
import type {
|
||||
InstantlyUpdateLeadInterestStatusParams,
|
||||
InstantlyUpdateLeadInterestStatusResponse,
|
||||
} from '@/tools/instantly/types'
|
||||
import {
|
||||
asRecord,
|
||||
compactBody,
|
||||
instantlyBaseParamFields,
|
||||
instantlyHeaders,
|
||||
instantlyUrl,
|
||||
parseInstantlyResponse,
|
||||
} from '@/tools/instantly/utils'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const updateLeadInterestStatusTool: ToolConfig<
|
||||
InstantlyUpdateLeadInterestStatusParams,
|
||||
InstantlyUpdateLeadInterestStatusResponse
|
||||
> = {
|
||||
id: 'instantly_update_lead_interest_status',
|
||||
name: 'Instantly Update Lead Interest Status',
|
||||
description: 'Submits an Instantly V2 background job to update a lead interest status.',
|
||||
version: '1.0.0',
|
||||
params: {
|
||||
...instantlyBaseParamFields,
|
||||
lead_email: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead email address',
|
||||
},
|
||||
interest_value: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Interest status value. Leave empty in the block or pass null to reset to Lead.',
|
||||
},
|
||||
campaign_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Campaign ID for the lead',
|
||||
},
|
||||
list_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lead list ID for the lead',
|
||||
},
|
||||
ai_interest_value: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'AI interest value to set for the lead',
|
||||
},
|
||||
disable_auto_interest: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether to disable auto interest',
|
||||
},
|
||||
},
|
||||
request: {
|
||||
url: () => instantlyUrl('/api/v2/leads/update-interest-status'),
|
||||
method: 'POST',
|
||||
headers: instantlyHeaders,
|
||||
body: (params) => {
|
||||
if (params.interest_value === undefined) {
|
||||
throw new Error('Interest Value is required for Instantly Update Lead Interest Status')
|
||||
}
|
||||
|
||||
return compactBody({
|
||||
lead_email: params.lead_email,
|
||||
interest_value: params.interest_value,
|
||||
campaign_id: params.campaign_id,
|
||||
list_id: params.list_id,
|
||||
ai_interest_value: params.ai_interest_value,
|
||||
disable_auto_interest: params.disable_auto_interest,
|
||||
})
|
||||
},
|
||||
},
|
||||
transformResponse: async (response) => {
|
||||
const data = await parseInstantlyResponse(response)
|
||||
const result = asRecord(data)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
message: typeof result.message === 'string' ? result.message : null,
|
||||
},
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
message: {
|
||||
type: 'string',
|
||||
description: 'Background job submission message',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,372 @@
|
||||
import { filterUndefined, isRecordLike } from '@sim/utils/object'
|
||||
import type {
|
||||
InstantlyCampaign,
|
||||
InstantlyEmail,
|
||||
InstantlyLead,
|
||||
InstantlyLeadList,
|
||||
} from '@/tools/instantly/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
const INSTANTLY_API_BASE_URL = 'https://api.instantly.ai'
|
||||
|
||||
type InstantlyBaseParams = { apiKey: string }
|
||||
type JsonRecord = Record<string, unknown>
|
||||
|
||||
export const instantlyBaseParamFields = {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Instantly API key with the required V2 scopes',
|
||||
},
|
||||
} satisfies ToolConfig<InstantlyBaseParams>['params']
|
||||
|
||||
export const instantlyHeaders = (params: InstantlyBaseParams) => ({
|
||||
Authorization: `Bearer ${params.apiKey.trim()}`,
|
||||
'Content-Type': 'application/json',
|
||||
})
|
||||
|
||||
export function instantlyUrl(path: string, query?: Record<string, unknown>): string {
|
||||
const url = new URL(path, INSTANTLY_API_BASE_URL)
|
||||
|
||||
if (query) {
|
||||
for (const [key, value] of Object.entries(query)) {
|
||||
if (value === undefined || value === null || value === '') continue
|
||||
url.searchParams.append(key, String(value))
|
||||
}
|
||||
}
|
||||
|
||||
return url.toString()
|
||||
}
|
||||
|
||||
export function compactBody(values: Record<string, unknown>): Record<string, unknown> {
|
||||
return filterUndefined(values)
|
||||
}
|
||||
|
||||
export async function parseInstantlyResponse(response: Response): Promise<unknown> {
|
||||
const data = await parseJsonResponse(response)
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
extractInstantlyError(data, `Instantly API request failed (${response.status})`)
|
||||
)
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
export function asRecord(value: unknown): JsonRecord {
|
||||
return isRecordLike(value) ? value : {}
|
||||
}
|
||||
|
||||
export function getItems(value: unknown): JsonRecord[] {
|
||||
const data = asRecord(value)
|
||||
return Array.isArray(data.items) ? data.items.map(asRecord) : []
|
||||
}
|
||||
|
||||
export function getNextStartingAfter(value: unknown): string | null {
|
||||
const data = asRecord(value)
|
||||
return asString(data.next_starting_after)
|
||||
}
|
||||
|
||||
export function mapLead(value: unknown): InstantlyLead {
|
||||
const lead = asRecord(value)
|
||||
|
||||
return {
|
||||
id: asString(lead.id),
|
||||
timestamp_created: asString(lead.timestamp_created),
|
||||
timestamp_updated: asString(lead.timestamp_updated),
|
||||
organization: asString(lead.organization),
|
||||
campaign: asString(lead.campaign),
|
||||
status: asNumber(lead.status),
|
||||
email: asString(lead.email),
|
||||
personalization: asString(lead.personalization),
|
||||
website: asString(lead.website),
|
||||
last_name: asString(lead.last_name),
|
||||
first_name: asString(lead.first_name),
|
||||
company_name: asString(lead.company_name),
|
||||
job_title: asString(lead.job_title),
|
||||
phone: asString(lead.phone),
|
||||
email_open_count: asNumber(lead.email_open_count),
|
||||
email_reply_count: asNumber(lead.email_reply_count),
|
||||
email_click_count: asNumber(lead.email_click_count),
|
||||
company_domain: asString(lead.company_domain),
|
||||
payload: isRecordLike(lead.payload) ? lead.payload : null,
|
||||
lt_interest_status: asNumber(lead.lt_interest_status),
|
||||
}
|
||||
}
|
||||
|
||||
export function mapCampaign(value: unknown): InstantlyCampaign {
|
||||
const campaign = asRecord(value)
|
||||
|
||||
return {
|
||||
id: asString(campaign.id),
|
||||
name: asString(campaign.name),
|
||||
pl_value: asNumber(campaign.pl_value),
|
||||
status: asNumber(campaign.status),
|
||||
is_evergreen: asBoolean(campaign.is_evergreen),
|
||||
timestamp_created: asString(campaign.timestamp_created),
|
||||
timestamp_updated: asString(campaign.timestamp_updated),
|
||||
email_gap: asNumber(campaign.email_gap),
|
||||
daily_limit: asNumber(campaign.daily_limit),
|
||||
daily_max_leads: asNumber(campaign.daily_max_leads),
|
||||
open_tracking: asBoolean(campaign.open_tracking),
|
||||
stop_on_reply: asBoolean(campaign.stop_on_reply),
|
||||
sequences: Array.isArray(campaign.sequences) ? campaign.sequences : [],
|
||||
campaign_schedule: isRecordLike(campaign.campaign_schedule) ? campaign.campaign_schedule : null,
|
||||
}
|
||||
}
|
||||
|
||||
export function mapEmail(value: unknown): InstantlyEmail {
|
||||
const email = asRecord(value)
|
||||
const body = asRecord(email.body)
|
||||
|
||||
return {
|
||||
id: asString(email.id),
|
||||
timestamp_created: asString(email.timestamp_created),
|
||||
timestamp_email: asString(email.timestamp_email),
|
||||
message_id: asString(email.message_id),
|
||||
subject: asString(email.subject),
|
||||
from_address_email: asString(email.from_address_email),
|
||||
to_address_email_list: asString(email.to_address_email_list),
|
||||
cc_address_email_list: asString(email.cc_address_email_list),
|
||||
bcc_address_email_list: asString(email.bcc_address_email_list),
|
||||
reply_to: asString(email.reply_to),
|
||||
body: {
|
||||
text: asString(body.text),
|
||||
html: asString(body.html),
|
||||
},
|
||||
organization_id: asString(email.organization_id),
|
||||
campaign_id: asString(email.campaign_id),
|
||||
subsequence_id: asString(email.subsequence_id),
|
||||
list_id: asString(email.list_id),
|
||||
lead: asString(email.lead),
|
||||
lead_id: asString(email.lead_id),
|
||||
eaccount: asString(email.eaccount),
|
||||
ue_type: asNumber(email.ue_type),
|
||||
is_unread: asNumber(email.is_unread),
|
||||
is_auto_reply: asNumber(email.is_auto_reply),
|
||||
i_status: asNumber(email.i_status),
|
||||
thread_id: asString(email.thread_id),
|
||||
content_preview: asString(email.content_preview),
|
||||
}
|
||||
}
|
||||
|
||||
export function mapLeadList(value: unknown): InstantlyLeadList {
|
||||
const leadList = asRecord(value)
|
||||
|
||||
return {
|
||||
id: asString(leadList.id),
|
||||
organization_id: asString(leadList.organization_id),
|
||||
has_enrichment_task: asBoolean(leadList.has_enrichment_task),
|
||||
owned_by: asString(leadList.owned_by),
|
||||
name: asString(leadList.name),
|
||||
timestamp_created: asString(leadList.timestamp_created),
|
||||
}
|
||||
}
|
||||
|
||||
export const leadOutputs = {
|
||||
lead: {
|
||||
type: 'object',
|
||||
description: 'Lead details',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Lead ID', nullable: true },
|
||||
email: { type: 'string', description: 'Lead email address', nullable: true },
|
||||
first_name: { type: 'string', description: 'Lead first name', nullable: true },
|
||||
last_name: { type: 'string', description: 'Lead last name', nullable: true },
|
||||
company_name: { type: 'string', description: 'Lead company name', nullable: true },
|
||||
job_title: { type: 'string', description: 'Lead job title', nullable: true },
|
||||
campaign: { type: 'string', description: 'Campaign ID', nullable: true },
|
||||
status: { type: 'number', description: 'Lead status', nullable: true },
|
||||
payload: { type: 'json', description: 'Lead custom variables', nullable: true },
|
||||
},
|
||||
},
|
||||
id: { type: 'string', description: 'Lead ID', optional: true },
|
||||
email_address: { type: 'string', description: 'Lead email address', optional: true },
|
||||
first_name: { type: 'string', description: 'Lead first name', optional: true },
|
||||
last_name: { type: 'string', description: 'Lead last name', optional: true },
|
||||
campaign: { type: 'string', description: 'Campaign ID', optional: true },
|
||||
status: { type: 'number', description: 'Lead status', optional: true },
|
||||
} satisfies ToolConfig['outputs']
|
||||
|
||||
export const leadsListOutputs = {
|
||||
leads: {
|
||||
type: 'array',
|
||||
description: 'List of leads',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Lead ID', nullable: true },
|
||||
email: { type: 'string', description: 'Lead email address', nullable: true },
|
||||
first_name: { type: 'string', description: 'Lead first name', nullable: true },
|
||||
last_name: { type: 'string', description: 'Lead last name', nullable: true },
|
||||
company_name: { type: 'string', description: 'Lead company name', nullable: true },
|
||||
campaign: { type: 'string', description: 'Campaign ID', nullable: true },
|
||||
status: { type: 'number', description: 'Lead status', nullable: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: { type: 'number', description: 'Number of leads returned' },
|
||||
next_starting_after: { type: 'string', description: 'Cursor for the next page', optional: true },
|
||||
} satisfies ToolConfig['outputs']
|
||||
|
||||
export const campaignOutputs = {
|
||||
campaign: {
|
||||
type: 'object',
|
||||
description: 'Campaign details',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Campaign ID', nullable: true },
|
||||
name: { type: 'string', description: 'Campaign name', nullable: true },
|
||||
status: { type: 'number', description: 'Campaign status', nullable: true },
|
||||
daily_limit: { type: 'number', description: 'Daily sending limit', nullable: true },
|
||||
daily_max_leads: { type: 'number', description: 'Daily max new leads', nullable: true },
|
||||
open_tracking: {
|
||||
type: 'boolean',
|
||||
description: 'Whether open tracking is enabled',
|
||||
nullable: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
id: { type: 'string', description: 'Campaign ID', optional: true },
|
||||
name: { type: 'string', description: 'Campaign name', optional: true },
|
||||
status: { type: 'number', description: 'Campaign status', optional: true },
|
||||
} satisfies ToolConfig['outputs']
|
||||
|
||||
export const campaignActionOutputs = {
|
||||
...campaignOutputs,
|
||||
message: { type: 'string', description: 'Confirmation message from Instantly', optional: true },
|
||||
} satisfies ToolConfig['outputs']
|
||||
|
||||
export const campaignsListOutputs = {
|
||||
campaigns: {
|
||||
type: 'array',
|
||||
description: 'List of campaigns',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Campaign ID', nullable: true },
|
||||
name: { type: 'string', description: 'Campaign name', nullable: true },
|
||||
status: { type: 'number', description: 'Campaign status', nullable: true },
|
||||
daily_limit: { type: 'number', description: 'Daily sending limit', nullable: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: { type: 'number', description: 'Number of campaigns returned' },
|
||||
next_starting_after: { type: 'string', description: 'Cursor for the next page', optional: true },
|
||||
} satisfies ToolConfig['outputs']
|
||||
|
||||
export const emailOutputs = {
|
||||
email: {
|
||||
type: 'object',
|
||||
description: 'Email details',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Email ID', nullable: true },
|
||||
subject: { type: 'string', description: 'Email subject', nullable: true },
|
||||
from_address_email: { type: 'string', description: 'Sender email', nullable: true },
|
||||
to_address_email_list: {
|
||||
type: 'string',
|
||||
description: 'Recipient email list',
|
||||
nullable: true,
|
||||
},
|
||||
thread_id: { type: 'string', description: 'Thread ID', nullable: true },
|
||||
content_preview: { type: 'string', description: 'Email content preview', nullable: true },
|
||||
},
|
||||
},
|
||||
id: { type: 'string', description: 'Email ID', optional: true },
|
||||
subject: { type: 'string', description: 'Email subject', optional: true },
|
||||
thread_id: { type: 'string', description: 'Thread ID', optional: true },
|
||||
} satisfies ToolConfig['outputs']
|
||||
|
||||
export const emailsListOutputs = {
|
||||
emails: {
|
||||
type: 'array',
|
||||
description: 'List of emails',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Email ID', nullable: true },
|
||||
subject: { type: 'string', description: 'Email subject', nullable: true },
|
||||
from_address_email: { type: 'string', description: 'Sender email', nullable: true },
|
||||
lead: { type: 'string', description: 'Lead email', nullable: true },
|
||||
thread_id: { type: 'string', description: 'Thread ID', nullable: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: { type: 'number', description: 'Number of emails returned' },
|
||||
next_starting_after: { type: 'string', description: 'Cursor for the next page', optional: true },
|
||||
} satisfies ToolConfig['outputs']
|
||||
|
||||
export const leadListOutputs = {
|
||||
lead_list: {
|
||||
type: 'object',
|
||||
description: 'Lead list details',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Lead list ID', nullable: true },
|
||||
organization_id: { type: 'string', description: 'Organization ID', nullable: true },
|
||||
has_enrichment_task: {
|
||||
type: 'boolean',
|
||||
description: 'Whether enrichment is enabled',
|
||||
nullable: true,
|
||||
},
|
||||
owned_by: { type: 'string', description: 'Owner user ID', nullable: true },
|
||||
name: { type: 'string', description: 'Lead list name', nullable: true },
|
||||
timestamp_created: { type: 'string', description: 'Creation timestamp', nullable: true },
|
||||
},
|
||||
},
|
||||
id: { type: 'string', description: 'Lead list ID', optional: true },
|
||||
name: { type: 'string', description: 'Lead list name', optional: true },
|
||||
} satisfies ToolConfig['outputs']
|
||||
|
||||
export const leadListsListOutputs = {
|
||||
lead_lists: {
|
||||
type: 'array',
|
||||
description: 'List of lead lists',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Lead list ID', nullable: true },
|
||||
name: { type: 'string', description: 'Lead list name', nullable: true },
|
||||
has_enrichment_task: {
|
||||
type: 'boolean',
|
||||
description: 'Whether enrichment is enabled',
|
||||
nullable: true,
|
||||
},
|
||||
timestamp_created: { type: 'string', description: 'Creation timestamp', nullable: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
count: { type: 'number', description: 'Number of lead lists returned' },
|
||||
next_starting_after: { type: 'string', description: 'Cursor for the next page', optional: true },
|
||||
} satisfies ToolConfig['outputs']
|
||||
|
||||
async function parseJsonResponse(response: Response): Promise<unknown> {
|
||||
try {
|
||||
return await response.json()
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export function getMessage(value: unknown): string | null {
|
||||
const data = asRecord(value)
|
||||
return typeof data.message === 'string' ? data.message : null
|
||||
}
|
||||
|
||||
function extractInstantlyError(value: unknown, fallback: string): string {
|
||||
const data = asRecord(value)
|
||||
if (typeof data.message === 'string') return data.message
|
||||
if (typeof data.error === 'string') return data.error
|
||||
return fallback
|
||||
}
|
||||
|
||||
function asString(value: unknown): string | null {
|
||||
return typeof value === 'string' ? value : null
|
||||
}
|
||||
|
||||
function asNumber(value: unknown): number | null {
|
||||
return typeof value === 'number' && Number.isFinite(value) ? value : null
|
||||
}
|
||||
|
||||
function asBoolean(value: unknown): boolean | null {
|
||||
return typeof value === 'boolean' ? value : null
|
||||
}
|
||||
Reference in New Issue
Block a user