Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
170 changes: 151 additions & 19 deletions apps/docs/content/docs/en/integrations/gong.mdx

Large diffs are not rendered by default.

343 changes: 327 additions & 16 deletions apps/sim/blocks/blocks/gong.ts

Large diffs are not rendered by default.

18 changes: 17 additions & 1 deletion apps/sim/lib/integrations/integrations.json
Original file line number Diff line number Diff line change
Expand Up @@ -6545,6 +6545,10 @@
"name": "Assign Flow Prospects",
"description": "Assign up to 200 CRM prospects (contacts or leads) to a Gong Engage flow."
},
{
"name": "Unassign Flow Prospects",
"description": "Remove a prospect from Gong Engage flows. Omit the flow ID to remove the prospect from all flows they are assigned to."
},
{
"name": "Get Prospect Flows",
"description": "Get the Gong Engage flows currently assigned to the given CRM prospects."
Expand All @@ -6553,6 +6557,18 @@
"name": "Get Coaching",
"description": "Retrieve coaching metrics for a manager from Gong."
},
{
"name": "Ask Anything",
"description": "Ask a natural-language question about a CRM account, deal, contact, or lead. Gong answers from up to 60 calls and 500 emails associated with the entity. Consumes Gong credits."
},
{
"name": "Get Brief",
"description": "Generate an AI brief (configured in Gong Agent Studio) for a CRM account, deal, contact, or lead. Consumes Gong credits."
},
{
"name": "Get Logs",
"description": "Retrieve Gong log entries of a specific type within a time range."
},
{
"name": "Lookup Email",
"description": "Find all references to an email address in Gong (calls, email messages, meetings, CRM data, engagement)."
Expand All @@ -6570,7 +6586,7 @@
"description": "Erase all Gong data (calls, leads, contacts) referencing a phone number. Asynchronous and irreversible."
}
],
"operationCount": 25,
"operationCount": 29,
"triggers": [
{
"id": "gong_webhook",
Expand Down
6 changes: 6 additions & 0 deletions apps/sim/tools/gong/aggregate_activity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export const aggregateActivityTool: ToolConfig<
return {
success: true,
output: {
requestId: data.requestId ?? null,
usersActivity,
timeZone: data.timeZone ?? null,
fromDateTime: data.fromDateTime ?? null,
Expand All @@ -113,6 +114,11 @@ export const aggregateActivityTool: ToolConfig<
},

outputs: {
requestId: {
type: 'string',
description: 'A Gong request reference ID for troubleshooting purposes',
optional: true,
},
usersActivity: {
type: 'array',
description: 'Aggregated activity statistics per user',
Expand Down
2 changes: 1 addition & 1 deletion apps/sim/tools/gong/aggregate_by_period.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export const aggregateByPeriodTool: ToolConfig<
const userIds = parseGongIdList(params.userIds)
if (userIds) filter.userIds = userIds
const body: Record<string, unknown> = {
aggregationPeriod: params.aggregationPeriod.trim(),
aggregationPeriod: params.aggregationPeriod.trim().toUpperCase(),
filter,
}
if (params.cursor?.trim()) body.cursor = params.cursor.trim()
Expand Down
16 changes: 15 additions & 1 deletion apps/sim/tools/gong/answered_scorecards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,20 +122,27 @@ export const answeredScorecardsTool: ToolConfig<
score: answer.score ?? null,
answerText: answer.answerText ?? null,
notApplicable: answer.notApplicable ?? null,
selectedOptions: answer.selectedOptions ?? null,
})
),
})
)
return {
success: true,
output: {
requestId: data.requestId ?? null,
answeredScorecards,
cursor: data.records?.cursor ?? null,
},
}
},

outputs: {
requestId: {
type: 'string',
description: 'A Gong request reference ID for troubleshooting purposes',
optional: true,
},
answeredScorecards: {
type: 'array',
description: 'List of answered scorecards with scores and answers',
Expand Down Expand Up @@ -183,7 +190,7 @@ export const answeredScorecardsTool: ToolConfig<
isOverall: { type: 'boolean', description: 'Whether this is the overall question' },
score: {
type: 'number',
description: 'Score between 1 to 5 if answered, null otherwise',
description: 'Score between 1 to 50 if answered, null otherwise',
},
answerText: {
type: 'string',
Expand All @@ -193,6 +200,12 @@ export const answeredScorecardsTool: ToolConfig<
type: 'boolean',
description: 'Whether the question is not applicable to this call',
},
selectedOptions: {
type: 'array',
description:
'Identifiers of the options selected for select-type questions, null otherwise',
items: { type: 'string' },
},
},
},
},
Expand All @@ -202,6 +215,7 @@ export const answeredScorecardsTool: ToolConfig<
cursor: {
type: 'string',
description: 'Pagination cursor for the next page',
optional: true,
},
},
}
161 changes: 161 additions & 0 deletions apps/sim/tools/gong/ask_anything.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import type { GongAskAnythingParams, GongAskAnythingResponse } from '@/tools/gong/types'
import { getGongErrorMessage } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'

