@@ -144,6 +144,7 @@ export class NotebookLMClient {
144144 }
145145
146146 const responseText = await response . text ( ) ;
147+ console . log ( `[NotebookLM] RPC ${ methodId } response: ${ responseText . length } bytes, first 200: ${ responseText . substring ( 0 , 200 ) } ` ) ;
147148 return decodeResponse ( responseText , methodId ) ;
148149 }
149150
@@ -341,6 +342,7 @@ export class NotebookLMClient {
341342 }
342343
343344 const result = await this . rpcCall ( methodId , params ) ;
345+ console . log ( `[NotebookLM] startResearch raw result:` , JSON . stringify ( result ) ) ;
344346 const resultArr = result as unknown [ ] ;
345347
346348 // Extract task ID from response
@@ -380,6 +382,8 @@ export class NotebookLMClient {
380382 EXTENDED_FETCH_TIMEOUT_MS
381383 ) ;
382384
385+ console . log ( `[NotebookLM] pollResearch raw result:` , JSON . stringify ( result ) ?. substring ( 0 , 500 ) ) ;
386+
383387 const resultArr = result as unknown [ ] ;
384388 const emptyResult : ResearchResult = {
385389 taskId : '' ,
@@ -389,54 +393,91 @@ export class NotebookLMClient {
389393 summary : '' ,
390394 } ;
391395
392- if ( ! Array . isArray ( resultArr ) ) {
396+ if ( ! Array . isArray ( resultArr ) || resultArr . length === 0 ) {
393397 return emptyResult ;
394398 }
395399
396- // Extract task ID
397- const taskId =
398- typeof resultArr [ 0 ] === 'string' ? resultArr [ 0 ] : '' ;
399-
400+ // Response format (from notebooklm-py _research.py):
401+ // result = [[task_data, ...], ...] or [task_data, ...]
402+ // task_data = [task_id, task_info]
403+ // task_info = [?, query_info, ?, sources_and_summary, status_code]
404+ // query_info = [query_text, ...]
405+ // sources_and_summary = [sources_array, summary_text]
400406 // Research status: 1=in_progress, 2=completed
401- const statusCode = safeGet ( resultArr , 1 ) ;
402- let status : ResearchResult [ 'status' ] = 'no_research' ;
403- if ( statusCode === 1 ) {
404- status = 'in_progress' ;
405- } else if ( statusCode === 2 ) {
406- status = 'completed' ;
407+
408+ // Unwrap if double-nested
409+ let tasks = resultArr ;
410+ if (
411+ Array . isArray ( tasks [ 0 ] ) &&
412+ tasks [ 0 ] . length > 0 &&
413+ Array . isArray ( tasks [ 0 ] [ 0 ] ) &&
414+ tasks [ 0 ] [ 0 ] . length > 0 &&
415+ Array . isArray ( tasks [ 0 ] [ 0 ] [ 0 ] )
416+ ) {
417+ tasks = tasks [ 0 ] as unknown [ ] ;
418+ } else if (
419+ Array . isArray ( tasks [ 0 ] ) &&
420+ tasks [ 0 ] . length > 0 &&
421+ typeof tasks [ 0 ] [ 0 ] === 'string'
422+ ) {
423+ // Already at task level: [[taskId, taskInfo], ...]
424+ // wrap in array for uniform processing
425+ tasks = [ tasks ] ;
407426 }
408427
409- // Extract query
410- const query =
411- typeof safeGet ( resultArr , 2 ) === 'string'
412- ? ( safeGet ( resultArr , 2 ) as string )
413- : '' ;
414-
415- // Extract sources — typically an array of [url, title] pairs
416- const sources : Array < { url : string ; title : string } > = [ ] ;
417- const sourcesArr = safeGet ( resultArr , 3 ) ;
418- if ( Array . isArray ( sourcesArr ) ) {
419- for ( const src of sourcesArr ) {
420- if ( Array . isArray ( src ) ) {
421- const srcUrl = safeGet ( src , 2 , 0 ) ;
422- const srcTitle = safeGet ( src , 2 , 1 ) ;
423- if ( typeof srcUrl === 'string' ) {
424- sources . push ( {
425- url : srcUrl ,
426- title : typeof srcTitle === 'string' ? srcTitle : '' ,
427- } ) ;
428+ // Find the most recent task
429+ for ( const taskData of tasks ) {
430+ if ( ! Array . isArray ( taskData ) || taskData . length < 2 ) continue ;
431+
432+ const taskId = taskData [ 0 ] ;
433+ const taskInfo = taskData [ 1 ] ;
434+
435+ if ( typeof taskId !== 'string' || ! Array . isArray ( taskInfo ) ) continue ;
436+
437+ const queryInfo = taskInfo [ 1 ] ;
438+ const sourcesAndSummary = taskInfo [ 3 ] ;
439+ const statusCode = taskInfo [ 4 ] ;
440+
441+ const queryText =
442+ Array . isArray ( queryInfo ) && typeof queryInfo [ 0 ] === 'string'
443+ ? queryInfo [ 0 ]
444+ : '' ;
445+
446+ // Parse sources
447+ const sources : Array < { url : string ; title : string } > = [ ] ;
448+ let summary = '' ;
449+
450+ if ( Array . isArray ( sourcesAndSummary ) && sourcesAndSummary . length >= 1 ) {
451+ const sourcesData = Array . isArray ( sourcesAndSummary [ 0 ] )
452+ ? sourcesAndSummary [ 0 ]
453+ : [ ] ;
454+ if (
455+ sourcesAndSummary . length >= 2 &&
456+ typeof sourcesAndSummary [ 1 ] === 'string'
457+ ) {
458+ summary = sourcesAndSummary [ 1 ] ;
459+ }
460+
461+ for ( const src of sourcesData ) {
462+ if ( ! Array . isArray ( src ) || src . length < 2 ) continue ;
463+ const url =
464+ typeof src [ 0 ] === 'string' ? src [ 0 ] : '' ;
465+ const title =
466+ typeof src [ 1 ] === 'string' ? src [ 1 ] : '' ;
467+ if ( title || url ) {
468+ sources . push ( { url, title } ) ;
428469 }
429470 }
430471 }
431- }
432472
433- // Extract summary
434- const summary =
435- typeof safeGet ( resultArr , 4 ) === 'string'
436- ? ( safeGet ( resultArr , 4 ) as string )
437- : '' ;
473+ // Research status: 1=in_progress, 2=completed
474+ const status : ResearchResult [ 'status' ] =
475+ statusCode === 2 ? 'completed' : 'in_progress' ;
476+
477+ return { taskId, status, query : queryText , sources, summary } ;
478+ }
438479
439- return { taskId , status , query , sources , summary } ;
480+ return emptyResult ;
440481 }
441482
442483 /**
0 commit comments