@@ -342,4 +342,83 @@ describe('ChromeAdapter', () => {
342342 } ) ;
343343 } ) ;
344344 } ) ;
345+ describe ( 'countTokens' , ( ) => {
346+ it ( 'With no initial prompts' , async ( ) => {
347+ const aiProvider = {
348+ languageModel : {
349+ create : ( ) => Promise . resolve ( { } )
350+ }
351+ } as AI ;
352+ const inputText = "first" ;
353+ const expectedCount = 10 ;
354+ const countPromptTokensStub = stub ( ) . resolves ( expectedCount ) ;
355+ const factoryStub = stub ( aiProvider . languageModel , 'create' ) . resolves ( {
356+ countPromptTokens : countPromptTokensStub
357+ } as unknown as AILanguageModel ) ;
358+ const adapter = new ChromeAdapter (
359+ aiProvider ,
360+ 'prefer_on_device' ,
361+ ) ;
362+ const response = await adapter . countTokens ( {
363+ contents : [
364+ { role : 'user' , parts : [ { text : inputText } ] }
365+ ]
366+ } ) ;
367+ expect ( factoryStub ) . to . have . been . calledOnceWith ( {
368+ // initialPrompts must be empty
369+ initialPrompts : [ ]
370+ } ) ;
371+ // validate count tokens gets called with the last entry from the input
372+ expect ( countPromptTokensStub ) . to . have . been . calledOnceWith ( {
373+ role : 'user' ,
374+ content : inputText
375+ } ) ;
376+ expect ( await response . json ( ) ) . to . deep . equal ( {
377+ totalTokens : expectedCount
378+ } ) ;
379+ } ) ;
380+ it ( 'Extracts initial prompts and then does counts tokens' , async ( ) => {
381+ const aiProvider = {
382+ languageModel : {
383+ create : ( ) => Promise . resolve ( { } )
384+ }
385+ } as AI ;
386+ const expectedCount = 10 ;
387+ const countPromptTokensStub = stub ( ) . resolves ( expectedCount ) ;
388+ const factoryStub = stub ( aiProvider . languageModel , 'create' ) . resolves ( {
389+ countPromptTokens : countPromptTokensStub
390+ } as unknown as AILanguageModel ) ;
391+ const text = [ 'first' , 'second' , 'third' ] ;
392+ const onDeviceParams = {
393+ initialPrompts : [ { role : 'user' , content : text [ 0 ] } ]
394+ } as AILanguageModelCreateOptionsWithSystemPrompt ;
395+ const adapter = new ChromeAdapter (
396+ aiProvider ,
397+ 'prefer_on_device' ,
398+ onDeviceParams
399+ ) ;
400+ const response = await adapter . countTokens ( {
401+ contents : [
402+ { role : 'model' , parts : [ { text : text [ 1 ] } ] } ,
403+ { role : 'user' , parts : [ { text : text [ 2 ] } ] }
404+ ]
405+ } ) ;
406+ expect ( factoryStub ) . to . have . been . calledOnceWith ( {
407+ initialPrompts : [
408+ { role : 'user' , content : text [ 0 ] } ,
409+ // Asserts tail is passed as initial prompts, and
410+ // role is normalized from model to assistant.
411+ { role : 'assistant' , content : text [ 1 ] }
412+ ]
413+ } ) ;
414+ // validate count tokens gets called with the last entry from the input
415+ expect ( countPromptTokensStub ) . to . have . been . calledOnceWith ( {
416+ role : 'user' ,
417+ content : text [ 2 ]
418+ } ) ;
419+ expect ( await response . json ( ) ) . to . deep . equal ( {
420+ totalTokens : expectedCount
421+ } ) ;
422+ } ) ;
423+ } ) ;
345424} ) ;
0 commit comments