chore: import upstream snapshot with attribution
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) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
+203
View File
@@ -0,0 +1,203 @@
import type { GongAggregateActivityParams, GongAggregateActivityResponse } from '@/tools/gong/types'
import { getGongErrorMessage, parseGongIdList } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const aggregateActivityTool: ToolConfig<
GongAggregateActivityParams,
GongAggregateActivityResponse
> = {
id: 'gong_aggregate_activity',
name: 'Gong Aggregate Activity',
description: 'Retrieve aggregated activity statistics for users by date range from Gong.',
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',
},
userIds: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of Gong user IDs (up to 20 digits each)',
},
fromDate: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Start date in YYYY-MM-DD format (inclusive, in company timezone)',
},
toDate: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'End date in YYYY-MM-DD format (exclusive, in company timezone, cannot exceed current day)',
},
cursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor from a previous response',
},
},
request: {
url: 'https://api.gong.io/v2/stats/activity/aggregate',
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`,
}),
body: (params) => {
const filter: Record<string, unknown> = {
fromDate: params.fromDate.trim(),
toDate: params.toDate.trim(),
}
const userIds = parseGongIdList(params.userIds)
if (userIds) filter.userIds = userIds
const body: Record<string, unknown> = { filter }
if (params.cursor?.trim()) body.cursor = params.cursor.trim()
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(getGongErrorMessage(data, 'Failed to get aggregate activity'))
}
const usersActivity = (data.usersAggregateActivityStats ?? []).map(
(ua: Record<string, unknown>) => {
const stats = (ua.userAggregateActivityStats ?? {}) as Record<string, unknown>
return {
userId: ua.userId ?? '',
userEmailAddress: ua.userEmailAddress ?? null,
callsAsHost: stats.callsAsHost ?? null,
callsAttended: stats.callsAttended ?? null,
callsGaveFeedback: stats.callsGaveFeedback ?? null,
callsReceivedFeedback: stats.callsReceivedFeedback ?? null,
callsRequestedFeedback: stats.callsRequestedFeedback ?? null,
callsScorecardsFilled: stats.callsScorecardsFilled ?? null,
callsScorecardsReceived: stats.callsScorecardsReceived ?? null,
ownCallsListenedTo: stats.ownCallsListenedTo ?? null,
othersCallsListenedTo: stats.othersCallsListenedTo ?? null,
callsSharedInternally: stats.callsSharedInternally ?? null,
callsSharedExternally: stats.callsSharedExternally ?? null,
callsCommentsGiven: stats.callsCommentsGiven ?? null,
callsCommentsReceived: stats.callsCommentsReceived ?? null,
callsMarkedAsFeedbackGiven: stats.callsMarkedAsFeedbackGiven ?? null,
callsMarkedAsFeedbackReceived: stats.callsMarkedAsFeedbackReceived ?? null,
}
}
)
return {
success: true,
output: {
usersActivity,
timeZone: data.timeZone ?? null,
fromDateTime: data.fromDateTime ?? null,
toDateTime: data.toDateTime ?? null,
cursor: data.records?.cursor ?? null,
},
}
},
outputs: {
usersActivity: {
type: 'array',
description: 'Aggregated activity statistics per user',
items: {
type: 'object',
properties: {
userId: { type: 'string', description: "Gong's unique numeric identifier for the user" },
userEmailAddress: { type: 'string', description: 'Email address of the Gong user' },
callsAsHost: { type: 'number', description: 'Number of recorded calls this user hosted' },
callsAttended: {
type: 'number',
description: 'Number of calls where this user was a participant (not host)',
},
callsGaveFeedback: {
type: 'number',
description: 'Number of recorded calls the user gave feedback on',
},
callsReceivedFeedback: {
type: 'number',
description: 'Number of recorded calls the user received feedback on',
},
callsRequestedFeedback: {
type: 'number',
description: 'Number of recorded calls the user requested feedback on',
},
callsScorecardsFilled: {
type: 'number',
description: 'Number of scorecards the user completed',
},
callsScorecardsReceived: {
type: 'number',
description: "Number of calls where someone filled a scorecard on the user's calls",
},
ownCallsListenedTo: {
type: 'number',
description: "Number of the user's own calls the user listened to",
},
othersCallsListenedTo: {
type: 'number',
description: "Number of other users' calls the user listened to",
},
callsSharedInternally: {
type: 'number',
description: 'Number of calls the user shared internally',
},
callsSharedExternally: {
type: 'number',
description: 'Number of calls the user shared externally',
},
callsCommentsGiven: {
type: 'number',
description: 'Number of calls where the user provided at least one comment',
},
callsCommentsReceived: {
type: 'number',
description: 'Number of calls where the user received at least one comment',
},
callsMarkedAsFeedbackGiven: {
type: 'number',
description: 'Number of calls where the user selected Mark as reviewed',
},
callsMarkedAsFeedbackReceived: {
type: 'number',
description:
"Number of calls where others selected Mark as reviewed on the user's calls",
},
},
},
},
timeZone: {
type: 'string',
description: "The company's defined timezone in Gong",
},
fromDateTime: {
type: 'string',
description: 'Start of results in ISO-8601 format',
},
toDateTime: {
type: 'string',
description: 'End of results in ISO-8601 format',
},
cursor: {
type: 'string',
description: 'Pagination cursor for the next page',
optional: true,
},
},
}
+219
View File
@@ -0,0 +1,219 @@
import type { GongAggregateByPeriodParams, GongAggregateByPeriodResponse } from '@/tools/gong/types'
import { getGongErrorMessage, parseGongIdList } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const aggregateByPeriodTool: ToolConfig<
GongAggregateByPeriodParams,
GongAggregateByPeriodResponse
> = {
id: 'gong_aggregate_by_period',
name: 'Gong Aggregate by Period',
description:
'Retrieve aggregated user activity grouped into time periods (day, week, month, quarter, year) by date range from Gong.',
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',
},
aggregationPeriod: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Calendar period to group activity by: DAY, WEEK, MONTH, QUARTER, or YEAR (week starts Monday)',
},
userIds: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of Gong user IDs (up to 20 digits each)',
},
fromDate: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Start date in YYYY-MM-DD format (inclusive, in company timezone)',
},
toDate: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'End date in YYYY-MM-DD format (exclusive, in company timezone, cannot exceed current day)',
},
cursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor from a previous response',
},
},
request: {
url: 'https://api.gong.io/v2/stats/activity/aggregate-by-period',
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`,
}),
body: (params) => {
const filter: Record<string, unknown> = {
fromDate: params.fromDate.trim(),
toDate: params.toDate.trim(),
}
const userIds = parseGongIdList(params.userIds)
if (userIds) filter.userIds = userIds
const body: Record<string, unknown> = {
aggregationPeriod: params.aggregationPeriod.trim(),
filter,
}
if (params.cursor?.trim()) body.cursor = params.cursor.trim()
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(getGongErrorMessage(data, 'Failed to get aggregate-by-period activity'))
}
const usersAggregateActivity = (data.usersAggregateActivity ?? []).map(
(ua: Record<string, unknown>) => ({
userId: ua.userId ?? '',
userEmailAddress: ua.userEmailAddress ?? null,
userAggregateActivity: (
(ua.userAggregateActivity as Record<string, unknown>[] | undefined) ?? []
).map((period: Record<string, unknown>) => ({
fromDate: period.fromDate ?? null,
toDate: period.toDate ?? null,
callsAsHost: period.callsAsHost ?? null,
callsAttended: period.callsAttended ?? null,
callsGaveFeedback: period.callsGaveFeedback ?? null,
callsReceivedFeedback: period.callsReceivedFeedback ?? null,
callsRequestedFeedback: period.callsRequestedFeedback ?? null,
callsScorecardsFilled: period.callsScorecardsFilled ?? null,
callsScorecardsReceived: period.callsScorecardsReceived ?? null,
ownCallsListenedTo: period.ownCallsListenedTo ?? null,
othersCallsListenedTo: period.othersCallsListenedTo ?? null,
callsSharedInternally: period.callsSharedInternally ?? null,
callsSharedExternally: period.callsSharedExternally ?? null,
callsCommentsGiven: period.callsCommentsGiven ?? null,
callsCommentsReceived: period.callsCommentsReceived ?? null,
callsMarkedAsFeedbackGiven: period.callsMarkedAsFeedbackGiven ?? null,
callsMarkedAsFeedbackReceived: period.callsMarkedAsFeedbackReceived ?? null,
})),
})
)
return {
success: true,
output: {
requestId: data.requestId ?? null,
usersAggregateActivity,
cursor: data.records?.cursor ?? null,
},
}
},
outputs: {
requestId: {
type: 'string',
description: 'A Gong request reference ID for troubleshooting purposes',
optional: true,
},
usersAggregateActivity: {
type: 'array',
description:
'Aggregated activity per user, one item per consecutive time period in the range',
items: {
type: 'object',
properties: {
userId: { type: 'string', description: "Gong's unique numeric identifier for the user" },
userEmailAddress: { type: 'string', description: 'Email address of the Gong user' },
userAggregateActivity: {
type: 'array',
description: 'Activity counts per time period',
items: {
type: 'object',
properties: {
fromDate: { type: 'string', description: 'Start of the period (ISO-8601)' },
toDate: { type: 'string', description: 'End of the period (ISO-8601)' },
callsAsHost: { type: 'number', description: 'Calls the user hosted' },
callsAttended: {
type: 'number',
description: 'Calls the user attended (not host)',
},
callsGaveFeedback: {
type: 'number',
description: 'Calls the user gave feedback on',
},
callsReceivedFeedback: {
type: 'number',
description: 'Calls the user received feedback on',
},
callsRequestedFeedback: {
type: 'number',
description: 'Calls the user requested feedback on',
},
callsScorecardsFilled: {
type: 'number',
description: 'Scorecards the user completed',
},
callsScorecardsReceived: {
type: 'number',
description: "Calls where someone filled a scorecard on the user's calls",
},
ownCallsListenedTo: {
type: 'number',
description: "The user's own calls the user listened to",
},
othersCallsListenedTo: {
type: 'number',
description: "Other users' calls the user listened to",
},
callsSharedInternally: {
type: 'number',
description: 'Calls the user shared internally',
},
callsSharedExternally: {
type: 'number',
description: 'Calls the user shared externally',
},
callsCommentsGiven: {
type: 'number',
description: 'Calls the user commented on',
},
callsCommentsReceived: {
type: 'number',
description: "Calls where the user's calls received a comment",
},
callsMarkedAsFeedbackGiven: {
type: 'number',
description: 'Calls the user marked as reviewed',
},
callsMarkedAsFeedbackReceived: {
type: 'number',
description: "The user's calls marked as reviewed by others",
},
},
},
},
},
},
},
cursor: {
type: 'string',
description: 'Pagination cursor for the next page',
optional: true,
},
},
}
+207
View File
@@ -0,0 +1,207 @@
import type {
GongAnsweredScorecardsParams,
GongAnsweredScorecardsResponse,
} from '@/tools/gong/types'
import { getGongErrorMessage, parseGongIdList } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const answeredScorecardsTool: ToolConfig<
GongAnsweredScorecardsParams,
GongAnsweredScorecardsResponse
> = {
id: 'gong_answered_scorecards',
name: 'Gong Answered Scorecards',
description: 'Retrieve answered scorecards for reviewed users or by date range from Gong.',
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',
},
callFromDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Start date for calls in YYYY-MM-DD format (inclusive, in company timezone). Defaults to earliest recorded call.',
},
callToDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'End date for calls in YYYY-MM-DD format (exclusive, in company timezone). Defaults to latest recorded call.',
},
reviewFromDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Start date for reviews in YYYY-MM-DD format (inclusive, in company timezone). Defaults to earliest reviewed call.',
},
reviewToDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'End date for reviews in YYYY-MM-DD format (exclusive, in company timezone). Defaults to latest reviewed call.',
},
scorecardIds: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of scorecard IDs to filter by',
},
reviewedUserIds: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of reviewed user IDs to filter by',
},
cursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor from a previous response',
},
},
request: {
url: 'https://api.gong.io/v2/stats/activity/scorecards',
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`,
}),
body: (params) => {
const filter: Record<string, unknown> = {}
if (params.callFromDate?.trim()) filter.callFromDate = params.callFromDate.trim()
if (params.callToDate?.trim()) filter.callToDate = params.callToDate.trim()
if (params.reviewFromDate?.trim()) filter.reviewFromDate = params.reviewFromDate.trim()
if (params.reviewToDate?.trim()) filter.reviewToDate = params.reviewToDate.trim()
const scorecardIds = parseGongIdList(params.scorecardIds)
const reviewedUserIds = parseGongIdList(params.reviewedUserIds)
if (scorecardIds) filter.scorecardIds = scorecardIds
if (reviewedUserIds) filter.reviewedUserIds = reviewedUserIds
const body: Record<string, unknown> = { filter }
if (params.cursor?.trim()) body.cursor = params.cursor.trim()
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(getGongErrorMessage(data, 'Failed to get answered scorecards'))
}
const answeredScorecards = (data.answeredScorecards ?? []).map(
(sc: Record<string, unknown>) => ({
answeredScorecardId: sc.answeredScorecardId ?? 0,
scorecardId: sc.scorecardId ?? null,
scorecardName: sc.scorecardName ?? null,
callId: sc.callId ?? null,
callStartTime: sc.callStartTime ?? null,
reviewedUserId: sc.reviewedUserId ?? null,
reviewerUserId: sc.reviewerUserId ?? null,
reviewTime: sc.reviewTime ?? null,
visibilityType: sc.visibilityType ?? null,
answers: ((sc.answers as Record<string, unknown>[]) ?? []).map(
(answer: Record<string, unknown>) => ({
questionId: answer.questionId ?? null,
questionRevisionId: answer.questionRevisionId ?? null,
isOverall: answer.isOverall ?? null,
score: answer.score ?? null,
answerText: answer.answerText ?? null,
notApplicable: answer.notApplicable ?? null,
})
),
})
)
return {
success: true,
output: {
answeredScorecards,
cursor: data.records?.cursor ?? null,
},
}
},
outputs: {
answeredScorecards: {
type: 'array',
description: 'List of answered scorecards with scores and answers',
items: {
type: 'object',
properties: {
answeredScorecardId: {
type: 'number',
description: 'Identifier of the answered scorecard',
},
scorecardId: { type: 'number', description: 'Identifier of the scorecard' },
scorecardName: { type: 'string', description: 'Scorecard name' },
callId: { type: 'number', description: "Gong's unique numeric identifier for the call" },
callStartTime: {
type: 'string',
description: 'Date/time of the call in ISO-8601 format',
},
reviewedUserId: {
type: 'number',
description: 'User ID of the team member being reviewed',
},
reviewerUserId: {
type: 'number',
description: 'User ID of the team member who completed the scorecard',
},
reviewTime: {
type: 'string',
description: 'Date/time when the review was completed in ISO-8601 format',
},
visibilityType: {
type: 'string',
description: 'Visibility type of the scorecard answer',
},
answers: {
type: 'array',
description: 'Answers in the answered scorecard',
items: {
type: 'object',
properties: {
questionId: { type: 'number', description: 'Identifier of the question' },
questionRevisionId: {
type: 'number',
description: 'Identifier of the revision version of the question',
},
isOverall: { type: 'boolean', description: 'Whether this is the overall question' },
score: {
type: 'number',
description: 'Score between 1 to 5 if answered, null otherwise',
},
answerText: {
type: 'string',
description: "The answer's text if answered, null otherwise",
},
notApplicable: {
type: 'boolean',
description: 'Whether the question is not applicable to this call',
},
},
},
},
},
},
},
cursor: {
type: 'string',
description: 'Pagination cursor for the next page',
},
},
}
@@ -0,0 +1,133 @@
import type {
GongAssignFlowProspectsParams,
GongAssignFlowProspectsResponse,
} from '@/tools/gong/types'
import { getGongErrorMessage, parseGongIdList } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const assignFlowProspectsTool: ToolConfig<
GongAssignFlowProspectsParams,
GongAssignFlowProspectsResponse
> = {
id: 'gong_assign_flow_prospects',
name: 'Gong Assign Flow Prospects',
description: 'Assign up to 200 CRM prospects (contacts or leads) to a Gong Engage flow.',
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',
},
flowId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The Gong Engage flow ID to assign the prospects to',
},
crmProspectsIds: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Comma-separated list of CRM prospect IDs (contacts or leads) to assign',
},
flowInstanceOwnerEmail: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Email of the Gong user who owns the flow instance and its to-dos',
},
},
request: {
url: 'https://api.gong.io/v2/flows/prospects/assign',
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`,
}),
body: (params) => ({
flowId: params.flowId.trim(),
crmProspectsIds: parseGongIdList(params.crmProspectsIds) ?? [],
flowInstanceOwnerEmail: params.flowInstanceOwnerEmail.trim(),
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(getGongErrorMessage(data, 'Failed to assign prospects to flow'))
}
return {
success: true,
output: {
requestId: data.requestId ?? null,
prospectsAssigned: data.prospectsAssigned ?? [],
prospectsNotAssigned: data.prospectsNotAssigned ?? [],
},
}
},
outputs: {
requestId: {
type: 'string',
description: 'A Gong request reference ID for troubleshooting purposes',
optional: true,
},
prospectsAssigned: {
type: 'array',
description: 'Prospects successfully assigned to the flow',
items: {
type: 'object',
properties: {
flowId: { type: 'string', description: 'The flow ID' },
flowName: { type: 'string', description: 'The flow name' },
crmProspectId: { type: 'string', description: 'The CRM prospect ID' },
flowInstanceId: { type: 'string', description: 'The created flow instance ID' },
flowInstanceOwnerEmail: {
type: 'string',
description: 'Email of the flow instance owner',
},
flowInstanceOwnerFullName: {
type: 'string',
description: 'Full name of the flow instance owner',
},
flowInstanceCreateDate: {
type: 'string',
description: 'Creation time of the flow instance in ISO-8601 format',
},
flowInstanceStatus: { type: 'string', description: 'Status of the flow instance' },
workspaceId: { type: 'string', description: 'Workspace ID' },
exclusive: {
type: 'boolean',
description: 'Whether this prospect can be added to other flows',
},
},
},
},
prospectsNotAssigned: {
type: 'array',
description: 'Prospects that failed to be assigned to the flow',
items: {
type: 'object',
properties: {
flowId: { type: 'string', description: 'The flow ID' },
crmProspectId: { type: 'string', description: 'The CRM prospect ID' },
errorCode: {
type: 'string',
description: 'Failure reason: InvalidArgument, InvalidState, or UnexpectedError',
},
errorMessage: { type: 'string', description: 'Human-readable failure message' },
},
},
},
},
}
+157
View File
@@ -0,0 +1,157 @@
import type { GongCreateCallParams, GongCreateCallResponse } from '@/tools/gong/types'
import { getGongErrorMessage, parseGongJsonArray } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const createCallTool: ToolConfig<GongCreateCallParams, GongCreateCallResponse> = {
id: 'gong_create_call',
name: 'Gong Create Call',
description: 'Upload call metadata to Gong and let Gong pull the media from a URL.',
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',
},
clientUniqueId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Unique call ID from the source telephony or recording system',
},
actualStart: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Actual call start time in ISO-8601 format',
},
primaryUser: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: "Gong user ID for the call's host or owner",
},
parties: {
type: 'json',
required: true,
visibility: 'user-or-llm',
description: 'Array of call parties, with at least the primary user included',
},
direction: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Call direction: Inbound, Outbound, Conference, or Unknown',
},
downloadMediaUrl: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'URL where Gong can download the call media file',
},
title: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Human-readable call title',
},
workspaceId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Optional Gong workspace ID',
},
disposition: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Optional call disposition',
},
purpose: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Optional call purpose',
},
context: {
type: 'json',
required: false,
visibility: 'user-or-llm',
description: 'Optional CRM context array for the call',
},
callProviderCode: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Optional conferencing or telephony provider code',
},
},
request: {
url: 'https://api.gong.io/v2/calls',
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`,
}),
body: (params) => {
const body: Record<string, unknown> = {
clientUniqueId: params.clientUniqueId.trim(),
actualStart: params.actualStart.trim(),
primaryUser: params.primaryUser.trim(),
parties: parseGongJsonArray(params.parties, 'parties'),
direction: params.direction,
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()
if (params.purpose?.trim()) body.purpose = params.purpose.trim()
if (params.context) body.context = parseGongJsonArray(params.context, 'context')
if (params.callProviderCode?.trim()) body.callProviderCode = params.callProviderCode.trim()
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(getGongErrorMessage(data, 'Failed to create Gong call'))
}
return {
success: true,
output: {
callId: data.callId ?? '',
requestId: data.requestId ?? '',
url: data.url ?? null,
},
}
},
outputs: {
callId: {
type: 'string',
description: "Gong's unique numeric identifier for the created call",
},
requestId: {
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,
},
},
}
+208
View File
@@ -0,0 +1,208 @@
import type { GongDayByDayActivityParams, GongDayByDayActivityResponse } from '@/tools/gong/types'
import { getGongErrorMessage, parseGongIdList } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const dayByDayActivityTool: ToolConfig<
GongDayByDayActivityParams,
GongDayByDayActivityResponse
> = {
id: 'gong_day_by_day_activity',
name: 'Gong Day-by-Day Activity',
description:
'Retrieve detailed day-by-day activity (call IDs per activity type) for users by date range from Gong.',
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',
},
userIds: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of Gong user IDs (up to 20 digits each)',
},
fromDate: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Start date in YYYY-MM-DD format (inclusive, in company timezone)',
},
toDate: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'End date in YYYY-MM-DD format (exclusive, in company timezone, cannot exceed current day)',
},
cursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor from a previous response',
},
},
request: {
url: 'https://api.gong.io/v2/stats/activity/day-by-day',
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`,
}),
body: (params) => {
const filter: Record<string, unknown> = {
fromDate: params.fromDate.trim(),
toDate: params.toDate.trim(),
}
const userIds = parseGongIdList(params.userIds)
if (userIds) filter.userIds = userIds
const body: Record<string, unknown> = { filter }
if (params.cursor?.trim()) body.cursor = params.cursor.trim()
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(getGongErrorMessage(data, 'Failed to get day-by-day activity'))
}
const usersDetailedActivities = (data.usersDetailedActivities ?? []).map(
(ud: Record<string, unknown>) => ({
userId: ud.userId ?? '',
userEmailAddress: ud.userEmailAddress ?? null,
userDailyActivityStats: (
(ud.userDailyActivityStats as Record<string, unknown>[] | undefined) ?? []
).map((day: Record<string, unknown>) => ({
fromDate: day.fromDate ?? null,
toDate: day.toDate ?? null,
callsAsHost: day.callsAsHost ?? [],
callsAttended: day.callsAttended ?? [],
callsGaveFeedback: day.callsGaveFeedback ?? [],
callsReceivedFeedback: day.callsReceivedFeedback ?? [],
callsRequestedFeedback: day.callsRequestedFeedback ?? [],
callsScorecardsFilled: day.callsScorecardsFilled ?? [],
callsScorecardsReceived: day.callsScorecardsReceived ?? [],
ownCallsListenedTo: day.ownCallsListenedTo ?? [],
othersCallsListenedTo: day.othersCallsListenedTo ?? [],
callsSharedInternally: day.callsSharedInternally ?? [],
callsSharedExternally: day.callsSharedExternally ?? [],
callsCommentsGiven: day.callsCommentsGiven ?? [],
callsCommentsReceived: day.callsCommentsReceived ?? [],
callsMarkedAsFeedbackGiven: day.callsMarkedAsFeedbackGiven ?? [],
callsMarkedAsFeedbackReceived: day.callsMarkedAsFeedbackReceived ?? [],
})),
})
)
return {
success: true,
output: {
requestId: data.requestId ?? null,
usersDetailedActivities,
cursor: data.records?.cursor ?? null,
},
}
},
outputs: {
requestId: {
type: 'string',
description: 'A Gong request reference ID for troubleshooting purposes',
optional: true,
},
usersDetailedActivities: {
type: 'array',
description: 'Day-by-day activity per user, with call IDs grouped by activity type',
items: {
type: 'object',
properties: {
userId: { type: 'string', description: "Gong's unique numeric identifier for the user" },
userEmailAddress: { type: 'string', description: 'Email address of the Gong user' },
userDailyActivityStats: {
type: 'array',
description: 'One record per day in the date range',
items: {
type: 'object',
properties: {
fromDate: { type: 'string', description: 'Start of the day (ISO-8601)' },
toDate: { type: 'string', description: 'End of the day (ISO-8601)' },
callsAsHost: { type: 'array', description: 'IDs of calls the user hosted' },
callsAttended: {
type: 'array',
description: 'IDs of calls the user attended (not host)',
},
callsGaveFeedback: {
type: 'array',
description: 'IDs of calls the user gave feedback on',
},
callsReceivedFeedback: {
type: 'array',
description: 'IDs of calls the user received feedback on',
},
callsRequestedFeedback: {
type: 'array',
description: 'IDs of calls the user requested feedback on',
},
callsScorecardsFilled: {
type: 'array',
description: 'IDs of calls the user filled scorecards on',
},
callsScorecardsReceived: {
type: 'array',
description: "IDs of the user's calls that received a scorecard",
},
ownCallsListenedTo: {
type: 'array',
description: "IDs of the user's own calls the user listened to",
},
othersCallsListenedTo: {
type: 'array',
description: "IDs of other users' calls the user listened to",
},
callsSharedInternally: {
type: 'array',
description: 'IDs of calls the user shared internally',
},
callsSharedExternally: {
type: 'array',
description: 'IDs of calls the user shared externally',
},
callsCommentsGiven: {
type: 'array',
description: 'IDs of calls the user commented on',
},
callsCommentsReceived: {
type: 'array',
description: "IDs of the user's calls that received a comment",
},
callsMarkedAsFeedbackGiven: {
type: 'array',
description: 'IDs of calls the user marked as reviewed',
},
callsMarkedAsFeedbackReceived: {
type: 'array',
description: "IDs of the user's calls marked as reviewed by others",
},
},
},
},
},
},
},
cursor: {
type: 'string',
description: 'Pagination cursor for the next page',
optional: true,
},
},
}
+140
View File
@@ -0,0 +1,140 @@
import type { GongGetCallParams, GongGetCallResponse } from '@/tools/gong/types'
import { getGongErrorMessage } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const getCallTool: ToolConfig<GongGetCallParams, GongGetCallResponse> = {
id: 'gong_get_call',
name: 'Gong Get Call',
description: 'Retrieve detailed data for a specific call from Gong.',
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',
},
callId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The Gong call ID to retrieve',
},
},
request: {
url: (params) => `https://api.gong.io/v2/calls/${params.callId.trim()}`,
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
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 get call'))
}
const call = data.call ?? data
return {
success: true,
output: {
id: call.id ?? '',
title: call.title ?? null,
url: call.url ?? null,
scheduled: call.scheduled ?? null,
started: call.started ?? '',
duration: call.duration ?? 0,
direction: call.direction ?? null,
system: call.system ?? null,
scope: call.scope ?? null,
media: call.media ?? null,
language: call.language ?? null,
primaryUserId: call.primaryUserId ?? null,
workspaceId: call.workspaceId ?? null,
sdrDisposition: call.sdrDisposition ?? null,
clientUniqueId: call.clientUniqueId ?? null,
customData: call.customData ?? null,
purpose: call.purpose ?? null,
meetingUrl: call.meetingUrl ?? null,
isPrivate: call.isPrivate ?? false,
calendarEventId: call.calendarEventId ?? null,
},
}
},
outputs: {
id: { type: 'string', description: "Gong's unique numeric identifier for the call" },
title: { type: 'string', description: 'Call title', optional: true },
url: { type: 'string', description: 'URL to the call in the Gong web app', optional: true },
scheduled: {
type: 'string',
description: 'Scheduled call time in ISO-8601 format',
optional: true,
},
started: { type: 'string', description: 'Recording start time in ISO-8601 format' },
duration: { type: 'number', description: 'Call duration in seconds' },
direction: {
type: 'string',
description: 'Call direction (Inbound/Outbound)',
optional: true,
},
system: {
type: 'string',
description: 'Communication platform used (e.g., Outreach)',
optional: true,
},
scope: {
type: 'string',
description: "Call scope: 'Internal', 'External', or 'Unknown'",
optional: true,
},
media: { type: 'string', description: 'Media type (e.g., Video)', optional: true },
language: {
type: 'string',
description: 'Language code in ISO-639-2B format',
optional: true,
},
primaryUserId: {
type: 'string',
description: 'Host team member identifier',
optional: true,
},
workspaceId: { type: 'string', description: 'Workspace identifier', optional: true },
sdrDisposition: {
type: 'string',
description: 'SDR disposition classification',
optional: true,
},
clientUniqueId: {
type: 'string',
description: 'Call identifier from the origin recording system',
optional: true,
},
customData: {
type: 'string',
description: 'Metadata provided during call creation',
optional: true,
},
purpose: { type: 'string', description: 'Call purpose', optional: true },
meetingUrl: {
type: 'string',
description: 'Web conference provider URL',
optional: true,
},
isPrivate: { type: 'boolean', description: 'Whether the call is private' },
calendarEventId: {
type: 'string',
description: 'Calendar event identifier',
optional: true,
},
},
}
+154
View File
@@ -0,0 +1,154 @@
import type { GongGetCallTranscriptParams, GongGetCallTranscriptResponse } from '@/tools/gong/types'
import { getGongErrorMessage, parseGongIdList } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const getCallTranscriptTool: ToolConfig<
GongGetCallTranscriptParams,
GongGetCallTranscriptResponse
> = {
id: 'gong_get_call_transcript',
name: 'Gong Get Call Transcript',
description: 'Retrieve transcripts of calls from Gong by call IDs or date range.',
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',
},
callIds: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of call IDs to retrieve transcripts for',
},
fromDateTime: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Start date/time filter in ISO-8601 format',
},
toDateTime: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'End date/time filter in ISO-8601 format',
},
workspaceId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Gong workspace ID to filter calls',
},
cursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor from a previous response',
},
},
request: {
url: 'https://api.gong.io/v2/calls/transcript',
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`,
}),
body: (params) => {
const filter: Record<string, unknown> = {}
const callIds = parseGongIdList(params.callIds)
if (callIds) filter.callIds = callIds
if (params.fromDateTime?.trim()) filter.fromDateTime = params.fromDateTime.trim()
if (params.toDateTime?.trim()) filter.toDateTime = params.toDateTime.trim()
if (params.workspaceId?.trim()) filter.workspaceId = params.workspaceId.trim()
const body: Record<string, unknown> = { filter }
if (params.cursor?.trim()) body.cursor = params.cursor.trim()
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(getGongErrorMessage(data, 'Failed to get call transcript'))
}
const callTranscripts = (data.callTranscripts ?? []).map((ct: Record<string, unknown>) => ({
callId: ct.callId ?? '',
transcript: ((ct.transcript as Record<string, unknown>[]) ?? []).map((t) => ({
speakerId: t.speakerId ?? null,
topic: t.topic ?? null,
sentences: ((t.sentences as Record<string, unknown>[]) ?? []).map((s) => ({
start: s.start ?? 0,
end: s.end ?? 0,
text: s.text ?? '',
})),
})),
}))
return {
success: true,
output: {
callTranscripts,
cursor: data.records?.cursor ?? null,
},
}
},
outputs: {
callTranscripts: {
type: 'array',
description: 'List of call transcripts with speaker turns and sentences',
items: {
type: 'object',
properties: {
callId: { type: 'string', description: "Gong's unique numeric identifier for the call" },
transcript: {
type: 'array',
description: 'List of monologues in the call',
items: {
type: 'object',
properties: {
speakerId: {
type: 'string',
description: 'Unique ID of the speaker, cross-reference with parties',
},
topic: { type: 'string', description: 'Name of the topic being discussed' },
sentences: {
type: 'array',
description: 'List of sentences spoken in the monologue',
items: {
type: 'object',
properties: {
start: {
type: 'number',
description: 'Start time of the sentence in milliseconds from call start',
},
end: {
type: 'number',
description: 'End time of the sentence in milliseconds from call start',
},
text: { type: 'string', description: 'The sentence text' },
},
},
},
},
},
},
},
},
},
cursor: {
type: 'string',
description: 'Pagination cursor for the next page',
optional: true,
},
},
}
+171
View File
@@ -0,0 +1,171 @@
import type {
GongCoachingMetricsData,
GongCoachingRepData,
GongCoachingUser,
GongGetCoachingParams,
GongGetCoachingResponse,
} from '@/tools/gong/types'
import { getGongErrorMessage } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const getCoachingTool: ToolConfig<GongGetCoachingParams, GongGetCoachingResponse> = {
id: 'gong_get_coaching',
name: 'Gong Get Coaching',
description: 'Retrieve coaching metrics for a manager from Gong.',
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',
},
managerId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Gong user ID of the manager',
},
workspaceId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Gong workspace ID',
},
fromDate: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Start date in ISO-8601 format',
},
toDate: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'End date in ISO-8601 format',
},
},
request: {
url: (params) => {
const url = new URL('https://api.gong.io/v2/coaching')
url.searchParams.set('manager-id', params.managerId.trim())
url.searchParams.set('workspace-id', params.workspaceId.trim())
url.searchParams.set('from', params.fromDate.trim())
url.searchParams.set('to', params.toDate.trim())
return url.toString()
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
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 get coaching metrics'))
}
const mapUser = (u: Record<string, unknown> | null | undefined): GongCoachingUser | null => {
if (!u) return null
return {
id: (u.id as string) ?? null,
emailAddress: (u.emailAddress as string) ?? null,
firstName: (u.firstName as string) ?? null,
lastName: (u.lastName as string) ?? null,
title: (u.title as string) ?? null,
}
}
const coachingData: GongCoachingMetricsData[] = (data.coachingData ?? []).map(
(item: Record<string, unknown>) => {
const directReportsMetrics: GongCoachingRepData[] = (
(item.directReportsMetrics as Record<string, unknown>[]) ?? []
).map((rep: Record<string, unknown>) => ({
report: mapUser(rep.report as Record<string, unknown> | null),
metrics: (rep.metrics as Record<string, string[]>) ?? null,
}))
return {
manager: mapUser(item.manager as Record<string, unknown> | null),
directReportsMetrics,
}
}
)
return {
success: true,
output: {
requestId: (data.requestId as string) ?? null,
coachingData,
},
}
},
outputs: {
requestId: {
type: 'string',
description: 'A Gong request reference ID for troubleshooting purposes',
},
coachingData: {
type: 'array',
description: "A list of coaching data entries, one per manager's team",
items: {
type: 'object',
properties: {
manager: {
type: 'object',
description: 'The manager user information',
properties: {
id: { type: 'string', description: 'Gong unique numeric identifier for the user' },
emailAddress: { type: 'string', description: 'Email address of the Gong user' },
firstName: { type: 'string', description: 'First name of the Gong user' },
lastName: { type: 'string', description: 'Last name of the Gong user' },
title: { type: 'string', description: 'Job title of the Gong user' },
},
},
directReportsMetrics: {
type: 'array',
description: 'Coaching metrics for each direct report',
items: {
type: 'object',
properties: {
report: {
type: 'object',
description: 'The direct report user information',
properties: {
id: {
type: 'string',
description: 'Gong unique numeric identifier for the user',
},
emailAddress: {
type: 'string',
description: 'Email address of the Gong user',
},
firstName: { type: 'string', description: 'First name of the Gong user' },
lastName: { type: 'string', description: 'Last name of the Gong user' },
title: { type: 'string', description: 'Job title of the Gong user' },
},
},
metrics: {
type: 'json',
description:
'A map of metric names to arrays of string values representing coaching metrics',
},
},
},
},
},
},
},
},
}
+446
View File
@@ -0,0 +1,446 @@
import type { GongGetExtensiveCallsParams, GongGetExtensiveCallsResponse } from '@/tools/gong/types'
import { getGongErrorMessage, parseGongIdList } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const getExtensiveCallsTool: ToolConfig<
GongGetExtensiveCallsParams,
GongGetExtensiveCallsResponse
> = {
id: 'gong_get_extensive_calls',
name: 'Gong Get Extensive Calls',
description:
'Retrieve detailed call data including trackers, topics, highlights, and AI spotlight content (brief, outline, key points, call outcome) from Gong.',
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',
},
callIds: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of call IDs to retrieve detailed data for',
},
fromDateTime: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Start date/time filter in ISO-8601 format',
},
toDateTime: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'End date/time filter in ISO-8601 format',
},
workspaceId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Gong workspace ID to filter calls',
},
primaryUserIds: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of user IDs to filter calls by host',
},
cursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor from a previous response',
},
},
request: {
url: 'https://api.gong.io/v2/calls/extensive',
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`,
}),
body: (params) => {
const filter: Record<string, unknown> = {}
const callIds = parseGongIdList(params.callIds)
const primaryUserIds = parseGongIdList(params.primaryUserIds)
if (callIds) filter.callIds = callIds
if (params.fromDateTime?.trim()) filter.fromDateTime = params.fromDateTime.trim()
if (params.toDateTime?.trim()) filter.toDateTime = params.toDateTime.trim()
if (params.workspaceId?.trim()) filter.workspaceId = params.workspaceId.trim()
if (primaryUserIds) filter.primaryUserIds = primaryUserIds
const body: Record<string, unknown> = {
filter,
contentSelector: {
context: 'Extended',
contextTiming: ['Now', 'TimeOfCall'],
exposedFields: {
parties: true,
content: {
structure: true,
topics: true,
trackers: true,
trackerOccurrences: true,
highlights: true,
brief: true,
outline: true,
keyPoints: true,
callOutcome: true,
},
collaboration: { publicComments: true },
interaction: {
personInteractionStats: true,
speakers: true,
video: true,
questions: true,
},
media: true,
},
},
}
if (params.cursor?.trim()) body.cursor = params.cursor.trim()
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(getGongErrorMessage(data, 'Failed to get extensive call data'))
}
return {
success: true,
output: {
calls: data.calls ?? [],
cursor: data.records?.cursor ?? null,
},
}
},
outputs: {
calls: {
type: 'array',
description:
'List of detailed call objects with metadata, content, interaction stats, and collaboration data',
items: {
type: 'object',
properties: {
metaData: {
type: 'object',
description: 'Call metadata (same fields as CallBasicData)',
properties: {
id: { type: 'string', description: 'Call ID' },
title: { type: 'string', description: 'Call title' },
scheduled: { type: 'string', description: 'Scheduled time in ISO-8601' },
started: { type: 'string', description: 'Start time in ISO-8601' },
duration: { type: 'number', description: 'Duration in seconds' },
direction: { type: 'string', description: 'Call direction' },
system: { type: 'string', description: 'Communication platform' },
scope: { type: 'string', description: 'Internal/External/Unknown' },
media: { type: 'string', description: 'Media type' },
language: { type: 'string', description: 'Language code (ISO-639-2B)' },
url: { type: 'string', description: 'Gong web app URL' },
primaryUserId: { type: 'string', description: 'Host user ID' },
workspaceId: { type: 'string', description: 'Workspace ID' },
sdrDisposition: { type: 'string', description: 'SDR disposition' },
clientUniqueId: { type: 'string', description: 'Origin system call ID' },
customData: { type: 'string', description: 'Custom metadata' },
purpose: { type: 'string', description: 'Call purpose' },
meetingUrl: { type: 'string', description: 'Meeting URL' },
isPrivate: { type: 'boolean', description: 'Whether call is private' },
calendarEventId: { type: 'string', description: 'Calendar event ID' },
},
},
context: {
type: 'array',
description: 'Links to external systems (CRM, Dialer, etc.)',
items: {
type: 'object',
properties: {
system: { type: 'string', description: 'External system name (e.g., Salesforce)' },
objects: {
type: 'array',
description: 'List of objects within the external system',
},
},
},
},
parties: {
type: 'array',
description: 'List of call participants',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Unique participant ID in the call' },
name: { type: 'string', description: 'Participant name' },
emailAddress: { type: 'string', description: 'Email address' },
title: { type: 'string', description: 'Job title' },
phoneNumber: { type: 'string', description: 'Phone number' },
speakerId: {
type: 'string',
description: 'Speaker ID for transcript cross-reference',
},
userId: { type: 'string', description: 'Gong user ID' },
affiliation: { type: 'string', description: 'Company or non-company' },
methods: { type: 'array', description: 'Whether invited or attended' },
context: { type: 'array', description: 'Links to external systems for this party' },
},
},
},
content: {
type: 'object',
description: 'Call content data',
properties: {
brief: {
type: 'string',
description: 'AI-generated brief summary of the call (Call Spotlight)',
},
outline: {
type: 'array',
description: 'AI-generated call outline sections',
items: {
type: 'object',
properties: {
section: { type: 'string', description: 'Outline section name' },
startTime: {
type: 'number',
description: 'Section start in seconds from call start',
},
duration: { type: 'number', description: 'Section duration in seconds' },
items: { type: 'array', description: 'Bullet items within the section' },
},
},
},
keyPoints: {
type: 'array',
description: 'AI-generated key points of the call',
items: {
type: 'object',
properties: {
text: { type: 'string', description: 'Key point text' },
},
},
},
callOutcome: {
type: 'object',
description: 'AI-determined call outcome (Call Spotlight)',
properties: {
id: { type: 'string', description: 'Outcome category ID' },
category: { type: 'string', description: 'Outcome category name' },
name: { type: 'string', description: 'Outcome name' },
},
},
structure: {
type: 'array',
description: 'Call agenda parts',
items: {
type: 'object',
properties: {
name: { type: 'string', description: 'Agenda name' },
duration: { type: 'number', description: 'Duration of this part in seconds' },
},
},
},
topics: {
type: 'array',
description: 'Topics and their durations',
items: {
type: 'object',
properties: {
name: { type: 'string', description: 'Topic name (e.g., Pricing)' },
duration: { type: 'number', description: 'Time spent on topic in seconds' },
},
},
},
trackers: {
type: 'array',
description: 'Trackers found in the call',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Tracker ID' },
name: { type: 'string', description: 'Tracker name' },
count: { type: 'number', description: 'Number of occurrences' },
type: { type: 'string', description: 'Keyword or Smart' },
occurrences: {
type: 'array',
description: 'Details for each occurrence',
items: {
type: 'object',
properties: {
speakerId: { type: 'string', description: 'Speaker who said it' },
startTime: { type: 'number', description: 'Seconds from call start' },
},
},
},
phrases: {
type: 'array',
description: 'Per-phrase occurrence counts',
items: {
type: 'object',
properties: {
phrase: { type: 'string', description: 'Specific phrase' },
count: { type: 'number', description: 'Occurrences of this phrase' },
occurrences: { type: 'array', description: 'Details per occurrence' },
},
},
},
},
},
},
highlights: {
type: 'array',
description:
'AI-generated highlights including next steps, action items, and key moments',
items: {
type: 'object',
properties: {
title: { type: 'string', description: 'Title of the highlight' },
items: {
type: 'array',
description: 'Individual highlight items',
items: {
type: 'object',
properties: {
text: { type: 'string', description: 'Text of the highlight item' },
startTimes: {
type: 'array',
description: 'Start times in seconds from call start',
},
},
},
},
},
},
},
},
},
interaction: {
type: 'object',
description: 'Interaction statistics',
properties: {
interactionStats: {
type: 'array',
description: 'Interaction stats per user',
items: {
type: 'object',
properties: {
userId: { type: 'string', description: 'Gong user ID' },
userEmailAddress: { type: 'string', description: 'User email' },
personInteractionStats: {
type: 'array',
description: 'Stats list (Longest Monologue, Interactivity, Patience, etc.)',
items: {
type: 'object',
properties: {
name: { type: 'string', description: 'Stat name' },
value: { type: 'number', description: 'Stat value' },
},
},
},
},
},
},
speakers: {
type: 'array',
description: 'Talk duration per speaker',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Participant ID' },
userId: { type: 'string', description: 'Gong user ID' },
talkTime: { type: 'number', description: 'Talk duration in seconds' },
},
},
},
video: {
type: 'array',
description: 'Video statistics',
items: {
type: 'object',
properties: {
name: {
type: 'string',
description:
'Segment type: Browser, Presentation, WebcamPrimaryUser, WebcamNonCompany, Webcam',
},
duration: { type: 'number', description: 'Total segment duration in seconds' },
},
},
},
questions: {
type: 'object',
description: 'Question counts',
properties: {
companyCount: { type: 'number', description: 'Questions by company speakers' },
nonCompanyCount: {
type: 'number',
description: 'Questions by non-company speakers',
},
},
},
},
},
collaboration: {
type: 'object',
description: 'Collaboration data',
properties: {
publicComments: {
type: 'array',
description: 'Public comments on the call',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Comment ID' },
commenterUserId: { type: 'string', description: 'Commenter user ID' },
comment: { type: 'string', description: 'Comment text' },
posted: { type: 'string', description: 'Posted time in ISO-8601' },
audioStartTime: {
type: 'number',
description: 'Seconds from call start the comment refers to',
},
audioEndTime: {
type: 'number',
description: 'Seconds from call start the comment end refers to',
},
duringCall: {
type: 'boolean',
description: 'Whether the comment was posted during the call',
},
inReplyTo: {
type: 'string',
description: 'ID of original comment if this is a reply',
},
},
},
},
},
},
media: {
type: 'object',
description: 'Media download URLs (available for 8 hours)',
properties: {
audioUrl: { type: 'string', description: 'Audio download URL' },
videoUrl: { type: 'string', description: 'Video download URL' },
},
},
},
},
},
cursor: {
type: 'string',
description: 'Pagination cursor for the next page',
optional: true,
},
},
}
+132
View File
@@ -0,0 +1,132 @@
import type { GongGetFolderContentParams, GongGetFolderContentResponse } from '@/tools/gong/types'
import { getGongErrorMessage } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const getFolderContentTool: ToolConfig<
GongGetFolderContentParams,
GongGetFolderContentResponse
> = {
id: 'gong_get_folder_content',
name: 'Gong Get Folder Content',
description: 'Retrieve the list of calls in a specific library folder from Gong.',
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',
},
folderId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The library folder ID to retrieve content for',
},
},
request: {
url: (params) => {
const url = new URL('https://api.gong.io/v2/library/folder-content')
url.searchParams.set('folderId', params.folderId.trim())
return url.toString()
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
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 get folder content'))
}
const calls = (data.calls ?? []).map((c: Record<string, unknown>) => ({
id: (c.id as string) ?? '',
title: c.title ?? null,
note: c.note ?? null,
addedBy: c.addedBy ?? null,
created: c.created ?? null,
url: c.url ?? null,
snippet: c.snippet
? {
fromSec: (c.snippet as Record<string, unknown>).fromSec ?? null,
toSec: (c.snippet as Record<string, unknown>).toSec ?? null,
}
: null,
}))
return {
success: true,
output: {
folderId: data.id ?? null,
folderName: data.name ?? null,
createdBy: data.createdBy ?? null,
updated: data.updated ?? null,
calls,
},
}
},
outputs: {
folderId: {
type: 'string',
description: "Gong's unique numeric identifier for the folder",
},
folderName: {
type: 'string',
description: 'Display name of the folder',
},
createdBy: {
type: 'string',
description: "Gong's unique numeric identifier for the user who added the folder",
},
updated: {
type: 'string',
description: "Folder's last update time in ISO-8601 format",
},
calls: {
type: 'array',
description: 'List of calls in the library folder',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Gong unique numeric identifier of the call' },
title: { type: 'string', description: 'The title of the call' },
note: { type: 'string', description: 'A note attached to the call in the folder' },
addedBy: {
type: 'string',
description: 'Gong unique numeric identifier for the user who added the call',
},
created: {
type: 'string',
description: 'Date and time the call was added to folder in ISO-8601 format',
},
url: { type: 'string', description: 'URL of the call' },
snippet: {
type: 'object',
description: 'Call snippet time range',
properties: {
fromSec: {
type: 'number',
description: 'Snippet start in seconds relative to call start',
},
toSec: {
type: 'number',
description: 'Snippet end in seconds relative to call start',
},
},
},
},
},
},
},
}
+99
View File
@@ -0,0 +1,99 @@
import type { GongGetProspectFlowsParams, GongGetProspectFlowsResponse } from '@/tools/gong/types'
import { getGongErrorMessage, parseGongIdList } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const getProspectFlowsTool: ToolConfig<
GongGetProspectFlowsParams,
GongGetProspectFlowsResponse
> = {
id: 'gong_get_prospect_flows',
name: 'Gong Get Prospect Flows',
description: 'Get the Gong Engage flows currently assigned to the given CRM prospects.',
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',
},
crmProspectsIds: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Comma-separated list of CRM prospect IDs (contacts or leads) to look up',
},
},
request: {
url: 'https://api.gong.io/v2/flows/prospects',
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`,
}),
body: (params) => ({
crmProspectsIds: parseGongIdList(params.crmProspectsIds) ?? [],
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(getGongErrorMessage(data, 'Failed to get prospect flows'))
}
return {
success: true,
output: {
requestId: data.requestId ?? null,
prospectsAssigned: data.prospectsAssigned ?? [],
},
}
},
outputs: {
requestId: {
type: 'string',
description: 'A Gong request reference ID for troubleshooting purposes',
optional: true,
},
prospectsAssigned: {
type: 'array',
description: 'Flows currently assigned to the requested prospects',
items: {
type: 'object',
properties: {
flowId: { type: 'string', description: 'The flow ID' },
flowName: { type: 'string', description: 'The flow name' },
crmProspectId: { type: 'string', description: 'The CRM prospect ID' },
flowInstanceId: { type: 'string', description: 'The flow instance ID' },
flowInstanceOwnerEmail: {
type: 'string',
description: 'Email of the flow instance owner',
},
flowInstanceOwnerFullName: {
type: 'string',
description: 'Full name of the flow instance owner',
},
flowInstanceCreateDate: {
type: 'string',
description: 'Creation time of the flow instance in ISO-8601 format',
},
flowInstanceStatus: { type: 'string', description: 'Status of the flow instance' },
workspaceId: { type: 'string', description: 'Workspace ID' },
exclusive: {
type: 'boolean',
description: 'Whether this prospect can be added to other flows',
},
},
},
},
},
}
+142
View File
@@ -0,0 +1,142 @@
import type { GongGetUserParams, GongGetUserResponse } from '@/tools/gong/types'
import { getGongErrorMessage } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const getUserTool: ToolConfig<GongGetUserParams, GongGetUserResponse> = {
id: 'gong_get_user',
name: 'Gong Get User',
description: 'Retrieve details for a specific user from Gong.',
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',
},
userId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The Gong user ID to retrieve',
},
},
request: {
url: (params) => `https://api.gong.io/v2/users/${params.userId.trim()}`,
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
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 get user'))
}
const user = data.user ?? data
return {
success: true,
output: {
id: user.id ?? '',
emailAddress: user.emailAddress ?? null,
created: user.created ?? null,
active: user.active ?? false,
emailAliases: user.emailAliases ?? [],
trustedEmailAddress: user.trustedEmailAddress ?? null,
firstName: user.firstName ?? null,
lastName: user.lastName ?? null,
title: user.title ?? null,
phoneNumber: user.phoneNumber ?? null,
extension: user.extension ?? null,
personalMeetingUrls: user.personalMeetingUrls ?? [],
settings: user.settings ?? null,
managerId: user.managerId ?? null,
meetingConsentPageUrl: user.meetingConsentPageUrl ?? null,
spokenLanguages: user.spokenLanguages ?? [],
},
}
},
outputs: {
id: { type: 'string', description: 'Unique numeric user ID (up to 20 digits)' },
emailAddress: { type: 'string', description: 'User email address', optional: true },
created: { type: 'string', description: 'User creation timestamp (ISO-8601)', optional: true },
active: { type: 'boolean', description: 'Whether the user is active' },
emailAliases: {
type: 'array',
description: 'Alternative email addresses for the user',
optional: true,
items: { type: 'string' },
},
trustedEmailAddress: {
type: 'string',
description: 'Trusted email address for the user',
optional: true,
},
firstName: { type: 'string', description: 'First name', optional: true },
lastName: { type: 'string', description: 'Last name', optional: true },
title: { type: 'string', description: 'Job title', optional: true },
phoneNumber: { type: 'string', description: 'Phone number', optional: true },
extension: { type: 'string', description: 'Phone extension number', optional: true },
personalMeetingUrls: {
type: 'array',
description: 'Personal meeting URLs',
optional: true,
items: { type: 'string' },
},
settings: {
type: 'object',
description: 'User settings',
optional: true,
properties: {
webConferencesRecorded: {
type: 'boolean',
description: 'Whether web conferences are recorded',
},
preventWebConferenceRecording: {
type: 'boolean',
description: 'Whether web conference recording is prevented',
},
telephonyCallsImported: {
type: 'boolean',
description: 'Whether telephony calls are imported',
},
emailsImported: { type: 'boolean', description: 'Whether emails are imported' },
preventEmailImport: { type: 'boolean', description: 'Whether email import is prevented' },
nonRecordedMeetingsImported: {
type: 'boolean',
description: 'Whether non-recorded meetings are imported',
},
gongConnectEnabled: { type: 'boolean', description: 'Whether Gong Connect is enabled' },
},
},
managerId: { type: 'string', description: 'Manager user ID', optional: true },
meetingConsentPageUrl: {
type: 'string',
description: 'Meeting consent page URL',
optional: true,
},
spokenLanguages: {
type: 'array',
description: 'Languages spoken by the user',
optional: true,
items: {
type: 'object',
properties: {
language: { type: 'string', description: 'Language code' },
primary: { type: 'boolean', description: 'Whether this is the primary language' },
},
},
},
},
}
+53
View File
@@ -0,0 +1,53 @@
import { aggregateActivityTool } from '@/tools/gong/aggregate_activity'
import { aggregateByPeriodTool } from '@/tools/gong/aggregate_by_period'
import { answeredScorecardsTool } from '@/tools/gong/answered_scorecards'
import { assignFlowProspectsTool } from '@/tools/gong/assign_flow_prospects'
import { createCallTool } from '@/tools/gong/create_call'
import { dayByDayActivityTool } from '@/tools/gong/day_by_day_activity'
import { getCallTool } from '@/tools/gong/get_call'
import { getCallTranscriptTool } from '@/tools/gong/get_call_transcript'
import { getCoachingTool } from '@/tools/gong/get_coaching'
import { getExtensiveCallsTool } from '@/tools/gong/get_extensive_calls'
import { getFolderContentTool } from '@/tools/gong/get_folder_content'
import { getProspectFlowsTool } from '@/tools/gong/get_prospect_flows'
import { getUserTool } from '@/tools/gong/get_user'
import { interactionStatsTool } from '@/tools/gong/interaction_stats'
import { listCallsTool } from '@/tools/gong/list_calls'
import { listFlowsTool } from '@/tools/gong/list_flows'
import { listLibraryFoldersTool } from '@/tools/gong/list_library_folders'
import { listScorecardsTool } from '@/tools/gong/list_scorecards'
import { listTrackersTool } from '@/tools/gong/list_trackers'
import { listUsersTool } from '@/tools/gong/list_users'
import { listWorkspacesTool } from '@/tools/gong/list_workspaces'
import { lookupEmailTool } from '@/tools/gong/lookup_email'
import { lookupPhoneTool } from '@/tools/gong/lookup_phone'
import { purgeEmailAddressTool } from '@/tools/gong/purge_email_address'
import { purgePhoneNumberTool } from '@/tools/gong/purge_phone_number'
export const gongListCallsTool = listCallsTool
export const gongCreateCallTool = createCallTool
export const gongGetCallTool = getCallTool
export const gongGetCallTranscriptTool = getCallTranscriptTool
export const gongGetExtensiveCallsTool = getExtensiveCallsTool
export const gongListUsersTool = listUsersTool
export const gongGetUserTool = getUserTool
export const gongAggregateActivityTool = aggregateActivityTool
export const gongDayByDayActivityTool = dayByDayActivityTool
export const gongAggregateByPeriodTool = aggregateByPeriodTool
export const gongInteractionStatsTool = interactionStatsTool
export const gongAnsweredScorecardsTool = answeredScorecardsTool
export const gongListLibraryFoldersTool = listLibraryFoldersTool
export const gongGetFolderContentTool = getFolderContentTool
export const gongListScorecardsTool = listScorecardsTool
export const gongListTrackersTool = listTrackersTool
export const gongListWorkspacesTool = listWorkspacesTool
export const gongListFlowsTool = listFlowsTool
export const gongGetCoachingTool = getCoachingTool
export const gongLookupEmailTool = lookupEmailTool
export const gongLookupPhoneTool = lookupPhoneTool
export const gongPurgeEmailAddressTool = purgeEmailAddressTool
export const gongPurgePhoneNumberTool = purgePhoneNumberTool
export const gongAssignFlowProspectsTool = assignFlowProspectsTool
export const gongGetProspectFlowsTool = getProspectFlowsTool
export * from './types'
+153
View File
@@ -0,0 +1,153 @@
import type { GongInteractionStatsParams, GongInteractionStatsResponse } from '@/tools/gong/types'
import { getGongErrorMessage, parseGongIdList } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const interactionStatsTool: ToolConfig<
GongInteractionStatsParams,
GongInteractionStatsResponse
> = {
id: 'gong_interaction_stats',
name: 'Gong Interaction Stats',
description:
'Retrieve interaction statistics for users by date range from Gong. Only includes calls with Whisper enabled.',
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',
},
userIds: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of Gong user IDs (up to 20 digits each)',
},
fromDate: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Start date in YYYY-MM-DD format (inclusive, in company timezone)',
},
toDate: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'End date in YYYY-MM-DD format (exclusive, in company timezone, cannot exceed current day)',
},
cursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor from a previous response',
},
},
request: {
url: 'https://api.gong.io/v2/stats/interaction',
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Basic ${btoa(`${params.accessKey}:${params.accessKeySecret}`)}`,
}),
body: (params) => {
const filter: Record<string, unknown> = {
fromDate: params.fromDate.trim(),
toDate: params.toDate.trim(),
}
const userIds = parseGongIdList(params.userIds)
if (userIds) filter.userIds = userIds
const body: Record<string, unknown> = { filter }
if (params.cursor?.trim()) body.cursor = params.cursor.trim()
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
throw new Error(getGongErrorMessage(data, 'Failed to get interaction stats'))
}
const peopleInteractionStats = (data.peopleInteractionStats ?? []).map(
(entry: Record<string, unknown>) => ({
userId: entry.userId ?? '',
userEmailAddress: entry.userEmailAddress ?? null,
personInteractionStats: (
(entry.personInteractionStats as Record<string, unknown>[]) ?? []
).map((stat: Record<string, unknown>) => ({
name: stat.name ?? '',
value: stat.value ?? null,
})),
})
)
return {
success: true,
output: {
peopleInteractionStats,
timeZone: data.timeZone ?? null,
fromDateTime: data.fromDateTime ?? null,
toDateTime: data.toDateTime ?? null,
cursor: data.records?.cursor ?? null,
},
}
},
outputs: {
peopleInteractionStats: {
type: 'array',
description:
"Interaction statistics per user. Applicable stat names: 'Longest Monologue', 'Longest Customer Story', 'Interactivity', 'Patience', 'Question Rate'.",
items: {
type: 'object',
properties: {
userId: { type: 'string', description: "Gong's unique numeric identifier for the user" },
userEmailAddress: { type: 'string', description: 'Email address of the Gong user' },
personInteractionStats: {
type: 'array',
description: 'List of interaction stat measurements for this user',
items: {
type: 'object',
properties: {
name: {
type: 'string',
description:
'Stat name (e.g. Longest Monologue, Interactivity, Patience, Question Rate)',
},
value: {
type: 'number',
description: 'Stat measurement value (can be double or integer)',
},
},
},
},
},
},
},
timeZone: {
type: 'string',
description: "The company's defined timezone in Gong",
},
fromDateTime: {
type: 'string',
description: 'Start of results in ISO-8601 format',
},
toDateTime: {
type: 'string',
description: 'End of results in ISO-8601 format',
},
cursor: {
type: 'string',
description: 'Pagination cursor for the next page',
optional: true,
},
},
}
+168
View File
@@ -0,0 +1,168 @@
import type { GongListCallsParams, GongListCallsResponse } from '@/tools/gong/types'
import { getGongErrorMessage } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const listCallsTool: ToolConfig<GongListCallsParams, GongListCallsResponse> = {
id: 'gong_list_calls',
name: 'Gong List Calls',
description: 'Retrieve call data by date range from Gong.',
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',
},
fromDateTime: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Start date/time in ISO-8601 format (e.g., 2024-01-01T00:00:00Z)',
},
toDateTime: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'End date/time in ISO-8601 format (e.g., 2024-01-31T23:59:59Z). Defaults to the current execution time when omitted.',
},
cursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor from a previous response',
},
workspaceId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Gong workspace ID to filter calls',
},
},
request: {
url: (params) => {
const url = new URL('https://api.gong.io/v2/calls')
url.searchParams.set('fromDateTime', params.fromDateTime.trim())
url.searchParams.set('toDateTime', params.toDateTime?.trim() || new Date().toISOString())
if (params.cursor?.trim()) url.searchParams.set('cursor', params.cursor.trim())
if (params.workspaceId?.trim()) url.searchParams.set('workspaceId', params.workspaceId.trim())
return url.toString()
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
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 list calls'))
}
const calls = (data.calls ?? []).map((call: Record<string, unknown>) => ({
id: call.id ?? '',
title: call.title ?? null,
scheduled: call.scheduled ?? null,
started: call.started ?? '',
duration: call.duration ?? 0,
direction: call.direction ?? null,
system: call.system ?? null,
scope: call.scope ?? null,
media: call.media ?? null,
language: call.language ?? null,
url: call.url ?? null,
primaryUserId: call.primaryUserId ?? null,
workspaceId: call.workspaceId ?? null,
sdrDisposition: call.sdrDisposition ?? null,
clientUniqueId: call.clientUniqueId ?? null,
customData: call.customData ?? null,
purpose: call.purpose ?? null,
meetingUrl: call.meetingUrl ?? null,
isPrivate: call.isPrivate ?? false,
calendarEventId: call.calendarEventId ?? null,
}))
return {
success: true,
output: {
requestId: data.requestId ?? null,
calls,
cursor: data.records?.cursor ?? null,
totalRecords: data.records?.totalRecords ?? calls.length,
currentPageSize: data.records?.currentPageSize ?? null,
currentPageNumber: data.records?.currentPageNumber ?? null,
},
}
},
outputs: {
requestId: {
type: 'string',
description: 'A Gong request reference ID for troubleshooting purposes',
optional: true,
},
calls: {
type: 'array',
description: 'List of calls matching the date range',
items: {
type: 'object',
properties: {
id: { type: 'string', description: "Gong's unique numeric identifier for the call" },
title: { type: 'string', description: 'Call title' },
scheduled: { type: 'string', description: 'Scheduled call time in ISO-8601 format' },
started: { type: 'string', description: 'Recording start time in ISO-8601 format' },
duration: { type: 'number', description: 'Call duration in seconds' },
direction: { type: 'string', description: 'Call direction (Inbound/Outbound)' },
system: { type: 'string', description: 'Communication platform used (e.g., Outreach)' },
scope: {
type: 'string',
description: "Call scope: 'Internal', 'External', or 'Unknown'",
},
media: { type: 'string', description: 'Media type (e.g., Video)' },
language: { type: 'string', description: 'Language code in ISO-639-2B format' },
url: { type: 'string', description: 'URL to the call in the Gong web app' },
primaryUserId: { type: 'string', description: 'Host team member identifier' },
workspaceId: { type: 'string', description: 'Workspace identifier' },
sdrDisposition: { type: 'string', description: 'SDR disposition classification' },
clientUniqueId: {
type: 'string',
description: 'Call identifier from the origin recording system',
},
customData: { type: 'string', description: 'Metadata provided during call creation' },
purpose: { type: 'string', description: 'Call purpose' },
meetingUrl: { type: 'string', description: 'Web conference provider URL' },
isPrivate: { type: 'boolean', description: 'Whether the call is private' },
calendarEventId: { type: 'string', description: 'Calendar event identifier' },
},
},
},
cursor: {
type: 'string',
description: 'Pagination cursor for the next page',
optional: true,
},
totalRecords: {
type: 'number',
description: 'Total number of records matching the filter',
},
currentPageSize: {
type: 'number',
description: 'Number of records in the current page',
optional: true,
},
currentPageNumber: {
type: 'number',
description: 'Current page number',
optional: true,
},
},
}
+136
View File
@@ -0,0 +1,136 @@
import type { GongListFlowsParams, GongListFlowsResponse } from '@/tools/gong/types'
import { getGongErrorMessage } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const listFlowsTool: ToolConfig<GongListFlowsParams, GongListFlowsResponse> = {
id: 'gong_list_flows',
name: 'Gong List Flows',
description: 'List Gong Engage flows (sales engagement sequences).',
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',
},
flowOwnerEmail: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
"Email of a Gong user. The API will return 'PERSONAL' flows belonging to this user in addition to 'COMPANY' flows.",
},
workspaceId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Optional workspace ID to filter flows to a specific workspace',
},
cursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor from a previous API call to retrieve the next page of records',
},
},
request: {
url: (params) => {
const url = new URL('https://api.gong.io/v2/flows')
url.searchParams.set('flowEmailOwner', params.flowOwnerEmail.trim())
if (params.workspaceId) url.searchParams.set('workspaceId', params.workspaceId.trim())
if (params.cursor?.trim()) url.searchParams.set('cursor', params.cursor.trim())
return url.toString()
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
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 list flows'))
}
const flows = (data.flows ?? []).map((f: Record<string, unknown>) => ({
id: f.id ?? '',
name: f.name ?? null,
folderId: f.folderId ?? null,
folderName: f.folderName ?? null,
visibility: f.visibility ?? null,
creationDate: f.creationDate ?? null,
exclusive: f.exclusive ?? null,
}))
return {
success: true,
output: {
requestId: data.requestId ?? null,
flows,
totalRecords: data.records?.totalRecords ?? null,
currentPageSize: data.records?.currentPageSize ?? null,
currentPageNumber: data.records?.currentPageNumber ?? null,
cursor: data.records?.cursor ?? null,
},
}
},
outputs: {
requestId: {
type: 'string',
description: 'A Gong request reference ID for troubleshooting purposes',
},
flows: {
type: 'array',
description: 'List of Gong Engage flows',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'The ID of the flow' },
name: { type: 'string', description: 'The name of the flow' },
folderId: { type: 'string', description: 'The ID of the folder this flow is under' },
folderName: { type: 'string', description: 'The name of the folder this flow is under' },
visibility: {
type: 'string',
description: 'The flow visibility type (COMPANY, PERSONAL, or SHARED)',
},
creationDate: {
type: 'string',
description: 'Creation time of the flow in ISO-8601 format',
},
exclusive: {
type: 'boolean',
description: 'Indicates whether a prospect in this flow can be added to other flows',
},
},
},
},
totalRecords: {
type: 'number',
description: 'Total number of flow records available',
},
currentPageSize: {
type: 'number',
description: 'Number of records returned in the current page',
},
currentPageNumber: {
type: 'number',
description: 'Current page number',
},
cursor: {
type: 'string',
description: 'Pagination cursor for retrieving the next page of records',
optional: true,
},
},
}
@@ -0,0 +1,95 @@
import type {
GongListLibraryFoldersParams,
GongListLibraryFoldersResponse,
} from '@/tools/gong/types'
import { getGongErrorMessage } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const listLibraryFoldersTool: ToolConfig<
GongListLibraryFoldersParams,
GongListLibraryFoldersResponse
> = {
id: 'gong_list_library_folders',
name: 'Gong List Library Folders',
description: 'Retrieve library folders from Gong.',
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: false,
visibility: 'user-or-llm',
description: 'Gong workspace ID to filter folders',
},
},
request: {
url: (params) => {
const url = new URL('https://api.gong.io/v2/library/folders')
if (params.workspaceId?.trim()) url.searchParams.set('workspaceId', params.workspaceId.trim())
return url.toString()
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
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 list library folders'))
}
const folders = (data.folders ?? []).map((f: Record<string, unknown>) => ({
id: f.id ?? '',
name: f.name ?? '',
parentFolderId: f.parentFolderId ?? null,
createdBy: f.createdBy ?? null,
updated: f.updated ?? null,
}))
return {
success: true,
output: { folders },
}
},
outputs: {
folders: {
type: 'array',
description: 'List of library folders with id, name, and parent relationships',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Gong unique numeric identifier for the folder' },
name: { type: 'string', description: 'Display name of the folder' },
parentFolderId: {
type: 'string',
description:
'Gong unique numeric identifier for the parent folder (null for root folder)',
},
createdBy: {
type: 'string',
description: 'Gong unique numeric identifier for the user who added the folder',
},
updated: {
type: 'string',
description: "Folder's last update time in ISO-8601 format",
},
},
},
},
},
}
+128
View File
@@ -0,0 +1,128 @@
import type { GongListScorecardsParams, GongListScorecardsResponse } from '@/tools/gong/types'
import { getGongErrorMessage } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const listScorecardsTool: ToolConfig<GongListScorecardsParams, GongListScorecardsResponse> =
{
id: 'gong_list_scorecards',
name: 'Gong List Scorecards',
description: 'Retrieve scorecard definitions from Gong settings.',
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',
},
},
request: {
url: 'https://api.gong.io/v2/settings/scorecards',
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
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 list scorecards'))
}
const scorecards = (data.scorecards ?? []).map((sc: Record<string, unknown>) => ({
scorecardId: sc.scorecardId ?? '',
scorecardName: sc.scorecardName ?? '',
workspaceId: sc.workspaceId ?? null,
enabled: sc.enabled ?? false,
updaterUserId: sc.updaterUserId ?? null,
created: sc.created ?? null,
updated: sc.updated ?? null,
questions: ((sc.questions as Record<string, unknown>[] | undefined) ?? []).map(
(q: Record<string, unknown>) => ({
questionId: q.questionId ?? '',
questionText: q.questionText ?? '',
questionRevisionId: q.questionRevisionId ?? null,
isOverall: q.isOverall ?? false,
created: q.created ?? null,
updated: q.updated ?? null,
updaterUserId: q.updaterUserId ?? null,
})
),
}))
return {
success: true,
output: { scorecards },
}
},
outputs: {
scorecards: {
type: 'array',
description: 'List of scorecard definitions with questions',
items: {
type: 'object',
properties: {
scorecardId: { type: 'string', description: 'Unique identifier for the scorecard' },
scorecardName: { type: 'string', description: 'Display name of the scorecard' },
workspaceId: {
type: 'string',
description: 'Workspace identifier associated with this scorecard',
},
enabled: { type: 'boolean', description: 'Whether the scorecard is active' },
updaterUserId: {
type: 'string',
description: 'ID of the user who last modified the scorecard',
},
created: {
type: 'string',
description: 'Creation timestamp in ISO-8601 format',
},
updated: {
type: 'string',
description: 'Last update timestamp in ISO-8601 format',
},
questions: {
type: 'array',
description: 'List of questions in the scorecard',
items: {
type: 'object',
properties: {
questionId: { type: 'string', description: 'Unique identifier for the question' },
questionText: { type: 'string', description: 'The text content of the question' },
questionRevisionId: {
type: 'string',
description: 'Identifier for the specific revision of the question',
},
isOverall: {
type: 'boolean',
description: 'Whether this is the primary overall question',
},
created: {
type: 'string',
description: 'Question creation timestamp in ISO-8601 format',
},
updated: {
type: 'string',
description: 'Question last update timestamp in ISO-8601 format',
},
updaterUserId: {
type: 'string',
description: 'ID of the user who last modified the question',
},
},
},
},
},
},
},
},
}
+165
View File
@@ -0,0 +1,165 @@
import type { GongListTrackersParams, GongListTrackersResponse } from '@/tools/gong/types'
import { getGongErrorMessage } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const listTrackersTool: ToolConfig<GongListTrackersParams, GongListTrackersResponse> = {
id: 'gong_list_trackers',
name: 'Gong List Trackers',
description: 'Retrieve smart tracker and keyword tracker definitions from Gong settings.',
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: false,
visibility: 'user-or-llm',
description:
'The ID of the workspace the keyword trackers are in. When empty, all trackers in all workspaces are returned.',
},
},
request: {
url: (params) => {
const url = new URL('https://api.gong.io/v2/settings/trackers')
if (params.workspaceId?.trim()) url.searchParams.set('workspaceId', params.workspaceId.trim())
return url.toString()
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
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 list trackers'))
}
const trackers = (data.keywordTrackers ?? []).map((t: Record<string, unknown>) => ({
trackerId: t.trackerId ?? '',
trackerName: t.trackerName ?? '',
workspaceId: t.workspaceId ?? null,
languageKeywords: ((t.languageKeywords as Record<string, unknown>[] | undefined) ?? []).map(
(lk: Record<string, unknown>) => ({
language: lk.language ?? null,
keywords: lk.keywords ?? [],
includeRelatedForms: lk.includeRelatedForms ?? false,
})
),
affiliation: t.affiliation ?? null,
partOfQuestion: t.partOfQuestion ?? null,
saidAt: t.saidAt ?? null,
saidAtInterval: t.saidAtInterval ?? null,
saidAtUnit: t.saidAtUnit ?? null,
saidInTopics: t.saidInTopics ?? [],
saidInCallParts: t.saidInCallParts ?? [],
filterQuery: t.filterQuery ?? null,
created: t.created ?? null,
creatorUserId: t.creatorUserId ?? null,
updated: t.updated ?? null,
updaterUserId: t.updaterUserId ?? null,
}))
return {
success: true,
output: { trackers },
}
},
outputs: {
trackers: {
type: 'array',
description: 'List of keyword tracker definitions',
items: {
type: 'object',
properties: {
trackerId: { type: 'string', description: 'Unique identifier for the tracker' },
trackerName: { type: 'string', description: 'Display name of the tracker' },
workspaceId: {
type: 'string',
description: 'ID of the workspace containing the tracker',
},
languageKeywords: {
type: 'array',
description: 'Keywords organized by language',
items: {
type: 'object',
properties: {
language: {
type: 'string',
description:
'ISO 639-2/B language code ("mul" means keywords apply across all languages)',
},
keywords: {
type: 'array',
description: 'Words and phrases in the designated language',
},
includeRelatedForms: {
type: 'boolean',
description: 'Whether to include different word forms',
},
},
},
},
affiliation: {
type: 'string',
description: 'Speaker affiliation filter: "Anyone", "Company", or "NonCompany"',
},
partOfQuestion: {
type: 'boolean',
description: 'Whether to track keywords only within questions',
},
saidAt: {
type: 'string',
description: 'Position in call: "Anytime", "First", or "Last"',
},
saidAtInterval: {
type: 'number',
description: 'Duration to search (in minutes or percentage)',
},
saidAtUnit: { type: 'string', description: 'Unit for saidAtInterval' },
saidInTopics: {
type: 'array',
description: 'Topics where keywords should be detected',
},
saidInCallParts: {
type: 'array',
description: 'Specific call segments to monitor',
},
filterQuery: {
type: 'string',
description: 'JSON-formatted call filtering criteria',
},
created: {
type: 'string',
description: 'Creation timestamp in ISO-8601 format',
},
creatorUserId: {
type: 'string',
description: 'ID of the user who created the tracker (null for built-in trackers)',
},
updated: {
type: 'string',
description: 'Last modification timestamp in ISO-8601 format',
},
updaterUserId: {
type: 'string',
description: 'ID of the user who last modified the tracker',
},
},
},
},
},
}
+179
View File
@@ -0,0 +1,179 @@
import type { GongListUsersParams, GongListUsersResponse } from '@/tools/gong/types'
import { getGongErrorMessage } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const listUsersTool: ToolConfig<GongListUsersParams, GongListUsersResponse> = {
id: 'gong_list_users',
name: 'Gong List Users',
description: 'List all users in your Gong account.',
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',
},
cursor: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor from a previous response',
},
includeAvatars: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Whether to include avatar URLs (true/false)',
},
},
request: {
url: (params) => {
const url = new URL('https://api.gong.io/v2/users')
if (params.cursor?.trim()) url.searchParams.set('cursor', params.cursor.trim())
if (params.includeAvatars) url.searchParams.set('includeAvatars', params.includeAvatars)
return url.toString()
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
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 list users'))
}
const users = (data.users ?? []).map((user: Record<string, unknown>) => ({
id: user.id ?? '',
emailAddress: user.emailAddress ?? null,
created: user.created ?? null,
active: user.active ?? false,
emailAliases: user.emailAliases ?? [],
trustedEmailAddress: user.trustedEmailAddress ?? null,
firstName: user.firstName ?? null,
lastName: user.lastName ?? null,
title: user.title ?? null,
phoneNumber: user.phoneNumber ?? null,
extension: user.extension ?? null,
personalMeetingUrls: user.personalMeetingUrls ?? [],
settings: user.settings ?? null,
managerId: user.managerId ?? null,
meetingConsentPageUrl: user.meetingConsentPageUrl ?? null,
spokenLanguages: user.spokenLanguages ?? [],
}))
return {
success: true,
output: {
requestId: data.requestId ?? null,
users,
cursor: data.records?.cursor ?? null,
totalRecords: data.records?.totalRecords ?? null,
currentPageSize: data.records?.currentPageSize ?? null,
currentPageNumber: data.records?.currentPageNumber ?? null,
},
}
},
outputs: {
requestId: {
type: 'string',
description: 'A Gong request reference ID for troubleshooting purposes',
optional: true,
},
users: {
type: 'array',
description: 'List of Gong users',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Unique numeric user ID (up to 20 digits)' },
emailAddress: { type: 'string', description: 'User email address' },
created: { type: 'string', description: 'User creation timestamp (ISO-8601)' },
active: { type: 'boolean', description: 'Whether the user is active' },
emailAliases: {
type: 'array',
description: 'Alternative email addresses for the user',
items: { type: 'string' },
},
trustedEmailAddress: {
type: 'string',
description: 'Trusted email address for the user',
},
firstName: { type: 'string', description: 'First name' },
lastName: { type: 'string', description: 'Last name' },
title: { type: 'string', description: 'Job title' },
phoneNumber: { type: 'string', description: 'Phone number' },
extension: { type: 'string', description: 'Phone extension number' },
personalMeetingUrls: {
type: 'array',
description: 'Personal meeting URLs',
items: { type: 'string' },
},
settings: {
type: 'object',
description: 'User settings',
properties: {
webConferencesRecorded: {
type: 'boolean',
description: 'Whether web conferences are recorded',
},
preventWebConferenceRecording: {
type: 'boolean',
description: 'Whether web conference recording is prevented',
},
telephonyCallsImported: {
type: 'boolean',
description: 'Whether telephony calls are imported',
},
emailsImported: { type: 'boolean', description: 'Whether emails are imported' },
preventEmailImport: {
type: 'boolean',
description: 'Whether email import is prevented',
},
nonRecordedMeetingsImported: {
type: 'boolean',
description: 'Whether non-recorded meetings are imported',
},
gongConnectEnabled: {
type: 'boolean',
description: 'Whether Gong Connect is enabled',
},
},
},
managerId: { type: 'string', description: 'Manager user ID' },
meetingConsentPageUrl: { type: 'string', description: 'Meeting consent page URL' },
spokenLanguages: {
type: 'array',
description: 'Languages spoken by the user',
items: {
type: 'object',
properties: {
language: { type: 'string', description: 'Language code' },
primary: { type: 'boolean', description: 'Whether this is the primary language' },
},
},
},
},
},
},
cursor: { type: 'string', description: 'Pagination cursor for the next page', optional: true },
totalRecords: { type: 'number', description: 'Total number of user records', optional: true },
currentPageSize: {
type: 'number',
description: 'Number of records in the current page',
optional: true,
},
currentPageNumber: { type: 'number', description: 'Current page number', optional: true },
},
}
+69
View File
@@ -0,0 +1,69 @@
import type { GongListWorkspacesParams, GongListWorkspacesResponse } from '@/tools/gong/types'
import { getGongErrorMessage } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const listWorkspacesTool: ToolConfig<GongListWorkspacesParams, GongListWorkspacesResponse> =
{
id: 'gong_list_workspaces',
name: 'Gong List Workspaces',
description: 'List all company workspaces in Gong.',
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',
},
},
request: {
url: 'https://api.gong.io/v2/workspaces',
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
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 list workspaces'))
}
const workspaces = (data.workspaces ?? []).map((w: Record<string, unknown>) => ({
id: w.id ?? '',
name: w.name ?? null,
description: w.description ?? null,
}))
return {
success: true,
output: { workspaces },
}
},
outputs: {
workspaces: {
type: 'array',
description: 'List of Gong workspaces',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Gong unique numeric identifier for the workspace' },
name: { type: 'string', description: 'Display name of the workspace' },
description: {
type: 'string',
description: "Description of the workspace's purpose or content",
},
},
},
},
},
}
+196
View File
@@ -0,0 +1,196 @@
import type { GongLookupEmailParams, GongLookupEmailResponse } from '@/tools/gong/types'
import { getGongErrorMessage } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const lookupEmailTool: ToolConfig<GongLookupEmailParams, GongLookupEmailResponse> = {
id: 'gong_lookup_email',
name: 'Gong Lookup Email',
description:
'Find all references to an email address in Gong (calls, email messages, meetings, CRM data, engagement).',
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',
},
emailAddress: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Email address to look up',
},
},
request: {
url: (params) => {
const url = new URL('https://api.gong.io/v2/data-privacy/data-for-email-address')
url.searchParams.set('emailAddress', params.emailAddress.trim())
return url.toString()
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
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 lookup email address'))
}
return {
success: true,
output: {
requestId: data.requestId ?? '',
calls: data.calls ?? [],
emails: data.emails ?? [],
meetings: data.meetings ?? [],
customerData: data.customerData ?? [],
customerEngagement: data.customerEngagement ?? [],
},
}
},
outputs: {
requestId: {
type: 'string',
description: 'Gong request reference ID for troubleshooting',
},
calls: {
type: 'array',
description: 'Related calls referencing this email address',
items: {
type: 'object',
properties: {
id: {
type: 'string',
description: "Gong's unique numeric identifier for the call (up to 20 digits)",
},
status: { type: 'string', description: 'Call status' },
externalSystems: {
type: 'array',
description: 'Links to external systems such as CRM, Telephony System, etc.',
items: {
type: 'object',
properties: {
system: { type: 'string', description: 'External system name' },
objects: {
type: 'array',
description: 'List of objects within the external system',
items: {
type: 'object',
properties: {
objectType: { type: 'string', description: 'Object type' },
externalId: { type: 'string', description: 'External ID' },
},
},
},
},
},
},
},
},
},
emails: {
type: 'array',
description: 'Related email messages referencing this email address',
items: {
type: 'object',
properties: {
id: {
type: 'string',
description: "Gong's unique 32 character identifier for the email message",
},
from: { type: 'string', description: "The sender's email address" },
sentTime: {
type: 'string',
description: 'Date and time the email was sent in ISO-8601 format',
},
mailbox: {
type: 'string',
description: 'The mailbox from which the email was retrieved',
},
messageHash: { type: 'string', description: 'Hash code of the email message' },
},
},
},
meetings: {
type: 'array',
description: 'Related meetings referencing this email address',
items: {
type: 'object',
properties: {
id: { type: 'string', description: "Gong's unique identifier for the meeting" },
},
},
},
customerData: {
type: 'array',
description:
'Links to data from external systems (CRM, Telephony, etc.) that reference this email',
items: {
type: 'object',
properties: {
system: { type: 'string', description: 'External system name' },
objects: {
type: 'array',
description: 'List of objects in the external system',
items: {
type: 'object',
properties: {
id: {
type: 'string',
description:
"Gong's unique numeric identifier for the Lead or Contact (up to 20 digits)",
},
objectType: { type: 'string', description: 'Object type' },
externalId: { type: 'string', description: 'External ID' },
mirrorId: { type: 'string', description: 'CRM Mirror ID' },
fields: {
type: 'array',
description: 'Object fields',
items: {
type: 'object',
properties: {
name: { type: 'string', description: 'Field name' },
value: { type: 'json', description: 'Field value' },
},
},
},
},
},
},
},
},
},
customerEngagement: {
type: 'array',
description: 'Customer engagement events (such as viewing external shared calls)',
items: {
type: 'object',
properties: {
eventType: { type: 'string', description: 'Event type' },
eventName: { type: 'string', description: 'Event name' },
timestamp: {
type: 'string',
description: 'Date and time the event occurred in ISO-8601 format',
},
contentId: { type: 'string', description: 'Event content ID' },
contentUrl: { type: 'string', description: 'Event content URL' },
reportingSystem: { type: 'string', description: 'Event reporting system' },
sourceEventId: { type: 'string', description: 'Source event ID' },
},
},
},
},
}
+197
View File
@@ -0,0 +1,197 @@
import type { GongLookupPhoneParams, GongLookupPhoneResponse } from '@/tools/gong/types'
import { getGongErrorMessage } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const lookupPhoneTool: ToolConfig<GongLookupPhoneParams, GongLookupPhoneResponse> = {
id: 'gong_lookup_phone',
name: 'Gong Lookup Phone',
description:
'Find all references to a phone number in Gong (calls, email messages, meetings, CRM data, and associated contacts).',
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',
},
phoneNumber: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Phone number to look up (must start with + followed by country code)',
},
},
request: {
url: (params) => {
const url = new URL('https://api.gong.io/v2/data-privacy/data-for-phone-number')
url.searchParams.set('phoneNumber', params.phoneNumber.trim())
return url.toString()
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
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 lookup phone number'))
}
return {
success: true,
output: {
requestId: data.requestId ?? '',
suppliedPhoneNumber: data.suppliedPhoneNumber ?? '',
matchingPhoneNumbers: data.matchingPhoneNumbers ?? [],
emailAddresses: data.emailAddresses ?? [],
calls: data.calls ?? [],
emails: data.emails ?? [],
meetings: data.meetings ?? [],
customerData: data.customerData ?? [],
},
}
},
outputs: {
requestId: {
type: 'string',
description: 'Gong request reference ID for troubleshooting',
},
suppliedPhoneNumber: {
type: 'string',
description: 'The phone number that was supplied in the request',
},
matchingPhoneNumbers: {
type: 'array',
description: 'Phone numbers found in the system that match the supplied number',
items: {
type: 'string',
},
},
emailAddresses: {
type: 'array',
description: 'Email addresses associated with the phone number',
items: {
type: 'string',
},
},
calls: {
type: 'array',
description: 'Related calls referencing this phone number',
items: {
type: 'object',
properties: {
id: {
type: 'string',
description: "Gong's unique numeric identifier for the call (up to 20 digits)",
},
status: { type: 'string', description: 'Call status' },
externalSystems: {
type: 'array',
description: 'Links to external systems such as CRM, Telephony System, etc.',
items: {
type: 'object',
properties: {
system: { type: 'string', description: 'External system name' },
objects: {
type: 'array',
description: 'List of objects within the external system',
items: {
type: 'object',
properties: {
objectType: { type: 'string', description: 'Object type' },
externalId: { type: 'string', description: 'External ID' },
},
},
},
},
},
},
},
},
},
emails: {
type: 'array',
description: 'Related email messages associated with contacts matching this phone number',
items: {
type: 'object',
properties: {
id: {
type: 'string',
description: "Gong's unique 32 character identifier for the email message",
},
from: { type: 'string', description: "The sender's email address" },
sentTime: {
type: 'string',
description: 'Date and time the email was sent in ISO-8601 format',
},
mailbox: {
type: 'string',
description: 'The mailbox from which the email was retrieved',
},
messageHash: { type: 'string', description: 'Hash code of the email message' },
},
},
},
meetings: {
type: 'array',
description: 'Related meetings associated with this phone number',
items: {
type: 'object',
properties: {
id: { type: 'string', description: "Gong's unique identifier for the meeting" },
},
},
},
customerData: {
type: 'array',
description:
'Links to data from external systems (CRM, Telephony, etc.) that reference this phone number',
items: {
type: 'object',
properties: {
system: { type: 'string', description: 'External system name' },
objects: {
type: 'array',
description: 'List of objects in the external system',
items: {
type: 'object',
properties: {
id: {
type: 'string',
description:
"Gong's unique numeric identifier for the Lead or Contact (up to 20 digits)",
},
objectType: { type: 'string', description: 'Object type' },
externalId: { type: 'string', description: 'External ID' },
mirrorId: { type: 'string', description: 'CRM Mirror ID' },
fields: {
type: 'array',
description: 'Object fields',
items: {
type: 'object',
properties: {
name: { type: 'string', description: 'Field name' },
value: { type: 'json', description: 'Field value' },
},
},
},
},
},
},
},
},
},
},
}
@@ -0,0 +1,69 @@
import type { GongPurgeEmailAddressParams, GongPurgeEmailAddressResponse } from '@/tools/gong/types'
import { getGongErrorMessage } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const purgeEmailAddressTool: ToolConfig<
GongPurgeEmailAddressParams,
GongPurgeEmailAddressResponse
> = {
id: 'gong_purge_email_address',
name: 'Gong Purge Email Address',
description:
'Erase all Gong data (calls, email messages, leads, contacts) referencing an email address. Asynchronous and irreversible.',
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',
},
emailAddress: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Email address whose associated data should be permanently erased from Gong',
},
},
request: {
url: (params) => {
const url = new URL('https://api.gong.io/v2/data-privacy/erase-data-for-email-address')
url.searchParams.set('emailAddress', params.emailAddress.trim())
return url.toString()
},
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
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 erase email address data'))
}
return {
success: true,
output: {
requestId: data.requestId ?? null,
},
}
},
outputs: {
requestId: {
type: 'string',
description: 'A Gong request reference ID for troubleshooting purposes',
optional: true,
},
},
}
+70
View File
@@ -0,0 +1,70 @@
import type { GongPurgePhoneNumberParams, GongPurgePhoneNumberResponse } from '@/tools/gong/types'
import { getGongErrorMessage } from '@/tools/gong/utils'
import type { ToolConfig } from '@/tools/types'
export const purgePhoneNumberTool: ToolConfig<
GongPurgePhoneNumberParams,
GongPurgePhoneNumberResponse
> = {
id: 'gong_purge_phone_number',
name: 'Gong Purge Phone Number',
description:
'Erase all Gong data (calls, leads, contacts) referencing a phone number. Asynchronous and irreversible.',
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',
},
phoneNumber: {
type: 'string',
required: true,
visibility: 'user-only',
description:
'Phone number whose associated data should be permanently erased from Gong. Must include a leading "+" and country code (e.g., +14255552671)',
},
},
request: {
url: (params) => {
const url = new URL('https://api.gong.io/v2/data-privacy/erase-data-for-phone-number')
url.searchParams.set('phoneNumber', params.phoneNumber.trim())
return url.toString()
},
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
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 erase phone number data'))
}
return {
success: true,
output: {
requestId: data.requestId ?? null,
},
}
},
outputs: {
requestId: {
type: 'string',
description: 'A Gong request reference ID for troubleshooting purposes',
optional: true,
},
},
}
+794
View File
@@ -0,0 +1,794 @@
import type { ToolResponse } from '@/tools/types'
/** Base parameters shared by all Gong tools */
interface GongBaseParams {
accessKey: string
accessKeySecret: string
}
/** List Calls */
export interface GongListCallsParams extends GongBaseParams {
fromDateTime: string
toDateTime?: string
cursor?: string
workspaceId?: string
}
/** Create Call */
export interface GongCreateCallParams extends GongBaseParams {
clientUniqueId: string
actualStart: string
primaryUser: string
parties: unknown
direction: string
downloadMediaUrl: string
title?: string
workspaceId?: string
disposition?: string
purpose?: string
context?: unknown
callProviderCode?: string
}
export interface GongCreateCallResponse extends ToolResponse {
output: {
callId: string
requestId: string
url: string | null
}
}
interface GongCallBasic {
id: string
title: string | null
scheduled: string | null
started: string
duration: number
direction: string | null
system: string | null
scope: string | null
media: string | null
language: string | null
url: string | null
primaryUserId: string | null
workspaceId: string | null
sdrDisposition: string | null
clientUniqueId: string | null
customData: string | null
purpose: string | null
meetingUrl: string | null
isPrivate: boolean
calendarEventId: string | null
}
interface GongParty {
id: string | null
name: string | null
emailAddress: string | null
phoneNumber: string | null
title: string | null
speakerId: string | null
userId: string | null
affiliation: string | null
methods: string[]
context: { system: string; objects: Record<string, unknown>[] }[]
}
export interface GongListCallsResponse extends ToolResponse {
output: {
requestId: string | null
calls: GongCallBasic[]
cursor: string | null
totalRecords: number
currentPageSize: number | null
currentPageNumber: number | null
}
}
/** Get Call */
export interface GongGetCallParams extends GongBaseParams {
callId: string
}
export interface GongGetCallResponse extends ToolResponse {
output: GongCallBasic
}
/** Get Call Transcript */
export interface GongGetCallTranscriptParams extends GongBaseParams {
callIds?: string
fromDateTime?: string
toDateTime?: string
workspaceId?: string
cursor?: string
}
interface GongTranscriptSentence {
start: number
end: number
text: string
}
interface GongTranscriptEntry {
speakerId: string | null
topic: string | null
sentences: GongTranscriptSentence[]
}
interface GongCallTranscript {
callId: string
transcript: GongTranscriptEntry[]
}
export interface GongGetCallTranscriptResponse extends ToolResponse {
output: {
callTranscripts: GongCallTranscript[]
cursor: string | null
}
}
/** Get Extensive Calls */
export interface GongGetExtensiveCallsParams extends GongBaseParams {
callIds?: string
fromDateTime?: string
toDateTime?: string
workspaceId?: string
primaryUserIds?: string
cursor?: string
}
interface GongExtensiveCall {
metaData: Record<string, unknown>
parties: GongParty[]
content: Record<string, unknown>
interaction: Record<string, unknown>
collaboration: Record<string, unknown>
media: Record<string, unknown>
}
export interface GongGetExtensiveCallsResponse extends ToolResponse {
output: {
calls: GongExtensiveCall[]
cursor: string | null
}
}
/** List Users */
export interface GongListUsersParams extends GongBaseParams {
cursor?: string
includeAvatars?: string
}
interface GongUserSettings {
webConferencesRecorded: boolean
preventWebConferenceRecording: boolean
telephonyCallsImported: boolean
emailsImported: boolean
preventEmailImport: boolean
nonRecordedMeetingsImported: boolean
gongConnectEnabled: boolean
}
interface GongSpokenLanguage {
language: string
primary: boolean
}
interface GongUser {
id: string
emailAddress: string | null
created: string | null
active: boolean
emailAliases: string[]
trustedEmailAddress: string | null
firstName: string | null
lastName: string | null
title: string | null
phoneNumber: string | null
extension: string | null
personalMeetingUrls: string[]
settings: GongUserSettings | null
managerId: string | null
meetingConsentPageUrl: string | null
spokenLanguages: GongSpokenLanguage[]
}
export interface GongListUsersResponse extends ToolResponse {
output: {
requestId: string | null
users: GongUser[]
cursor: string | null
totalRecords: number | null
currentPageSize: number | null
currentPageNumber: number | null
}
}
/** Get User */
export interface GongGetUserParams extends GongBaseParams {
userId: string
}
export interface GongGetUserResponse extends ToolResponse {
output: {
id: string
emailAddress: string | null
created: string | null
active: boolean
emailAliases: string[]
trustedEmailAddress: string | null
firstName: string | null
lastName: string | null
title: string | null
phoneNumber: string | null
extension: string | null
personalMeetingUrls: string[]
settings: GongUserSettings | null
managerId: string | null
meetingConsentPageUrl: string | null
spokenLanguages: GongSpokenLanguage[]
}
}
/** Aggregate Activity */
export interface GongAggregateActivityParams extends GongBaseParams {
userIds?: string
fromDate: string
toDate: string
cursor?: string
}
interface GongUserActivity {
userId: string
userEmailAddress: string | null
callsAsHost: number | null
callsAttended: number | null
callsGaveFeedback: number | null
callsReceivedFeedback: number | null
callsRequestedFeedback: number | null
callsScorecardsFilled: number | null
callsScorecardsReceived: number | null
ownCallsListenedTo: number | null
othersCallsListenedTo: number | null
callsSharedInternally: number | null
callsSharedExternally: number | null
callsCommentsGiven: number | null
callsCommentsReceived: number | null
callsMarkedAsFeedbackGiven: number | null
callsMarkedAsFeedbackReceived: number | null
}
export interface GongAggregateActivityResponse extends ToolResponse {
output: {
usersActivity: GongUserActivity[]
timeZone: string | null
fromDateTime: string | null
toDateTime: string | null
cursor: string | null
}
}
/** Interaction Stats */
interface GongInteractionStatEntry {
name: string
value: number | null
}
interface GongUserInteractionStats {
userId: string
userEmailAddress: string | null
personInteractionStats: GongInteractionStatEntry[]
}
export interface GongInteractionStatsParams extends GongBaseParams {
userIds?: string
fromDate: string
toDate: string
cursor?: string
}
export interface GongInteractionStatsResponse extends ToolResponse {
output: {
peopleInteractionStats: GongUserInteractionStats[]
timeZone: string | null
fromDateTime: string | null
toDateTime: string | null
cursor: string | null
}
}
/** Day-by-Day Activity */
export interface GongDayByDayActivityParams extends GongBaseParams {
userIds?: string
fromDate: string
toDate: string
cursor?: string
}
interface GongDailyActivity {
fromDate: string | null
toDate: string | null
callsAsHost: string[]
callsAttended: string[]
callsGaveFeedback: string[]
callsReceivedFeedback: string[]
callsRequestedFeedback: string[]
callsScorecardsFilled: string[]
callsScorecardsReceived: string[]
ownCallsListenedTo: string[]
othersCallsListenedTo: string[]
callsSharedInternally: string[]
callsSharedExternally: string[]
callsCommentsGiven: string[]
callsCommentsReceived: string[]
callsMarkedAsFeedbackGiven: string[]
callsMarkedAsFeedbackReceived: string[]
}
interface GongUserDayByDayActivity {
userId: string
userEmailAddress: string | null
userDailyActivityStats: GongDailyActivity[]
}
export interface GongDayByDayActivityResponse extends ToolResponse {
output: {
requestId: string | null
usersDetailedActivities: GongUserDayByDayActivity[]
cursor: string | null
}
}
/** Aggregate by Period */
export interface GongAggregateByPeriodParams extends GongBaseParams {
aggregationPeriod: string
userIds?: string
fromDate: string
toDate: string
cursor?: string
}
interface GongPeriodActivity {
fromDate: string | null
toDate: string | null
callsAsHost: number | null
callsAttended: number | null
callsGaveFeedback: number | null
callsReceivedFeedback: number | null
callsRequestedFeedback: number | null
callsScorecardsFilled: number | null
callsScorecardsReceived: number | null
ownCallsListenedTo: number | null
othersCallsListenedTo: number | null
callsSharedInternally: number | null
callsSharedExternally: number | null
callsCommentsGiven: number | null
callsCommentsReceived: number | null
callsMarkedAsFeedbackGiven: number | null
callsMarkedAsFeedbackReceived: number | null
}
interface GongUserAggregateByPeriod {
userId: string
userEmailAddress: string | null
userAggregateActivity: GongPeriodActivity[]
}
export interface GongAggregateByPeriodResponse extends ToolResponse {
output: {
requestId: string | null
usersAggregateActivity: GongUserAggregateByPeriod[]
cursor: string | null
}
}
/** Answered Scorecards */
export interface GongAnsweredScorecardsParams extends GongBaseParams {
callFromDate?: string
callToDate?: string
reviewFromDate?: string
reviewToDate?: string
scorecardIds?: string
reviewedUserIds?: string
cursor?: string
}
interface GongScorecardAnswer {
questionId: number | null
questionRevisionId: number | null
isOverall: boolean | null
score: number | null
answerText: string | null
notApplicable: boolean | null
}
interface GongAnsweredScorecard {
answeredScorecardId: number
scorecardId: number | null
scorecardName: string | null
callId: number | null
callStartTime: string | null
reviewedUserId: number | null
reviewerUserId: number | null
reviewTime: string | null
visibilityType: string | null
answers: GongScorecardAnswer[]
}
export interface GongAnsweredScorecardsResponse extends ToolResponse {
output: {
answeredScorecards: GongAnsweredScorecard[]
cursor: string | null
}
}
/** List Library Folders */
export interface GongListLibraryFoldersParams extends GongBaseParams {
workspaceId?: string
}
interface GongLibraryFolder {
id: string
name: string
parentFolderId: string | null
createdBy: string | null
updated: string | null
}
export interface GongListLibraryFoldersResponse extends ToolResponse {
output: {
folders: GongLibraryFolder[]
}
}
/** Get Folder Content */
export interface GongGetFolderContentParams extends GongBaseParams {
folderId: string
}
interface GongFolderCallSnippet {
fromSec: number | null
toSec: number | null
}
interface GongFolderCall {
id: string
title: string | null
note: string | null
addedBy: string | null
created: string | null
url: string | null
snippet: GongFolderCallSnippet | null
}
export interface GongGetFolderContentResponse extends ToolResponse {
output: {
folderId: string | null
folderName: string | null
createdBy: string | null
updated: string | null
calls: GongFolderCall[]
}
}
/** List Scorecards */
export interface GongListScorecardsParams extends GongBaseParams {}
interface GongScorecardQuestion {
questionId: string
questionText: string
questionRevisionId: string | null
isOverall: boolean
created: string | null
updated: string | null
updaterUserId: string | null
}
interface GongScorecard {
scorecardId: string
scorecardName: string
workspaceId: string | null
enabled: boolean
updaterUserId: string | null
created: string | null
updated: string | null
questions: GongScorecardQuestion[]
}
export interface GongListScorecardsResponse extends ToolResponse {
output: {
scorecards: GongScorecard[]
}
}
/** List Trackers */
export interface GongListTrackersParams extends GongBaseParams {
workspaceId?: string
}
interface GongTrackerLanguageKeyword {
language: string | null
keywords: string[]
includeRelatedForms: boolean
}
interface GongTracker {
trackerId: string
trackerName: string
workspaceId: string | null
languageKeywords: GongTrackerLanguageKeyword[]
affiliation: string | null
partOfQuestion: boolean | null
saidAt: string | null
saidAtInterval: number | null
saidAtUnit: string | null
saidInTopics: string[]
saidInCallParts: string[]
filterQuery: string | null
created: string | null
creatorUserId: string | null
updated: string | null
updaterUserId: string | null
}
export interface GongListTrackersResponse extends ToolResponse {
output: {
trackers: GongTracker[]
}
}
/** List Workspaces */
export interface GongListWorkspacesParams extends GongBaseParams {}
interface GongWorkspace {
id: string
name: string | null
description: string | null
}
export interface GongListWorkspacesResponse extends ToolResponse {
output: {
workspaces: GongWorkspace[]
}
}
/** List Flows */
export interface GongListFlowsParams extends GongBaseParams {
flowOwnerEmail: string
workspaceId?: string
cursor?: string
}
interface GongFlow {
id: string
name: string | null
folderId: string | null
folderName: string | null
visibility: string | null
creationDate: string | null
exclusive: boolean | null
}
export interface GongListFlowsResponse extends ToolResponse {
output: {
requestId: string | null
flows: GongFlow[]
totalRecords: number | null
currentPageSize: number | null
currentPageNumber: number | null
cursor: string | null
}
}
/** Get Coaching */
export interface GongGetCoachingParams extends GongBaseParams {
managerId: string
workspaceId: string
fromDate: string
toDate: string
}
export interface GongCoachingUser {
id: string | null
emailAddress: string | null
firstName: string | null
lastName: string | null
title: string | null
}
export interface GongCoachingRepData {
report: GongCoachingUser | null
metrics: Record<string, string[]> | null
}
export interface GongCoachingMetricsData {
manager: GongCoachingUser | null
directReportsMetrics: GongCoachingRepData[]
}
export interface GongGetCoachingResponse extends ToolResponse {
output: {
requestId: string | null
coachingData: GongCoachingMetricsData[]
}
}
/** Shared data-privacy sub-types */
interface GongCallReference {
id: string
status: string
externalSystems: {
system: string
objects: {
objectType: string
externalId: string
}[]
}[]
}
interface GongEmailMessage {
id: string
from: string
sentTime: string
mailbox: string
messageHash: string
}
interface GongMeeting {
id: string
}
interface GongCustomerDataObject {
id: string
objectType: string
externalId: string
mirrorId: string
fields: { name: string; value: unknown }[]
}
interface GongCustomerData {
system: string
objects: GongCustomerDataObject[]
}
interface GongCustomerEngagement {
eventType: string
eventName: string
timestamp: string
contentId: string
contentUrl: string
reportingSystem: string
sourceEventId: string
}
/** Lookup Email */
export interface GongLookupEmailParams extends GongBaseParams {
emailAddress: string
}
export interface GongLookupEmailResponse extends ToolResponse {
output: {
requestId: string
calls: GongCallReference[]
emails: GongEmailMessage[]
meetings: GongMeeting[]
customerData: GongCustomerData[]
customerEngagement: GongCustomerEngagement[]
}
}
/** Lookup Phone */
export interface GongLookupPhoneParams extends GongBaseParams {
phoneNumber: string
}
export interface GongLookupPhoneResponse extends ToolResponse {
output: {
requestId: string
suppliedPhoneNumber: string
matchingPhoneNumbers: string[]
emailAddresses: string[]
calls: GongCallReference[]
emails: GongEmailMessage[]
meetings: GongMeeting[]
customerData: GongCustomerData[]
}
}
/** Purge Email Address */
export interface GongPurgeEmailAddressParams extends GongBaseParams {
emailAddress: string
}
export interface GongPurgeEmailAddressResponse extends ToolResponse {
output: {
requestId: string | null
}
}
/** Purge Phone Number */
export interface GongPurgePhoneNumberParams extends GongBaseParams {
phoneNumber: string
}
export interface GongPurgePhoneNumberResponse extends ToolResponse {
output: {
requestId: string | null
}
}
/** Shared Engage Flow prospect assignment sub-types */
interface GongAssignedFlow {
flowId: string
flowName: string
crmProspectId: string
flowInstanceId: string
flowInstanceOwnerEmail: string
flowInstanceOwnerFullName: string
flowInstanceCreateDate: string
flowInstanceStatus: string
workspaceId: string
exclusive: boolean
}
interface GongAssignedFlowFailure {
flowId: string
crmProspectId: string
errorCode: string
errorMessage: string
}
/** Assign Flow Prospects */
export interface GongAssignFlowProspectsParams extends GongBaseParams {
flowId: string
crmProspectsIds: string
flowInstanceOwnerEmail: string
}
export interface GongAssignFlowProspectsResponse extends ToolResponse {
output: {
requestId: string | null
prospectsAssigned: GongAssignedFlow[]
prospectsNotAssigned: GongAssignedFlowFailure[]
}
}
/** Get Prospect Flows */
export interface GongGetProspectFlowsParams extends GongBaseParams {
crmProspectsIds: string
}
export interface GongGetProspectFlowsResponse extends ToolResponse {
output: {
requestId: string | null
prospectsAssigned: GongAssignedFlow[]
}
}
/** Union type for all Gong responses */
export type GongResponse =
| GongListCallsResponse
| GongCreateCallResponse
| GongGetCallResponse
| GongGetCallTranscriptResponse
| GongGetExtensiveCallsResponse
| GongListUsersResponse
| GongGetUserResponse
| GongAggregateActivityResponse
| GongDayByDayActivityResponse
| GongAggregateByPeriodResponse
| GongInteractionStatsResponse
| GongAnsweredScorecardsResponse
| GongListLibraryFoldersResponse
| GongGetFolderContentResponse
| GongListScorecardsResponse
| GongListTrackersResponse
| GongListWorkspacesResponse
| GongListFlowsResponse
| GongGetCoachingResponse
| GongLookupEmailResponse
| GongLookupPhoneResponse
| GongPurgeEmailAddressResponse
| GongPurgePhoneNumberResponse
| GongAssignFlowProspectsResponse
| GongGetProspectFlowsResponse
+68
View File
@@ -0,0 +1,68 @@
/**
* Extract a useful Gong API error message from documented error payloads.
*/
export function getGongErrorMessage(data: unknown, fallback: string): string {
if (!data || typeof data !== 'object') {
return fallback
}
const payload = data as Record<string, unknown>
const firstError = Array.isArray(payload.errors) ? payload.errors[0] : undefined
if (typeof firstError === 'string' && firstError.trim()) {
return firstError
}
if (firstError && typeof firstError === 'object') {
const message = (firstError as Record<string, unknown>).message
if (typeof message === 'string' && message.trim()) {
return message
}
}
if (typeof payload.message === 'string' && payload.message.trim()) {
return payload.message
}
return fallback
}
/**
* Normalize comma-separated Gong IDs from block text inputs.
*/
export function parseGongIdList(value?: string): string[] | undefined {
if (!value) {
return undefined
}
const ids = value
.split(',')
.map((id) => id.trim())
.filter(Boolean)
return ids.length > 0 ? ids : undefined
}
/**
* Parse a JSON object or array field that may already be resolved to structured data.
*/
export function parseGongJsonField<T>(value: unknown, fieldName: string): T {
if (typeof value === 'string') {
try {
return JSON.parse(value) as T
} catch {
throw new Error(`${fieldName} must be valid JSON`)
}
}
return value as T
}
/**
* Parse and validate a JSON array field.
*/
export function parseGongJsonArray(value: unknown, fieldName: string): unknown[] {
const parsed = parseGongJsonField<unknown>(value, fieldName)
if (!Array.isArray(parsed)) {
throw new Error(`${fieldName} must be a JSON array`)
}
return parsed
}