export const askAnythingTool: ToolConfig<GongAskAnythingParams, GongAskAnythingResponse> = {
id: 'gong_ask_anything',
name: 'Gong Ask Anything',
description:
'Ask a natural-language question about a CRM account, deal, contact, or lead. Gong answers from up to 60 calls and 500 emails associated with the entity. Consumes Gong credits.',
version: '1.0.0',

params: {
accessKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Gong API Access Key',
},
accessKeySecret: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Gong API Access Key Secret',
},
workspaceId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Gong workspace ID the entity belongs to',
},
crmEntityType: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Type of the CRM entity: ACCOUNT, CONTACT, DEAL, or LEAD',
},
crmEntityId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The CRM ID of the entity the question is asked about',
},
question: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The natural-language question to ask about the entity',
},
timePeriod: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Time period of conversations to consider: LAST_7DAYS, LAST_30DAYS, LAST_90DAYS, LAST_90_DAYS_SINCE_LAST_ACTIVITY, LAST_YEAR_SINCE_LAST_ACTIVITY, LAST_YEAR, THIS_WEEK, THIS_MONTH, THIS_YEAR, THIS_QUARTER, CUSTOM_RANGE, or ALL_CONVERSATIONS',
},
fromDateTime: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Start date/time (UTC, ISO-8601) for calls and emails to include. Required when timePeriod is CUSTOM_RANGE.',
},
toDateTime: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'End date/time (UTC, ISO-8601) for calls and emails to include. Required when timePeriod is CUSTOM_RANGE.',
},
},

request: {
url: (params) => {
const timePeriod = params.timePeriod.trim().toUpperCase()
if (
timePeriod === 'CUSTOM_RANGE' &&
(!params.fromDateTime?.trim() || !params.toDateTime?.trim())
) {
throw new Error('fromDateTime and toDateTime are required when timePeriod is CUSTOM_RANGE')
}
const url = new URL('https://api.gong.io/v2/entities/ask-entity')
url.searchParams.set('workspaceId', params.workspaceId.trim())
url.searchParams.set('crmEntityType', params.crmEntityType.trim().toUpperCase())
url.searchParams.set('crmEntityId', params.crmEntityId.trim())
url.searchParams.set('timePeriod', timePeriod)
url.searchParams.set('question', params.question.trim())
if (timePeriod === 'CUSTOM_RANGE') {
url.searchParams.set('fromDateTime', params.fromDateTime?.trim() ?? '')
url.searchParams.set('toDateTime', params.toDateTime?.trim() ?? '')
}
return url.toString()
},
method: 'GET',
headers: (params) => ({
Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`,
}),
},

transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(getGongErrorMessage(data, 'Failed to ask about the entity'))
}
const answer = (data.answer ?? []).map((section: Record<string, unknown>) => ({
answerItems: section.answerItems ?? [],
callFindings: section.callFindings ?? [],
emailFindings: section.emailFindings ?? [],
}))
return {
success: true,
output: {
requestId: data.requestId ?? null,
numOfCallsSearched: data.numOfCallsSearched ?? null,
numOfEmailsSearched: data.numOfEmailsSearched ?? null,
answer,
},
}
},

outputs: {
requestId: {
type: 'string',
description: 'A Gong request reference ID for troubleshooting purposes',
optional: true,
},
numOfCallsSearched: {
type: 'number',
description: 'Number of calls used to generate the answer',
optional: true,
},
numOfEmailsSearched: {
type: 'number',
description: 'Number of emails used to generate the answer',
optional: true,
},
answer: {
type: 'array',
description: 'Sections of the generated answer with supporting evidence',
items: {
type: 'object',
properties: {
answerItems: {
type: 'array',
description: 'Text items that make up this part of the answer',
items: { type: 'string' },
},
callFindings: {
type: 'array',
description: 'Evidence from calls used to generate this answer item',
items: { type: 'object' },
},
emailFindings: {
type: 'array',
description: 'Evidence from emails used to generate this answer item',
items: { type: 'object' },
},
},
},
},
},
}
15 changes: 5 additions & 10 deletions apps/sim/tools/gong/create_call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,10 @@ export const createCallTool: ToolConfig<GongCreateCallParams, GongCreateCallResp
},
downloadMediaUrl: {
type: 'string',
required: true,
required: false,
visibility: 'user-or-llm',
description: 'URL where Gong can download the call media file',
description:
'URL where Gong can download the call media file. If omitted, the call is created without media and Gong waits for a separate media upload.',
},
title: {
type: 'string',
Expand Down Expand Up @@ -108,10 +109,10 @@ export const createCallTool: ToolConfig<GongCreateCallParams, GongCreateCallResp
actualStart: params.actualStart.trim(),
primaryUser: params.primaryUser.trim(),
parties: parseGongJsonArray(params.parties, 'parties'),
direction: params.direction,
downloadMediaUrl: params.downloadMediaUrl.trim(),
direction: params.direction.trim(),
}

if (params.downloadMediaUrl?.trim()) body.downloadMediaUrl = params.downloadMediaUrl.trim()
if (params.title?.trim()) body.title = params.title.trim()
if (params.workspaceId?.trim()) body.workspaceId = params.workspaceId.trim()
if (params.disposition?.trim()) body.disposition = params.disposition.trim()
Expand All @@ -134,7 +135,6 @@ export const createCallTool: ToolConfig<GongCreateCallParams, GongCreateCallResp
output: {
callId: data.callId ?? '',
Comment thread
waleedlatif1 marked this conversation as resolved.
requestId: data.requestId ?? '',
url: data.url ?? null,
},
}
},
Expand All @@ -148,10 +148,5 @@ export const createCallTool: ToolConfig<GongCreateCallParams, GongCreateCallResp
type: 'string',
description: 'Gong request reference ID for troubleshooting',
},
url: {
type: 'string',
description: 'URL to the created call in the Gong web app',
optional: true,
},
},
}
Loading
Loading