Skip to content

Commit 3a39177

Browse files
authored
fix(search): accept Fireflies data-array responses (#9490)
* test(search): cover Fireflies data-array responses * fix(search): accept Fireflies data-array responses
1 parent c63e93e commit 3a39177

2 files changed

Lines changed: 80 additions & 23 deletions

File tree

‎apps/sim/lib/sim-search/live/fireflies-mcp.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ export async function searchFirefliesMcp(
181181
const data = toRecord(result)
182182
const rows = Array.isArray(result)
183183
? result
184-
: (data.transcripts ?? toRecord(data.data).transcripts)
184+
: (data.transcripts ?? (Array.isArray(data.data) ? data.data : toRecord(data.data).transcripts))
185185
if (!Array.isArray(rows)) {
186186
logger.warn('Unsupported Fireflies transcript list response shape', {
187187
response: responseShape(result),

‎apps/sim/lib/sim-search/live/meeting-mcp.test.ts‎

Lines changed: 79 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,36 +13,81 @@ const meetingId = '11111111-2222-4333-8444-555555555555'
1313
* an unrelated read response is attached to a signed reference; malformed wire shapes hide gaps.
1414
*/
1515
describe('meeting MCP provider wire contracts', () => {
16-
it('finds spoken Fireflies content and continues a full metadata page without inventing modification times', async () => {
17-
const client: ManagedSearchMcpClient = {
18-
async call(name, args) {
19-
if (name !== 'fireflies_get_transcripts' || args.scope !== 'all' || args.format !== 'json')
20-
throw new Error('Transcript-content search requires all scope and JSON output')
21-
if (args.skip !== 10) throw new Error('Wrong continuation offset')
22-
return {
23-
transcripts: [
16+
it.each(['bare array', 'data array', 'transcripts', 'nested transcripts'] as const)(
17+
'finds spoken Fireflies content and continues a %s page without inventing modification times',
18+
async (shape) => {
19+
const client: ManagedSearchMcpClient = {
20+
async call(name, args) {
21+
if (
22+
name !== 'fireflies_get_transcripts' ||
23+
args.scope !== 'all' ||
24+
args.format !== 'json'
25+
)
26+
throw new Error('Transcript-content search requires all scope and JSON output')
27+
if (args.skip !== 10) throw new Error('Wrong continuation offset')
28+
const transcripts = [
2429
{
2530
id: 'meeting-1',
2631
title: 'Planning',
2732
date: 1788220800000,
2833
summary: { overview: 'Launch in September' },
2934
},
3035
{ id: 'meeting-2', title: 'Next match' },
36+
]
37+
if (shape === 'bare array') return transcripts
38+
if (shape === 'data array') return { data: transcripts }
39+
if (shape === 'nested transcripts') return { data: { transcripts } }
40+
return { transcripts }
41+
},
42+
}
43+
const result = await searchFirefliesMcp(client, {
44+
...input,
45+
limit: 1,
46+
native: { provider: 'fireflies', query: 'launch', cursor: '10' },
47+
})
48+
expect(result.documents).toHaveLength(1)
49+
expect(result.documents[0]).toMatchObject({
50+
id: 'meeting-1',
51+
eventStartAt: '2026-09-01T00:00:00.000Z',
52+
})
53+
expect(result.documents[0]?.modifiedAt).toBeUndefined()
54+
expect(result.nextCursor).toBe('11')
55+
expect(result.partial).toBe(false)
56+
}
57+
)
58+
59+
it('returns an empty Fireflies data page without reporting unavailable', async () => {
60+
const client: ManagedSearchMcpClient = {
61+
async call() {
62+
return { data: [] }
63+
},
64+
}
65+
const result = await searchFirefliesMcp(client, input)
66+
expect(result.documents).toEqual([])
67+
expect(result.nextCursor).toBeUndefined()
68+
expect(result.partial).toBe(false)
69+
})
70+
71+
it('keeps partial coverage and provider offsets when a Fireflies data page has invalid rows', async () => {
72+
const client: ManagedSearchMcpClient = {
73+
async call() {
74+
return {
75+
data: [
76+
{ id: '../invalid', title: 'Invalid meeting' },
77+
{ id: 'meeting-1', title: 'Planning' },
78+
{ id: 'meeting-2', title: 'Next match' },
3179
],
3280
}
3381
},
3482
}
3583
const result = await searchFirefliesMcp(client, {
3684
...input,
37-
limit: 1,
85+
limit: 2,
3886
native: { provider: 'fireflies', query: 'launch', cursor: '10' },
3987
})
40-
expect(result.documents[0]).toMatchObject({
41-
id: 'meeting-1',
42-
eventStartAt: '2026-09-01T00:00:00.000Z',
43-
})
44-
expect(result.documents[0]?.modifiedAt).toBeUndefined()
45-
expect(result.nextCursor).toBe('11')
88+
expect(result.documents.map((document) => document.id)).toEqual(['meeting-1'])
89+
expect(result.nextCursor).toBe('12')
90+
expect(result.partial).toBe(true)
4691
})
4792

4893
it('keeps meetings earlier on a partial UTC end day and omits keyword scope from termless listings', async () => {
@@ -149,14 +194,26 @@ describe('meeting MCP provider wire contracts', () => {
149194
expect(document.content).toContain(transcript)
150195
})
151196

152-
it('fails on unknown Fireflies list formats rather than claiming zero matches', async () => {
153-
const client = {
154-
async call() {
155-
return { answer: 'No matching meetings' }
156-
},
197+
it.each([
198+
{ shape: 'unknown', response: { answer: 'No matching meetings' } },
199+
{ shape: 'null data', response: { data: null } },
200+
{ shape: 'text data', response: { data: '[]' } },
201+
{ shape: 'object data', response: { data: {} } },
202+
{
203+
shape: 'malformed transcripts with a data array',
204+
response: { transcripts: 'invalid', data: [] },
205+
},
206+
])(
207+
'rejects $shape Fireflies list formats rather than claiming zero matches',
208+
async ({ response }) => {
209+
const client: ManagedSearchMcpClient = {
210+
async call() {
211+
return response
212+
},
213+
}
214+
await expect(searchFirefliesMcp(client, input)).rejects.toThrow('unsupported')
157215
}
158-
await expect(searchFirefliesMcp(client, input)).rejects.toThrow('unsupported')
159-
})
216+
)
160217

161218
it.each(['text', 'json', 'code_fence', 'oversized'] as const)(
162219
'diagnoses unsupported Fireflies %s envelopes without logging private values or arbitrary keys',

0 commit comments

Comments
 (0)