Skip to content

Commit b1bd2b5

Browse files
authored
feat(gong): align tools with official API spec + 4 new tools (#5632)
* feat(gong): align tools with official API spec, add ask-anything, brief, unassign, and logs tools - fix gong_list_flows: query param was flowEmailOwner (typo copied from Gong's endpoint prose); the API requires flowOwnerEmail, so every call failed - create_call: drop phantom url output (API returns only requestId/callId) and make downloadMediaUrl optional per spec - list_scorecards: refresh to current spec (numeric IDs, questionType/answerGuide/minRange/maxRange/answerOptions, reviewMethod) - answered_scorecards: map selectedOptions on answers, correct score range description (1-50) - surface requestId uniformly across all read tools; totalRecords no longer fabricated from page size - normalize includeAvatars to a strict boolean param, uppercase aggregationPeriod, encode userId path param - validate email/phone format before irreversible GDPR purge calls - new tools: gong_ask_anything, gong_get_brief (AI entity Q&A/briefs), gong_unassign_flow_prospects, gong_get_logs * fix(gong): require custom-range dates and gate param remapping by operation - ask_anything/get_brief: entityFromDateTime/entityToDateTime now conditionally required (UI) and validated tool-side when timePeriod is CUSTOM_RANGE - block params mapper: remaps are gated by the selected operation so stale values from previously configured operations can no longer overwrite fromDateTime/fromDate/workspaceId * fix(gong): final spec-alignment pass, review fixes, and regenerated docs - ask_anything/get_brief: send fromDateTime/toDateTime only for CUSTOM_RANGE; declare mcpResult brief section field - unassign: dedicated optional unassignFlowId subblock so a stale assign-flow ID can never silently narrow an unassign to one flow - get_logs: logType is a closed enum (AccessLog, UserActivityLog, UserCallPlay, ExternallySharedCallAccess, ExternallySharedCallPlay) - dropdown in block, enumerated in tool description - get_folder_content: folderId optional per spec; get_call: encode callId path param - list_trackers: drop saidInCallParts (absent from the spec's KeywordTracker schema) - get_extensive_calls: correct declared interactionStats item shape to {name, value} - block inputs: list all remapped subblock params; optional flags on nullable outputs; absolute types re-export - regenerate Gong integration docs and integrations.json entries (29 operations)
1 parent 0d9f860 commit b1bd2b5

30 files changed

Lines changed: 1395 additions & 116 deletions

apps/docs/content/docs/en/integrations/gong.mdx

Lines changed: 151 additions & 19 deletions
Large diffs are not rendered by default.

apps/sim/blocks/blocks/gong.ts

Lines changed: 327 additions & 16 deletions
Large diffs are not rendered by default.

apps/sim/lib/integrations/integrations.json

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6545,6 +6545,10 @@
65456545
"name": "Assign Flow Prospects",
65466546
"description": "Assign up to 200 CRM prospects (contacts or leads) to a Gong Engage flow."
65476547
},
6548+
{
6549+
"name": "Unassign Flow Prospects",
6550+
"description": "Remove a prospect from Gong Engage flows. Omit the flow ID to remove the prospect from all flows they are assigned to."
6551+
},
65486552
{
65496553
"name": "Get Prospect Flows",
65506554
"description": "Get the Gong Engage flows currently assigned to the given CRM prospects."
@@ -6553,6 +6557,18 @@
65536557
"name": "Get Coaching",
65546558
"description": "Retrieve coaching metrics for a manager from Gong."
65556559
},
6560+
{
6561+
"name": "Ask Anything",
6562+
"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."
6563+
},
6564+
{
6565+
"name": "Get Brief",
6566+
"description": "Generate an AI brief (configured in Gong Agent Studio) for a CRM account, deal, contact, or lead. Consumes Gong credits."
6567+
},
6568+
{
6569+
"name": "Get Logs",
6570+
"description": "Retrieve Gong log entries of a specific type within a time range."
6571+
},
65566572
{
65576573
"name": "Lookup Email",
65586574
"description": "Find all references to an email address in Gong (calls, email messages, meetings, CRM data, engagement)."
@@ -6570,7 +6586,7 @@
65706586
"description": "Erase all Gong data (calls, leads, contacts) referencing a phone number. Asynchronous and irreversible."
65716587
}
65726588
],
6573-
"operationCount": 25,
6589+
"operationCount": 29,
65746590
"triggers": [
65756591
{
65766592
"id": "gong_webhook",

apps/sim/tools/gong/aggregate_activity.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ export const aggregateActivityTool: ToolConfig<
103103
return {
104104
success: true,
105105
output: {
106+
requestId: data.requestId ?? null,
106107
usersActivity,
107108
timeZone: data.timeZone ?? null,
108109
fromDateTime: data.fromDateTime ?? null,
@@ -113,6 +114,11 @@ export const aggregateActivityTool: ToolConfig<
113114
},
114115

115116
outputs: {
117+
requestId: {
118+
type: 'string',
119+
description: 'A Gong request reference ID for troubleshooting purposes',
120+
optional: true,
121+
},
116122
usersActivity: {
117123
type: 'array',
118124
description: 'Aggregated activity statistics per user',

apps/sim/tools/gong/aggregate_by_period.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export const aggregateByPeriodTool: ToolConfig<
7474
const userIds = parseGongIdList(params.userIds)
7575
if (userIds) filter.userIds = userIds
7676
const body: Record<string, unknown> = {
77-
aggregationPeriod: params.aggregationPeriod.trim(),
77+
aggregationPeriod: params.aggregationPeriod.trim().toUpperCase(),
7878
filter,
7979
}
8080
if (params.cursor?.trim()) body.cursor = params.cursor.trim()

apps/sim/tools/gong/answered_scorecards.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,20 +122,27 @@ export const answeredScorecardsTool: ToolConfig<
122122
score: answer.score ?? null,
123123
answerText: answer.answerText ?? null,
124124
notApplicable: answer.notApplicable ?? null,
125+
selectedOptions: answer.selectedOptions ?? null,
125126
})
126127
),
127128
})
128129
)
129130
return {
130131
success: true,
131132
output: {
133+
requestId: data.requestId ?? null,
132134
answeredScorecards,
133135
cursor: data.records?.cursor ?? null,
134136
},
135137
}
136138
},
137139

