@@ -30,6 +30,25 @@ import { GenerateContentRequest } from '../types';
30
30
use ( sinonChai ) ;
31
31
use ( chaiAsPromised ) ;
32
32
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
+
33
52
describe ( 'ChromeAdapter' , ( ) => {
34
53
describe ( 'isAvailable' , ( ) => {
35
54
it ( 'returns false if mode is only cloud' , async ( ) => {
@@ -280,7 +299,7 @@ describe('ChromeAdapter', () => {
280
299
const request = {
281
300
contents : [ { role : 'user' , parts : [ { text : 'anything' } ] } ]
282
301
} as GenerateContentRequest ;
283
- const response = await adapter . generateContentOnDevice ( request ) ;
302
+ const response = await adapter . generateContent ( request ) ;
284
303
// Asserts initialization params are proxied.
285
304
expect ( createStub ) . to . have . been . calledOnceWith ( onDeviceParams ) ;
286
305
// Asserts Vertex input type is mapped to Chrome type.
@@ -325,6 +344,7 @@ describe('ChromeAdapter', () => {
325
344
const createStub = stub ( languageModelProvider , 'create' ) . resolves (
326
345
languageModel
327
346
) ;
347
+
328
348
// overrides impl with stub method
329
349
const measureInputUsageStub = stub (
330
350
languageModel ,
@@ -336,6 +356,7 @@ describe('ChromeAdapter', () => {
336
356
'prefer_on_device' ,
337
357
onDeviceParams
338
358
) ;
359
+
339
360
const countTokenRequest = {
340
361
contents : [ { role : 'user' , parts : [ { text : inputText } ] } ]
341
362
} as GenerateContentRequest ;
@@ -359,4 +380,52 @@ describe('ChromeAdapter', () => {
359
380
} ) ;
360
381
} ) ;
361
382
} ) ;
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
+ } ) ;
362
431
} ) ;
0 commit comments