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
@@ -0,0 +1,148 @@
import type {
FirefliesAddToLiveMeetingParams,
FirefliesAddToLiveMeetingResponse,
} from '@/tools/fireflies/types'
import type { ToolConfig } from '@/tools/types'
export const firefliesAddToLiveMeetingTool: ToolConfig<
FirefliesAddToLiveMeetingParams,
FirefliesAddToLiveMeetingResponse
> = {
id: 'fireflies_add_to_live_meeting',
name: 'Fireflies Add to Live Meeting',
description: 'Add the Fireflies.ai bot to an ongoing meeting to record and transcribe',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Fireflies API key',
},
meetingLink: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Valid meeting URL (Zoom, Google Meet, Microsoft Teams, etc.)',
},
title: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Title for the meeting (max 256 characters)',
},
meetingPassword: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Password for the meeting if required (max 32 characters)',
},
duration: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Meeting duration in minutes (15-120, default: 60)',
},
language: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Language code for transcription (e.g., "en", "es", "de")',
},
},
request: {
url: 'https://api.fireflies.ai/graphql',
method: 'POST',
headers: (params) => {
if (!params.apiKey) {
throw new Error('Missing API key for Fireflies API request')
}
return {
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}
},
body: (params) => {
if (!params.meetingLink || !params.meetingLink.startsWith('http')) {
throw new Error('Meeting link must be a valid HTTP/HTTPS URL')
}
const variables: Record<string, unknown> = {
meetingLink: params.meetingLink,
}
if (params.title) variables.title = params.title.substring(0, 256)
if (params.meetingPassword)
variables.meeting_password = params.meetingPassword.substring(0, 32)
if (params.duration) {
const duration = Math.min(Math.max(Number(params.duration), 15), 120)
variables.duration = duration
}
if (params.language) variables.language = params.language.substring(0, 5)
return {
query: `
mutation AddToLiveMeeting(
$meetingLink: String!
$title: String
$meeting_password: String
$duration: Int
$language: String
) {
addToLiveMeeting(
meeting_link: $meetingLink
title: $title
meeting_password: $meeting_password
duration: $duration
language: $language
) {
success
}
}
`,
variables,
}
},
},
transformResponse: async (response) => {
const data = await response.json()
if (data.errors) {
const error = data.errors[0]
const errorCode = error?.extensions?.code || ''
let errorMessage = error?.message || 'Failed to add bot to meeting'
if (errorCode === 'too_many_requests') {
errorMessage = 'Rate limit exceeded. This endpoint allows 3 requests per 20 minutes.'
} else if (errorCode === 'invalid_language_code') {
errorMessage = 'Invalid language code provided'
} else if (errorCode === 'unsupported_platform') {
errorMessage = 'Meeting platform is not supported'
}
return {
success: false,
error: errorMessage,
output: {},
}
}
const result = data.data?.addToLiveMeeting
return {
success: result?.success ?? false,
output: {
success: result?.success ?? false,
},
}
},
outputs: {
success: {
type: 'boolean',
description: 'Whether the bot was successfully added to the meeting',
},
},
}
+166
View File
@@ -0,0 +1,166 @@
import type {
FirefliesCreateBiteParams,
FirefliesCreateBiteResponse,
} from '@/tools/fireflies/types'
import type { ToolConfig } from '@/tools/types'
export const firefliesCreateBiteTool: ToolConfig<
FirefliesCreateBiteParams,
FirefliesCreateBiteResponse
> = {
id: 'fireflies_create_bite',
name: 'Fireflies Create Bite',
description: 'Create a soundbite/highlight from a specific time range in a transcript',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Fireflies API key',
},
transcriptId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'ID of the transcript to create the bite from (e.g., "abc123def456")',
},
startTime: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'Start time of the bite in seconds',
},
endTime: {
type: 'number',
required: true,
visibility: 'user-or-llm',
description: 'End time of the bite in seconds',
},
name: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Name for the bite (max 256 characters)',
},
mediaType: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Media type: "video" or "audio"',
},
summary: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Summary for the bite (max 500 characters)',
},
},
request: {
url: 'https://api.fireflies.ai/graphql',
method: 'POST',
headers: (params) => {
if (!params.apiKey) {
throw new Error('Missing API key for Fireflies API request')
}
return {
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}
},
body: (params) => {
if (!params.transcriptId) {
throw new Error('Transcript ID is required')
}
if (params.startTime === undefined || params.endTime === undefined) {
throw new Error('Start time and end time are required')
}
if (params.startTime >= params.endTime) {
throw new Error('Start time must be less than end time')
}
const variables: Record<string, unknown> = {
transcriptId: params.transcriptId,
startTime: Number(params.startTime),
endTime: Number(params.endTime),
}
if (params.name) variables.name = params.name.substring(0, 256)
if (params.mediaType) variables.media_type = params.mediaType
if (params.summary) variables.summary = params.summary.substring(0, 500)
return {
query: `
mutation CreateBite(
$transcriptId: ID!
$startTime: Float!
$endTime: Float!
$name: String
$media_type: String
$summary: String
) {
createBite(
transcript_id: $transcriptId
start_time: $startTime
end_time: $endTime
name: $name
media_type: $media_type
summary: $summary
) {
id
name
status
}
}
`,
variables,
}
},
},
transformResponse: async (response) => {
const data = await response.json()
if (data.errors) {
return {
success: false,
error: data.errors[0]?.message || 'Failed to create bite',
output: {},
}
}
const bite = data.data?.createBite
if (!bite) {
return {
success: false,
error: 'Failed to create bite',
output: {},
}
}
return {
success: true,
output: {
bite: {
id: bite.id,
name: bite.name,
status: bite.status,
},
},
}
},
outputs: {
bite: {
type: 'object',
description: 'Created bite details',
properties: {
id: { type: 'string', description: 'Bite ID' },
name: { type: 'string', description: 'Bite name' },
status: { type: 'string', description: 'Processing status' },
},
},
},
}
@@ -0,0 +1,123 @@
import type {
FirefliesDeleteTranscriptParams,
FirefliesDeleteTranscriptResponse,
} from '@/tools/fireflies/types'
import type { ToolConfig } from '@/tools/types'
export const firefliesDeleteTranscriptTool: ToolConfig<
FirefliesDeleteTranscriptParams,
FirefliesDeleteTranscriptResponse
> = {
id: 'fireflies_delete_transcript',
name: 'Fireflies Delete Transcript',
description: 'Delete a transcript from Fireflies.ai',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Fireflies API key',
},
transcriptId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The transcript ID to delete (e.g., "abc123def456")',
},
},
request: {
url: 'https://api.fireflies.ai/graphql',
method: 'POST',
headers: (params) => {
if (!params.apiKey) {
throw new Error('Missing API key for Fireflies API request')
}
return {
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}
},
body: (params) => {
if (!params.transcriptId) {
throw new Error('Transcript ID is required')
}
return {
query: `
mutation DeleteTranscript($id: String!) {
deleteTranscript(id: $id) {
id
title
date
duration
host_email
organizer_email
}
}
`,
variables: {
id: params.transcriptId,
},
}
},
},
transformResponse: async (response) => {
const data = await response.json()
if (data.errors) {
return {
success: false,
error: data.errors[0]?.message || 'Failed to delete transcript',
output: {},
}
}
const deleted = data.data?.deleteTranscript
if (!deleted) {
return {
success: false,
error: 'Failed to delete transcript',
output: { success: false },
}
}
return {
success: true,
output: {
success: true,
transcript: {
id: deleted.id,
title: deleted.title ?? null,
date: deleted.date ?? null,
duration: deleted.duration ?? null,
host_email: deleted.host_email ?? null,
organizer_email: deleted.organizer_email ?? null,
},
},
}
},
outputs: {
success: {
type: 'boolean',
description: 'Whether the transcript was successfully deleted',
},
transcript: {
type: 'object',
description: 'The deleted transcript',
optional: true,
properties: {
id: { type: 'string', description: 'Transcript ID' },
title: { type: 'string', description: 'Meeting title' },
date: { type: 'number', description: 'Meeting timestamp' },
duration: { type: 'number', description: 'Meeting duration' },
host_email: { type: 'string', description: 'Host email address' },
organizer_email: { type: 'string', description: 'Organizer email address' },
},
},
},
}
+205
View File
@@ -0,0 +1,205 @@
import type {
FirefliesGetTranscriptParams,
FirefliesGetTranscriptResponse,
} from '@/tools/fireflies/types'
import type { ToolConfig } from '@/tools/types'
export const firefliesGetTranscriptTool: ToolConfig<
FirefliesGetTranscriptParams,
FirefliesGetTranscriptResponse
> = {
id: 'fireflies_get_transcript',
name: 'Fireflies Get Transcript',
description:
'Get a single transcript with full details including summary, action items, and analytics',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Fireflies API key',
},
transcriptId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The transcript ID to retrieve (e.g., "abc123def456")',
},
},
request: {
url: 'https://api.fireflies.ai/graphql',
method: 'POST',
headers: (params) => {
if (!params.apiKey) {
throw new Error('Missing API key for Fireflies API request')
}
return {
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}
},
body: (params) => ({
query: `
query Transcript($id: String!) {
transcript(id: $id) {
id
title
date
dateString
duration
privacy
transcript_url
audio_url
video_url
meeting_link
host_email
organizer_email
participants
fireflies_users
speakers {
id
name
}
meeting_attendees {
displayName
email
phoneNumber
name
location
}
sentences {
index
speaker_name
speaker_id
text
raw_text
start_time
end_time
ai_filters {
task
pricing
metric
question
date_and_time
sentiment
}
}
summary {
keywords
action_items
outline
shorthand_bullet
overview
bullet_gist
gist
short_summary
short_overview
meeting_type
topics_discussed
}
analytics {
sentiments {
negative_pct
neutral_pct
positive_pct
}
categories {
questions
date_times
metrics
tasks
}
speakers {
speaker_id
name
duration
word_count
longest_monologue
monologues_count
filler_words
questions
duration_pct
words_per_minute
}
}
}
}
`,
variables: {
id: params.transcriptId,
},
}),
},
transformResponse: async (response) => {
const data = await response.json()
if (data.errors) {
return {
success: false,
error: data.errors[0]?.message || 'Failed to fetch transcript',
output: {},
}
}
const transcript = data.data?.transcript
if (!transcript) {
return {
success: false,
error: 'Transcript not found',
output: {},
}
}
return {
success: true,
output: {
transcript: {
id: transcript.id,
title: transcript.title,
date: transcript.date,
dateString: transcript.dateString,
duration: transcript.duration,
privacy: transcript.privacy,
transcript_url: transcript.transcript_url,
audio_url: transcript.audio_url,
video_url: transcript.video_url,
meeting_link: transcript.meeting_link,
host_email: transcript.host_email,
organizer_email: transcript.organizer_email,
participants: transcript.participants,
fireflies_users: transcript.fireflies_users,
speakers: transcript.speakers,
meeting_attendees: transcript.meeting_attendees,
sentences: transcript.sentences,
summary: transcript.summary,
analytics: transcript.analytics,
},
},
}
},
outputs: {
transcript: {
type: 'object',
description: 'The transcript with full details',
properties: {
id: { type: 'string', description: 'Transcript ID' },
title: { type: 'string', description: 'Meeting title' },
date: { type: 'number', description: 'Meeting timestamp' },
duration: { type: 'number', description: 'Meeting duration in seconds' },
transcript_url: { type: 'string', description: 'URL to view transcript' },
audio_url: { type: 'string', description: 'URL to audio recording' },
host_email: { type: 'string', description: 'Host email address' },
participants: { type: 'array', description: 'List of participant emails' },
speakers: { type: 'array', description: 'List of speakers' },
sentences: { type: 'array', description: 'Transcript sentences' },
summary: { type: 'object', description: 'Meeting summary and action items' },
analytics: { type: 'object', description: 'Meeting analytics and sentiment' },
},
},
},
}
+112
View File
@@ -0,0 +1,112 @@
import type { FirefliesGetUserParams, FirefliesGetUserResponse } from '@/tools/fireflies/types'
import type { ToolConfig } from '@/tools/types'
export const firefliesGetUserTool: ToolConfig<FirefliesGetUserParams, FirefliesGetUserResponse> = {
id: 'fireflies_get_user',
name: 'Fireflies Get User',
description: 'Get user information from Fireflies.ai. Returns current user if no ID specified.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Fireflies API key',
},
userId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'User ID to retrieve (e.g., "user_abc123", defaults to API key owner)',
},
},
request: {
url: 'https://api.fireflies.ai/graphql',
method: 'POST',
headers: (params) => {
if (!params.apiKey) {
throw new Error('Missing API key for Fireflies API request')
}
return {
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}
},
body: (params) => ({
query: `
query User($id: String) {
user(id: $id) {
user_id
name
email
integrations
is_admin
minutes_consumed
num_transcripts
recent_transcript
recent_meeting
}
}
`,
variables: params.userId ? { id: params.userId } : {},
}),
},
transformResponse: async (response) => {
const data = await response.json()
if (data.errors) {
return {
success: false,
error: data.errors[0]?.message || 'Failed to fetch user',
output: {},
}
}
const user = data.data?.user
if (!user) {
return {
success: false,
error: 'User not found',
output: {},
}
}
return {
success: true,
output: {
user: {
user_id: user.user_id,
name: user.name,
email: user.email,
integrations: user.integrations,
is_admin: user.is_admin,
minutes_consumed: user.minutes_consumed,
num_transcripts: user.num_transcripts,
recent_transcript: user.recent_transcript,
recent_meeting: user.recent_meeting,
},
},
}
},
outputs: {
user: {
type: 'object',
description: 'User information',
properties: {
user_id: { type: 'string', description: 'User ID' },
name: { type: 'string', description: 'User name' },
email: { type: 'string', description: 'User email' },
integrations: { type: 'array', description: 'Connected integrations' },
is_admin: { type: 'boolean', description: 'Whether user is admin' },
minutes_consumed: { type: 'number', description: 'Total minutes transcribed' },
num_transcripts: { type: 'number', description: 'Number of transcripts' },
recent_transcript: { type: 'string', description: 'Most recent transcript ID' },
recent_meeting: { type: 'string', description: 'Most recent meeting date' },
},
},
},
}
+11
View File
@@ -0,0 +1,11 @@
export { firefliesAddToLiveMeetingTool } from './add_to_live_meeting'
export { firefliesCreateBiteTool } from './create_bite'
export { firefliesDeleteTranscriptTool } from './delete_transcript'
export { firefliesGetTranscriptTool } from './get_transcript'
export { firefliesGetUserTool } from './get_user'
export { firefliesListBitesTool } from './list_bites'
export { firefliesListContactsTool } from './list_contacts'
export { firefliesListTranscriptsTool } from './list_transcripts'
export { firefliesListUsersTool } from './list_users'
export * from './types'
export { firefliesUploadAudioTool } from './upload_audio'
+155
View File
@@ -0,0 +1,155 @@
import type { FirefliesListBitesParams, FirefliesListBitesResponse } from '@/tools/fireflies/types'
import type { ToolConfig } from '@/tools/types'
export const firefliesListBitesTool: ToolConfig<
FirefliesListBitesParams,
FirefliesListBitesResponse
> = {
id: 'fireflies_list_bites',
name: 'Fireflies List Bites',
description: 'List soundbites/highlights from Fireflies.ai',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Fireflies API key',
},
transcriptId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter bites for a specific transcript (e.g., "abc123def456")',
},
mine: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Only return bites owned by the API key owner (default: true)',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of bites to return (e.g., 10, max 50)',
},
skip: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of bites to skip for pagination (e.g., 0, 10, 20)',
},
},
request: {
url: 'https://api.fireflies.ai/graphql',
method: 'POST',
headers: (params) => {
if (!params.apiKey) {
throw new Error('Missing API key for Fireflies API request')
}
return {
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}
},
body: (params) => {
const variables: Record<string, unknown> = {
mine: params.mine !== false,
}
if (params.transcriptId) variables.transcript_id = params.transcriptId
if (params.limit) variables.limit = Math.min(Number(params.limit), 50)
if (params.skip) variables.skip = Number(params.skip)
return {
query: `
query Bites(
$mine: Boolean
$transcript_id: ID
$limit: Int
$skip: Int
) {
bites(
mine: $mine
transcript_id: $transcript_id
limit: $limit
skip: $skip
) {
id
name
transcript_id
user_id
start_time
end_time
status
summary
media_type
thumbnail
preview
created_at
}
}
`,
variables,
}
},
},
transformResponse: async (response) => {
const data = await response.json()
if (data.errors) {
return {
success: false,
error: data.errors[0]?.message || 'Failed to fetch bites',
output: {},
}
}
const bites = data.data?.bites || []
return {
success: true,
output: {
bites: bites.map(
(b: {
id: string
name?: string
transcript_id?: string
user_id?: string
start_time?: number
end_time?: number
status?: string
summary?: string
media_type?: string
thumbnail?: string
preview?: string
created_at?: string
}) => ({
id: b.id,
name: b.name,
transcript_id: b.transcript_id,
user_id: b.user_id,
start_time: b.start_time,
end_time: b.end_time,
status: b.status,
summary: b.summary,
media_type: b.media_type,
thumbnail: b.thumbnail,
preview: b.preview,
created_at: b.created_at,
})
),
},
}
},
outputs: {
bites: {
type: 'array',
description: 'List of bites/soundbites',
},
},
}
+84
View File
@@ -0,0 +1,84 @@
import type {
FirefliesListContactsParams,
FirefliesListContactsResponse,
} from '@/tools/fireflies/types'
import type { ToolConfig } from '@/tools/types'
export const firefliesListContactsTool: ToolConfig<
FirefliesListContactsParams,
FirefliesListContactsResponse
> = {
id: 'fireflies_list_contacts',
name: 'Fireflies List Contacts',
description: 'List all contacts from your Fireflies.ai meetings',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Fireflies API key',
},
},
request: {
url: 'https://api.fireflies.ai/graphql',
method: 'POST',
headers: (params) => {
if (!params.apiKey) {
throw new Error('Missing API key for Fireflies API request')
}
return {
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}
},
body: () => ({
query: `
query Contacts {
contacts {
email
name
picture
last_meeting_date
}
}
`,
}),
},
transformResponse: async (response) => {
const data = await response.json()
if (data.errors) {
return {
success: false,
error: data.errors[0]?.message || 'Failed to fetch contacts',
output: {},
}
}
const contacts = data.data?.contacts || []
return {
success: true,
output: {
contacts: contacts.map(
(c: { email?: string; name?: string; picture?: string; last_meeting_date?: string }) => ({
email: c.email,
name: c.name,
picture: c.picture,
last_meeting_date: c.last_meeting_date,
})
),
},
}
},
outputs: {
contacts: {
type: 'array',
description: 'List of contacts from meetings',
},
},
}
@@ -0,0 +1,173 @@
import type {
FirefliesListTranscriptsParams,
FirefliesListTranscriptsResponse,
} from '@/tools/fireflies/types'
import type { ToolConfig } from '@/tools/types'
export const firefliesListTranscriptsTool: ToolConfig<
FirefliesListTranscriptsParams,
FirefliesListTranscriptsResponse
> = {
id: 'fireflies_list_transcripts',
name: 'Fireflies List Transcripts',
description: 'List meeting transcripts from Fireflies.ai with optional filtering',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Fireflies API key',
},
keyword: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search keyword in meeting title or transcript (e.g., "quarterly review")',
},
fromDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter transcripts from this date (ISO 8601 format)',
},
toDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter transcripts until this date (ISO 8601 format)',
},
hostEmail: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by meeting host email',
},
participants: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by participant emails (comma-separated)',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of transcripts to return (e.g., 10, max 50)',
},
skip: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of transcripts to skip for pagination (e.g., 0, 10, 20)',
},
},
request: {
url: 'https://api.fireflies.ai/graphql',
method: 'POST',
headers: (params) => {
if (!params.apiKey) {
throw new Error('Missing API key for Fireflies API request')
}
return {
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}
},
body: (params) => {
const variables: Record<string, unknown> = {}
if (params.keyword) variables.keyword = params.keyword
if (params.fromDate) variables.fromDate = params.fromDate
if (params.toDate) variables.toDate = params.toDate
if (params.hostEmail) variables.host_email = params.hostEmail
if (params.participants) {
variables.participants = params.participants.split(',').map((p) => p.trim())
}
if (params.limit) variables.limit = Math.min(Number(params.limit), 50)
if (params.skip) variables.skip = Number(params.skip)
return {
query: `
query Transcripts(
$keyword: String
$fromDate: DateTime
$toDate: DateTime
$host_email: String
$participants: [String!]
$limit: Int
$skip: Int
) {
transcripts(
keyword: $keyword
fromDate: $fromDate
toDate: $toDate
host_email: $host_email
participants: $participants
limit: $limit
skip: $skip
) {
id
title
date
duration
host_email
participants
}
}
`,
variables,
}
},
},
transformResponse: async (response) => {
const data = await response.json()
if (data.errors) {
return {
success: false,
error: data.errors[0]?.message || 'Failed to fetch transcripts',
output: {},
}
}
const transcripts = data.data?.transcripts || []
return {
success: true,
output: {
transcripts: transcripts.map(
(t: {
id: string
title: string
date: number
duration: number
host_email?: string
participants?: string[]
}) => ({
id: t.id,
title: t.title,
date: t.date,
duration: t.duration,
host_email: t.host_email,
participants: t.participants,
})
),
count: transcripts.length,
},
}
},
outputs: {
transcripts: {
type: 'array',
description: 'List of transcripts',
},
count: {
type: 'number',
description: 'Number of transcripts returned',
},
},
}
+98
View File
@@ -0,0 +1,98 @@
import type { FirefliesListUsersParams, FirefliesListUsersResponse } from '@/tools/fireflies/types'
import type { ToolConfig } from '@/tools/types'
export const firefliesListUsersTool: ToolConfig<
FirefliesListUsersParams,
FirefliesListUsersResponse
> = {
id: 'fireflies_list_users',
name: 'Fireflies List Users',
description: 'List all users within your Fireflies.ai team',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Fireflies API key',
},
},
request: {
url: 'https://api.fireflies.ai/graphql',
method: 'POST',
headers: (params) => {
if (!params.apiKey) {
throw new Error('Missing API key for Fireflies API request')
}
return {
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}
},
body: () => ({
query: `
query Users {
users {
user_id
email
name
num_transcripts
recent_meeting
minutes_consumed
is_admin
integrations
}
}
`,
}),
},
transformResponse: async (response) => {
const data = await response.json()
if (data.errors) {
return {
success: false,
error: data.errors[0]?.message || 'Failed to fetch users',
output: {},
}
}
const users = data.data?.users || []
return {
success: true,
output: {
users: users.map(
(u: {
user_id: string
email: string
name: string
num_transcripts?: number
recent_meeting?: string
minutes_consumed?: number
is_admin?: boolean
integrations?: string[]
}) => ({
user_id: u.user_id,
email: u.email,
name: u.name,
num_transcripts: u.num_transcripts,
recent_meeting: u.recent_meeting,
minutes_consumed: u.minutes_consumed,
is_admin: u.is_admin,
integrations: u.integrations,
})
),
},
}
},
outputs: {
users: {
type: 'array',
description: 'List of team users',
},
},
}
+309
View File
@@ -0,0 +1,309 @@
import type { ToolResponse } from '@/tools/types'
interface FirefliesTranscript {
id: string
title: string
date: number
dateString?: string
duration: number
privacy?: string
transcript_url?: string
audio_url?: string
video_url?: string
meeting_link?: string
host_email?: string
organizer_email?: string
participants?: string[]
fireflies_users?: string[]
speakers?: FirefliesSpeaker[]
meeting_attendees?: FirefliesAttendee[]
sentences?: FirefliesSentence[]
summary?: FirefliesSummary
analytics?: FirefliesAnalytics
}
interface FirefliesSpeaker {
id: number
name: string
}
interface FirefliesAttendee {
displayName?: string
email?: string
phoneNumber?: string
name?: string
location?: string
}
interface FirefliesSentence {
index: number
speaker_name?: string
speaker_id?: number
text: string
raw_text?: string
start_time: number
end_time: number
ai_filters?: {
task?: boolean
pricing?: boolean
metric?: boolean
question?: boolean
date_and_time?: boolean
text_cleanup?: string
sentiment?: string
}
}
interface FirefliesSummary {
keywords?: string[]
action_items?: string
outline?: string
shorthand_bullet?: string
overview?: string
bullet_gist?: string
gist?: string
short_summary?: string
short_overview?: string
meeting_type?: string
topics_discussed?: string
transcript_chapters?: Array<{
title?: string
start_time?: number
end_time?: number
}>
}
interface FirefliesAnalytics {
sentiments?: {
negative_pct?: number
neutral_pct?: number
positive_pct?: number
}
categories?: {
questions?: number
date_times?: number
metrics?: number
tasks?: number
}
speakers?: FirefliesSpeakerAnalytics[]
}
interface FirefliesSpeakerAnalytics {
speaker_id?: number
name?: string
duration?: number
word_count?: number
longest_monologue?: number
monologues_count?: number
filler_words?: number
questions?: number
duration_pct?: number
words_per_minute?: number
}
interface FirefliesUser {
user_id: string
name: string
email: string
integrations?: string[]
is_admin?: boolean
minutes_consumed?: number
num_transcripts?: number
recent_transcript?: string
recent_meeting?: string
}
export interface FirefliesListTranscriptsParams {
apiKey: string
keyword?: string
fromDate?: string
toDate?: string
hostEmail?: string
participants?: string
limit?: number
skip?: number
}
export interface FirefliesGetTranscriptParams {
apiKey: string
transcriptId: string
}
export interface FirefliesGetUserParams {
apiKey: string
userId?: string
}
export interface FirefliesUploadAudioParams {
apiKey: string
audioUrl?: string
audioFile?: {
url?: string
path?: string
name?: string
size?: number
type?: string
key?: string
}
title?: string
webhook?: string
language?: string
attendees?: string
clientReferenceId?: string
}
export interface FirefliesDeleteTranscriptParams {
apiKey: string
transcriptId: string
}
export interface FirefliesAddToLiveMeetingParams {
apiKey: string
meetingLink: string
title?: string
meetingPassword?: string
duration?: number
language?: string
}
export interface FirefliesListUsersParams {
apiKey: string
}
export interface FirefliesCreateBiteParams {
apiKey: string
transcriptId: string
startTime: number
endTime: number
name?: string
mediaType?: string
summary?: string
}
export interface FirefliesListBitesParams {
apiKey: string
transcriptId?: string
mine?: boolean
limit?: number
skip?: number
}
export interface FirefliesListContactsParams {
apiKey: string
}
export interface FirefliesListTranscriptsResponse extends ToolResponse {
output: {
transcripts?: Array<{
id: string
title: string
date: number
duration: number
host_email?: string
participants?: string[]
}>
count?: number
}
}
export interface FirefliesGetTranscriptResponse extends ToolResponse {
output: {
transcript?: FirefliesTranscript
}
}
export interface FirefliesGetUserResponse extends ToolResponse {
output: {
user?: FirefliesUser
}
}
export interface FirefliesUploadAudioResponse extends ToolResponse {
output: {
success?: boolean
title?: string
message?: string
}
}
export interface FirefliesDeleteTranscriptResponse extends ToolResponse {
output: {
success?: boolean
transcript?: {
id: string
title: string | null
date: number | null
duration: number | null
host_email: string | null
organizer_email: string | null
}
}
}
export interface FirefliesAddToLiveMeetingResponse extends ToolResponse {
output: {
success?: boolean
}
}
export interface FirefliesListUsersResponse extends ToolResponse {
output: {
users?: FirefliesUser[]
}
}
interface FirefliesBite {
id: string
name?: string
transcript_id?: string
user_id?: string
start_time?: number
end_time?: number
status?: string
summary?: string
media_type?: string
thumbnail?: string
preview?: string
created_at?: string
}
export interface FirefliesCreateBiteResponse extends ToolResponse {
output: {
bite?: {
id: string
name?: string
status?: string
}
}
}
export interface FirefliesListBitesResponse extends ToolResponse {
output: {
bites?: FirefliesBite[]
}
}
interface FirefliesContact {
email?: string
name?: string
picture?: string
last_meeting_date?: string
}
export interface FirefliesListContactsResponse extends ToolResponse {
output: {
contacts?: FirefliesContact[]
}
}
export type FirefliesResponse =
| FirefliesListTranscriptsResponse
| FirefliesGetTranscriptResponse
| FirefliesGetUserResponse
| FirefliesUploadAudioResponse
| FirefliesDeleteTranscriptResponse
| FirefliesAddToLiveMeetingResponse
| FirefliesListUsersResponse
| FirefliesCreateBiteResponse
| FirefliesListBitesResponse
| FirefliesListContactsResponse
+176
View File
@@ -0,0 +1,176 @@
import type {
FirefliesUploadAudioParams,
FirefliesUploadAudioResponse,
} from '@/tools/fireflies/types'
import type { ToolConfig } from '@/tools/types'
export const firefliesUploadAudioTool: ToolConfig<
FirefliesUploadAudioParams,
FirefliesUploadAudioResponse
> = {
id: 'fireflies_upload_audio',
name: 'Fireflies Upload Audio',
description: 'Upload an audio file URL to Fireflies.ai for transcription',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Fireflies API key',
},
audioFile: {
type: 'file',
required: false,
visibility: 'user-or-llm',
description: 'Audio/video file to upload for transcription',
},
audioUrl: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Public HTTPS URL of the audio/video file (MP3, MP4, WAV, M4A, OGG)',
},
title: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Title for the meeting/transcript',
},
webhook: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Webhook URL to notify when transcription is complete',
},
language: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Language code for transcription (e.g., "es" for Spanish, "de" for German)',
},
attendees: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Attendees in JSON format: [{"displayName": "Name", "email": "email@example.com"}]',
},
clientReferenceId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Custom reference ID for tracking',
},
},
request: {
url: 'https://api.fireflies.ai/graphql',
method: 'POST',
headers: (params) => {
if (!params.apiKey) {
throw new Error('Missing API key for Fireflies API request')
}
return {
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}
},
body: (params) => {
let url: string | undefined
if (params.audioFile) {
url = params.audioFile.url || params.audioFile.path
}
if (!url && params.audioUrl) {
url = params.audioUrl
}
if (!url) {
throw new Error('Either an audio file or audio URL is required')
}
if (!url.startsWith('https://')) {
throw new Error('Audio URL must be a valid HTTPS URL')
}
const input: Record<string, unknown> = {
url,
}
if (params.title) input.title = params.title
if (params.webhook) input.webhook = params.webhook
if (params.language) input.custom_language = params.language
if (params.clientReferenceId) input.client_reference_id = params.clientReferenceId
if (params.attendees) {
try {
input.attendees = JSON.parse(params.attendees)
} catch {
throw new Error('Invalid attendees JSON format')
}
}
return {
query: `
mutation UploadAudio($input: AudioUploadInput) {
uploadAudio(input: $input) {
success
title
message
}
}
`,
variables: {
input,
},
}
},
},
transformResponse: async (response) => {
const data = await response.json()
if (data.errors) {
return {
success: false,
error: data.errors[0]?.message || 'Failed to upload audio',
output: {},
}
}
const result = data.data?.uploadAudio
if (!result) {
return {
success: false,
error: 'Upload failed',
output: {},
}
}
return {
success: result.success,
output: {
success: result.success,
title: result.title,
message: result.message,
},
}
},
outputs: {
success: {
type: 'boolean',
description: 'Whether the upload was successful',
},
title: {
type: 'string',
description: 'Title of the uploaded meeting',
},
message: {
type: 'string',
description: 'Status message from Fireflies',
},
},
}