1+ import { createLogger } from '@sim/logger'
12import { toArray , toRecord } from '@sim/utils/object'
23import { nativeText } from '@/lib/sim-search/live/dates'
34import { NativeSearchError , string } from '@/lib/sim-search/live/http'
@@ -6,7 +7,49 @@ import { boundedMeetingContent } from '@/lib/sim-search/live/meeting-content'
67import type { NativeDocument , NativePage , NativeSearchInput } from '@/lib/sim-search/live/types'
78
89const MAX_MEETING_CONTENT = 200_000
10+ const MAX_DIAGNOSTIC_TEXT_LENGTH = 65_536
911const UTC_DAY_MS = 86_400_000
12+ const logger = createLogger ( 'FirefliesMcpSearch' , { logLevel : 'WARN' } )
13+
14+ /** Only fixed envelope keys and value kinds may enter diagnostics, never provider keys or values. */
15+ function responseShape ( value : unknown ) {
16+ const record = toRecord ( value )
17+ const kind = ( entry : unknown ) =>
18+ entry === null ? 'null' : Array . isArray ( entry ) ? 'array' : typeof entry
19+ return {
20+ type : kind ( value ) ,
21+ fields : Object . fromEntries (
22+ [
23+ 'transcripts' ,
24+ 'data' ,
25+ 'result' ,
26+ 'results' ,
27+ 'items' ,
28+ 'output' ,
29+ 'text' ,
30+ 'error' ,
31+ 'errors' ,
32+ ] . flatMap ( ( key ) => ( Object . hasOwn ( record , key ) ? [ [ key , kind ( record [ key ] ) ] ] : [ ] ) )
33+ ) ,
34+ }
35+ }
36+
37+ function responseTextShape ( value : unknown ) {
38+ if ( typeof value !== 'string' ) return undefined
39+ if ( value . length > MAX_DIAGNOSTIC_TEXT_LENGTH )
40+ return { length : value . length , inspection : 'skipped_size_limit' }
41+ const text = value . trim ( )
42+ const fenced = text . match ( / ^ ` ` ` (?: j s o n ) ? \r ? \n ( [ \s \S ] * ) \r ? \n ` ` ` $ / i) ?. [ 1 ]
43+ let jsonShape : ReturnType < typeof responseShape > | undefined
44+ try {
45+ jsonShape = responseShape ( JSON . parse ( fenced ?? text ) )
46+ } catch { }
47+ return {
48+ length : value . length ,
49+ format : fenced !== undefined ? 'code_fence' : jsonShape ? 'json' : 'text' ,
50+ ...( jsonShape ? { jsonShape } : { } ) ,
51+ }
52+ }
1053
1154function requireMeetingId ( id : string ) : string {
1255 if ( ! / ^ [ \w - ] { 1 , 200 } $ / . test ( id ) )
@@ -139,11 +182,19 @@ export async function searchFirefliesMcp(
139182 const rows = Array . isArray ( result )
140183 ? result
141184 : ( data . transcripts ?? toRecord ( data . data ) . transcripts )
142- if ( ! Array . isArray ( rows ) )
185+ if ( ! Array . isArray ( rows ) ) {
186+ logger . warn ( 'Unsupported Fireflies transcript list response shape' , {
187+ response : responseShape ( result ) ,
188+ data : responseShape ( data . data ) ,
189+ result : responseShape ( data . result ) ,
190+ output : responseShape ( data . output ) ,
191+ text : responseTextShape ( typeof result === 'string' ? result : data . text ) ,
192+ } )
143193 throw new NativeSearchError (
144194 'unavailable' ,
145195 'Fireflies returned an unsupported transcript list format.'
146196 )
197+ }
147198 const documents = rows . slice ( 0 , limit ) . flatMap ( ( value ) => {
148199 const document = meetingDocument ( toRecord ( value ) )
149200 return document ? [ document ] : [ ]
0 commit comments