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
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:
@@ -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,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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'
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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 },
|
||||
},
|
||||
}
|
||||
@@ -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",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user