chore: import upstream snapshot with attribution
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
+221
View File
@@ -0,0 +1,221 @@
import type { ToolConfig } from '@/tools/types'
import type { ZoomCreateMeetingParams, ZoomCreateMeetingResponse } from '@/tools/zoom/types'
import { MEETING_OUTPUT_PROPERTIES } from '@/tools/zoom/types'
export const zoomCreateMeetingTool: ToolConfig<ZoomCreateMeetingParams, ZoomCreateMeetingResponse> =
{
id: 'zoom_create_meeting',
name: 'Zoom Create Meeting',
description: 'Create a new Zoom meeting',
version: '1.0.0',
oauth: {
required: true,
provider: 'zoom',
requiredScopes: ['meeting:write:meeting'],
},
params: {
userId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'The user ID or email address (e.g., "me", "user@example.com", or "AbcDefGHi"). Use "me" for the authenticated user.',
},
topic: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Meeting topic (e.g., "Weekly Team Standup" or "Project Review")',
},
type: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description:
'Meeting type: 1=instant, 2=scheduled, 3=recurring no fixed time, 8=recurring fixed time',
},
startTime: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Meeting start time in ISO 8601 format (e.g., 2025-06-03T10:00:00Z)',
},
duration: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Meeting duration in minutes (e.g., 30, 60, 90)',
},
timezone: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Timezone for the meeting (e.g., America/Los_Angeles)',
},
password: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Meeting password',
},
agenda: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Meeting agenda or description text',
},
hostVideo: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Start with host video on',
},
participantVideo: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Start with participant video on',
},
joinBeforeHost: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Allow participants to join before host',
},
muteUponEntry: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Mute participants upon entry',
},
waitingRoom: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Enable waiting room',
},
autoRecording: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Auto recording setting: local, cloud, or none',
},
},
request: {
url: (params) => `https://api.zoom.us/v2/users/${encodeURIComponent(params.userId)}/meetings`,
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Missing access token for Zoom API request')
}
return {
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}
},
body: (params) => {
if (!params.topic || !params.topic.trim()) {
throw new Error('Topic is required to create a Zoom meeting')
}
const body: Record<string, any> = {
topic: params.topic,
type: params.type || 2, // Default to scheduled meeting
}
if (params.startTime) {
body.start_time = params.startTime
}
if (params.duration != null) {
body.duration = params.duration
}
if (params.timezone) {
body.timezone = params.timezone
}
if (params.password) {
body.password = params.password
}
if (params.agenda) {
body.agenda = params.agenda
}
// Build settings object
const settings: Record<string, any> = {}
if (params.hostVideo != null) {
settings.host_video = params.hostVideo
}
if (params.participantVideo != null) {
settings.participant_video = params.participantVideo
}
if (params.joinBeforeHost != null) {
settings.join_before_host = params.joinBeforeHost
}
if (params.muteUponEntry != null) {
settings.mute_upon_entry = params.muteUponEntry
}
if (params.waitingRoom != null) {
settings.waiting_room = params.waitingRoom
}
if (params.autoRecording) {
settings.auto_recording = params.autoRecording
}
if (Object.keys(settings).length > 0) {
body.settings = settings
}
return body
},
},
transformResponse: async (response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
error: errorData.message || `Zoom API error: ${response.status} ${response.statusText}`,
output: { meeting: {} as any },
}
}
const data = await response.json()
return {
success: true,
output: {
meeting: {
id: data.id,
uuid: data.uuid,
host_id: data.host_id,
host_email: data.host_email,
topic: data.topic,
type: data.type,
status: data.status,
start_time: data.start_time,
duration: data.duration,
timezone: data.timezone,
agenda: data.agenda,
created_at: data.created_at,
start_url: data.start_url,
join_url: data.join_url,
password: data.password,
h323_password: data.h323_password,
pstn_password: data.pstn_password,
encrypted_password: data.encrypted_password,
settings: data.settings,
},
},
}
},
outputs: {
meeting: {
type: 'object',
description: 'The created meeting with all its properties',
properties: MEETING_OUTPUT_PROPERTIES,
},
},
}
+99
View File
@@ -0,0 +1,99 @@
import type { ToolConfig } from '@/tools/types'
import type { ZoomDeleteMeetingParams, ZoomDeleteMeetingResponse } from '@/tools/zoom/types'
export const zoomDeleteMeetingTool: ToolConfig<ZoomDeleteMeetingParams, ZoomDeleteMeetingResponse> =
{
id: 'zoom_delete_meeting',
name: 'Zoom Delete Meeting',
description: 'Delete or cancel a Zoom meeting',
version: '1.0.0',
oauth: {
required: true,
provider: 'zoom',
requiredScopes: ['meeting:delete:meeting'],
},
params: {
meetingId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The meeting ID to delete (e.g., "1234567890" or "85746065432")',
},
occurrenceId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Occurrence ID for deleting a specific occurrence of a recurring meeting',
},
scheduleForReminder: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Send cancellation reminder email to registrants',
},
cancelMeetingReminder: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Send cancellation email to registrants and alternative hosts',
},
},
request: {
url: (params) => {
const baseUrl = `https://api.zoom.us/v2/meetings/${encodeURIComponent(params.meetingId)}`
const queryParams = new URLSearchParams()
if (params.occurrenceId) {
queryParams.append('occurrence_id', params.occurrenceId)
}
if (params.scheduleForReminder != null) {
queryParams.append('schedule_for_reminder', String(params.scheduleForReminder))
}
if (params.cancelMeetingReminder != null) {
queryParams.append('cancel_meeting_reminder', String(params.cancelMeetingReminder))
}
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'DELETE',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Missing access token for Zoom API request')
}
return {
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}
},
},
transformResponse: async (response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
error: errorData.message || `Zoom API error: ${response.status} ${response.statusText}`,
output: { success: false },
}
}
// Zoom returns 204 No Content on successful deletion
return {
success: true,
output: {
success: true,
},
}
},
outputs: {
success: {
type: 'boolean',
description: 'Whether the meeting was deleted successfully',
},
},
}
+94
View File
@@ -0,0 +1,94 @@
import type { ToolConfig } from '@/tools/types'
import type { ZoomDeleteRecordingParams, ZoomDeleteRecordingResponse } from '@/tools/zoom/types'
export const zoomDeleteRecordingTool: ToolConfig<
ZoomDeleteRecordingParams,
ZoomDeleteRecordingResponse
> = {
id: 'zoom_delete_recording',
name: 'Zoom Delete Recording',
description: 'Delete cloud recordings for a Zoom meeting',
version: '1.0.0',
oauth: {
required: true,
provider: 'zoom',
requiredScopes: ['cloud_recording:delete:recording_file'],
},
params: {
meetingId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'The meeting ID or meeting UUID (e.g., "1234567890" or "4444AAABBBccccc12345==")',
},
recordingId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Specific recording file ID to delete. If not provided, deletes all recordings.',
},
action: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Delete action: "trash" (move to trash) or "delete" (permanently delete)',
},
},
request: {
url: (params) => {
let baseUrl = `https://api.zoom.us/v2/meetings/${encodeURIComponent(params.meetingId)}/recordings`
if (params.recordingId) {
baseUrl += `/${encodeURIComponent(params.recordingId)}`
}
const queryParams = new URLSearchParams()
if (params.action) {
queryParams.append('action', params.action)
}
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'DELETE',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Missing access token for Zoom API request')
}
return {
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}
},
},
transformResponse: async (response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
error: errorData.message || `Zoom API error: ${response.status} ${response.statusText}`,
output: { success: false },
}
}
// Zoom returns 204 No Content on successful deletion
return {
success: true,
output: {
success: true,
},
}
},
outputs: {
success: {
type: 'boolean',
description: 'Whether the recording was deleted successfully',
},
},
}
+114
View File
@@ -0,0 +1,114 @@
import type { ToolConfig } from '@/tools/types'
import type { ZoomGetMeetingParams, ZoomGetMeetingResponse } from '@/tools/zoom/types'
import { MEETING_OUTPUT_PROPERTIES } from '@/tools/zoom/types'
export const zoomGetMeetingTool: ToolConfig<ZoomGetMeetingParams, ZoomGetMeetingResponse> = {
id: 'zoom_get_meeting',
name: 'Zoom Get Meeting',
description: 'Get details of a specific Zoom meeting',
version: '1.0.0',
oauth: {
required: true,
provider: 'zoom',
requiredScopes: ['meeting:read:meeting'],
},
params: {
meetingId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The meeting ID (e.g., "1234567890" or "85746065432")',
},
occurrenceId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Occurrence ID for recurring meetings',
},
showPreviousOccurrences: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Show previous occurrences for recurring meetings',
},
},
request: {
url: (params) => {
const baseUrl = `https://api.zoom.us/v2/meetings/${encodeURIComponent(params.meetingId)}`
const queryParams = new URLSearchParams()
if (params.occurrenceId) {
queryParams.append('occurrence_id', params.occurrenceId)
}
if (params.showPreviousOccurrences != null) {
queryParams.append('show_previous_occurrences', String(params.showPreviousOccurrences))
}
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Missing access token for Zoom API request')
}
return {
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}
},
},
transformResponse: async (response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
error: errorData.message || `Zoom API error: ${response.status} ${response.statusText}`,
output: { meeting: {} as any },
}
}
const data = await response.json()
return {
success: true,
output: {
meeting: {
id: data.id,
uuid: data.uuid,
host_id: data.host_id,
host_email: data.host_email,
topic: data.topic,
type: data.type,
status: data.status,
start_time: data.start_time,
duration: data.duration,
timezone: data.timezone,
agenda: data.agenda,
created_at: data.created_at,
start_url: data.start_url,
join_url: data.join_url,
password: data.password,
h323_password: data.h323_password,
pstn_password: data.pstn_password,
encrypted_password: data.encrypted_password,
settings: data.settings,
recurrence: data.recurrence,
occurrences: data.occurrences,
},
},
}
},
outputs: {
meeting: {
type: 'object',
description: 'The meeting details',
properties: MEETING_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,72 @@
import type { ToolConfig } from '@/tools/types'
import type {
ZoomGetMeetingInvitationParams,
ZoomGetMeetingInvitationResponse,
} from '@/tools/zoom/types'
export const zoomGetMeetingInvitationTool: ToolConfig<
ZoomGetMeetingInvitationParams,
ZoomGetMeetingInvitationResponse
> = {
id: 'zoom_get_meeting_invitation',
name: 'Zoom Get Meeting Invitation',
description: 'Get the meeting invitation text for a Zoom meeting',
version: '1.0.0',
oauth: {
required: true,
provider: 'zoom',
requiredScopes: ['meeting:read:invitation'],
},
params: {
meetingId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The meeting ID (e.g., "1234567890" or "85746065432")',
},
},
request: {
url: (params) =>
`https://api.zoom.us/v2/meetings/${encodeURIComponent(params.meetingId)}/invitation`,
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Missing access token for Zoom API request')
}
return {
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}
},
},
transformResponse: async (response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
error: errorData.message || `Zoom API error: ${response.status} ${response.statusText}`,
output: { invitation: '' },
}
}
const data = await response.json()
return {
success: true,
output: {
invitation: data.invitation || '',
},
}
},
outputs: {
invitation: {
type: 'string',
description: 'The meeting invitation text',
},
},
}
@@ -0,0 +1,78 @@
import type { ToolConfig } from '@/tools/types'
import type {
ZoomGetMeetingRecordingsParams,
ZoomGetMeetingRecordingsResponse,
} from '@/tools/zoom/types'
import { RECORDING_OUTPUT_PROPERTIES } from '@/tools/zoom/types'
export const zoomGetMeetingRecordingsTool: ToolConfig<
ZoomGetMeetingRecordingsParams,
ZoomGetMeetingRecordingsResponse
> = {
id: 'zoom_get_meeting_recordings',
name: 'Zoom Get Meeting Recordings',
description: 'Get all recordings for a specific Zoom meeting',
version: '1.0.0',
oauth: {
required: true,
provider: 'zoom',
requiredScopes: ['cloud_recording:read:list_recording_files'],
},
params: {
meetingId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'The meeting ID or meeting UUID (e.g., "1234567890" or "4444AAABBBccccc12345==")',
},
includeFolderItems: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Include items within a folder',
},
ttl: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Time to live for download URLs in seconds (max 604800)',
},
downloadFiles: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Download recording files into file outputs',
},
},
request: {
url: '/api/tools/zoom/get-recordings',
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params) => ({
accessToken: params.accessToken,
meetingId: params.meetingId,
includeFolderItems: params.includeFolderItems,
ttl: params.ttl,
downloadFiles: params.downloadFiles,
}),
},
outputs: {
recording: {
type: 'object',
description: 'The meeting recording with all files',
properties: RECORDING_OUTPUT_PROPERTIES,
},
files: {
type: 'file[]',
description: 'Downloaded recording files',
optional: true,
},
},
}
+11
View File
@@ -0,0 +1,11 @@
// Zoom tools exports
export { zoomCreateMeetingTool } from './create_meeting'
export { zoomDeleteMeetingTool } from './delete_meeting'
export { zoomDeleteRecordingTool } from './delete_recording'
export { zoomGetMeetingTool } from './get_meeting'
export { zoomGetMeetingInvitationTool } from './get_meeting_invitation'
export { zoomGetMeetingRecordingsTool } from './get_meeting_recordings'
export { zoomListMeetingsTool } from './list_meetings'
export { zoomListPastParticipantsTool } from './list_past_participants'
export { zoomListRecordingsTool } from './list_recordings'
export { zoomUpdateMeetingTool } from './update_meeting'
+141
View File
@@ -0,0 +1,141 @@
import type { ToolConfig } from '@/tools/types'
import type { ZoomListMeetingsParams, ZoomListMeetingsResponse } from '@/tools/zoom/types'
import {
MEETING_LIST_ITEM_OUTPUT_PROPERTIES,
MEETING_PAGE_INFO_OUTPUT_PROPERTIES,
} from '@/tools/zoom/types'
export const zoomListMeetingsTool: ToolConfig<ZoomListMeetingsParams, ZoomListMeetingsResponse> = {
id: 'zoom_list_meetings',
name: 'Zoom List Meetings',
description: 'List all meetings for a Zoom user',
version: '1.0.0',
oauth: {
required: true,
provider: 'zoom',
requiredScopes: ['meeting:read:list_meetings'],
},
params: {
userId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'The user ID or email address (e.g., "me", "user@example.com", or "AbcDefGHi"). Use "me" for the authenticated user.',
},
type: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Meeting type filter: scheduled, live, upcoming, upcoming_meetings, or previous_meetings',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of records per page, 1-300 (e.g., 30, 50, 100)',
},
nextPageToken: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Token for pagination to get next page of results',
},
},
request: {
url: (params) => {
const baseUrl = `https://api.zoom.us/v2/users/${encodeURIComponent(params.userId)}/meetings`
const queryParams = new URLSearchParams()
if (params.type) {
queryParams.append('type', params.type)
}
if (params.pageSize) {
queryParams.append('page_size', String(params.pageSize))
}
if (params.nextPageToken) {
queryParams.append('next_page_token', params.nextPageToken)
}
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Missing access token for Zoom API request')
}
return {
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}
},
},
transformResponse: async (response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
error: errorData.message || `Zoom API error: ${response.status} ${response.statusText}`,
output: {
meetings: [],
pageInfo: {
pageCount: 0,
pageNumber: 0,
pageSize: 0,
totalRecords: 0,
},
},
}
}
const data = await response.json()
return {
success: true,
output: {
meetings: (data.meetings || []).map((meeting: any) => ({
id: meeting.id,
uuid: meeting.uuid,
host_id: meeting.host_id,
topic: meeting.topic,
type: meeting.type,
start_time: meeting.start_time,
duration: meeting.duration,
timezone: meeting.timezone,
agenda: meeting.agenda,
created_at: meeting.created_at,
join_url: meeting.join_url,
})),
pageInfo: {
pageCount: data.page_count || 0,
pageNumber: data.page_number || 0,
pageSize: data.page_size || 0,
totalRecords: data.total_records || 0,
nextPageToken: data.next_page_token,
},
},
}
},
outputs: {
meetings: {
type: 'array',
description: 'List of meetings',
items: {
type: 'object',
properties: MEETING_LIST_ITEM_OUTPUT_PROPERTIES,
},
},
pageInfo: {
type: 'object',
description: 'Pagination information',
properties: MEETING_PAGE_INFO_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,131 @@
import type { ToolConfig } from '@/tools/types'
import type {
ZoomListPastParticipantsParams,
ZoomListPastParticipantsResponse,
} from '@/tools/zoom/types'
import {
PARTICIPANT_OUTPUT_PROPERTIES,
PARTICIPANT_PAGE_INFO_OUTPUT_PROPERTIES,
} from '@/tools/zoom/types'
export const zoomListPastParticipantsTool: ToolConfig<
ZoomListPastParticipantsParams,
ZoomListPastParticipantsResponse
> = {
id: 'zoom_list_past_participants',
name: 'Zoom List Past Participants',
description: 'List participants from a past Zoom meeting',
version: '1.0.0',
oauth: {
required: true,
provider: 'zoom',
requiredScopes: ['meeting:read:list_past_participants'],
},
params: {
meetingId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The past meeting ID or UUID (e.g., "1234567890" or "4444AAABBBccccc12345==")',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of records per page, 1-300 (e.g., 30, 50, 100)',
},
nextPageToken: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Token for pagination to get next page of results',
},
},
request: {
url: (params) => {
const baseUrl = `https://api.zoom.us/v2/past_meetings/${encodeURIComponent(params.meetingId)}/participants`
const queryParams = new URLSearchParams()
if (params.pageSize) {
queryParams.append('page_size', String(params.pageSize))
}
if (params.nextPageToken) {
queryParams.append('next_page_token', params.nextPageToken)
}
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Missing access token for Zoom API request')
}
return {
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}
},
},
transformResponse: async (response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
error: errorData.message || `Zoom API error: ${response.status} ${response.statusText}`,
output: {
participants: [],
pageInfo: {
pageSize: 0,
totalRecords: 0,
},
},
}
}
const data = await response.json()
return {
success: true,
output: {
participants: (data.participants || []).map((participant: any) => ({
id: participant.id,
user_id: participant.user_id,
name: participant.name,
user_email: participant.user_email,
join_time: participant.join_time,
leave_time: participant.leave_time,
duration: participant.duration,
attentiveness_score: participant.attentiveness_score,
failover: participant.failover,
status: participant.status,
})),
pageInfo: {
pageSize: data.page_size || 0,
totalRecords: data.total_records || 0,
nextPageToken: data.next_page_token,
},
},
}
},
outputs: {
participants: {
type: 'array',
description: 'List of meeting participants',
items: {
type: 'object',
properties: PARTICIPANT_OUTPUT_PROPERTIES,
},
},
pageInfo: {
type: 'object',
description: 'Pagination information',
properties: PARTICIPANT_PAGE_INFO_OUTPUT_PROPERTIES,
},
},
}
+162
View File
@@ -0,0 +1,162 @@
import type { ToolConfig } from '@/tools/types'
import type { ZoomListRecordingsParams, ZoomListRecordingsResponse } from '@/tools/zoom/types'
import {
RECORDING_OUTPUT_PROPERTIES,
RECORDING_PAGE_INFO_OUTPUT_PROPERTIES,
} from '@/tools/zoom/types'
export const zoomListRecordingsTool: ToolConfig<
ZoomListRecordingsParams,
ZoomListRecordingsResponse
> = {
id: 'zoom_list_recordings',
name: 'Zoom List Recordings',
description: 'List all cloud recordings for a Zoom user',
version: '1.0.0',
oauth: {
required: true,
provider: 'zoom',
requiredScopes: ['cloud_recording:read:list_user_recordings'],
},
params: {
userId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'The user ID or email address (e.g., "me", "user@example.com", or "AbcDefGHi"). Use "me" for the authenticated user.',
},
from: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Start date in yyyy-mm-dd format (within last 6 months)',
},
to: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'End date in yyyy-mm-dd format',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of records per page, 1-300 (e.g., 30, 50, 100)',
},
nextPageToken: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Token for pagination to get next page of results',
},
trash: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Set to true to list recordings from trash',
},
},
request: {
url: (params) => {
const baseUrl = `https://api.zoom.us/v2/users/${encodeURIComponent(params.userId)}/recordings`
const queryParams = new URLSearchParams()
if (params.from) {
queryParams.append('from', params.from)
}
if (params.to) {
queryParams.append('to', params.to)
}
if (params.pageSize) {
queryParams.append('page_size', String(params.pageSize))
}
if (params.nextPageToken) {
queryParams.append('next_page_token', params.nextPageToken)
}
if (params.trash) {
queryParams.append('trash', 'true')
}
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Missing access token for Zoom API request')
}
return {
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}
},
},
transformResponse: async (response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
error: errorData.message || `Zoom API error: ${response.status} ${response.statusText}`,
output: {
recordings: [],
pageInfo: {
from: '',
to: '',
pageSize: 0,
totalRecords: 0,
},
},
}
}
const data = await response.json()
return {
success: true,
output: {
recordings: (data.meetings || []).map((recording: any) => ({
uuid: recording.uuid,
id: recording.id,
account_id: recording.account_id,
host_id: recording.host_id,
topic: recording.topic,
type: recording.type,
start_time: recording.start_time,
duration: recording.duration,
total_size: recording.total_size,
recording_count: recording.recording_count,
share_url: recording.share_url,
recording_files: recording.recording_files || [],
})),
pageInfo: {
from: data.from || '',
to: data.to || '',
pageSize: data.page_size || 0,
totalRecords: data.total_records || 0,
nextPageToken: data.next_page_token,
},
},
}
},
outputs: {
recordings: {
type: 'array',
description: 'List of recordings',
items: {
type: 'object',
properties: RECORDING_OUTPUT_PROPERTIES,
},
},
pageInfo: {
type: 'object',
description: 'Pagination information',
properties: RECORDING_PAGE_INFO_OUTPUT_PROPERTIES,
},
},
}
+625
View File
@@ -0,0 +1,625 @@
// Common types for Zoom tools
import type { OutputProperty, ToolFileData, ToolResponse } from '@/tools/types'
/**
* Shared output property definitions for Zoom API responses.
* These are reusable across all Zoom tools to ensure consistency.
* Based on the official Zoom API documentation.
*/
/**
* Output definition for meeting settings objects
* @see https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/meetingCreate
*/
export const MEETING_SETTINGS_OUTPUT_PROPERTIES = {
host_video: { type: 'boolean', description: 'Start with host video on' },
participant_video: { type: 'boolean', description: 'Start with participant video on' },
join_before_host: { type: 'boolean', description: 'Allow participants to join before host' },
mute_upon_entry: { type: 'boolean', description: 'Mute participants upon entry' },
watermark: { type: 'boolean', description: 'Add watermark when viewing shared screen' },
audio: { type: 'string', description: 'Audio options: both, telephony, or voip' },
auto_recording: { type: 'string', description: 'Auto recording: local, cloud, or none' },
waiting_room: { type: 'boolean', description: 'Enable waiting room' },
meeting_authentication: { type: 'boolean', description: 'Require meeting authentication' },
approval_type: { type: 'number', description: 'Approval type: 0=auto, 1=manual, 2=none' },
} as const satisfies Record<string, OutputProperty>
/**
* Complete meeting settings object output definition
*/
export const MEETING_SETTINGS_OUTPUT: OutputProperty = {
type: 'object',
description: 'Meeting settings',
properties: MEETING_SETTINGS_OUTPUT_PROPERTIES,
}
/**
* Output definition for recurrence objects in recurring meetings
* @see https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/meetingCreate
*/
export const RECURRENCE_OUTPUT_PROPERTIES = {
type: { type: 'number', description: 'Recurrence type: 1=daily, 2=weekly, 3=monthly' },
repeat_interval: { type: 'number', description: 'Interval between recurring meetings' },
weekly_days: {
type: 'string',
description: 'Days of week for weekly recurrence (1-7, comma-separated)',
},
monthly_day: { type: 'number', description: 'Day of month for monthly recurrence' },
monthly_week: { type: 'number', description: 'Week of month for monthly recurrence' },
monthly_week_day: { type: 'number', description: 'Day of week for monthly recurrence' },
end_times: { type: 'number', description: 'Number of occurrences' },
end_date_time: { type: 'string', description: 'End date time in ISO 8601 format' },
} as const satisfies Record<string, OutputProperty>
/**
* Complete recurrence object output definition
*/
export const RECURRENCE_OUTPUT: OutputProperty = {
type: 'object',
description: 'Recurrence settings for recurring meetings',
properties: RECURRENCE_OUTPUT_PROPERTIES,
}
/**
* Output definition for occurrence objects in recurring meetings
* @see https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/meeting
*/
export const OCCURRENCE_OUTPUT_PROPERTIES = {
occurrence_id: { type: 'string', description: 'Occurrence ID' },
start_time: { type: 'string', description: 'Start time in ISO 8601 format' },
duration: { type: 'number', description: 'Duration in minutes' },
status: { type: 'string', description: 'Occurrence status' },
} as const satisfies Record<string, OutputProperty>
/**
* Complete occurrences array output definition
*/
export const OCCURRENCES_OUTPUT: OutputProperty = {
type: 'array',
description: 'Meeting occurrences for recurring meetings',
items: {
type: 'object',
properties: OCCURRENCE_OUTPUT_PROPERTIES,
},
}
/**
* Common meeting output properties shared across meeting tools
* @see https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/meetingCreate
* @see https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/meeting
*/
export const MEETING_OUTPUT_PROPERTIES = {
id: { type: 'number', description: 'Meeting ID' },
uuid: { type: 'string', description: 'Meeting UUID' },
host_id: { type: 'string', description: 'Host user ID' },
host_email: { type: 'string', description: 'Host email address' },
topic: { type: 'string', description: 'Meeting topic' },
type: {
type: 'number',
description:
'Meeting type: 1=instant, 2=scheduled, 3=recurring no fixed time, 8=recurring fixed time',
},
status: { type: 'string', description: 'Meeting status (e.g., waiting, started)' },
start_time: { type: 'string', description: 'Start time in ISO 8601 format' },
duration: { type: 'number', description: 'Duration in minutes' },
timezone: { type: 'string', description: 'Timezone (e.g., America/Los_Angeles)' },
agenda: { type: 'string', description: 'Meeting agenda' },
created_at: { type: 'string', description: 'Creation timestamp in ISO 8601 format' },
start_url: { type: 'string', description: 'URL for host to start the meeting' },
join_url: { type: 'string', description: 'URL for participants to join the meeting' },
password: { type: 'string', description: 'Meeting password' },
h323_password: { type: 'string', description: 'H.323/SIP room system password' },
pstn_password: { type: 'string', description: 'PSTN password for phone dial-in' },
encrypted_password: { type: 'string', description: 'Encrypted password for joining' },
settings: MEETING_SETTINGS_OUTPUT,
recurrence: RECURRENCE_OUTPUT,
occurrences: OCCURRENCES_OUTPUT,
} as const satisfies Record<string, OutputProperty>
/**
* Output definition for meeting object (used in create/get meeting responses)
*/
export const MEETING_OUTPUT: OutputProperty = {
type: 'object',
description: 'Meeting object with all properties',
properties: MEETING_OUTPUT_PROPERTIES,
}
/**
* Meeting list item output properties (subset returned in list responses)
* @see https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/meetings
*/
export const MEETING_LIST_ITEM_OUTPUT_PROPERTIES = {
id: { type: 'number', description: 'Meeting ID' },
uuid: { type: 'string', description: 'Meeting UUID' },
host_id: { type: 'string', description: 'Host user ID' },
topic: { type: 'string', description: 'Meeting topic' },
type: { type: 'number', description: 'Meeting type' },
start_time: { type: 'string', description: 'Start time in ISO 8601 format' },
duration: { type: 'number', description: 'Duration in minutes' },
timezone: { type: 'string', description: 'Timezone' },
agenda: { type: 'string', description: 'Meeting agenda' },
created_at: { type: 'string', description: 'Creation timestamp' },
join_url: { type: 'string', description: 'URL for participants to join' },
} as const satisfies Record<string, OutputProperty>
/**
* Output definition for meetings array in list responses
*/
export const MEETINGS_ARRAY_OUTPUT: OutputProperty = {
type: 'array',
description: 'List of meetings',
items: {
type: 'object',
properties: MEETING_LIST_ITEM_OUTPUT_PROPERTIES,
},
}
/**
* Pagination output properties for meeting list endpoints
* @see https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/meetings
*/
export const MEETING_PAGE_INFO_OUTPUT_PROPERTIES = {
pageCount: { type: 'number', description: 'Total number of pages' },
pageNumber: { type: 'number', description: 'Current page number' },
pageSize: { type: 'number', description: 'Number of records per page' },
totalRecords: { type: 'number', description: 'Total number of records' },
nextPageToken: { type: 'string', description: 'Token for next page of results' },
} as const satisfies Record<string, OutputProperty>
/**
* Complete page info output definition for meeting lists
*/
export const MEETING_PAGE_INFO_OUTPUT: OutputProperty = {
type: 'object',
description: 'Pagination information',
properties: MEETING_PAGE_INFO_OUTPUT_PROPERTIES,
}
/**
* Output definition for recording file objects
* @see https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/recordingGet
*/
export const RECORDING_FILE_OUTPUT_PROPERTIES = {
id: { type: 'string', description: 'Recording file ID' },
meeting_id: { type: 'string', description: 'Meeting ID associated with the recording' },
recording_start: { type: 'string', description: 'Start time of the recording' },
recording_end: { type: 'string', description: 'End time of the recording' },
file_type: { type: 'string', description: 'Type of recording file (MP4, M4A, etc.)' },
file_extension: { type: 'string', description: 'File extension' },
file_size: { type: 'number', description: 'File size in bytes' },
play_url: { type: 'string', description: 'URL to play the recording' },
download_url: { type: 'string', description: 'URL to download the recording' },
status: { type: 'string', description: 'Recording status' },
recording_type: {
type: 'string',
description: 'Type of recording (shared_screen, audio_only, etc.)',
},
} as const satisfies Record<string, OutputProperty>
/**
* Complete recording files array output definition
*/
export const RECORDING_FILES_OUTPUT: OutputProperty = {
type: 'array',
description: 'List of recording files',
items: {
type: 'object',
properties: RECORDING_FILE_OUTPUT_PROPERTIES,
},
}
/**
* Output definition for recording objects
* @see https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/recordingGet
* @see https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/recordingsList
*/
export const RECORDING_OUTPUT_PROPERTIES = {
uuid: { type: 'string', description: 'Meeting UUID' },
id: { type: 'number', description: 'Meeting ID' },
account_id: { type: 'string', description: 'Account ID' },
host_id: { type: 'string', description: 'Host user ID' },
topic: { type: 'string', description: 'Meeting topic' },
type: { type: 'number', description: 'Meeting type' },
start_time: { type: 'string', description: 'Meeting start time' },
duration: { type: 'number', description: 'Meeting duration in minutes' },
total_size: { type: 'number', description: 'Total size of all recordings in bytes' },
recording_count: { type: 'number', description: 'Number of recording files' },
share_url: { type: 'string', description: 'URL to share recordings' },
recording_files: RECORDING_FILES_OUTPUT,
} as const satisfies Record<string, OutputProperty>
/**
* Complete recording object output definition
*/
export const RECORDING_OUTPUT: OutputProperty = {
type: 'object',
description: 'Recording object with all files',
properties: RECORDING_OUTPUT_PROPERTIES,
}
/**
* Output definition for recordings array in list responses
*/
export const RECORDINGS_ARRAY_OUTPUT: OutputProperty = {
type: 'array',
description: 'List of recordings',
items: {
type: 'object',
properties: RECORDING_OUTPUT_PROPERTIES,
},
}
/**
* Pagination output properties for recording list endpoints
* @see https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/recordingsList
*/
export const RECORDING_PAGE_INFO_OUTPUT_PROPERTIES = {
from: { type: 'string', description: 'Start date of query range' },
to: { type: 'string', description: 'End date of query range' },
pageSize: { type: 'number', description: 'Number of records per page' },
totalRecords: { type: 'number', description: 'Total number of records' },
nextPageToken: { type: 'string', description: 'Token for next page of results' },
} as const satisfies Record<string, OutputProperty>
/**
* Complete page info output definition for recording lists
*/
export const RECORDING_PAGE_INFO_OUTPUT: OutputProperty = {
type: 'object',
description: 'Pagination information',
properties: RECORDING_PAGE_INFO_OUTPUT_PROPERTIES,
}
/**
* Output definition for participant objects
* @see https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/pastMeetingParticipants
*/
export const PARTICIPANT_OUTPUT_PROPERTIES = {
id: { type: 'string', description: 'Participant unique identifier' },
user_id: { type: 'string', description: 'User ID if registered Zoom user' },
name: { type: 'string', description: 'Participant display name' },
user_email: { type: 'string', description: 'Participant email address' },
join_time: { type: 'string', description: 'Time when participant joined (ISO 8601)' },
leave_time: { type: 'string', description: 'Time when participant left (ISO 8601)' },
duration: { type: 'number', description: 'Duration in seconds participant was in meeting' },
attentiveness_score: { type: 'string', description: 'Attentiveness score (deprecated)' },
failover: {
type: 'boolean',
description: 'Whether participant failed over to another data center',
},
status: { type: 'string', description: 'Participant status' },
} as const satisfies Record<string, OutputProperty>
/**
* Complete participants array output definition
*/
export const PARTICIPANTS_ARRAY_OUTPUT: OutputProperty = {
type: 'array',
description: 'List of meeting participants',
items: {
type: 'object',
properties: PARTICIPANT_OUTPUT_PROPERTIES,
},
}
/**
* Pagination output properties for participant list endpoints
* @see https://developers.zoom.us/docs/api/rest/reference/zoom-api/methods/#operation/pastMeetingParticipants
*/
export const PARTICIPANT_PAGE_INFO_OUTPUT_PROPERTIES = {
pageSize: { type: 'number', description: 'Number of records per page' },
totalRecords: { type: 'number', description: 'Total number of records' },
nextPageToken: { type: 'string', description: 'Token for next page of results' },
} as const satisfies Record<string, OutputProperty>
/**
* Complete page info output definition for participant lists
*/
export const PARTICIPANT_PAGE_INFO_OUTPUT: OutputProperty = {
type: 'object',
description: 'Pagination information',
properties: PARTICIPANT_PAGE_INFO_OUTPUT_PROPERTIES,
}
// Common parameters for all Zoom tools
interface ZoomBaseParams {
accessToken: string
}
// Meeting types
export type ZoomMeetingType = 1 | 2 | 3 | 8 // 1=instant, 2=scheduled, 3=recurring no fixed time, 8=recurring fixed time
interface ZoomMeetingSettings {
host_video?: boolean
participant_video?: boolean
join_before_host?: boolean
mute_upon_entry?: boolean
watermark?: boolean
audio?: 'both' | 'telephony' | 'voip'
auto_recording?: 'local' | 'cloud' | 'none'
waiting_room?: boolean
meeting_authentication?: boolean
approval_type?: 0 | 1 | 2 // 0=auto, 1=manual, 2=none
}
interface ZoomMeeting {
id: number
uuid: string
host_id: string
host_email?: string
topic: string
type: ZoomMeetingType
status?: string
start_time?: string
duration?: number
timezone?: string
agenda?: string
created_at?: string
start_url?: string
join_url: string
password?: string
h323_password?: string
pstn_password?: string
encrypted_password?: string
settings?: ZoomMeetingSettings
recurrence?: {
type: number
repeat_interval?: number
weekly_days?: string
monthly_day?: number
monthly_week?: number
monthly_week_day?: number
end_times?: number
end_date_time?: string
}
occurrences?: Array<{
occurrence_id: string
start_time: string
duration: number
status: string
}>
}
interface ZoomMeetingListResponse {
page_count: number
page_number: number
page_size: number
total_records: number
next_page_token?: string
meetings: ZoomMeeting[]
}
// Create Meeting tool types
export interface ZoomCreateMeetingParams extends ZoomBaseParams {
userId: string
topic: string
type?: ZoomMeetingType
startTime?: string
duration?: number
timezone?: string
password?: string
agenda?: string
hostVideo?: boolean
participantVideo?: boolean
joinBeforeHost?: boolean
muteUponEntry?: boolean
waitingRoom?: boolean
autoRecording?: 'local' | 'cloud' | 'none'
}
export interface ZoomCreateMeetingResponse extends ToolResponse {
output: {
meeting: ZoomMeeting
}
}
// List Meetings tool types
export interface ZoomListMeetingsParams extends ZoomBaseParams {
userId: string
type?: 'scheduled' | 'live' | 'upcoming' | 'upcoming_meetings' | 'previous_meetings'
pageSize?: number
nextPageToken?: string
}
export interface ZoomListMeetingsResponse extends ToolResponse {
output: {
meetings: ZoomMeeting[]
pageInfo: {
pageCount: number
pageNumber: number
pageSize: number
totalRecords: number
nextPageToken?: string
}
}
}
// Get Meeting tool types
export interface ZoomGetMeetingParams extends ZoomBaseParams {
meetingId: string
occurrenceId?: string
showPreviousOccurrences?: boolean
}
export interface ZoomGetMeetingResponse extends ToolResponse {
output: {
meeting: ZoomMeeting
}
}
// Update Meeting tool types
export interface ZoomUpdateMeetingParams extends ZoomBaseParams {
meetingId: string
topic?: string
type?: ZoomMeetingType
startTime?: string
duration?: number
timezone?: string
password?: string
agenda?: string
hostVideo?: boolean
participantVideo?: boolean
joinBeforeHost?: boolean
muteUponEntry?: boolean
waitingRoom?: boolean
autoRecording?: 'local' | 'cloud' | 'none'
}
export interface ZoomUpdateMeetingResponse extends ToolResponse {
output: {
success: boolean
}
}
// Delete Meeting tool types
export interface ZoomDeleteMeetingParams extends ZoomBaseParams {
meetingId: string
occurrenceId?: string
scheduleForReminder?: boolean
cancelMeetingReminder?: boolean
}
export interface ZoomDeleteMeetingResponse extends ToolResponse {
output: {
success: boolean
}
}
// Get Meeting Invitation tool types
export interface ZoomGetMeetingInvitationParams extends ZoomBaseParams {
meetingId: string
}
export interface ZoomGetMeetingInvitationResponse extends ToolResponse {
output: {
invitation: string
}
}
// Recording types
interface ZoomRecordingFile {
id: string
meeting_id: string
recording_start: string
recording_end: string
file_type: string
file_extension: string
file_size: number
play_url?: string
download_url?: string
status: string
recording_type: string
}
interface ZoomRecording {
uuid: string
id: number
account_id: string
host_id: string
topic: string
type: number
start_time: string
duration: number
total_size: number
recording_count: number
share_url?: string
recording_files: ZoomRecordingFile[]
}
// List Recordings tool types
export interface ZoomListRecordingsParams extends ZoomBaseParams {
userId: string
from?: string
to?: string
pageSize?: number
nextPageToken?: string
trash?: boolean
trashType?: 'meeting_recordings' | 'recording_file'
}
export interface ZoomListRecordingsResponse extends ToolResponse {
output: {
recordings: ZoomRecording[]
pageInfo: {
from: string
to: string
pageSize: number
totalRecords: number
nextPageToken?: string
}
}
}
// Get Meeting Recordings tool types
export interface ZoomGetMeetingRecordingsParams extends ZoomBaseParams {
meetingId: string
includeFolderItems?: boolean
ttl?: number
downloadFiles?: boolean
}
export interface ZoomGetMeetingRecordingsResponse extends ToolResponse {
output: {
recording: ZoomRecording
files?: ToolFileData[]
}
}
// Delete Recording tool types
export interface ZoomDeleteRecordingParams extends ZoomBaseParams {
meetingId: string
recordingId?: string
action?: 'trash' | 'delete'
}
export interface ZoomDeleteRecordingResponse extends ToolResponse {
output: {
success: boolean
}
}
// Participant types
interface ZoomParticipant {
id: string
user_id?: string
name: string
user_email?: string
join_time: string
leave_time?: string
duration: number
attentiveness_score?: string
failover?: boolean
status?: string
}
// List Past Participants tool types
export interface ZoomListPastParticipantsParams extends ZoomBaseParams {
meetingId: string
pageSize?: number
nextPageToken?: string
}
export interface ZoomListPastParticipantsResponse extends ToolResponse {
output: {
participants: ZoomParticipant[]
pageInfo: {
pageSize: number
totalRecords: number
nextPageToken?: string
}
}
}
// Combined response type for block
export type ZoomResponse =
| ZoomCreateMeetingResponse
| ZoomListMeetingsResponse
| ZoomGetMeetingResponse
| ZoomUpdateMeetingResponse
| ZoomDeleteMeetingResponse
| ZoomGetMeetingInvitationResponse
| ZoomListRecordingsResponse
| ZoomGetMeetingRecordingsResponse
| ZoomDeleteRecordingResponse
| ZoomListPastParticipantsResponse
+196
View File
@@ -0,0 +1,196 @@
import type { ToolConfig } from '@/tools/types'
import type { ZoomUpdateMeetingParams, ZoomUpdateMeetingResponse } from '@/tools/zoom/types'
export const zoomUpdateMeetingTool: ToolConfig<ZoomUpdateMeetingParams, ZoomUpdateMeetingResponse> =
{
id: 'zoom_update_meeting',
name: 'Zoom Update Meeting',
description: 'Update an existing Zoom meeting',
version: '1.0.0',
oauth: {
required: true,
provider: 'zoom',
requiredScopes: ['meeting:update:meeting'],
},
params: {
meetingId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The meeting ID to update (e.g., "1234567890" or "85746065432")',
},
topic: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Meeting topic (e.g., "Weekly Team Standup" or "Project Review")',
},
type: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description:
'Meeting type: 1=instant, 2=scheduled, 3=recurring no fixed time, 8=recurring fixed time',
},
startTime: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Meeting start time in ISO 8601 format (e.g., 2025-06-03T10:00:00Z)',
},
duration: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Meeting duration in minutes (e.g., 30, 60, 90)',
},
timezone: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Timezone for the meeting (e.g., America/Los_Angeles)',
},
password: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Meeting password',
},
agenda: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Meeting agenda or description text',
},
hostVideo: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Start with host video on',
},
participantVideo: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Start with participant video on',
},
joinBeforeHost: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Allow participants to join before host',
},
muteUponEntry: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Mute participants upon entry',
},
waitingRoom: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Enable waiting room',
},
autoRecording: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Auto recording setting: local, cloud, or none',
},
},
request: {
url: (params) => `https://api.zoom.us/v2/meetings/${encodeURIComponent(params.meetingId)}`,
method: 'PATCH',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Missing access token for Zoom API request')
}
return {
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
}
},
body: (params) => {
const body: Record<string, any> = {}
if (params.topic) {
body.topic = params.topic
}
if (params.type != null) {
body.type = params.type
}
if (params.startTime) {
body.start_time = params.startTime
}
if (params.duration != null) {
body.duration = params.duration
}
if (params.timezone) {
body.timezone = params.timezone
}
if (params.password) {
body.password = params.password
}
if (params.agenda) {
body.agenda = params.agenda
}
// Build settings object
const settings: Record<string, any> = {}
if (params.hostVideo != null) {
settings.host_video = params.hostVideo
}
if (params.participantVideo != null) {
settings.participant_video = params.participantVideo
}
if (params.joinBeforeHost != null) {
settings.join_before_host = params.joinBeforeHost
}
if (params.muteUponEntry != null) {
settings.mute_upon_entry = params.muteUponEntry
}
if (params.waitingRoom != null) {
settings.waiting_room = params.waitingRoom
}
if (params.autoRecording) {
settings.auto_recording = params.autoRecording
}
if (Object.keys(settings).length > 0) {
body.settings = settings
}
return body
},
},
transformResponse: async (response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
error: errorData.message || `Zoom API error: ${response.status} ${response.statusText}`,
output: { success: false },
}
}
// Zoom returns 204 No Content on successful update
return {
success: true,
output: {
success: true,
},
}
},
outputs: {
success: {
type: 'boolean',
description: 'Whether the meeting was updated successfully',
},
},
}