138140
outputs: {
141+
requestId: {
142+
type: 'string',
143+
description: 'A Gong request reference ID for troubleshooting purposes',
144+
optional: true,
145+
},
139146
answeredScorecards: {
140147
type: 'array',
141148
description: 'List of answered scorecards with scores and answers',
@@ -183,7 +190,7 @@ export const answeredScorecardsTool: ToolConfig<
183190
isOverall: { type: 'boolean', description: 'Whether this is the overall question' },
184191
score: {
185192
type: 'number',
186-
description: 'Score between 1 to 5 if answered, null otherwise',
193+
description: 'Score between 1 to 50 if answered, null otherwise',
187194
},
188195
answerText: {
189196
type: 'string',
@@ -193,6 +200,12 @@ export const answeredScorecardsTool: ToolConfig<
193200
type: 'boolean',
194201
description: 'Whether the question is not applicable to this call',
195202
},
203+
selectedOptions: {
204+
type: 'array',
205+
description:
206+
'Identifiers of the options selected for select-type questions, null otherwise',
207+
items: { type: 'string' },
208+
},
196209
},
197210
},
198211
},
@@ -202,6 +215,7 @@ export const answeredScorecardsTool: ToolConfig<
202215
cursor: {
203216
type: 'string',
204217
description: 'Pagination cursor for the next page',
218+
optional: true,
205219
},
206220
},
207221
}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import type { GongAskAnythingParams, GongAskAnythingResponse } from '@/tools/gong/types'
2+
import { getGongErrorMessage } from '@/tools/gong/utils'
3+
import type { ToolConfig } from '@/tools/types'
4+
5+
export const askAnythingTool: ToolConfig<GongAskAnythingParams, GongAskAnythingResponse> = {
6+
id: 'gong_ask_anything',
7+
name: 'Gong Ask Anything',
8+
description:
9+
'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.',
10+
version: '1.0.0',
11+
12+
params: {
13+
accessKey: {
14+
type: 'string',
15+
required: true,
16+
visibility: 'user-only',
17+
description: 'Gong API Access Key',
18+
},
19+
accessKeySecret: {
20+
type: 'string',
21+
required: true,
22+
visibility: 'user-only',
23+
description: 'Gong API Access Key Secret',
24+
},
25+
workspaceId: {
26+
type: 'string',
27+
required: true,
28+
visibility: 'user-or-llm',
29+
description: 'Gong workspace ID the entity belongs to',
30+
},
31+
crmEntityType: {
32+
type: 'string',
33+
required: true,
34+
visibility: 'user-or-llm',
35+
description: 'Type of the CRM entity: ACCOUNT, CONTACT, DEAL, or LEAD',
36+
},
37+
crmEntityId: {
38+
type: 'string',
39+
required: true,
40+
visibility: 'user-or-llm',
41+
description: 'The CRM ID of the entity the question is asked about',
42+
},
43+
question: {
44+
type: 'string',
45+
required: true,
46+
visibility: 'user-or-llm',
47+
description: 'The natural-language question to ask about the entity',
48+
},
49+
timePeriod: {
50+
type: 'string',
51+
required: true,
52+
visibility: 'user-or-llm',
53+
description:
54+
'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',
55+
},
56+
fromDateTime: {
57+
type: 'string',
58+
required: false,
59+
visibility: 'user-or-llm',
60+
description:
61+
'Start date/time (UTC, ISO-8601) for calls and emails to include. Required when timePeriod is CUSTOM_RANGE.',
62+
},
63+
toDateTime: {
64+
type: 'string',
65+
required: false,
66+
visibility: 'user-or-llm',
67+
description:
68+
'End date/time (UTC, ISO-8601) for calls and emails to include. Required when timePeriod is CUSTOM_RANGE.',
69+
},
70+
},
71+
72+
request: {
73+
url: (params) => {
74+
const timePeriod = params.timePeriod.trim().toUpperCase()
75+
if (
76+
timePeriod === 'CUSTOM_RANGE' &&
77+
(!params.fromDateTime?.trim() || !params.toDateTime?.trim())
78+
) {
79+
throw new Error('fromDateTime and toDateTime are required when timePeriod is CUSTOM_RANGE')
80+
}
81+
const url = new URL('https://api.gong.io/v2/entities/ask-entity')
82+
url.searchParams.set('workspaceId', params.workspaceId.trim())
83+
url.searchParams.set('crmEntityType', params.crmEntityType.trim().toUpperCase())
84+
url.searchParams.set('crmEntityId', params.crmEntityId.trim())
85+
url.searchParams.set('timePeriod', timePeriod)
86+
url.searchParams.set('question', params.question.trim())
87+
if (timePeriod === 'CUSTOM_RANGE') {
88+
url.searchParams.set('fromDateTime', params.fromDateTime?.trim() ?? '')
89+
url.searchParams.set('toDateTime', params.toDateTime?.trim() ?? '')
90+
}
91+
return url.toString()
92+
},
93+
method: 'GET',
94+
headers: (params) => ({
95+
Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`,
96+
}),
97+
},
98+
99+
transformResponse: async (response: Response) => {
100+
const data = await response.json()
101+
if (!response.ok) {
102+
throw new Error(getGongErrorMessage(data, 'Failed to ask about the entity'))
103+
}
104+
const answer = (data.answer ?? []).map((section: Record<string, unknown>) => ({
105+
answerItems: section.answerItems ?? [],
106+
callFindings: section.callFindings ?? [],
107+
emailFindings: section.emailFindings ?? [],
108+
}))
109+
return {
110+
success: true,
111+
output: {
112+
requestId: data.requestId ?? null,
113+
numOfCallsSearched: data.numOfCallsSearched ?? null,
114+
numOfEmailsSearched: data.numOfEmailsSearched ?? null,
115+
answer,
116+
},
117+
}
118+
},
119+
120+
outputs: {
121+
requestId: {
122+
type: 'string',
123+
description: 'A Gong request reference ID for troubleshooting purposes',
124+
optional: true,
125+
},
126+
numOfCallsSearched: {
127+
type: 'number',
128+
description: 'Number of calls used to generate the answer',
129+
optional: true,
130+
},
131+
numOfEmailsSearched: {
132+
type: 'number',
133+
description: 'Number of emails used to generate the answer',
134+
optional: true,
135+
},
136+
answer: {
137+
type: 'array',
138+
description: 'Sections of the generated answer with supporting evidence',
139+
items: {
140+
type: 'object',
141+
properties: {
142+
answerItems: {
143+
type: 'array',
144+
description: 'Text items that make up this part of the answer',
145+
items: { type: 'string' },
146+
},
147+
callFindings: {
148+
type: 'array',
149+
description: 'Evidence from calls used to generate this answer item',
150+
items: { type: 'object' },
151+
},
152+
emailFindings: {
153+
type: 'array',
154+
description: 'Evidence from emails used to generate this answer item',
155+
items: { type: 'object' },
156+
},
157+
},
158+
},
159+
},
160+
},
161+
}

apps/sim/tools/gong/create_call.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,10 @@ export const createCallTool: ToolConfig<GongCreateCallParams, GongCreateCallResp
5353
},
5454
downloadMediaUrl: {
5555
type: 'string',
56-
required: true,
56+
required: false,
5757
visibility: 'user-or-llm',
58-
description: 'URL where Gong can download the call media file',
58+
description:
59+
'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.',
5960
},
6061
title: {
6162
type: 'string',
@@ -108,10 +109,10 @@ export const createCallTool: ToolConfig<GongCreateCallParams, GongCreateCallResp
108109
actualStart: params.actualStart.trim(),
109110
primaryUser: params.primaryUser.trim(),
110111
parties: parseGongJsonArray(params.parties, 'parties'),
111-
direction: params.direction,
112-
downloadMediaUrl: params.downloadMediaUrl.trim(),
112+
direction: params.direction.trim(),
113113
}
114114

115+
if (params.downloadMediaUrl?.trim()) body.downloadMediaUrl = params.downloadMediaUrl.trim()
115116
if (params.title?.trim()) body.title = params.title.trim()
116117
if (params.workspaceId?.trim()) body.workspaceId = params.workspaceId.trim()
117118
if (params.disposition?.trim()) body.disposition = params.disposition.trim()
@@ -134,7 +135,6 @@ export const createCallTool: ToolConfig<GongCreateCallParams, GongCreateCallResp
134135
output: {
135136
callId: data.callId ?? '',
136137
requestId: data.requestId ?? '',
137-
url: data.url ?? null,
138138
},
139139
}
140140
},
@@ -148,10 +148,5 @@ export const createCallTool: ToolConfig<GongCreateCallParams, GongCreateCallResp
148148
type: 'string',
149149
description: 'Gong request reference ID for troubleshooting',
150150
},
151-
url: {
152-
type: 'string',
153-
description: 'URL to the created call in the Gong web app',
154-
optional: true,
155-
},
156151
},
157152
}

0 commit comments

Comments
 (0)