@@ -30,6 +30,25 @@ import { GenerateContentRequest } from '../types';
3030use ( sinonChai ) ;
3131use ( chaiAsPromised ) ;
3232
33+ /**
34+ * Converts the ReadableStream from response.body to an array of strings.
35+ */
36+ async function toStringArray (
37+ stream : ReadableStream < Uint8Array >
38+ ) : Promise < string [ ] > {
39+ const decoder = new TextDecoder ( ) ;
40+ const actual = [ ] ;
41+ const reader = stream . getReader ( ) ;
42+ while ( true ) {
43+ const { done, value } = await reader . read ( ) ;
44+ if ( done ) {
45+ break ;
46+ }
47+ actual . push ( decoder . decode ( value ) ) ;
48+ }
49+ return actual ;
50+ }
51+
3352describe ( 'ChromeAdapter' , ( ) => {
3453 describe ( 'isAvailable' , ( ) => {
3554 it ( 'returns false if mode is only cloud' , async ( ) => {
@@ -280,7 +299,7 @@ describe('ChromeAdapter', () => {
280299 const request = {
281300 contents : [ { role : 'user' , parts : [ { text : 'anything' } ] } ]
282301 } as GenerateContentRequest ;
283- const response = await adapter . generateContentOnDevice ( request ) ;
302+ const response = await adapter . generateContent ( request ) ;
284303 // Asserts initialization params are proxied.
285304 expect ( createStub ) . to . have . been . calledOnceWith ( onDeviceParams ) ;
286305 // Asserts Vertex input type is mapped to Chrome type.
@@ -325,6 +344,7 @@ describe('ChromeAdapter', () => {
325344 const createStub = stub ( languageModelProvider , 'create' ) . resolves (
326345 languageModel
327346 ) ;
347+
328348 // overrides impl with stub method
329349 const measureInputUsageStub = stub (
330350 languageModel ,
@@ -336,6 +356,7 @@ describe('ChromeAdapter', () => {
336356 'prefer_on_device' ,
337357 onDeviceParams
338358 ) ;
359+
339360 const countTokenRequest = {
340361 contents : [ { role : 'user' , parts : [ { text : inputText } ] } ]
341362 } as GenerateContentRequest ;
@@ -359,4 +380,52 @@ describe('ChromeAdapter', () => {
359380 } ) ;
360381 } ) ;
361382 } ) ;
383+ describe ( 'generateContentStreamOnDevice' , ( ) => {
384+ it ( 'generates content stream' , async ( ) => {
385+ const languageModelProvider = {
386+ create : ( ) => Promise . resolve ( { } )
387+ } as LanguageModel ;
388+ const languageModel = {
389+ promptStreaming : _i => new ReadableStream ( )
390+ } as LanguageModel ;
391+ const createStub = stub ( languageModelProvider , 'create' ) . resolves (
392+ languageModel
393+ ) ;
394+ const part = 'hi' ;
395+ const promptStub = stub ( languageModel , 'promptStreaming' ) . returns (
396+ new ReadableStream ( {
397+ start ( controller ) {
398+ controller . enqueue ( [ part ] ) ;
399+ controller . close ( ) ;
400+ }
401+ } )
402+ ) ;
403+ const onDeviceParams = { } as LanguageModelCreateOptions ;
404+ const adapter = new ChromeAdapter (
405+ languageModelProvider ,
406+ 'prefer_on_device' ,
407+ onDeviceParams
408+ ) ;
409+ const request = {
410+ contents : [ { role : 'user' , parts : [ { text : 'anything' } ] } ]
411+ } as GenerateContentRequest ;
412+ const response = await adapter . generateContentStream ( request ) ;
413+ expect ( createStub ) . to . have . been . calledOnceWith ( onDeviceParams ) ;
414+ expect ( promptStub ) . to . have . been . calledOnceWith ( [
415+ {
416+ role : request . contents [ 0 ] . role ,
417+ content : [
418+ {
419+ type : 'text' ,
420+ content : request . contents [ 0 ] . parts [ 0 ] . text
421+ }
422+ ]
423+ }
424+ ] ) ;
425+ const actual = await toStringArray ( response . body ! ) ;
426+ expect ( actual ) . to . deep . equal ( [
427+ `data: {"candidates":[{"content":{"role":"model","parts":[{"text":["${ part } "]}]}}]}\n\n`
428+ ] ) ;
429+ } ) ;
430+ } ) ;
362431} ) ;
0 commit comments