|  | 
|  | 1 | +/** | 
|  | 2 | + * @license | 
|  | 3 | + * Copyright 2025 Google LLC | 
|  | 4 | + * | 
|  | 5 | + * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 6 | + * you may not use this file except in compliance with the License. | 
|  | 7 | + * You may obtain a copy of the License at | 
|  | 8 | + * | 
|  | 9 | + *   http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 10 | + * | 
|  | 11 | + * Unless required by applicable law or agreed to in writing, software | 
|  | 12 | + * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 13 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 14 | + * See the License for the specific language governing permissions and | 
|  | 15 | + * limitations under the License. | 
|  | 16 | + */ | 
|  | 17 | + | 
|  | 18 | +import { expect } from 'chai'; | 
|  | 19 | +import { | 
|  | 20 | +  Content, | 
|  | 21 | +  GenerationConfig, | 
|  | 22 | +  HarmBlockThreshold, | 
|  | 23 | +  HarmCategory, | 
|  | 24 | +  SafetySetting, | 
|  | 25 | +  getGenerativeModel | 
|  | 26 | +} from '../src'; | 
|  | 27 | +import { testConfigs, TOKEN_COUNT_DELTA } from './constants'; | 
|  | 28 | + | 
|  | 29 | +describe('Chat Session', () => { | 
|  | 30 | +  testConfigs.forEach(testConfig => { | 
|  | 31 | +    describe(`${testConfig.toString()}`, () => { | 
|  | 32 | +      const commonGenerationConfig: GenerationConfig = { | 
|  | 33 | +        temperature: 0, | 
|  | 34 | +        topP: 0, | 
|  | 35 | +        responseMimeType: 'text/plain' | 
|  | 36 | +      }; | 
|  | 37 | + | 
|  | 38 | +      const commonSafetySettings: SafetySetting[] = [ | 
|  | 39 | +        { | 
|  | 40 | +          category: HarmCategory.HARM_CATEGORY_HARASSMENT, | 
|  | 41 | +          threshold: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE | 
|  | 42 | +        }, | 
|  | 43 | +        { | 
|  | 44 | +          category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, | 
|  | 45 | +          threshold: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE | 
|  | 46 | +        }, | 
|  | 47 | +        { | 
|  | 48 | +          category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, | 
|  | 49 | +          threshold: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE | 
|  | 50 | +        }, | 
|  | 51 | +        { | 
|  | 52 | +          category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, | 
|  | 53 | +          threshold: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE | 
|  | 54 | +        } | 
|  | 55 | +      ]; | 
|  | 56 | + | 
|  | 57 | +      const commonSystemInstruction: Content = { | 
|  | 58 | +        role: 'system', | 
|  | 59 | +        parts: [ | 
|  | 60 | +          { | 
|  | 61 | +            text: 'You are a friendly and helpful assistant.' | 
|  | 62 | +          } | 
|  | 63 | +        ] | 
|  | 64 | +      }; | 
|  | 65 | + | 
|  | 66 | +      it('startChat and sendMessage: text input, text output', async () => { | 
|  | 67 | +        const model = getGenerativeModel(testConfig.ai, { | 
|  | 68 | +          model: testConfig.model, | 
|  | 69 | +          generationConfig: commonGenerationConfig, | 
|  | 70 | +          safetySettings: commonSafetySettings, | 
|  | 71 | +          systemInstruction: commonSystemInstruction | 
|  | 72 | +        }); | 
|  | 73 | + | 
|  | 74 | +        const chat = model.startChat(); | 
|  | 75 | +        const result1 = await chat.sendMessage( | 
|  | 76 | +          'What is the capital of France?' | 
|  | 77 | +        ); | 
|  | 78 | +        const response1 = result1.response; | 
|  | 79 | +        expect(response1.text().trim().toLowerCase()).to.include('paris'); | 
|  | 80 | + | 
|  | 81 | +        let history = await chat.getHistory(); | 
|  | 82 | +        expect(history.length).to.equal(2); | 
|  | 83 | +        expect(history[0].role).to.equal('user'); | 
|  | 84 | +        expect(history[0].parts[0].text).to.equal( | 
|  | 85 | +          'What is the capital of France?' | 
|  | 86 | +        ); | 
|  | 87 | +        expect(history[1].role).to.equal('model'); | 
|  | 88 | +        expect(history[1].parts[0].text?.toLowerCase()).to.include('paris'); | 
|  | 89 | + | 
|  | 90 | +        expect(response1.usageMetadata).to.not.be.null; | 
|  | 91 | +        // Token counts can vary slightly in chat context | 
|  | 92 | +        expect(response1.usageMetadata!.promptTokenCount).to.be.closeTo( | 
|  | 93 | +          15, // "What is the capital of France?" + system instruction | 
|  | 94 | +          TOKEN_COUNT_DELTA + 2 // More variance for chat context | 
|  | 95 | +        ); | 
|  | 96 | +        expect(response1.usageMetadata!.candidatesTokenCount).to.be.closeTo( | 
|  | 97 | +          8, // "Paris" | 
|  | 98 | +          TOKEN_COUNT_DELTA | 
|  | 99 | +        ); | 
|  | 100 | +        expect(response1.usageMetadata!.totalTokenCount).to.be.closeTo( | 
|  | 101 | +          23, // "What is the capital of France?" + system instruction + "Paris" | 
|  | 102 | +          TOKEN_COUNT_DELTA + 3 // More variance for chat context | 
|  | 103 | +        ); | 
|  | 104 | + | 
|  | 105 | +        const result2 = await chat.sendMessage('And what about Italy?'); | 
|  | 106 | +        const response2 = result2.response; | 
|  | 107 | +        expect(response2.text().trim().toLowerCase()).to.include('rome'); | 
|  | 108 | + | 
|  | 109 | +        history = await chat.getHistory(); | 
|  | 110 | +        expect(history.length).to.equal(4); | 
|  | 111 | +        expect(history[2].role).to.equal('user'); | 
|  | 112 | +        expect(history[2].parts[0].text).to.equal('And what about Italy?'); | 
|  | 113 | +        expect(history[3].role).to.equal('model'); | 
|  | 114 | +        expect(history[3].parts[0].text?.toLowerCase()).to.include('rome'); | 
|  | 115 | + | 
|  | 116 | +        expect(response2.usageMetadata).to.not.be.null; | 
|  | 117 | +        expect(response2.usageMetadata!.promptTokenCount).to.be.closeTo( | 
|  | 118 | +          28, // History + "And what about Italy?" + system instruction | 
|  | 119 | +          TOKEN_COUNT_DELTA + 5 // More variance for chat context with history | 
|  | 120 | +        ); | 
|  | 121 | +        expect(response2.usageMetadata!.candidatesTokenCount).to.be.closeTo( | 
|  | 122 | +          8, | 
|  | 123 | +          TOKEN_COUNT_DELTA | 
|  | 124 | +        ); | 
|  | 125 | +        expect(response2.usageMetadata!.totalTokenCount).to.be.closeTo( | 
|  | 126 | +          36, | 
|  | 127 | +          TOKEN_COUNT_DELTA | 
|  | 128 | +        ); | 
|  | 129 | +      }); | 
|  | 130 | +    }); | 
|  | 131 | +  }); | 
|  | 132 | +}); | 
0 commit comments