"use strict";
/**
 * @license
 * Copyright 2024 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
const util_1 = require("../../util");
const generative_models_1 = require("../generative_models");
const chat_session_1 = require("../chat_session");
const types_1 = require("../../types");
const PostFetchFunctions = require("../../functions/post_fetch_processing");
const GenerateContentFunctions = require("../../functions/generate_content");
const CountTokensFunctions = require("../../functions/count_tokens");
const fake_google_auth_1 = require("../../testing/fake_google_auth");
const PROJECT = 'test_project';
const LOCATION = 'test_location';
const TEST_TOKEN = 'testtoken';
const FAKE_GOOGLE_AUTH = (0, fake_google_auth_1.createFakeGoogleAuth)({
    scopes: 'https://www.googleapis.com/auth/cloud-platform',
    accessToken: TEST_TOKEN,
});
const TEST_CHAT_MESSSAGE_TEXT = 'How are you doing today?';
const TEST_USER_CHAT_MESSAGE = [
    { role: util_1.constants.USER_ROLE, parts: [{ text: TEST_CHAT_MESSSAGE_TEXT }] },
];
const TEST_SAFETY_RATINGS = [
    {
        category: types_1.HarmCategory.HARM_CATEGORY_HATE_SPEECH,
        probability: types_1.HarmProbability.NEGLIGIBLE,
    },
];
const TEST_CANDIDATES = [
    {
        index: 1,
        content: {
            role: util_1.constants.MODEL_ROLE,
            parts: [{ text: 'Im doing great! How are you?' }],
        },
        finishReason: types_1.FinishReason.STOP,
        finishMessage: '',
        safetyRatings: TEST_SAFETY_RATINGS,
        citationMetadata: {
            citations: [
                {
                    startIndex: 367,
                    endIndex: 491,
                    uri: 'https://www.numerade.com/ask/question/why-does-the-uncertainty-principle-make-it-impossible-to-predict-a-trajectory-for-the-clectron-95172/',
                },
            ],
        },
    },
];
const TEST_CANDIDATES2 = [
    {
        index: 1,
        content: {
            role: util_1.constants.MODEL_ROLE,
            parts: [{ text: 'Goodbye. Wish you the best.' }],
        },
    },
];
const TEST_MODEL_RESPONSE = {
    candidates: TEST_CANDIDATES,
    usageMetadata: { promptTokenCount: 0, candidatesTokenCount: 0 },
};
const TEST_USER_CHAT_MESSAGE_WITH_GCS_FILE = [
    {
        role: util_1.constants.USER_ROLE,
        parts: [
            { text: TEST_CHAT_MESSSAGE_TEXT },
            {
                fileData: {
                    fileUri: 'gs://test_bucket/test_image.jpeg',
                    mimeType: 'image/jpeg',
                },
            },
        ],
    },
];
const TEST_USER_CHAT_MESSAGE_WITH_INVALID_GCS_FILE = [
    {
        role: util_1.constants.USER_ROLE,
        parts: [
            { text: TEST_CHAT_MESSSAGE_TEXT },
            { fileData: { fileUri: 'test_image.jpeg', mimeType: 'image/jpeg' } },
        ],
    },
];
const TEST_SAFETY_SETTINGS = [
    {
        category: types_1.HarmCategory.HARM_CATEGORY_HATE_SPEECH,
        threshold: types_1.HarmBlockThreshold.BLOCK_ONLY_HIGH,
    },
];
const TEST_GENERATION_CONFIG = {
    candidateCount: 1,
    stopSequences: ['hello'],
};
const TEST_ENDPOINT_BASE_PATH = 'test.googleapis.com';
const TEST_FUNCTION_CALL_RESPONSE = {
    functionCall: {
        name: 'get_current_weather',
        args: {
            location: 'LA',
            unit: 'fahrenheit',
        },
    },
};
const TEST_CANDIDATES_WITH_FUNCTION_CALL = [
    {
        index: 1,
        content: {
            role: util_1.constants.MODEL_ROLE,
            parts: [TEST_FUNCTION_CALL_RESPONSE],
        },
        finishReason: types_1.FinishReason.STOP,
        finishMessage: '',
        safetyRatings: TEST_SAFETY_RATINGS,
    },
];
const TEST_MODEL_RESPONSE_WITH_FUNCTION_CALL = {
    candidates: TEST_CANDIDATES_WITH_FUNCTION_CALL,
};
const TEST_FUNCTION_RESPONSE_PART = [
    {
        functionResponse: {
            name: 'get_current_weather',
            response: { name: 'get_current_weather', content: { weather: 'super nice' } },
        },
    },
];
const TEST_TOOLS_WITH_FUNCTION_DECLARATION = [
    {
        functionDeclarations: [
            {
                name: 'get_current_weather',
                description: 'get weather in a given location',
                parameters: {
                    type: types_1.FunctionDeclarationSchemaType.OBJECT,
                    properties: {
                        location: { type: types_1.FunctionDeclarationSchemaType.STRING },
                        unit: {
                            type: types_1.FunctionDeclarationSchemaType.STRING,
                            enum: ['celsius', 'fahrenheit'],
                        },
                    },
                    required: ['location'],
                },
            },
        ],
    },
];
const TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL = [
    {
        googleSearchRetrieval: {
            dynamicRetrievalConfig: {
                dynamicThreshold: 0.5,
                mode: types_1.Mode.MODE_DYNAMIC,
            },
        },
    },
];
const TEST_GCS_FILENAME = 'gs://test_bucket/test_image.jpeg';
const TEST_MULTIPART_MESSAGE = [
    {
        role: util_1.constants.USER_ROLE,
        parts: [
            { text: 'What is in this picture?' },
            { fileData: { fileUri: TEST_GCS_FILENAME, mimeType: 'image/jpeg' } },
        ],
    },
];
const BASE_64_IMAGE = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==';
const INLINE_DATA_FILE_PART = {
    inlineData: {
        data: BASE_64_IMAGE,
        mimeType: 'image/jpeg',
    },
};
const TEST_MULTIPART_MESSAGE_BASE64 = [
    {
        role: util_1.constants.USER_ROLE,
        parts: [{ text: 'What is in this picture?' }, INLINE_DATA_FILE_PART],
    },
];
const fetchResponseObj = {
    status: 200,
    statusText: 'OK',
    ok: true,
    headers: { 'Content-Type': 'application/json' },
    url: 'url',
};
const TEST_REQUEST_OPTIONS = {
    timeout: 0,
};
const TEST_SYSTEM_INSTRUCTION = {
    role: util_1.constants.SYSTEM_ROLE,
    parts: [{ text: 'system instruction' }],
};
const TEST_SYSTEM_INSTRUCTION_1 = {
    role: util_1.constants.SYSTEM_ROLE,
    parts: [{ text: 'system instruction1' }],
};
const TEST_SYSTEM_INSTRUCTION_WRONG_ROLE = {
    role: 'WRONG_ROLE',
    parts: [{ text: 'system instruction' }],
};
async function* testGenerator() {
    yield {
        candidates: TEST_CANDIDATES,
    };
}
const DATE_NOW_PRECISION_MILLIS = 2;
async function* testGeneratorMultiStream() {
    yield {
        candidates: TEST_CANDIDATES,
    };
    await new Promise(resolve => setTimeout(resolve, 200));
    yield {
        candidates: TEST_CANDIDATES2,
    };
}
class ChatSessionForTest extends chat_session_1.ChatSession {
}
class ChatSessionPreviewForTest extends chat_session_1.ChatSessionPreview {
}
describe('GenerativeModel startChat', () => {
    it('returns ChatSession when pass no arg', () => {
        const model = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const chat = model.startChat();
        expect(chat).toBeInstanceOf(chat_session_1.ChatSession);
    });
    it('returns ChatSession when pass an arg', () => {
        const model = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const chat = model.startChat({
            history: TEST_USER_CHAT_MESSAGE,
        });
        expect(chat).toBeInstanceOf(chat_session_1.ChatSession);
    });
    it('returns ChatSession when pass an arg with generationConfig including responseMimeType', async () => {
        const fetchResult = Promise.resolve(new Response(JSON.stringify(TEST_MODEL_RESPONSE), fetchResponseObj));
        const fetchSpy = spyOn(global, 'fetch').and.returnValue(fetchResult);
        const model = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const chat = model.startChat({
            generationConfig: {
                ...TEST_GENERATION_CONFIG,
                responseMimeType: 'application/json',
            },
        });
        expect(chat).toBeInstanceOf(chat_session_1.ChatSession);
    });
    it('set timeout info in ChatSession', () => {
        const model = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            requestOptions: TEST_REQUEST_OPTIONS,
        });
        const chat = model.startChat({
            history: TEST_USER_CHAT_MESSAGE,
        });
        expect(chat.requestOptions).toEqual(TEST_REQUEST_OPTIONS);
    });
    it('pass tools to remote endpoint from GenerativeModel constructor', async () => {
        const expectedResult = TEST_MODEL_RESPONSE;
        const fetchResult = Promise.resolve(new Response(JSON.stringify(expectedResult), fetchResponseObj));
        const fetchSpy = spyOn(global, 'fetch').and.returnValue(fetchResult);
        const req = 'How are you doing today?';
        const model = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL,
        });
        const chat = model.startChat({
            history: TEST_USER_CHAT_MESSAGE,
        });
        const expectedBody = '{"contents":[{"role":"user","parts":[{"text":"How are you doing today?"}]},{"role":"user","parts":[{"text":"How are you doing today?"}]}],"tools":[{"googleSearchRetrieval":{"dynamicRetrievalConfig":{"dynamicThreshold":0.5,"mode":"MODE_DYNAMIC"}}}]}';
        await chat.sendMessage(req);
        // @ts-ignore
        const actualBody = fetchSpy.calls.allArgs()[0][1].body;
        expect(actualBody).toEqual(expectedBody);
    });
    it('pass tools to remote endpoint from startChat', async () => {
        const expectedResult = TEST_MODEL_RESPONSE;
        const fetchResult = Promise.resolve(new Response(JSON.stringify(expectedResult), fetchResponseObj));
        const fetchSpy = spyOn(global, 'fetch').and.returnValue(fetchResult);
        const req = 'How are you doing today?';
        const model = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION,
        });
        const chat = model.startChat({
            history: TEST_USER_CHAT_MESSAGE,
            tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL,
        });
        const expectedBody = '{"contents":[{"role":"user","parts":[{"text":"How are you doing today?"}]},{"role":"user","parts":[{"text":"How are you doing today?"}]}],"tools":[{"googleSearchRetrieval":{"dynamicRetrievalConfig":{"dynamicThreshold":0.5,"mode":"MODE_DYNAMIC"}}}]}';
        await chat.sendMessage(req);
        // @ts-ignore
        const actualBody = fetchSpy.calls.allArgs()[0][1].body;
        expect(actualBody).toEqual(expectedBody);
    });
    it('pass system instruction to remote endpoint from GenerativeModel constructor', async () => {
        const expectedResult = TEST_MODEL_RESPONSE;
        const fetchResult = Promise.resolve(new Response(JSON.stringify(expectedResult), fetchResponseObj));
        const fetchSpy = spyOn(global, 'fetch').and.returnValue(fetchResult);
        const req = 'How are you doing today?';
        const model = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            systemInstruction: TEST_SYSTEM_INSTRUCTION,
        });
        const chat = model.startChat({
            history: TEST_USER_CHAT_MESSAGE,
        });
        const expectedBody = '{"contents":[{"role":"user","parts":[{"text":"How are you doing today?"}]},{"role":"user","parts":[{"text":"How are you doing today?"}]}],"systemInstruction":{"role":"system","parts":[{"text":"system instruction"}]}}';
        await chat.sendMessage(req);
        // @ts-ignore
        const actualBody = fetchSpy.calls.allArgs()[0][1].body;
        expect(actualBody).toEqual(expectedBody, `unit test failed in chat.sendMessage with ${actualBody} not equal to ${expectedBody}`);
    });
    it('pass system instruction to remote endpoint from startChat', async () => {
        const expectedResult = TEST_MODEL_RESPONSE;
        const fetchResult = Promise.resolve(new Response(JSON.stringify(expectedResult), fetchResponseObj));
        const fetchSpy = spyOn(global, 'fetch').and.returnValue(fetchResult);
        const req = 'How are you doing today?';
        const model = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            systemInstruction: TEST_SYSTEM_INSTRUCTION_1,
        });
        const chat = model.startChat({
            history: TEST_USER_CHAT_MESSAGE,
            // this is different from constructor
            systemInstruction: TEST_SYSTEM_INSTRUCTION,
        });
        const expectedBody = '{"contents":[{"role":"user","parts":[{"text":"How are you doing today?"}]},{"role":"user","parts":[{"text":"How are you doing today?"}]}],"systemInstruction":{"role":"system","parts":[{"text":"system instruction"}]}}';
        await chat.sendMessage(req);
        // @ts-ignore
        const actualBody = fetchSpy.calls.allArgs()[0][1].body;
        expect(actualBody).toEqual(expectedBody, `unit test failed in chat.sendMessage with ${actualBody} not equal to ${expectedBody}`);
    });
    it('pass system instruction with wrong role to remote endpoint from GenerativeModel constructor', async () => {
        const expectedResult = TEST_MODEL_RESPONSE;
        const fetchResult = Promise.resolve(new Response(JSON.stringify(expectedResult), fetchResponseObj));
        const fetchSpy = spyOn(global, 'fetch').and.returnValue(fetchResult);
        const req = 'How are you doing today?';
        const model = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            systemInstruction: TEST_SYSTEM_INSTRUCTION_WRONG_ROLE,
        });
        const chat = model.startChat({
            history: TEST_USER_CHAT_MESSAGE,
        });
        const expectedBody = '{"contents":[{"role":"user","parts":[{"text":"How are you doing today?"}]},{"role":"user","parts":[{"text":"How are you doing today?"}]}],"systemInstruction":{"role":"system","parts":[{"text":"system instruction"}]}}';
        await chat.sendMessage(req);
        // @ts-ignore
        const actualBody = fetchSpy.calls.allArgs()[0][1].body;
        expect(actualBody).toEqual(expectedBody, `unit test failed in chat.sendMessage with ${actualBody} not equal to ${expectedBody}`);
    });
    it('pass system instruction with wrong role to remote endpoint from startChat', async () => {
        const expectedResult = TEST_MODEL_RESPONSE;
        const fetchResult = Promise.resolve(new Response(JSON.stringify(expectedResult), fetchResponseObj));
        const fetchSpy = spyOn(global, 'fetch').and.returnValue(fetchResult);
        const req = 'How are you doing today?';
        const model = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            systemInstruction: TEST_SYSTEM_INSTRUCTION_1,
        });
        const chat = model.startChat({
            history: TEST_USER_CHAT_MESSAGE,
            // this is different from constructor
            systemInstruction: TEST_SYSTEM_INSTRUCTION_WRONG_ROLE,
        });
        const expectedBody = '{"contents":[{"role":"user","parts":[{"text":"How are you doing today?"}]},{"role":"user","parts":[{"text":"How are you doing today?"}]}],"systemInstruction":{"role":"system","parts":[{"text":"system instruction"}]}}';
        await chat.sendMessage(req);
        // @ts-ignore
        const actualBody = fetchSpy.calls.allArgs()[0][1].body;
        expect(actualBody).toEqual(expectedBody, `unit test failed in chat.sendMessage with ${actualBody} not equal to ${expectedBody}`);
    });
});
describe('GenerativeModelPreview startChat', () => {
    it('returns ChatSessionPreview when pass no arg', () => {
        const model = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const chat = model.startChat();
        expect(chat).toBeInstanceOf(chat_session_1.ChatSessionPreview);
    });
    it('returns ChatSessionPreview when pass an arg', () => {
        const model = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const chat = model.startChat({
            history: TEST_USER_CHAT_MESSAGE,
        });
        expect(chat).toBeInstanceOf(chat_session_1.ChatSessionPreview);
    });
    it('returns ChatSessionPreview when pass an arg with generationConfig including responseMimeType', async () => {
        const model = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const chat = model.startChat({
            generationConfig: {
                ...TEST_GENERATION_CONFIG,
                responseMimeType: 'application/json',
            },
        });
        expect(chat).toBeInstanceOf(chat_session_1.ChatSessionPreview);
    });
    it('set timeout info in ChatSession', () => {
        const model = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            requestOptions: TEST_REQUEST_OPTIONS,
        });
        const chat = model.startChat({
            history: TEST_USER_CHAT_MESSAGE,
        });
        expect(chat.requestOptions).toEqual(TEST_REQUEST_OPTIONS);
    });
    it('in preview, pass tools to remote endpoint from GenerativeModelPreview constructor', async () => {
        const expectedResult = TEST_MODEL_RESPONSE;
        const fetchResult = Promise.resolve(new Response(JSON.stringify(expectedResult), fetchResponseObj));
        const fetchSpy = spyOn(global, 'fetch').and.returnValue(fetchResult);
        const req = 'How are you doing today?';
        const model = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL,
        });
        const chat = model.startChat({
            history: TEST_USER_CHAT_MESSAGE,
        });
        const expectedBody = '{"contents":[{"role":"user","parts":[{"text":"How are you doing today?"}]},{"role":"user","parts":[{"text":"How are you doing today?"}]}],"tools":[{"googleSearchRetrieval":{"dynamicRetrievalConfig":{"dynamicThreshold":0.5,"mode":"MODE_DYNAMIC"}}}]}';
        await chat.sendMessage(req);
        // @ts-ignore
        const actualBody = fetchSpy.calls.allArgs()[0][1].body;
        expect(actualBody).toEqual(expectedBody);
    });
    it('in preview, pass tools to remote endpoint from startChat', async () => {
        const expectedResult = TEST_MODEL_RESPONSE;
        const fetchResult = Promise.resolve(new Response(JSON.stringify(expectedResult), fetchResponseObj));
        const fetchSpy = spyOn(global, 'fetch').and.returnValue(fetchResult);
        const req = 'How are you doing today?';
        const model = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION,
        });
        const chat = model.startChat({
            history: TEST_USER_CHAT_MESSAGE,
            tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL,
        });
        const expectedBody = '{"contents":[{"role":"user","parts":[{"text":"How are you doing today?"}]},{"role":"user","parts":[{"text":"How are you doing today?"}]}],"tools":[{"googleSearchRetrieval":{"dynamicRetrievalConfig":{"dynamicThreshold":0.5,"mode":"MODE_DYNAMIC"}}}]}';
        await chat.sendMessage(req);
        // @ts-ignore
        const actualBody = fetchSpy.calls.allArgs()[0][1].body;
        expect(actualBody).toEqual(expectedBody);
    });
    it('pass system instruction to remote endpoint from GenerativeModelPreview constructor', async () => {
        const expectedResult = TEST_MODEL_RESPONSE;
        const fetchResult = Promise.resolve(new Response(JSON.stringify(expectedResult), fetchResponseObj));
        const fetchSpy = spyOn(global, 'fetch').and.returnValue(fetchResult);
        const req = 'How are you doing today?';
        const model = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            systemInstruction: TEST_SYSTEM_INSTRUCTION,
        });
        const chat = model.startChat({
            history: TEST_USER_CHAT_MESSAGE,
        });
        const expectedBody = '{"contents":[{"role":"user","parts":[{"text":"How are you doing today?"}]},{"role":"user","parts":[{"text":"How are you doing today?"}]}],"systemInstruction":{"role":"system","parts":[{"text":"system instruction"}]}}';
        await chat.sendMessage(req);
        // @ts-ignore
        const actualBody = fetchSpy.calls.allArgs()[0][1].body;
        expect(actualBody).toEqual(expectedBody, `unit test failed in chat.sendMessage with ${actualBody} not equal to ${expectedBody}`);
    });
    it('pass system instruction to remote endpoint from startChat', async () => {
        const expectedResult = TEST_MODEL_RESPONSE;
        const fetchResult = Promise.resolve(new Response(JSON.stringify(expectedResult), fetchResponseObj));
        const fetchSpy = spyOn(global, 'fetch').and.returnValue(fetchResult);
        const req = 'How are you doing today?';
        const model = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            systemInstruction: TEST_SYSTEM_INSTRUCTION_1,
        });
        const chat = model.startChat({
            history: TEST_USER_CHAT_MESSAGE,
            // this is different from constructor
            systemInstruction: TEST_SYSTEM_INSTRUCTION,
        });
        const expectedBody = '{"contents":[{"role":"user","parts":[{"text":"How are you doing today?"}]},{"role":"user","parts":[{"text":"How are you doing today?"}]}],"systemInstruction":{"role":"system","parts":[{"text":"system instruction"}]}}';
        await chat.sendMessage(req);
        // @ts-ignore
        const actualBody = fetchSpy.calls.allArgs()[0][1].body;
        expect(actualBody).toEqual(expectedBody, `unit test failed in chat.sendMessage with ${actualBody} not equal to ${expectedBody}`);
    });
    it('pass system instruction with wrong role to remote endpoint from GenerativeModelPreview constructor', async () => {
        const expectedResult = TEST_MODEL_RESPONSE;
        const fetchResult = Promise.resolve(new Response(JSON.stringify(expectedResult), fetchResponseObj));
        const fetchSpy = spyOn(global, 'fetch').and.returnValue(fetchResult);
        const req = 'How are you doing today?';
        const model = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            systemInstruction: TEST_SYSTEM_INSTRUCTION_WRONG_ROLE,
        });
        const chat = model.startChat({
            history: TEST_USER_CHAT_MESSAGE,
        });
        const expectedBody = '{"contents":[{"role":"user","parts":[{"text":"How are you doing today?"}]},{"role":"user","parts":[{"text":"How are you doing today?"}]}],"systemInstruction":{"role":"system","parts":[{"text":"system instruction"}]}}';
        await chat.sendMessage(req);
        // @ts-ignore
        const actualBody = fetchSpy.calls.allArgs()[0][1].body;
        expect(actualBody).toEqual(expectedBody, `unit test failed in chat.sendMessage with ${actualBody} not equal to ${expectedBody}`);
    });
    it('pass system instruction with wrong role to remote endpoint from startChat', async () => {
        const expectedResult = TEST_MODEL_RESPONSE;
        const fetchResult = Promise.resolve(new Response(JSON.stringify(expectedResult), fetchResponseObj));
        const fetchSpy = spyOn(global, 'fetch').and.returnValue(fetchResult);
        const req = 'How are you doing today?';
        const model = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            systemInstruction: TEST_SYSTEM_INSTRUCTION_1,
        });
        const chat = model.startChat({
            history: TEST_USER_CHAT_MESSAGE,
            // this is different from constructor
            systemInstruction: TEST_SYSTEM_INSTRUCTION_WRONG_ROLE,
        });
        const expectedBody = '{"contents":[{"role":"user","parts":[{"text":"How are you doing today?"}]},{"role":"user","parts":[{"text":"How are you doing today?"}]}],"systemInstruction":{"role":"system","parts":[{"text":"system instruction"}]}}';
        await chat.sendMessage(req);
        // @ts-ignore
        const actualBody = fetchSpy.calls.allArgs()[0][1].body;
        expect(actualBody).toEqual(expectedBody, `unit test failed in chat.sendMessage with ${actualBody} not equal to ${expectedBody}`);
    });
});
describe('GenerativeModel generateContent', () => {
    let model;
    let fetchSpy;
    let expectedResult;
    beforeEach(() => {
        model = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        expectedResult = TEST_MODEL_RESPONSE;
        const fetchResult = new Response(JSON.stringify(expectedResult), fetchResponseObj);
        fetchSpy = spyOn(global, 'fetch').and.resolveTo(fetchResult);
    });
    it('returns a GenerateContentResponse', async () => {
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const expectedResult = {
            response: TEST_MODEL_RESPONSE,
        };
        const resp = await model.generateContent(req);
        expect(resp).toEqual(expectedResult);
    });
    it('gemini-pro model send correct resourcePath to functions', async () => {
        const modelWithShortName = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent');
        const expectedResourcePath = 'projects/test_project/locations/test_location/publishers/google/models/gemini-pro';
        await modelWithShortName.generateContent(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
    });
    it('models/gemini-pro model send correct resourcePath to functions', async () => {
        const modelWithLongName = new generative_models_1.GenerativeModel({
            model: 'models/gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent');
        const expectedResourcePath = 'projects/test_project/locations/test_location/publishers/google/models/gemini-pro';
        await modelWithLongName.generateContent(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
    });
    it('projects/my-project/my-tuned-gemini-pro model send correct resourcePath to functions', async () => {
        const modelWithFullName = new generative_models_1.GenerativeModel({
            model: 'projects/my-project/my-tuned-gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent');
        const expectedResourcePath = 'projects/my-project/my-tuned-gemini-pro';
        await modelWithFullName.generateContent(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
    });
    it('empty model raise ClientError', () => {
        const expectedErrorMessage = '[VertexAI.ClientError]: model parameter must not be empty.';
        try {
            new generative_models_1.GenerativeModel({
                model: '',
                project: PROJECT,
                location: LOCATION,
                googleAuth: FAKE_GOOGLE_AUTH,
            });
        }
        catch (e) {
            // @ts-ignore
            expect(e.message).toEqual(expectedErrorMessage);
        }
    });
    it('invalid model raise ClientError', () => {
        const expectedErrorMessage = '[VertexAI.ClientError]: model parameter must be either a Model Garden model ID or a full resource name.';
        try {
            new generative_models_1.GenerativeModel({
                model: 'invalid/my-tuned-mode',
                project: PROJECT,
                location: LOCATION,
                googleAuth: FAKE_GOOGLE_AUTH,
            });
        }
        catch (e) {
            // @ts-ignore
            expect(e.message).toEqual(expectedErrorMessage);
        }
    });
    it('send timeout options to functions', async () => {
        const modelWithRequestOptions = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            requestOptions: TEST_REQUEST_OPTIONS,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent');
        await modelWithRequestOptions.generateContent(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][9].timeout).toEqual(0);
    });
    it('set system instruction in constructor, should send system instruction to functions', async () => {
        const modelWithSystemInstruction = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            systemInstruction: TEST_SYSTEM_INSTRUCTION,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent');
        const expectedRequest = {
            contents: [
                {
                    role: 'user',
                    parts: [
                        {
                            text: 'How are you doing today?',
                        },
                    ],
                },
            ],
            systemInstruction: {
                role: 'system',
                parts: [
                    {
                        text: 'system instruction',
                    },
                ],
            },
        };
        await modelWithSystemInstruction.generateContent(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][3]).toEqual(expectedRequest);
    });
    it('set system instruction in generateContent, should send system instruction to functions', async () => {
        const modelWithSystemInstruction = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
            systemInstruction: TEST_SYSTEM_INSTRUCTION,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent');
        const expectedRequest = {
            contents: [
                {
                    role: 'user',
                    parts: [
                        {
                            text: 'How are you doing today?',
                        },
                    ],
                },
            ],
            systemInstruction: {
                role: 'system',
                parts: [
                    {
                        text: 'system instruction',
                    },
                ],
            },
        };
        await modelWithSystemInstruction.generateContent(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][3]).toEqual(expectedRequest);
    });
    it('set system instruction in constructor, wrong role, should send system instruction to functions', async () => {
        const modelWithSystemInstruction = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            systemInstruction: TEST_SYSTEM_INSTRUCTION_WRONG_ROLE,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent');
        const expectedRequest = {
            contents: [
                {
                    role: 'user',
                    parts: [
                        {
                            text: 'How are you doing today?',
                        },
                    ],
                },
            ],
            systemInstruction: {
                role: 'system',
                parts: [
                    {
                        text: 'system instruction',
                    },
                ],
            },
        };
        await modelWithSystemInstruction.generateContent(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][3]).toEqual(expectedRequest);
    });
    it('set system instruction in generateContent, wrong role, should send system instruction to functions', async () => {
        const modelWithSystemInstruction = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
            systemInstruction: TEST_SYSTEM_INSTRUCTION_WRONG_ROLE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent');
        const expectedRequest = {
            contents: [
                {
                    role: 'user',
                    parts: [
                        {
                            text: 'How are you doing today?',
                        },
                    ],
                },
            ],
            systemInstruction: {
                role: 'system',
                parts: [
                    {
                        text: 'system instruction',
                    },
                ],
            },
        };
        await modelWithSystemInstruction.generateContent(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][3]).toEqual(expectedRequest);
    });
    it('returns a GenerateContentResponse when passed a string', async () => {
        const expectedResult = {
            response: TEST_MODEL_RESPONSE,
        };
        const resp = await model.generateContent(TEST_CHAT_MESSSAGE_TEXT);
        expect(resp).toEqual(expectedResult);
    });
    it('returns a GenerateContentResponse when passed a GCS URI', async () => {
        const req = {
            contents: TEST_USER_CHAT_MESSAGE_WITH_GCS_FILE,
        };
        const expectedResult = {
            response: TEST_MODEL_RESPONSE,
        };
        const resp = await model.generateContent(req);
        expect(resp).toEqual(expectedResult);
    });
    it('returns a GenerateContentResponse when passed safetySettings and generationConfig', async () => {
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
            safetySettings: TEST_SAFETY_SETTINGS,
            generationConfig: TEST_GENERATION_CONFIG,
        };
        const expectedResult = {
            response: TEST_MODEL_RESPONSE,
        };
        const resp = await model.generateContent(req);
        expect(resp).toEqual(expectedResult);
    });
    it('updates the base API endpoint when provided', async () => {
        model = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            apiEndpoint: TEST_ENDPOINT_BASE_PATH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        await model.generateContent(req);
        expect(fetchSpy.calls.allArgs()[0][0].toString()).toContain(TEST_ENDPOINT_BASE_PATH);
    });
    it('default the base API endpoint when base API not provided', async () => {
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        await model.generateContent(req);
        expect(fetchSpy.calls.allArgs()[0][0].toString()).toContain(`${LOCATION}-aiplatform.googleapis.com`);
    });
    it('removes topK when it is set to 0', async () => {
        const reqWithEmptyConfigs = {
            contents: TEST_USER_CHAT_MESSAGE_WITH_GCS_FILE,
            generationConfig: { topK: 0 },
            safetySettings: [],
        };
        await model.generateContent(reqWithEmptyConfigs);
        const requestArgs = fetchSpy.calls.allArgs()[0][1];
        if (typeof requestArgs === 'object' && requestArgs) {
            expect(JSON.stringify(requestArgs['body'])).not.toContain('topK');
        }
    });
    it('includes topK when it is within 1 - 40', async () => {
        const reqWithEmptyConfigs = {
            contents: TEST_USER_CHAT_MESSAGE_WITH_GCS_FILE,
            generationConfig: { topK: 1 },
            safetySettings: [],
        };
        await model.generateContent(reqWithEmptyConfigs);
        const requestArgs = fetchSpy.calls.allArgs()[0][1];
        if (typeof requestArgs === 'object' && requestArgs) {
            expect(JSON.stringify(requestArgs['body'])).toContain('topK');
        }
    });
    it('includes responseMimeType', async () => {
        const reqWithEmptyConfigs = {
            contents: TEST_USER_CHAT_MESSAGE_WITH_GCS_FILE,
            generationConfig: { responseMimeType: 'application/json' },
            safetySettings: [],
        };
        const expectedRequestArgBody = '{"contents":[{"role":"user","parts":[{"text":"How are you doing today?"},{"fileData":{"fileUri":"gs://test_bucket/test_image.jpeg","mimeType":"image/jpeg"}}]}],"generationConfig":{"responseMimeType":"application/json"},"safetySettings":[]}';
        await model.generateContent(reqWithEmptyConfigs);
        const actualRequestArgsBody = fetchSpy.calls.allArgs()[0][1].body;
        expect(actualRequestArgsBody).toEqual(expectedRequestArgBody);
    });
    it('aggregates citation metadata', async () => {
        var _a;
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const resp = await model.generateContent(req);
        expect((_a = resp.response.candidates[0].citationMetadata) === null || _a === void 0 ? void 0 : _a.citations.length).toEqual(TEST_MODEL_RESPONSE.candidates[0].citationMetadata.citations.length);
    });
    it('returns a FunctionCall when passed a FunctionDeclaration', async () => {
        const req = {
            contents: [
                { role: 'user', parts: [{ text: 'What is the weater like in Boston?' }] },
            ],
            tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION,
        };
        const expectedResult = {
            response: TEST_MODEL_RESPONSE_WITH_FUNCTION_CALL,
        };
        spyOn(PostFetchFunctions, 'processUnary').and.resolveTo(expectedResult);
        const resp = await model.generateContent(req);
        expect(resp).toEqual(expectedResult);
    });
    it('pass tools to remote endpoint when tools are passed via constructor', async () => {
        model = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION,
        });
        const expectedBody = '{"contents":[{"role":"user","parts":[{"text":"How are you doing today?"}]}],"tools":[{"functionDeclarations":[{"name":"get_current_weather","description":"get weather in a given location","parameters":{"type":"OBJECT","properties":{"location":{"type":"STRING"},"unit":{"type":"STRING","enum":["celsius","fahrenheit"]}},"required":["location"]}}]}]}';
        await model.generateContent(TEST_CHAT_MESSSAGE_TEXT);
        // @ts-ignore
        const actualBody = fetchSpy.calls.allArgs()[0][1].body;
        expect(actualBody).toEqual(expectedBody);
    });
    it('pass tools to remote endpoint when tools are passed via generateContent', async () => {
        model = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION,
        });
        const req = {
            contents: [
                { role: 'user', parts: [{ text: 'What is the weater like in Boston?' }] },
            ],
            tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL,
        };
        const expectedBody = '{"contents":[{"role":"user","parts":[{"text":"What is the weater like in Boston?"}]}],"tools":[{"googleSearchRetrieval":{"dynamicRetrievalConfig":{"dynamicThreshold":0.5,"mode":"MODE_DYNAMIC"}}}]}';
        await model.generateContent(req);
        // @ts-ignore
        const actualBody = fetchSpy.calls.allArgs()[0][1].body;
        expect(actualBody).toEqual(expectedBody);
    });
});
describe('GenerativeModelPreview generateContent', () => {
    let model;
    let fetchSpy;
    let expectedResult;
    beforeEach(() => {
        model = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        expectedResult = TEST_MODEL_RESPONSE;
        const fetchResult = new Response(JSON.stringify(expectedResult), fetchResponseObj);
        fetchSpy = spyOn(global, 'fetch').and.resolveTo(fetchResult);
    });
    it('returns a GenerateContentResponse', async () => {
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const expectedResult = {
            response: TEST_MODEL_RESPONSE,
        };
        const resp = await model.generateContent(req);
        expect(resp).toEqual(expectedResult);
    });
    it('gemini-pro model send correct resourcePath to functions', async () => {
        const modelWithShortName = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent');
        const expectedResourcePath = 'projects/test_project/locations/test_location/publishers/google/models/gemini-pro';
        await modelWithShortName.generateContent(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
    });
    it('models/gemini-pro model send correct resourcePath to functions', async () => {
        const modelWithLongName = new generative_models_1.GenerativeModelPreview({
            model: 'models/gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent');
        const expectedResourcePath = 'projects/test_project/locations/test_location/publishers/google/models/gemini-pro';
        await modelWithLongName.generateContent(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
    });
    it('projects/my-project/my-tuned-gemini-pro model send correct resourcePath to functions', async () => {
        const modelWithFullName = new generative_models_1.GenerativeModelPreview({
            model: 'projects/my-project/my-tuned-gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent');
        const expectedResourcePath = 'projects/my-project/my-tuned-gemini-pro';
        await modelWithFullName.generateContent(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
    });
    it('empty model raise ClientError', () => {
        const expectedErrorMessage = '[VertexAI.ClientError]: model parameter must not be empty.';
        try {
            new generative_models_1.GenerativeModelPreview({
                model: '',
                project: PROJECT,
                location: LOCATION,
                googleAuth: FAKE_GOOGLE_AUTH,
            });
        }
        catch (e) {
            // @ts-ignore
            expect(e.message).toEqual(expectedErrorMessage);
        }
    });
    it('invalid model raise ClientError', () => {
        const expectedErrorMessage = '[VertexAI.ClientError]: model parameter must be either a Model Garden model ID or a full resource name.';
        try {
            new generative_models_1.GenerativeModelPreview({
                model: 'invalid/my-tuned-mode',
                project: PROJECT,
                location: LOCATION,
                googleAuth: FAKE_GOOGLE_AUTH,
            });
        }
        catch (e) {
            // @ts-ignore
            expect(e.message).toEqual(expectedErrorMessage);
        }
    });
    it('send timeout options to functions', async () => {
        const modelWithRequestOptions = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            requestOptions: TEST_REQUEST_OPTIONS,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent');
        await modelWithRequestOptions.generateContent(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][9].timeout).toEqual(0);
    });
    it('set system instruction in constructor, should send system instruction to functions', async () => {
        const modelWithSystemInstruction = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            systemInstruction: TEST_SYSTEM_INSTRUCTION,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent');
        const expectedRequest = {
            contents: [
                {
                    role: 'user',
                    parts: [
                        {
                            text: 'How are you doing today?',
                        },
                    ],
                },
            ],
            systemInstruction: {
                role: 'system',
                parts: [
                    {
                        text: 'system instruction',
                    },
                ],
            },
            cachedContent: undefined,
        };
        await modelWithSystemInstruction.generateContent(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][3]).toEqual(expectedRequest);
    });
    it('set system instruction in generateContent, should send system instruction to functions', async () => {
        const modelWithSystemInstruction = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
            systemInstruction: TEST_SYSTEM_INSTRUCTION,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent');
        const expectedRequest = {
            contents: [
                {
                    role: 'user',
                    parts: [
                        {
                            text: 'How are you doing today?',
                        },
                    ],
                },
            ],
            systemInstruction: {
                role: 'system',
                parts: [
                    {
                        text: 'system instruction',
                    },
                ],
            },
            cachedContent: undefined,
        };
        await modelWithSystemInstruction.generateContent(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][3]).toEqual(expectedRequest);
    });
    it('set system instruction in constructor, wrong role, should send system instruction to functions', async () => {
        const modelWithSystemInstruction = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            systemInstruction: TEST_SYSTEM_INSTRUCTION_WRONG_ROLE,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent');
        const expectedRequest = {
            contents: [
                {
                    role: 'user',
                    parts: [
                        {
                            text: 'How are you doing today?',
                        },
                    ],
                },
            ],
            systemInstruction: {
                role: 'system',
                parts: [
                    {
                        text: 'system instruction',
                    },
                ],
            },
            cachedContent: undefined,
        };
        await modelWithSystemInstruction.generateContent(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][3]).toEqual(expectedRequest);
    });
    it('set system instruction in generateContent, wrong role, should send system instruction to functions', async () => {
        const modelWithSystemInstruction = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
            systemInstruction: TEST_SYSTEM_INSTRUCTION_WRONG_ROLE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent');
        const expectedRequest = {
            contents: [
                {
                    role: 'user',
                    parts: [
                        {
                            text: 'How are you doing today?',
                        },
                    ],
                },
            ],
            systemInstruction: {
                role: 'system',
                parts: [
                    {
                        text: 'system instruction',
                    },
                ],
            },
            cachedContent: undefined,
        };
        await modelWithSystemInstruction.generateContent(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][3]).toEqual(expectedRequest);
    });
    it('returns a GenerateContentResponse when passed a string', async () => {
        const expectedResult = {
            response: TEST_MODEL_RESPONSE,
        };
        const resp = await model.generateContent(TEST_CHAT_MESSSAGE_TEXT);
        expect(resp).toEqual(expectedResult);
    });
    it('returns a GenerateContentResponse when passed a GCS URI', async () => {
        const req = {
            contents: TEST_USER_CHAT_MESSAGE_WITH_GCS_FILE,
        };
        const expectedResult = {
            response: TEST_MODEL_RESPONSE,
        };
        const resp = await model.generateContent(req);
        expect(resp).toEqual(expectedResult);
    });
    it('returns a GenerateContentResponse when passed safetySettings and generationConfig', async () => {
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
            safetySettings: TEST_SAFETY_SETTINGS,
            generationConfig: TEST_GENERATION_CONFIG,
        };
        const expectedResult = {
            response: TEST_MODEL_RESPONSE,
        };
        const resp = await model.generateContent(req);
        expect(resp).toEqual(expectedResult);
    });
    it('updates the base API endpoint when provided', async () => {
        model = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            apiEndpoint: TEST_ENDPOINT_BASE_PATH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        await model.generateContent(req);
        expect(fetchSpy.calls.allArgs()[0][0].toString()).toContain(TEST_ENDPOINT_BASE_PATH);
    });
    it('default the base API endpoint when base API not provided', async () => {
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        await model.generateContent(req);
        expect(fetchSpy.calls.allArgs()[0][0].toString()).toContain(`${LOCATION}-aiplatform.googleapis.com`);
    });
    it('removes topK when it is set to 0', async () => {
        const reqWithEmptyConfigs = {
            contents: TEST_USER_CHAT_MESSAGE_WITH_GCS_FILE,
            generationConfig: { topK: 0 },
            safetySettings: [],
        };
        await model.generateContent(reqWithEmptyConfigs);
        const requestArgs = fetchSpy.calls.allArgs()[0][1];
        if (typeof requestArgs === 'object' && requestArgs) {
            expect(JSON.stringify(requestArgs['body'])).not.toContain('topK');
        }
    });
    it('includes topK when it is within 1 - 40', async () => {
        const reqWithEmptyConfigs = {
            contents: TEST_USER_CHAT_MESSAGE_WITH_GCS_FILE,
            generationConfig: { topK: 1 },
            safetySettings: [],
        };
        await model.generateContent(reqWithEmptyConfigs);
        const requestArgs = fetchSpy.calls.allArgs()[0][1];
        if (typeof requestArgs === 'object' && requestArgs) {
            expect(JSON.stringify(requestArgs['body'])).toContain('topK');
        }
    });
    it('includes responseMimeType', async () => {
        const reqWithEmptyConfigs = {
            contents: TEST_USER_CHAT_MESSAGE_WITH_GCS_FILE,
            generationConfig: { responseMimeType: 'application/json' },
            safetySettings: [],
        };
        const expectedRequestArgsBody = '{"contents":[{"role":"user","parts":[{"text":"How are you doing today?"},{"fileData":{"fileUri":"gs://test_bucket/test_image.jpeg","mimeType":"image/jpeg"}}]}],"generationConfig":{"responseMimeType":"application/json"},"safetySettings":[]}';
        await model.generateContent(reqWithEmptyConfigs);
        const actualRequestArgsBody = fetchSpy.calls.allArgs()[0][1].body;
        expect(actualRequestArgsBody).toEqual(expectedRequestArgsBody);
    });
    it('aggregates citation metadata', async () => {
        var _a;
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const resp = await model.generateContent(req);
        expect((_a = resp.response.candidates[0].citationMetadata) === null || _a === void 0 ? void 0 : _a.citations.length).toEqual(TEST_MODEL_RESPONSE.candidates[0].citationMetadata.citations.length);
    });
    it('returns a FunctionCall when passed a FunctionDeclaration', async () => {
        const req = {
            contents: [
                { role: 'user', parts: [{ text: 'What is the weater like in Boston?' }] },
            ],
            tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION,
        };
        const expectedResult = {
            response: TEST_MODEL_RESPONSE_WITH_FUNCTION_CALL,
        };
        spyOn(PostFetchFunctions, 'processUnary').and.resolveTo(expectedResult);
        const resp = await model.generateContent(req);
        expect(resp).toEqual(expectedResult);
    });
    it('in preview, pass tools to remote endpoint when tools are passed via constructor', async () => {
        model = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION,
        });
        const expectedBody = '{"contents":[{"role":"user","parts":[{"text":"How are you doing today?"}]}],"tools":[{"functionDeclarations":[{"name":"get_current_weather","description":"get weather in a given location","parameters":{"type":"OBJECT","properties":{"location":{"type":"STRING"},"unit":{"type":"STRING","enum":["celsius","fahrenheit"]}},"required":["location"]}}]}]}';
        await model.generateContent(TEST_CHAT_MESSSAGE_TEXT);
        const actualBody = fetchSpy.calls.allArgs()[0][1].body;
        expect(actualBody).toEqual(expectedBody);
    });
    it('in preview, pass tools to remote endpoint when tools are passed via generateContent', async () => {
        model = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION,
        });
        const req = {
            contents: [
                { role: 'user', parts: [{ text: 'What is the weater like in Boston?' }] },
            ],
            tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL,
        };
        const expectedBody = '{"contents":[{"role":"user","parts":[{"text":"What is the weater like in Boston?"}]}],"tools":[{"googleSearchRetrieval":{"dynamicRetrievalConfig":{"dynamicThreshold":0.5,"mode":"MODE_DYNAMIC"}}}]}';
        await model.generateContent(req);
        // @ts-ignore
        const actualBody = fetchSpy.calls.allArgs()[0][1].body;
        expect(actualBody).toEqual(expectedBody);
    });
});
describe('GenerativeModel generateContentStream', () => {
    let model;
    let expectedStreamResult;
    let fetchSpy;
    beforeEach(() => {
        model = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        expectedStreamResult = {
            response: Promise.resolve(TEST_MODEL_RESPONSE),
            stream: testGenerator(),
        };
        const fetchResult = new Response(JSON.stringify(expectedStreamResult), fetchResponseObj);
        fetchSpy = spyOn(global, 'fetch').and.resolveTo(fetchResult);
    });
    it('returns a GenerateContentResponse when passed text content', async () => {
        const req = { contents: TEST_USER_CHAT_MESSAGE };
        const expectedResult = {
            response: Promise.resolve(TEST_MODEL_RESPONSE),
            stream: testGeneratorMultiStream(),
        };
        spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult);
        const resp = await model.generateContentStream(req);
        let firstChunkTimestamp = 0;
        for await (const item of resp.stream) {
            if (firstChunkTimestamp === 0) {
                firstChunkTimestamp = Date.now();
            }
        }
        expect(Date.now() - firstChunkTimestamp).toBeGreaterThanOrEqual(200 - DATE_NOW_PRECISION_MILLIS);
    });
    it('gemini-pro model send correct resourcePath to functions', async () => {
        const modelWithShortName = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContentStream');
        const expectedResourcePath = 'projects/test_project/locations/test_location/publishers/google/models/gemini-pro';
        await modelWithShortName.generateContentStream(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
    });
    it('models/gemini-pro model send correct resourcePath to functions', async () => {
        const modelWithLongName = new generative_models_1.GenerativeModel({
            model: 'models/gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContentStream');
        const expectedResourcePath = 'projects/test_project/locations/test_location/publishers/google/models/gemini-pro';
        await modelWithLongName.generateContentStream(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
    });
    it('projects/my-project/my-tuned-gemini-pro model send correct resourcePath to functions', async () => {
        const modelWithFullName = new generative_models_1.GenerativeModel({
            model: 'projects/my-project/my-tuned-gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContentStream');
        const expectedResourcePath = 'projects/my-project/my-tuned-gemini-pro';
        await modelWithFullName.generateContentStream(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
    });
    it('send timeout options to functions', async () => {
        const modelWithRequestOptions = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            requestOptions: TEST_REQUEST_OPTIONS,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContentStream');
        await modelWithRequestOptions.generateContentStream(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][9].timeout).toEqual(0);
    });
    it('set system instruction in generateContent, should send system instruction to functions', async () => {
        const modelWithSystemInstruction = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
            systemInstruction: TEST_SYSTEM_INSTRUCTION,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContentStream');
        const expectedRequest = {
            contents: [
                {
                    role: 'user',
                    parts: [
                        {
                            text: 'How are you doing today?',
                        },
                    ],
                },
            ],
            systemInstruction: {
                role: 'system',
                parts: [
                    {
                        text: 'system instruction',
                    },
                ],
            },
        };
        await modelWithSystemInstruction.generateContentStream(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][3]).toEqual(expectedRequest);
    });
    it('set system instruction in generateContent, wrong role, should send system instruction to functions', async () => {
        const modelWithSystemInstruction = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
            systemInstruction: TEST_SYSTEM_INSTRUCTION_WRONG_ROLE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContentStream');
        const expectedRequest = {
            contents: [
                {
                    role: 'user',
                    parts: [
                        {
                            text: 'How are you doing today?',
                        },
                    ],
                },
            ],
            systemInstruction: {
                role: 'system',
                parts: [
                    {
                        text: 'system instruction',
                    },
                ],
            },
        };
        await modelWithSystemInstruction.generateContentStream(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][3]).toEqual(expectedRequest);
    });
    it('returns a GenerateContentResponse when passed a string', async () => {
        const expectedResult = {
            response: Promise.resolve(TEST_MODEL_RESPONSE),
            stream: testGenerator(),
        };
        spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult);
        const resp = await model.generateContentStream(TEST_CHAT_MESSSAGE_TEXT);
        expect(resp).toEqual(expectedResult);
    });
    it('returns a GenerateContentResponse when passed multi-part content with a GCS URI', async () => {
        const req = {
            contents: TEST_MULTIPART_MESSAGE,
        };
        const expectedResult = {
            response: Promise.resolve(TEST_MODEL_RESPONSE),
            stream: testGenerator(),
        };
        spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult);
        const resp = await model.generateContentStream(req);
        expect(resp).toEqual(expectedResult);
    });
    it('returns a GenerateContentResponse when passed multi-part content with base64 data', async () => {
        const req = {
            contents: TEST_MULTIPART_MESSAGE_BASE64,
        };
        const expectedResult = {
            response: Promise.resolve(TEST_MODEL_RESPONSE),
            stream: testGenerator(),
        };
        spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult);
        const resp = await model.generateContentStream(req);
        expect(resp).toEqual(expectedResult);
    });
    it('returns a FunctionCall when passed a FunctionDeclaration', async () => {
        const req = {
            contents: [
                { role: 'user', parts: [{ text: 'What is the weater like in Boston?' }] },
            ],
            tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION,
        };
        const expectedStreamResult = {
            response: Promise.resolve(TEST_MODEL_RESPONSE_WITH_FUNCTION_CALL),
            stream: testGenerator(),
        };
        spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedStreamResult);
        const resp = await model.generateContentStream(req);
        expect(resp).toEqual(expectedStreamResult);
    });
    it('pass tools to remote endpoint when tools are passed via constructor', async () => {
        model = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION,
        });
        const expectedResult = {
            response: Promise.resolve(TEST_MODEL_RESPONSE_WITH_FUNCTION_CALL),
            stream: testGenerator(),
        };
        spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult);
        const expectedBody = '{"contents":[{"role":"user","parts":[{"text":"How are you doing today?"}]}],"tools":[{"functionDeclarations":[{"name":"get_current_weather","description":"get weather in a given location","parameters":{"type":"OBJECT","properties":{"location":{"type":"STRING"},"unit":{"type":"STRING","enum":["celsius","fahrenheit"]}},"required":["location"]}}]}]}';
        await model.generateContentStream(TEST_CHAT_MESSSAGE_TEXT);
        // @ts-ignore
        const actualBody = fetchSpy.calls.allArgs()[0][1].body;
        expect(actualBody).toEqual(expectedBody);
    });
    it('pass tools to remote endpoint when tools are passed via generateContent', async () => {
        model = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION,
        });
        const expectedResult = {
            response: Promise.resolve(TEST_MODEL_RESPONSE_WITH_FUNCTION_CALL),
            stream: testGenerator(),
        };
        const req = {
            contents: [
                { role: 'user', parts: [{ text: 'What is the weater like in Boston?' }] },
            ],
            tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL,
        };
        spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult);
        const expectedBody = '{"contents":[{"role":"user","parts":[{"text":"What is the weater like in Boston?"}]}],"tools":[{"googleSearchRetrieval":{"dynamicRetrievalConfig":{"dynamicThreshold":0.5,"mode":"MODE_DYNAMIC"}}}]}';
        await model.generateContent(req);
        // @ts-ignore
        const actualBody = fetchSpy.calls.allArgs()[0][1].body;
        expect(actualBody).toEqual(expectedBody);
    });
});
describe('GenerativeModelPreview generateContentStream', () => {
    let model;
    let expectedStreamResult;
    let fetchSpy;
    beforeEach(() => {
        model = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        expectedStreamResult = {
            response: Promise.resolve(TEST_MODEL_RESPONSE),
            stream: testGenerator(),
        };
        const fetchResult = new Response(JSON.stringify(expectedStreamResult), fetchResponseObj);
        fetchSpy = spyOn(global, 'fetch').and.resolveTo(fetchResult);
    });
    it('returns a GenerateContentResponse when passed text content', async () => {
        const req = { contents: TEST_USER_CHAT_MESSAGE };
        const expectedResult = {
            response: Promise.resolve(TEST_MODEL_RESPONSE),
            stream: testGenerator(),
        };
        spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult);
        const resp = await model.generateContentStream(req);
        expect(resp).toEqual(expectedResult);
    });
    it('returns a GenerateContentResponse when passed text content', async () => {
        const req = { contents: TEST_USER_CHAT_MESSAGE };
        const expectedResult = {
            response: Promise.resolve(TEST_MODEL_RESPONSE),
            stream: testGeneratorMultiStream(),
        };
        spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult);
        const resp = await model.generateContentStream(req);
        let firstChunkTimestamp = 0;
        for await (const item of resp.stream) {
            if (firstChunkTimestamp === 0) {
                firstChunkTimestamp = Date.now();
            }
        }
        expect(Date.now() - firstChunkTimestamp).toBeGreaterThanOrEqual(200 - DATE_NOW_PRECISION_MILLIS);
    });
    it('gemini-pro model send correct resourcePath to functions', async () => {
        const modelWithShortName = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContentStream');
        const expectedResourcePath = 'projects/test_project/locations/test_location/publishers/google/models/gemini-pro';
        await modelWithShortName.generateContentStream(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
    });
    it('models/gemini-pro model send correct resourcePath to functions', async () => {
        const modelWithLongName = new generative_models_1.GenerativeModelPreview({
            model: 'models/gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContentStream');
        const expectedResourcePath = 'projects/test_project/locations/test_location/publishers/google/models/gemini-pro';
        await modelWithLongName.generateContentStream(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
    });
    it('projects/my-project/my-tuned-gemini-pro model send correct resourcePath to functions', async () => {
        const modelWithFullName = new generative_models_1.GenerativeModelPreview({
            model: 'projects/my-project/my-tuned-gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContentStream');
        const expectedResourcePath = 'projects/my-project/my-tuned-gemini-pro';
        await modelWithFullName.generateContentStream(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
    });
    it('send timeout options to functions', async () => {
        const modelWithRequestOptions = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            requestOptions: TEST_REQUEST_OPTIONS,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContentStream');
        await modelWithRequestOptions.generateContentStream(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][9].timeout).toEqual(0);
    });
    it('set system instruction in generateContent, should send system instruction to functions', async () => {
        const modelWithSystemInstruction = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
            systemInstruction: TEST_SYSTEM_INSTRUCTION,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContentStream');
        const expectedRequest = {
            contents: [
                {
                    role: 'user',
                    parts: [
                        {
                            text: 'How are you doing today?',
                        },
                    ],
                },
            ],
            systemInstruction: {
                role: 'system',
                parts: [
                    {
                        text: 'system instruction',
                    },
                ],
            },
            cachedContent: undefined,
        };
        await modelWithSystemInstruction.generateContentStream(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][3]).toEqual(expectedRequest);
    });
    it('set system instruction in generateContent, wrong role, should send system instruction to functions', async () => {
        const modelWithSystemInstruction = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
            systemInstruction: TEST_SYSTEM_INSTRUCTION_WRONG_ROLE,
        };
        const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContentStream');
        const expectedRequest = {
            contents: [
                {
                    role: 'user',
                    parts: [
                        {
                            text: 'How are you doing today?',
                        },
                    ],
                },
            ],
            systemInstruction: {
                role: 'system',
                parts: [
                    {
                        text: 'system instruction',
                    },
                ],
            },
            cachedContent: undefined,
        };
        await modelWithSystemInstruction.generateContentStream(req);
        // @ts-ignore
        expect(generateContentSpy.calls.allArgs()[0][3]).toEqual(expectedRequest);
    });
    it('returns a GenerateContentResponse when passed a string', async () => {
        const expectedResult = {
            response: Promise.resolve(TEST_MODEL_RESPONSE),
            stream: testGenerator(),
        };
        spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult);
        const resp = await model.generateContentStream(TEST_CHAT_MESSSAGE_TEXT);
        expect(resp).toEqual(expectedResult);
    });
    it('returns a GenerateContentResponse when passed multi-part content with a GCS URI', async () => {
        const req = {
            contents: TEST_MULTIPART_MESSAGE,
        };
        const expectedResult = {
            response: Promise.resolve(TEST_MODEL_RESPONSE),
            stream: testGenerator(),
        };
        spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult);
        const resp = await model.generateContentStream(req);
        expect(resp).toEqual(expectedResult);
    });
    it('returns a GenerateContentResponse when passed multi-part content with base64 data', async () => {
        const req = {
            contents: TEST_MULTIPART_MESSAGE_BASE64,
        };
        const expectedResult = {
            response: Promise.resolve(TEST_MODEL_RESPONSE),
            stream: testGenerator(),
        };
        spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult);
        const resp = await model.generateContentStream(req);
        expect(resp).toEqual(expectedResult);
    });
    it('returns a FunctionCall when passed a FunctionDeclaration', async () => {
        const req = {
            contents: [
                { role: 'user', parts: [{ text: 'What is the weater like in Boston?' }] },
            ],
            tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION,
        };
        const expectedStreamResult = {
            response: Promise.resolve(TEST_MODEL_RESPONSE_WITH_FUNCTION_CALL),
            stream: testGenerator(),
        };
        spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedStreamResult);
        const resp = await model.generateContentStream(req);
        expect(resp).toEqual(expectedStreamResult);
    });
    it('in preivew, pass tools to remote endpoint when tools are passed via constructor', async () => {
        model = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION,
        });
        const expectedResult = {
            response: Promise.resolve(TEST_MODEL_RESPONSE_WITH_FUNCTION_CALL),
            stream: testGenerator(),
        };
        spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult);
        const expectedBody = '{"contents":[{"role":"user","parts":[{"text":"How are you doing today?"}]}],"tools":[{"functionDeclarations":[{"name":"get_current_weather","description":"get weather in a given location","parameters":{"type":"OBJECT","properties":{"location":{"type":"STRING"},"unit":{"type":"STRING","enum":["celsius","fahrenheit"]}},"required":["location"]}}]}]}';
        await model.generateContentStream(TEST_CHAT_MESSSAGE_TEXT);
        // @ts-ignore
        const actualBody = fetchSpy.calls.allArgs()[0][1].body;
        expect(actualBody).toEqual(expectedBody);
    });
    it('in preview, pass tools to remote endpoint when tools are passed via generateContent', async () => {
        model = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION,
        });
        const expectedResult = {
            response: Promise.resolve(TEST_MODEL_RESPONSE_WITH_FUNCTION_CALL),
            stream: testGenerator(),
        };
        const req = {
            contents: [
                { role: 'user', parts: [{ text: 'What is the weater like in Boston?' }] },
            ],
            tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL,
        };
        spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult);
        const expectedBody = '{"contents":[{"role":"user","parts":[{"text":"What is the weater like in Boston?"}]}],"tools":[{"googleSearchRetrieval":{"dynamicRetrievalConfig":{"dynamicThreshold":0.5,"mode":"MODE_DYNAMIC"}}}]}';
        await model.generateContent(req);
        // @ts-ignore
        const actualBody = fetchSpy.calls.allArgs()[0][1].body;
        expect(actualBody).toEqual(expectedBody);
    });
});
describe('ChatSession', () => {
    let chatSession;
    let chatSessionWithNoArgs;
    let chatSessionWithFunctionCall;
    let model;
    beforeEach(async () => {
        model = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        chatSession = model.startChat({
            history: TEST_USER_CHAT_MESSAGE,
        });
        expect(await chatSession.getHistory()).toEqual(TEST_USER_CHAT_MESSAGE);
        chatSessionWithNoArgs = model.startChat();
        chatSessionWithFunctionCall = model.startChat({
            tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION,
        });
    });
    describe('sendMessage', () => {
        let fetchSpy;
        const expectedResponse = TEST_MODEL_RESPONSE;
        const fetchResult = Promise.resolve(new Response(JSON.stringify(expectedResponse), fetchResponseObj));
        beforeEach(() => {
            fetchSpy = spyOn(global, 'fetch').and.returnValue(fetchResult);
        });
        it('returns a GenerateContentResponse and appends to history', async () => {
            const req = 'How are you doing today?';
            const expectedResult = {
                response: TEST_MODEL_RESPONSE,
            };
            const resp = await chatSession.sendMessage(req);
            expect(resp).toEqual(expectedResult);
            expect((await chatSession.getHistory()).length).toEqual(3);
        });
        it('gemini-pro model send correct resourcePath to functions', async () => {
            const modelWithShortName = new generative_models_1.GenerativeModel({
                model: 'gemini-pro',
                project: PROJECT,
                location: LOCATION,
                googleAuth: FAKE_GOOGLE_AUTH,
            });
            const chatSessionWithShortName = modelWithShortName.startChat();
            const req = TEST_CHAT_MESSSAGE_TEXT;
            const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent').and.callThrough();
            const expectedResult = {
                response: TEST_MODEL_RESPONSE,
            };
            spyOn(PostFetchFunctions, 'processUnary').and.resolveTo(expectedResult);
            const expectedResourcePath = 'projects/test_project/locations/test_location/publishers/google/models/gemini-pro';
            await chatSessionWithShortName.sendMessage(req);
            // @ts-ignore
            expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
        });
        it('models/gemini-pro model send correct resourcePath to functions', async () => {
            const modelWithLongName = new generative_models_1.GenerativeModel({
                model: 'models/gemini-pro',
                project: PROJECT,
                location: LOCATION,
                googleAuth: FAKE_GOOGLE_AUTH,
            });
            const chatSessionWithLongName = modelWithLongName.startChat();
            const req = TEST_CHAT_MESSSAGE_TEXT;
            const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent').and.callThrough();
            const expectedResult = {
                response: TEST_MODEL_RESPONSE,
            };
            spyOn(PostFetchFunctions, 'processUnary').and.resolveTo(expectedResult);
            const expectedResourcePath = 'projects/test_project/locations/test_location/publishers/google/models/gemini-pro';
            await chatSessionWithLongName.sendMessage(req);
            // @ts-ignore
            expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
        });
        it('projects/my-project/my-tuned-gemini-pro model send correct resourcePath to functions', async () => {
            const modelWithFullName = new generative_models_1.GenerativeModel({
                model: 'projects/my-project/my-tuned-gemini-pro',
                project: PROJECT,
                location: LOCATION,
                googleAuth: FAKE_GOOGLE_AUTH,
            });
            const chatSessionWithFullName = modelWithFullName.startChat();
            const req = TEST_CHAT_MESSSAGE_TEXT;
            const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent').and.callThrough();
            const expectedResult = {
                response: TEST_MODEL_RESPONSE,
            };
            spyOn(PostFetchFunctions, 'processUnary').and.resolveTo(expectedResult);
            const expectedResourcePath = 'projects/my-project/my-tuned-gemini-pro';
            await chatSessionWithFullName.sendMessage(req);
            // @ts-ignore
            expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
        });
        it('send a message body with the responseMimeType property to functions', async () => {
            const expectedResult = {
                response: TEST_MODEL_RESPONSE,
            };
            const model = new generative_models_1.GenerativeModel({
                model: 'gemini-pro',
                project: PROJECT,
                location: LOCATION,
                googleAuth: FAKE_GOOGLE_AUTH,
            });
            const chat = model.startChat({
                generationConfig: {
                    ...TEST_GENERATION_CONFIG,
                    responseMimeType: 'application/json',
                },
            });
            const req = 'How are you doing today?';
            const expectedBody = '{"contents":[{"role":"user","parts":[{"text":"How are you doing today?"}]}],"generationConfig":{"candidateCount":1,"stopSequences":["hello"],"responseMimeType":"application/json"}}';
            spyOn(PostFetchFunctions, 'processUnary').and.resolveTo(expectedResult);
            await chat.sendMessage(req);
            const actualBody = fetchSpy.calls.allArgs()[0][1].body;
            expect(actualBody).toEqual(expectedBody);
        });
        it('send timeout to functions', async () => {
            const modelWithRequestOptions = new generative_models_1.GenerativeModel({
                model: 'gemini-pro',
                project: PROJECT,
                location: LOCATION,
                googleAuth: FAKE_GOOGLE_AUTH,
                requestOptions: TEST_REQUEST_OPTIONS,
            });
            const chatSessionWithRequestOptions = modelWithRequestOptions.startChat({
                history: TEST_USER_CHAT_MESSAGE,
            });
            const req = 'How are you doing today?';
            const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent').and.resolveTo({
                response: TEST_MODEL_RESPONSE,
            });
            await chatSessionWithRequestOptions.sendMessage(req);
            expect(chatSessionWithRequestOptions.requestOptions).toEqual(TEST_REQUEST_OPTIONS);
            expect(generateContentSpy.calls.allArgs()[0][9].timeout).toEqual(0);
        });
        it('returns a GenerateContentResponse and appends to history when startChat is passed with no args', async () => {
            const req = 'How are you doing today?';
            const expectedResult = {
                response: TEST_MODEL_RESPONSE,
            };
            spyOn(PostFetchFunctions, 'processUnary').and.resolveTo(expectedResult);
            const resp = await chatSessionWithNoArgs.sendMessage(req);
            expect(resp).toEqual(expectedResult);
            expect((await chatSessionWithNoArgs.getHistory()).length).toEqual(2);
        });
        it('returns a GenerateContentResponse when passed multi-part content', async () => {
            const req = TEST_MULTIPART_MESSAGE[0]['parts'];
            const expectedResult = {
                response: TEST_MODEL_RESPONSE,
            };
            spyOn(PostFetchFunctions, 'processUnary').and.resolveTo(expectedResult);
            const resp = await chatSessionWithNoArgs.sendMessage(req);
            expect(resp).toEqual(expectedResult);
            expect((await chatSessionWithNoArgs.getHistory()).length).toEqual(2);
        });
        it('returns a FunctionCall and appends to history when passed a FunctionDeclaration', async () => {
            const functionCallChatMessage = 'What is the weather in LA?';
            const expectedFunctionCallResponse = {
                response: TEST_MODEL_RESPONSE_WITH_FUNCTION_CALL,
            };
            const expectedResult = {
                response: TEST_MODEL_RESPONSE_WITH_FUNCTION_CALL,
            };
            const streamSpy = spyOn(PostFetchFunctions, 'processUnary');
            streamSpy.and.resolveTo(expectedResult);
            const response1 = await chatSessionWithFunctionCall.sendMessage(functionCallChatMessage);
            expect(response1).toEqual(expectedFunctionCallResponse);
            expect((await chatSessionWithFunctionCall.getHistory()).length).toEqual(2);
            // Send a follow-up message with a FunctionResponse
            const expectedFollowUpResponse = {
                response: TEST_MODEL_RESPONSE,
            };
            const expectedFollowUpResult = {
                response: TEST_MODEL_RESPONSE,
            };
            streamSpy.and.resolveTo(expectedFollowUpResult);
            const response2 = await chatSessionWithFunctionCall.sendMessage(TEST_FUNCTION_RESPONSE_PART);
            expect(response2).toEqual(expectedFollowUpResponse);
            expect((await chatSessionWithFunctionCall.getHistory()).length).toEqual(4);
        });
        it('throw ClientError when request has no content', async () => {
            const expectedErrorMessage = '[VertexAI.ClientError]: No content is provided for sending chat message.';
            await chatSessionWithNoArgs.sendMessage([]).catch(e => {
                expect(e.message).toEqual(expectedErrorMessage);
            });
        });
        it('throw ClientError when request mix functionCall part with other types of part', async () => {
            const chatRequest = [
                'what is the weather like in LA',
                TEST_FUNCTION_RESPONSE_PART[0],
            ];
            const expectedErrorMessage = '[VertexAI.ClientError]: Within a single message, FunctionResponse cannot be mixed with other type of part in the request for sending chat message.';
            await chatSessionWithNoArgs.sendMessage(chatRequest).catch(e => {
                expect(e.message).toEqual(expectedErrorMessage);
            });
        });
    });
    describe('sendMessageStream', () => {
        const expectedStreamResult = {
            response: Promise.resolve(TEST_MODEL_RESPONSE),
            stream: testGenerator(),
        };
        const fetchResult = Promise.resolve(new Response(JSON.stringify(expectedStreamResult), fetchResponseObj));
        beforeEach(() => {
            spyOn(global, 'fetch').and.returnValue(fetchResult);
        });
        it('returns a StreamGenerateContentResponse and appends to history', async () => {
            const req = 'How are you doing today?';
            const expectedResult = {
                response: Promise.resolve(TEST_MODEL_RESPONSE),
                stream: testGenerator(),
            };
            const chatSession = model.startChat({
                history: [
                    {
                        role: util_1.constants.USER_ROLE,
                        parts: [{ text: 'How are you doing today?' }],
                    },
                ],
            });
            spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult);
            const history = await chatSession.getHistory();
            expect(history.length).toEqual(1);
            expect(history[0].role).toEqual(util_1.constants.USER_ROLE);
            const result = await chatSession.sendMessageStream(req);
            const response = await result.response;
            const expectedResponse = await expectedResult.response;
            const secondHistory = await chatSession.getHistory();
            expect(response).toEqual(expectedResponse);
            expect(secondHistory.length).toEqual(3);
            expect(secondHistory[0].role).toEqual(util_1.constants.USER_ROLE);
            expect(secondHistory[1].role).toEqual(util_1.constants.USER_ROLE);
            expect(secondHistory[2].role).toEqual(util_1.constants.MODEL_ROLE);
        });
        it('returns a StreamGenerateContentResponse in streaming mode', async () => {
            const req = 'How are you doing today?';
            const expectedResult = {
                response: Promise.resolve(TEST_MODEL_RESPONSE),
                stream: testGeneratorMultiStream(),
            };
            spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult);
            const chatSession = model.startChat({
                history: [
                    {
                        role: util_1.constants.USER_ROLE,
                        parts: [{ text: 'How are you doing today?' }],
                    },
                ],
            });
            const resp = await chatSession.sendMessageStream(req);
            let firstChunkTimestamp = 0;
            for await (const item of resp.stream) {
                if (firstChunkTimestamp === 0) {
                    firstChunkTimestamp = Date.now();
                }
            }
            expect(Date.now() - firstChunkTimestamp).toBeGreaterThanOrEqual(200 - DATE_NOW_PRECISION_MILLIS);
        });
        it('gemini-pro model send correct resourcePath to functions', async () => {
            const modelWithShortName = new generative_models_1.GenerativeModel({
                model: 'gemini-pro',
                project: PROJECT,
                location: LOCATION,
                googleAuth: FAKE_GOOGLE_AUTH,
            });
            const chatSessionWithShortName = modelWithShortName.startChat();
            const req = TEST_CHAT_MESSSAGE_TEXT;
            const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContentStream').and.callThrough();
            const expectedResult = {
                response: Promise.resolve(TEST_MODEL_RESPONSE),
                stream: testGeneratorMultiStream(),
            };
            spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult);
            const expectedResourcePath = 'projects/test_project/locations/test_location/publishers/google/models/gemini-pro';
            await chatSessionWithShortName.sendMessageStream(req);
            // @ts-ignore
            expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
        });
        it('models/gemini-pro model send correct resourcePath to functions', async () => {
            const modelWithLongName = new generative_models_1.GenerativeModel({
                model: 'models/gemini-pro',
                project: PROJECT,
                location: LOCATION,
                googleAuth: FAKE_GOOGLE_AUTH,
            });
            const chatSessionWithLongName = modelWithLongName.startChat();
            const req = TEST_CHAT_MESSSAGE_TEXT;
            const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContentStream').and.callThrough();
            const expectedResult = {
                response: Promise.resolve(TEST_MODEL_RESPONSE),
                stream: testGeneratorMultiStream(),
            };
            spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult);
            const expectedResourcePath = 'projects/test_project/locations/test_location/publishers/google/models/gemini-pro';
            await chatSessionWithLongName.sendMessageStream(req);
            // @ts-ignore
            expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
        });
        it('projects/my-project/my-tuned-gemini-pro model send correct resourcePath to functions', async () => {
            const modelWithFullName = new generative_models_1.GenerativeModel({
                model: 'projects/my-project/my-tuned-gemini-pro',
                project: PROJECT,
                location: LOCATION,
                googleAuth: FAKE_GOOGLE_AUTH,
            });
            const chatSessionWithFullName = modelWithFullName.startChat();
            const req = TEST_CHAT_MESSSAGE_TEXT;
            const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContentStream').and.callThrough();
            const expectedResult = {
                response: Promise.resolve(TEST_MODEL_RESPONSE),
                stream: testGeneratorMultiStream(),
            };
            spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult);
            const expectedResourcePath = 'projects/my-project/my-tuned-gemini-pro';
            await chatSessionWithFullName.sendMessageStream(req);
            // @ts-ignore
            expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
        });
        it('send timeout to functions', async () => {
            const modelWithRequestOptions = new generative_models_1.GenerativeModel({
                model: 'gemini-pro',
                project: PROJECT,
                location: LOCATION,
                googleAuth: FAKE_GOOGLE_AUTH,
                requestOptions: TEST_REQUEST_OPTIONS,
            });
            const chatSessionWithRequestOptions = modelWithRequestOptions.startChat({
                history: TEST_USER_CHAT_MESSAGE,
            });
            const req = 'How are you doing today?';
            const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContentStream').and.resolveTo({
                response: Promise.resolve(TEST_MODEL_RESPONSE),
                stream: testGenerator(),
            });
            await chatSessionWithRequestOptions.sendMessageStream(req);
            expect(chatSessionWithRequestOptions.requestOptions).toEqual(TEST_REQUEST_OPTIONS);
            expect(generateContentSpy.calls.allArgs()[0][9].timeout).toEqual(0);
        });
        it('returns a FunctionCall and appends to history when passed a FunctionDeclaration', async () => {
            const functionCallChatMessage = 'What is the weather in LA?';
            const expectedStreamResult = {
                response: Promise.resolve(TEST_MODEL_RESPONSE_WITH_FUNCTION_CALL),
                stream: testGenerator(),
            };
            const streamSpy = spyOn(PostFetchFunctions, 'processStream');
            streamSpy.and.resolveTo(expectedStreamResult);
            const response1 = await chatSessionWithFunctionCall.sendMessageStream(functionCallChatMessage);
            expect(response1).toEqual(expectedStreamResult);
            expect((await chatSessionWithFunctionCall.getHistory()).length).toEqual(2);
            // Send a follow-up message with a FunctionResponse
            const expectedFollowUpStreamResult = {
                response: Promise.resolve(TEST_MODEL_RESPONSE),
                stream: testGenerator(),
            };
            streamSpy.and.resolveTo(expectedFollowUpStreamResult);
            const response2 = await chatSessionWithFunctionCall.sendMessageStream(TEST_FUNCTION_RESPONSE_PART);
            expect(response2).toEqual(expectedFollowUpStreamResult);
            expect((await chatSessionWithFunctionCall.getHistory()).length).toEqual(4);
        });
        it('throw ClientError when request has no content', async () => {
            const expectedErrorMessage = '[VertexAI.ClientError]: No content is provided for sending chat message.';
            await chatSessionWithNoArgs.sendMessageStream([]).catch(e => {
                expect(e.message).toEqual(expectedErrorMessage);
            });
        });
        it('throw ClientError when request mix functionCall part with other types of part', async () => {
            const chatRequest = [
                'what is the weather like in LA',
                TEST_FUNCTION_RESPONSE_PART[0],
            ];
            const expectedErrorMessage = '[VertexAI.ClientError]: Within a single message, FunctionResponse cannot be mixed with other type of part in the request for sending chat message.';
            await chatSessionWithNoArgs.sendMessageStream(chatRequest).catch(e => {
                expect(e.message).toEqual(expectedErrorMessage);
            });
        });
    });
});
describe('ChatSessionPreview', () => {
    let chatSession;
    let chatSessionWithNoArgs;
    let chatSessionWithFunctionCall;
    let model;
    let expectedStreamResult;
    let fetchSpy;
    beforeEach(async () => {
        model = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        chatSession = model.startChat({
            history: TEST_USER_CHAT_MESSAGE,
        });
        expect(await chatSession.getHistory()).toEqual(TEST_USER_CHAT_MESSAGE);
        chatSessionWithNoArgs = model.startChat();
        chatSessionWithFunctionCall = model.startChat({
            tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION,
        });
        expectedStreamResult = {
            response: Promise.resolve(TEST_MODEL_RESPONSE),
            stream: testGenerator(),
        };
        const fetchResult = Promise.resolve(new Response(JSON.stringify(expectedStreamResult), fetchResponseObj));
        fetchSpy = spyOn(global, 'fetch').and.returnValue(fetchResult);
    });
    describe('sendMessage', () => {
        it('returns a GenerateContentResponse and appends to history', async () => {
            const req = TEST_CHAT_MESSSAGE_TEXT;
            const expectedResult = {
                response: TEST_MODEL_RESPONSE,
            };
            spyOn(PostFetchFunctions, 'processUnary').and.resolveTo(expectedResult);
            const resp = await chatSession.sendMessage(req);
            expect(resp).toEqual(expectedResult);
            expect((await chatSession.getHistory()).length).toEqual(3);
        });
        it('gemini-pro model send correct resourcePath to functions', async () => {
            const modelWithShortName = new generative_models_1.GenerativeModelPreview({
                model: 'gemini-pro',
                project: PROJECT,
                location: LOCATION,
                googleAuth: FAKE_GOOGLE_AUTH,
            });
            const chatSessionWithShortName = modelWithShortName.startChat();
            const req = TEST_CHAT_MESSSAGE_TEXT;
            const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent').and.callThrough();
            const expectedResult = {
                response: TEST_MODEL_RESPONSE,
            };
            spyOn(PostFetchFunctions, 'processUnary').and.resolveTo(expectedResult);
            const expectedResourcePath = 'projects/test_project/locations/test_location/publishers/google/models/gemini-pro';
            await chatSessionWithShortName.sendMessage(req);
            // @ts-ignore
            expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
        });
        it('models/gemini-pro model send correct resourcePath to functions', async () => {
            const modelWithLongName = new generative_models_1.GenerativeModelPreview({
                model: 'models/gemini-pro',
                project: PROJECT,
                location: LOCATION,
                googleAuth: FAKE_GOOGLE_AUTH,
            });
            const chatSessionWithLongName = modelWithLongName.startChat();
            const req = TEST_CHAT_MESSSAGE_TEXT;
            const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent').and.callThrough();
            const expectedResult = {
                response: TEST_MODEL_RESPONSE,
            };
            spyOn(PostFetchFunctions, 'processUnary').and.resolveTo(expectedResult);
            const expectedResourcePath = 'projects/test_project/locations/test_location/publishers/google/models/gemini-pro';
            await chatSessionWithLongName.sendMessage(req);
            // @ts-ignore
            expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
        });
        it('projects/my-project/my-tuned-gemini-pro model send correct resourcePath to functions', async () => {
            const modelWithFullName = new generative_models_1.GenerativeModelPreview({
                model: 'projects/my-project/my-tuned-gemini-pro',
                project: PROJECT,
                location: LOCATION,
                googleAuth: FAKE_GOOGLE_AUTH,
            });
            const chatSessionWithFullName = modelWithFullName.startChat();
            const req = TEST_CHAT_MESSSAGE_TEXT;
            const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent').and.callThrough();
            const expectedResult = {
                response: TEST_MODEL_RESPONSE,
            };
            spyOn(PostFetchFunctions, 'processUnary').and.resolveTo(expectedResult);
            const expectedResourcePath = 'projects/my-project/my-tuned-gemini-pro';
            await chatSessionWithFullName.sendMessage(req);
            // @ts-ignore
            expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
        });
        it('send a message with responseMimeType to functions', async () => {
            const model = new generative_models_1.GenerativeModelPreview({
                model: 'gemini-pro',
                project: PROJECT,
                location: LOCATION,
                googleAuth: FAKE_GOOGLE_AUTH,
            });
            const chat = model.startChat({
                generationConfig: {
                    ...TEST_GENERATION_CONFIG,
                    responseMimeType: 'application/json',
                },
            });
            const req = 'How are you doing today?';
            await chat.sendMessage(req);
            const expectedBody = '{"contents":[{"role":"user","parts":[{"text":"How are you doing today?"}]}],"generationConfig":{"candidateCount":1,"stopSequences":["hello"],"responseMimeType":"application/json"}}';
            // @ts-ignore
            const actualBody = fetchSpy.calls.allArgs()[0][1].body;
            expect(actualBody).toEqual(expectedBody);
        });
        it('send timeout to functions', async () => {
            const modelWithRequestOptions = new generative_models_1.GenerativeModelPreview({
                model: 'gemini-pro',
                project: PROJECT,
                location: LOCATION,
                googleAuth: FAKE_GOOGLE_AUTH,
                requestOptions: TEST_REQUEST_OPTIONS,
            });
            const chatSessionWithRequestOptions = modelWithRequestOptions.startChat({
                history: TEST_USER_CHAT_MESSAGE,
            });
            const req = TEST_CHAT_MESSSAGE_TEXT;
            const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContent').and.resolveTo({
                response: TEST_MODEL_RESPONSE,
            });
            await chatSessionWithRequestOptions.sendMessage(req);
            expect(chatSessionWithRequestOptions.requestOptions).toEqual(TEST_REQUEST_OPTIONS);
            expect(generateContentSpy.calls.allArgs()[0][9].timeout).toEqual(0);
        });
        it('returns a GenerateContentResponse and appends to history when startChat is passed with no args', async () => {
            const req = TEST_CHAT_MESSSAGE_TEXT;
            const expectedResult = {
                response: TEST_MODEL_RESPONSE,
            };
            spyOn(PostFetchFunctions, 'processUnary').and.resolveTo(expectedResult);
            const resp = await chatSessionWithNoArgs.sendMessage(req);
            expect(resp).toEqual(expectedResult);
            expect((await chatSessionWithNoArgs.getHistory()).length).toEqual(2);
        });
        it('returns a GenerateContentResponse when passed multi-part content', async () => {
            const req = TEST_MULTIPART_MESSAGE[0]['parts'];
            const expectedResult = {
                response: TEST_MODEL_RESPONSE,
            };
            spyOn(PostFetchFunctions, 'processUnary').and.resolveTo(expectedResult);
            const resp = await chatSessionWithNoArgs.sendMessage(req);
            expect(resp).toEqual(expectedResult);
            expect((await chatSessionWithNoArgs.getHistory()).length).toEqual(2);
        });
        it('returns a FunctionCall and appends to history when passed a FunctionDeclaration', async () => {
            const functionCallChatMessage = 'What is the weather in LA?';
            const expectedFunctionCallResponse = {
                response: TEST_MODEL_RESPONSE_WITH_FUNCTION_CALL,
            };
            const expectedResult = {
                response: TEST_MODEL_RESPONSE_WITH_FUNCTION_CALL,
            };
            const streamSpy = spyOn(PostFetchFunctions, 'processUnary');
            streamSpy.and.resolveTo(expectedResult);
            const response1 = await chatSessionWithFunctionCall.sendMessage(functionCallChatMessage);
            expect(response1).toEqual(expectedFunctionCallResponse);
            expect((await chatSessionWithFunctionCall.getHistory()).length).toEqual(2);
            // Send a follow-up message with a FunctionResponse
            const expectedFollowUpResponse = {
                response: TEST_MODEL_RESPONSE,
            };
            const expectedFollowUpResult = {
                response: TEST_MODEL_RESPONSE,
            };
            streamSpy.and.resolveTo(expectedFollowUpResult);
            const response2 = await chatSessionWithFunctionCall.sendMessage(TEST_FUNCTION_RESPONSE_PART);
            expect(response2).toEqual(expectedFollowUpResponse);
            expect((await chatSessionWithFunctionCall.getHistory()).length).toEqual(4);
        });
        it('throw ClientError when request has no content', async () => {
            const expectedErrorMessage = '[VertexAI.ClientError]: No content is provided for sending chat message.';
            await chatSessionWithNoArgs.sendMessage([]).catch(e => {
                expect(e.message).toEqual(expectedErrorMessage);
            });
        });
        it('throw ClientError when request mix functionCall part with other types of part', async () => {
            const chatRequest = [
                'what is the weather like in LA',
                TEST_FUNCTION_RESPONSE_PART[0],
            ];
            const expectedErrorMessage = '[VertexAI.ClientError]: Within a single message, FunctionResponse cannot be mixed with other type of part in the request for sending chat message.';
            await chatSessionWithNoArgs.sendMessage(chatRequest).catch(e => {
                expect(e.message).toEqual(expectedErrorMessage);
            });
        });
    });
    describe('sendMessageStream', () => {
        it('returns a StreamGenerateContentResponse and appends to history', async () => {
            const req = TEST_CHAT_MESSSAGE_TEXT;
            const expectedResult = {
                response: Promise.resolve(TEST_MODEL_RESPONSE),
                stream: testGenerator(),
            };
            const chatSession = model.startChat({
                history: [
                    {
                        role: util_1.constants.USER_ROLE,
                        parts: [{ text: 'How are you doing today?' }],
                    },
                ],
            });
            spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult);
            const history = await chatSession.getHistory();
            expect(history.length).toEqual(1);
            expect(history[0].role).toEqual(util_1.constants.USER_ROLE);
            const result = await chatSession.sendMessageStream(req);
            const response = await result.response;
            const expectedResponse = await expectedResult.response;
            expect(response).toEqual(expectedResponse);
            const secondHistory = await chatSession.getHistory();
            expect(secondHistory.length).toEqual(3);
            expect(secondHistory[0].role).toEqual(util_1.constants.USER_ROLE);
            expect(secondHistory[1].role).toEqual(util_1.constants.USER_ROLE);
            expect(secondHistory[2].role).toEqual(util_1.constants.MODEL_ROLE);
        });
        it('returns a StreamGenerateContentResponse in streaming mode', async () => {
            const req = TEST_CHAT_MESSSAGE_TEXT;
            const expectedResult = {
                response: Promise.resolve(TEST_MODEL_RESPONSE),
                stream: testGeneratorMultiStream(),
            };
            spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult);
            const chatSession = model.startChat({
                history: [
                    {
                        role: util_1.constants.USER_ROLE,
                        parts: [{ text: 'How are you doing today?' }],
                    },
                ],
            });
            const resp = await chatSession.sendMessageStream(req);
            let firstChunkTimestamp = 0;
            for await (const item of resp.stream) {
                if (firstChunkTimestamp === 0) {
                    firstChunkTimestamp = Date.now();
                }
            }
            expect(Date.now() - firstChunkTimestamp).toBeGreaterThanOrEqual(200 - DATE_NOW_PRECISION_MILLIS);
        });
        it('gemini-pro model send correct resourcePath to functions', async () => {
            const modelWithShortName = new generative_models_1.GenerativeModelPreview({
                model: 'gemini-pro',
                project: PROJECT,
                location: LOCATION,
                googleAuth: FAKE_GOOGLE_AUTH,
            });
            const chatSessionWithShortName = modelWithShortName.startChat();
            const req = TEST_CHAT_MESSSAGE_TEXT;
            const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContentStream').and.callThrough();
            const expectedResult = {
                response: Promise.resolve(TEST_MODEL_RESPONSE),
                stream: testGeneratorMultiStream(),
            };
            spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult);
            const expectedResourcePath = 'projects/test_project/locations/test_location/publishers/google/models/gemini-pro';
            await chatSessionWithShortName.sendMessageStream(req);
            // @ts-ignore
            expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
        });
        it('models/gemini-pro model send correct resourcePath to functions', async () => {
            const modelWithLongName = new generative_models_1.GenerativeModelPreview({
                model: 'models/gemini-pro',
                project: PROJECT,
                location: LOCATION,
                googleAuth: FAKE_GOOGLE_AUTH,
            });
            const chatSessionWithLongName = modelWithLongName.startChat();
            const req = TEST_CHAT_MESSSAGE_TEXT;
            const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContentStream').and.callThrough();
            const expectedResult = {
                response: Promise.resolve(TEST_MODEL_RESPONSE),
                stream: testGeneratorMultiStream(),
            };
            spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult);
            const expectedResourcePath = 'projects/test_project/locations/test_location/publishers/google/models/gemini-pro';
            await chatSessionWithLongName.sendMessageStream(req);
            // @ts-ignore
            expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
        });
        it('projects/my-project/my-tuned-gemini-pro model send correct resourcePath to functions', async () => {
            const modelWithFullName = new generative_models_1.GenerativeModelPreview({
                model: 'projects/my-project/my-tuned-gemini-pro',
                project: PROJECT,
                location: LOCATION,
                googleAuth: FAKE_GOOGLE_AUTH,
            });
            const chatSessionWithFullName = modelWithFullName.startChat();
            const req = TEST_CHAT_MESSSAGE_TEXT;
            const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContentStream').and.callThrough();
            const expectedResult = {
                response: Promise.resolve(TEST_MODEL_RESPONSE),
                stream: testGeneratorMultiStream(),
            };
            spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult);
            const expectedResourcePath = 'projects/my-project/my-tuned-gemini-pro';
            await chatSessionWithFullName.sendMessageStream(req);
            // @ts-ignore
            expect(generateContentSpy.calls.allArgs()[0][1]).toEqual(expectedResourcePath);
        });
        it('send timeout to functions', async () => {
            const modelWithRequestOptions = new generative_models_1.GenerativeModelPreview({
                model: 'gemini-pro',
                project: PROJECT,
                location: LOCATION,
                googleAuth: FAKE_GOOGLE_AUTH,
                requestOptions: TEST_REQUEST_OPTIONS,
            });
            const chatSessionWithRequestOptions = modelWithRequestOptions.startChat({
                history: TEST_USER_CHAT_MESSAGE,
            });
            const req = TEST_CHAT_MESSSAGE_TEXT;
            const generateContentSpy = spyOn(GenerateContentFunctions, 'generateContentStream').and.resolveTo({
                response: Promise.resolve(TEST_MODEL_RESPONSE),
                stream: testGenerator(),
            });
            await chatSessionWithRequestOptions.sendMessageStream(req);
            expect(chatSessionWithRequestOptions.requestOptions).toEqual(TEST_REQUEST_OPTIONS);
            expect(generateContentSpy.calls.allArgs()[0][9].timeout).toEqual(0);
        });
        it('returns a FunctionCall and appends to history when passed a FunctionDeclaration', async () => {
            const functionCallChatMessage = 'What is the weather in LA?';
            const expectedStreamResult = {
                response: Promise.resolve(TEST_MODEL_RESPONSE_WITH_FUNCTION_CALL),
                stream: testGenerator(),
            };
            const streamSpy = spyOn(PostFetchFunctions, 'processStream');
            streamSpy.and.resolveTo(expectedStreamResult);
            const response1 = await chatSessionWithFunctionCall.sendMessageStream(functionCallChatMessage);
            expect(response1).toEqual(expectedStreamResult);
            expect((await chatSessionWithFunctionCall.getHistory()).length).toEqual(2);
            // Send a follow-up message with a FunctionResponse
            const expectedFollowUpStreamResult = {
                response: Promise.resolve(TEST_MODEL_RESPONSE),
                stream: testGenerator(),
            };
            streamSpy.and.resolveTo(expectedFollowUpStreamResult);
            const response2 = await chatSessionWithFunctionCall.sendMessageStream(TEST_FUNCTION_RESPONSE_PART);
            expect(response2).toEqual(expectedFollowUpStreamResult);
            expect((await chatSessionWithFunctionCall.getHistory()).length).toEqual(4);
        });
        it('throw ClientError when request has no content', async () => {
            const expectedErrorMessage = '[VertexAI.ClientError]: No content is provided for sending chat message.';
            await chatSessionWithNoArgs.sendMessageStream([]).catch(e => {
                expect(e.message).toEqual(expectedErrorMessage);
            });
        });
        it('throw ClientError when request mix functionCall part with other types of part', async () => {
            const chatRequest = [
                'what is the weather like in LA',
                TEST_FUNCTION_RESPONSE_PART[0],
            ];
            const expectedErrorMessage = '[VertexAI.ClientError]: Within a single message, FunctionResponse cannot be mixed with other type of part in the request for sending chat message.';
            await chatSessionWithNoArgs.sendMessageStream(chatRequest).catch(e => {
                expect(e.message).toEqual(expectedErrorMessage);
            });
        });
    });
});
describe('GenerativeModel countTokens', () => {
    it('returns the token count', async () => {
        const model = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const responseBody = {
            totalTokens: 1,
        };
        const response = new Response(JSON.stringify(responseBody), fetchResponseObj);
        spyOn(global, 'fetch').and.resolveTo(response);
        const resp = await model.countTokens(req);
        expect(resp).toEqual(responseBody);
    });
    it('send timeout to functions', async () => {
        const model = new generative_models_1.GenerativeModel({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            requestOptions: TEST_REQUEST_OPTIONS,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const countTokenSpy = spyOn(CountTokensFunctions, 'countTokens');
        await model.countTokens(req);
        // @ts-ignore
        expect(countTokenSpy.calls.allArgs()[0][5].timeout).toEqual(0);
    });
});
describe('GenerativeModelPreview countTokens', () => {
    it('returns the token count', async () => {
        const model = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const responseBody = {
            totalTokens: 1,
        };
        const response = new Response(JSON.stringify(responseBody), fetchResponseObj);
        spyOn(global, 'fetch').and.resolveTo(response);
        const resp = await model.countTokens(req);
        expect(resp).toEqual(responseBody);
    });
    it('send timeout to functions', async () => {
        const model = new generative_models_1.GenerativeModelPreview({
            model: 'gemini-pro',
            project: PROJECT,
            location: LOCATION,
            googleAuth: FAKE_GOOGLE_AUTH,
            requestOptions: TEST_REQUEST_OPTIONS,
        });
        const req = {
            contents: TEST_USER_CHAT_MESSAGE,
        };
        const countTokenSpy = spyOn(CountTokensFunctions, 'countTokens');
        await model.countTokens(req);
        // @ts-ignore
        expect(countTokenSpy.calls.allArgs()[0][5].timeout).toEqual(0);
    });
});
describe('GenerativeModel when exception at fetch', () => {
    const model = new generative_models_1.GenerativeModel({
        model: 'gemini-pro',
        project: PROJECT,
        location: LOCATION,
        googleAuth: FAKE_GOOGLE_AUTH,
    });
    const chatSession = model.startChat();
    const message = 'hi';
    const req = {
        contents: TEST_USER_CHAT_MESSAGE,
    };
    const countTokenReq = {
        contents: TEST_USER_CHAT_MESSAGE,
    };
    beforeEach(() => {
        spyOn(global, 'fetch').and.throwError('error');
    });
    it('generateContent should throw GoogleGenerativeAI error', async () => {
        await expectAsync(model.generateContent(req)).toBeRejected();
    });
    it('generateContentStream should throw GoogleGenerativeAI error', async () => {
        await expectAsync(model.generateContentStream(req)).toBeRejected();
    });
    it('sendMessage should throw GoogleGenerativeAI error', async () => {
        await expectAsync(chatSession.sendMessage(message)).toBeRejected();
    });
    it('countTokens should throw GoogleGenerativeAI error', async () => {
        await expectAsync(model.countTokens(countTokenReq)).toBeRejected();
    });
});
describe('GenerativeModelPreview when exception at fetch', () => {
    const model = new generative_models_1.GenerativeModelPreview({
        model: 'gemini-pro',
        project: PROJECT,
        location: LOCATION,
        googleAuth: FAKE_GOOGLE_AUTH,
    });
    const chatSession = model.startChat();
    const message = 'hi';
    const req = {
        contents: TEST_USER_CHAT_MESSAGE,
    };
    const countTokenReq = {
        contents: TEST_USER_CHAT_MESSAGE,
    };
    beforeEach(() => {
        spyOn(global, 'fetch').and.throwError('error');
    });
    it('generateContent should throw GoogleGenerativeAI error', async () => {
        await expectAsync(model.generateContent(req)).toBeRejected();
    });
    it('generateContentStream should throw GoogleGenerativeAI error', async () => {
        await expectAsync(model.generateContentStream(req)).toBeRejected();
    });
    it('sendMessage should throw GoogleGenerativeAI error', async () => {
        await expectAsync(chatSession.sendMessage(message)).toBeRejected();
    });
    it('countTokens should throw GoogleGenerativeAI error', async () => {
        await expectAsync(model.countTokens(countTokenReq)).toBeRejected();
    });
});
describe('GenerativeModel when response is undefined', () => {
    const expectedErrorMessage = '[VertexAI.GoogleGenerativeAIError]: response is undefined';
    const model = new generative_models_1.GenerativeModel({
        model: 'gemini-pro',
        project: PROJECT,
        location: LOCATION,
        googleAuth: FAKE_GOOGLE_AUTH,
    });
    const req = {
        contents: TEST_USER_CHAT_MESSAGE,
    };
    const message = 'hi';
    const chatSession = model.startChat();
    const countTokenReq = {
        contents: TEST_USER_CHAT_MESSAGE,
    };
    beforeEach(() => {
        spyOn(global, 'fetch').and.resolveTo();
    });
    it('generateContent should throw GoogleGenerativeAI error', async () => {
        await expectAsync(model.generateContent(req)).toBeRejected();
        await model.generateContent(req).catch(e => {
            expect(e.message).toEqual(expectedErrorMessage);
        });
    });
    it('generateContentStream should throw GoogleGenerativeAI error', async () => {
        await expectAsync(model.generateContentStream(req)).toBeRejected();
        await model.generateContentStream(req).catch(e => {
            expect(e.message).toEqual(expectedErrorMessage);
        });
    });
    it('sendMessage should throw GoogleGenerativeAI error', async () => {
        await expectAsync(chatSession.sendMessage(message)).toBeRejected();
        await chatSession.sendMessage(message).catch(e => {
            expect(e.message).toEqual(expectedErrorMessage);
        });
    });
    it('countTokens should throw GoogleGenerativeAI error', async () => {
        await expectAsync(model.countTokens(countTokenReq)).toBeRejected();
        await model.countTokens(countTokenReq).catch(e => {
            expect(e.message).toEqual(expectedErrorMessage);
        });
    });
});
describe('GenerativeModelPreview when response is undefined', () => {
    const expectedErrorMessage = '[VertexAI.GoogleGenerativeAIError]: response is undefined';
    const model = new generative_models_1.GenerativeModelPreview({
        model: 'gemini-pro',
        project: PROJECT,
        location: LOCATION,
        googleAuth: FAKE_GOOGLE_AUTH,
    });
    const req = {
        contents: TEST_USER_CHAT_MESSAGE,
    };
    const message = 'hi';
    const chatSession = model.startChat();
    const countTokenReq = {
        contents: TEST_USER_CHAT_MESSAGE,
    };
    beforeEach(() => {
        spyOn(global, 'fetch').and.resolveTo();
    });
    it('generateContent should throw GoogleGenerativeAI error', async () => {
        await expectAsync(model.generateContent(req)).toBeRejected();
        await model.generateContent(req).catch(e => {
            expect(e.message).toEqual(expectedErrorMessage);
        });
    });
    it('generateContentStream should throw GoogleGenerativeAI error', async () => {
        await expectAsync(model.generateContentStream(req)).toBeRejected();
        await model.generateContentStream(req).catch(e => {
            expect(e.message).toEqual(expectedErrorMessage);
        });
    });
    it('sendMessage should throw GoogleGenerativeAI error', async () => {
        await expectAsync(chatSession.sendMessage(message)).toBeRejected();
        await chatSession.sendMessage(message).catch(e => {
            expect(e.message).toEqual(expectedErrorMessage);
        });
    });
    it('countTokens should throw GoogleGenerativeAI error', async () => {
        await expectAsync(model.countTokens(countTokenReq)).toBeRejected();
        await model.countTokens(countTokenReq).catch(e => {
            expect(e.message).toEqual(expectedErrorMessage);
        });
    });
});
describe('GeneratvieModel when response is 4XX', () => {
    const req = {
        contents: TEST_USER_CHAT_MESSAGE,
    };
    const fetch400Obj = {
        status: 400,
        statusText: 'Bad Request',
        ok: false,
    };
    const body = {
        code: 400,
        message: 'request is invalid',
        status: 'INVALID_ARGUMENT',
    };
    const response = new Response(JSON.stringify(body), fetch400Obj);
    const model = new generative_models_1.GenerativeModel({
        model: 'gemini-pro',
        project: PROJECT,
        location: LOCATION,
        googleAuth: FAKE_GOOGLE_AUTH,
    });
    const message = 'hi';
    const chatSession = model.startChat();
    const countTokenReq = {
        contents: TEST_USER_CHAT_MESSAGE,
    };
    beforeEach(() => {
        spyOn(global, 'fetch').and.resolveTo(response);
    });
    it('generateContent should throw ClientError error', async () => {
        await expectAsync(model.generateContent(req)).toBeRejected();
        // TODO: update jasmine version or use flush to uncomment
        // await model.generateContent(req).catch(e => {
        //   expect(e.message).toEqual(expectedErrorMessage);
        // });
    });
    it('generateContentStream should throw ClientError error', async () => {
        await expectAsync(model.generateContentStream(req)).toBeRejected();
        // TODO: update jasmine version or use flush to uncomment
        // await model.generateContentStream(req).catch(e => {
        //   expect(e.message).toEqual(expectedErrorMessage);
        // });
    });
    it('sendMessage should throw ClientError error', async () => {
        await expectAsync(chatSession.sendMessage(message)).toBeRejected();
        // TODO: update jasmine version or use flush to uncomment
        // await chatSession.sendMessage(message).catch(e => {
        //   expect(e.message).toEqual(expectedErrorMessage);
        // });
    });
    it('countTokens should throw ClientError error', async () => {
        await expectAsync(model.countTokens(countTokenReq)).toBeRejected();
        // TODO: update jasmine version or use flush to uncomment
        // await model.countTokens(countTokenReq).catch(e => {
        //   expect(e.message).toEqual(expectedErrorMessage);
        // });
    });
});
describe('GeneratvieModelPreview when response is 4XX', () => {
    const req = {
        contents: TEST_USER_CHAT_MESSAGE,
    };
    const fetch400Obj = {
        status: 400,
        statusText: 'Bad Request',
        ok: false,
    };
    const body = {
        code: 400,
        message: 'request is invalid',
        status: 'INVALID_ARGUMENT',
    };
    const response = new Response(JSON.stringify(body), fetch400Obj);
    const model = new generative_models_1.GenerativeModelPreview({
        model: 'gemini-pro',
        project: PROJECT,
        location: LOCATION,
        googleAuth: FAKE_GOOGLE_AUTH,
    });
    const message = 'hi';
    const chatSession = model.startChat();
    const countTokenReq = {
        contents: TEST_USER_CHAT_MESSAGE,
    };
    beforeEach(() => {
        spyOn(global, 'fetch').and.resolveTo(response);
    });
    it('generateContent should throw ClientError error', async () => {
        await expectAsync(model.generateContent(req)).toBeRejected();
        // TODO: update jasmine version or use flush to uncomment
        // await model.generateContent(req).catch(e => {
        //   expect(e.message).toEqual(expectedErrorMessage);
        // });
    });
    it('generateContentStream should throw ClientError error', async () => {
        await expectAsync(model.generateContentStream(req)).toBeRejected();
        // TODO: update jasmine version or use flush to uncomment
        // await model.generateContentStream(req).catch(e => {
        //   expect(e.message).toEqual(expectedErrorMessage);
        // });
    });
    it('sendMessage should throw ClientError error', async () => {
        await expectAsync(chatSession.sendMessage(message)).toBeRejected();
        // TODO: update jasmine version or use flush to uncomment
        // await chatSession.sendMessage(message).catch(e => {
        //   expect(e.message).toEqual(expectedErrorMessage);
        // });
    });
    it('countTokens should throw ClientError error', async () => {
        await expectAsync(model.countTokens(countTokenReq)).toBeRejected();
        // TODO: update jasmine version or use flush to uncomment
        // await model.countTokens(countTokenReq).catch(e => {
        //   expect(e.message).toEqual(expectedErrorMessage);
        // });
    });
});
describe('GenerativeModel when response is not OK and not 4XX', () => {
    const req = {
        contents: TEST_USER_CHAT_MESSAGE,
    };
    const fetch500Obj = {
        status: 500,
        statusText: 'Internal Server Error',
        ok: false,
    };
    const body = {
        code: 500,
        message: 'service is having downtime',
        status: 'INTERNAL_SERVER_ERROR',
    };
    const response = new Response(JSON.stringify(body), fetch500Obj);
    const model = new generative_models_1.GenerativeModel({
        model: 'gemini-pro',
        project: PROJECT,
        location: LOCATION,
        googleAuth: FAKE_GOOGLE_AUTH,
    });
    const message = 'hi';
    const chatSession = model.startChat();
    const countTokenReq = {
        contents: TEST_USER_CHAT_MESSAGE,
    };
    beforeEach(() => {
        spyOn(global, 'fetch').and.resolveTo(response);
    });
    it('generateContent should throws GoogleGenerativeAIError', async () => {
        await expectAsync(model.generateContent(req)).toBeRejected();
        // TODO: update jasmine version or use flush to uncomment
        // await model.generateContent(req).catch(e => {
        //   expect(e.message).toEqual(expectedErrorMessage);
        // });
    });
    it('generateContentStream should throws GoogleGenerativeAIError', async () => {
        await expectAsync(model.generateContentStream(req)).toBeRejected();
        // TODO: update jasmine version or use flush to uncomment
        // await model.generateContentStream(req).catch(e => {
        //   expect(e.message).toEqual(expectedErrorMessage);
        // });
    });
    it('sendMessage should throws GoogleGenerativeAIError', async () => {
        await expectAsync(chatSession.sendMessage(message)).toBeRejected();
        // TODO: update jasmine version or use flush to uncomment
        // await chatSession.sendMessage(message).catch(e => {
        //   expect(e.message).toEqual(expectedErrorMessage);
        // });
    });
    it('countTokens should throws GoogleGenerativeAIError', async () => {
        await expectAsync(model.countTokens(countTokenReq)).toBeRejected();
        // TODO: update jasmine version or use flush to uncomment
        // await model.countTokens(countTokenReq).catch(e => {
        //   expect(e.message).toEqual(expectedErrorMessage);
        // });
    });
});
describe('GenerativeModelPreview when response is not OK and not 4XX', () => {
    const req = {
        contents: TEST_USER_CHAT_MESSAGE,
    };
    const fetch500Obj = {
        status: 500,
        statusText: 'Internal Server Error',
        ok: false,
    };
    const body = {
        code: 500,
        message: 'service is having downtime',
        status: 'INTERNAL_SERVER_ERROR',
    };
    const response = new Response(JSON.stringify(body), fetch500Obj);
    const model = new generative_models_1.GenerativeModelPreview({
        model: 'gemini-pro',
        project: PROJECT,
        location: LOCATION,
        googleAuth: FAKE_GOOGLE_AUTH,
    });
    const message = 'hi';
    const chatSession = model.startChat();
    const countTokenReq = {
        contents: TEST_USER_CHAT_MESSAGE,
    };
    beforeEach(() => {
        spyOn(global, 'fetch').and.resolveTo(response);
    });
    it('generateContent should throws GoogleGenerativeAIError', async () => {
        await expectAsync(model.generateContent(req)).toBeRejected();
        // TODO: update jasmine version or use flush to uncomment
        // await model.generateContent(req).catch(e => {
        //   expect(e.message).toEqual(expectedErrorMessage);
        // });
    });
    it('generateContentStream should throws GoogleGenerativeAIError', async () => {
        await expectAsync(model.generateContentStream(req)).toBeRejected();
        // TODO: update jasmine version or use flush to uncomment
        // await model.generateContentStream(req).catch(e => {
        //   expect(e.message).toEqual(expectedErrorMessage);
        // });
    });
    it('sendMessage should throws GoogleGenerativeAIError', async () => {
        await expectAsync(chatSession.sendMessage(message)).toBeRejected();
        // TODO: update jasmine version or use flush to uncomment
        // await chatSession.sendMessage(message).catch(e => {
        //   expect(e.message).toEqual(expectedErrorMessage);
        // });
    });
    it('countTokens should throws GoogleGenerativeAIError', async () => {
        await expectAsync(model.countTokens(countTokenReq)).toBeRejected();
        // TODO: update jasmine version or use flush to uncomment
        // await model.countTokens(countTokenReq).catch(e => {
        //   expect(e.message).toEqual(expectedErrorMessage);
        // });
    });
});
//# sourceMappingURL=models_test.js.map