Repository: googleapis/nodejs-vertexai Branch: main Commit: 77d956444566 Files: 114 Total size: 828.1 KB Directory structure: gitextract_z_dw_qc9/ ├── .eslintignore ├── .eslintrc.json ├── .github/ │ ├── CODEOWNERS │ ├── release-please.yml │ ├── release-trigger.yml │ ├── sync-repo-settings.yaml │ └── workflows/ │ └── presubmit.yaml ├── .gitignore ├── .jsdoc.js ├── .kokoro/ │ ├── docs.sh │ ├── populate-secrets.sh │ ├── presubmit/ │ │ ├── node18/ │ │ │ ├── common.cfg │ │ │ ├── continuous-system-test.cfg │ │ │ ├── docs.cfg │ │ │ ├── docs.sh │ │ │ └── system-test.cfg │ │ └── node22/ │ │ ├── common.cfg │ │ ├── docs.cfg │ │ ├── docs.sh │ │ └── system-test.cfg │ ├── publish.sh │ ├── system-test.sh │ ├── test.sh │ └── trampoline_v2.sh ├── .prettierignore ├── .prettierrc.js ├── .release-please-manifest.json ├── .repo-metadata.json ├── .trampolinerc ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── SECURITY.md ├── package.json ├── release-please-config.json ├── src/ │ ├── .prettierignore │ ├── .prettierrc │ ├── _internal_types.ts │ ├── agentengines.ts │ ├── client.ts │ ├── converters/ │ │ ├── _agentengines_converters.ts │ │ ├── _memories_converters.ts │ │ ├── _memoryrevisions_converters.ts │ │ ├── _sandboxes_converters.ts │ │ ├── _sessionevents_converters.ts │ │ ├── _sessions_converters.ts │ │ └── _skills_converters.ts │ ├── eslint.config.mjs │ ├── index.ts │ ├── memories.ts │ ├── memoryrevisions.ts │ ├── releases.txt │ ├── sandboxes.ts │ ├── sessionevents.ts │ ├── sessions.ts │ ├── skills.ts │ ├── types/ │ │ └── common.ts │ └── types.ts ├── system_test/ │ └── agent_engine_e2e_test.ts ├── test/ │ ├── replays/ │ │ ├── _replay_client.ts │ │ ├── agentengines_memories_test.ts │ │ ├── agentengines_sandboxes_test.ts │ │ ├── agentengines_sessions_test.ts │ │ ├── agentengines_test.ts │ │ ├── run_replay_tests.sh │ │ ├── sessionevents_test.ts │ │ ├── skills_test.ts │ │ └── test_env.js │ ├── spec/ │ │ └── reporter.js │ └── unit/ │ └── client_test.ts ├── tsconfig.json └── vertexai/ ├── .eslintrc.json ├── README.md ├── package.json ├── src/ │ ├── functions/ │ │ ├── count_tokens.ts │ │ ├── generate_content.ts │ │ ├── index.ts │ │ ├── post_fetch_processing.ts │ │ ├── post_request.ts │ │ ├── pre_fetch_processing.ts │ │ ├── test/ │ │ │ ├── functions_test.ts │ │ │ ├── post_fetch_processing_test.ts │ │ │ ├── post_request_test.ts │ │ │ ├── pre_fetch_processing_test.ts │ │ │ └── test_data.ts │ │ └── util.ts │ ├── index.ts │ ├── models/ │ │ ├── chat_session.ts │ │ ├── generative_models.ts │ │ ├── index.ts │ │ ├── test/ │ │ │ ├── chat_session_test.ts │ │ │ ├── generative_models_test.ts │ │ │ └── models_test.ts │ │ └── util.ts │ ├── resources/ │ │ ├── cached_contents.ts │ │ ├── index.ts │ │ └── shared/ │ │ └── api_client.ts │ ├── testing/ │ │ ├── fake_google_auth.ts │ │ └── fake_google_auth_test.ts │ ├── types/ │ │ ├── common.ts │ │ ├── content.ts │ │ ├── errors.ts │ │ ├── generate_content_response_handler.ts │ │ ├── index.ts │ │ └── tool.ts │ ├── util/ │ │ ├── constants.ts │ │ └── index.ts │ └── vertex_ai.ts ├── system_test/ │ └── end_to_end_sample_test.ts ├── test/ │ ├── index_test.ts │ └── vertex_ai_test.ts └── tsconfig.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .eslintignore ================================================ **/node_modules build/ docs/ src/genai/ test/ system_test/ sdk_schema_test/ src/**/test/ ================================================ FILE: .eslintrc.json ================================================ { "extends": "./node_modules/gts" } ================================================ FILE: .github/CODEOWNERS ================================================ # Code owners file. # This file controls who is tagged for review for any given pull request. # # For syntax help see: # https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners#codeowners-syntax # The Vertex AI SDK team is the default owner for approving PRs. * @googleapis/vertexai-team ================================================ FILE: .github/release-please.yml ================================================ handleGHRelease: true manifest: true ================================================ FILE: .github/release-trigger.yml ================================================ enabled: true ================================================ FILE: .github/sync-repo-settings.yaml ================================================ # https://github.com/googleapis/repo-automation-bots/tree/main/packages/sync-repo-settings # We are disabling this bot until https://github.com/googleapis/repo-automation-bots/issues/4617 # is resolved enabled: false ================================================ FILE: .github/workflows/presubmit.yaml ================================================ on: pull_request: name: presubmit jobs: units: runs-on: ubuntu-latest strategy: matrix: node: [20, 22, 24] steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v2 with: version: ^6.24.1 - run: node --version - run: npm install - run: npm run test name: Run unit tests env: BUILD_TYPE: presubmit TEST_TYPE: units ================================================ FILE: .gitignore ================================================ # Ignore directories generated automatically. node_modules/ build/ docs/ .nyc_output/ # Ignore files generated automatically. test/spec/sponge_log.xml # Ignore JetBrains IDE files .idea/ ================================================ FILE: .jsdoc.js ================================================ /** * @license * Copyright 2023 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. */ 'use strict'; module.exports = { opts: { readme: './README.md', package: './package.json', template: './node_modules/jsdoc-fresh', recurse: true, verbose: true, destination: './docs/' }, plugins: [ 'plugins/markdown', 'jsdoc-region-tag' ], source: { excludePattern: '(^|\\/|\\\\)[._]', include: [ 'build/src', ], includePattern: '\\.js$' }, templates: { copyright: 'Copyright 2023 Google LLC', includeDate: false, sourceFiles: false, systemName: '@google-cloud/vertexai', theme: 'lumen', default: { outputSourceFiles: false } }, markdown: { idInHeadings: true } }; ================================================ FILE: .kokoro/docs.sh ================================================ #!/bin/bash # Copyright 2023 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. # set -eo pipefail export NPM_CONFIG_PREFIX=${HOME}/.npm-global cd $(dirname $0)/.. npm install npm run docs-test ================================================ FILE: .kokoro/populate-secrets.sh ================================================ #!/bin/bash # Copyright 2020 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 # # http://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. # This file is called in the early stage of `trampoline_v2.sh` to # populate secrets needed for the CI builds. set -eo pipefail function now { date +"%Y-%m-%d %H:%M:%S" | tr -d '\n' ;} function msg { println "$*" >&2 ;} function println { printf '%s\n' "$(now) $*" ;} # Populates requested secrets set in SECRET_MANAGER_KEYS # In Kokoro CI builds, we use the service account attached to the # Kokoro VM. This means we need to setup auth on other CI systems. # For local run, we just use the gcloud command for retrieving the # secrets. if [[ "${RUNNING_IN_CI:-}" == "true" ]]; then GCLOUD_COMMANDS=( "docker" "run" "--entrypoint=gcloud" "--volume=${KOKORO_GFILE_DIR}:${KOKORO_GFILE_DIR}" "gcr.io/google.com/cloudsdktool/cloud-sdk" ) if [[ "${TRAMPOLINE_CI:-}" == "kokoro" ]]; then SECRET_LOCATION="${KOKORO_GFILE_DIR}/secret_manager" else echo "Authentication for this CI system is not implemented yet." exit 2 # TODO: Determine appropriate SECRET_LOCATION and the GCLOUD_COMMANDS. fi else # For local run, use /dev/shm or temporary directory for # KOKORO_GFILE_DIR. if [[ -d "/dev/shm" ]]; then export KOKORO_GFILE_DIR=/dev/shm else export KOKORO_GFILE_DIR=$(mktemp -d -t ci-XXXXXXXX) fi SECRET_LOCATION="${KOKORO_GFILE_DIR}/secret_manager" GCLOUD_COMMANDS=("gcloud") fi msg "Creating folder on disk for secrets: ${SECRET_LOCATION}" mkdir -p ${SECRET_LOCATION} for key in $(echo ${SECRET_MANAGER_KEYS} | sed "s/,/ /g") do msg "Retrieving secret ${key}" "${GCLOUD_COMMANDS[@]}" \ secrets versions access latest \ --project cloud-devrel-kokoro-resources \ --secret $key > \ "$SECRET_LOCATION/$key" if [[ $? == 0 ]]; then msg "Secret written to ${SECRET_LOCATION}/${key}" else msg "Error retrieving secret ${key}" exit 2 fi done ================================================ FILE: .kokoro/presubmit/node18/common.cfg ================================================ # Format: //devtools/kokoro/config/proto/build.proto # Build logs will be here action { define_artifacts { regex: "**/*sponge_log.xml" } } # Download trampoline resources. gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" # Use the trampoline script to run in docker. build_file: "nodejs-vertexai/.kokoro/trampoline_v2.sh" # Configure the docker image for kokoro-trampoline. env_vars: { key: "TRAMPOLINE_IMAGE" value: "gcr.io/cloud-devrel-kokoro-resources/node:18-user" } env_vars: { key: "TRAMPOLINE_BUILD_FILE" value: "github/nodejs-vertexai/.kokoro/test.sh" } ================================================ FILE: .kokoro/presubmit/node18/continuous-system-test.cfg ================================================ # Download resources for system tests (service account key, etc.) gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/google-cloud-nodejs" env_vars: { key: "TRAMPOLINE_BUILD_FILE" value: "github/nodejs-vertexai/.kokoro/system-test.sh" } ================================================ FILE: .kokoro/presubmit/node18/docs.cfg ================================================ # doc publications use a Python image. env_vars: { key: "TRAMPOLINE_IMAGE" value: "gcr.io/cloud-devrel-kokoro-resources/node:18-user" } # Download trampoline resources. gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" # Use the trampoline script to run in docker. build_file: "nodejs-vertexai/.kokoro/trampoline_v2.sh" env_vars: { key: "TRAMPOLINE_BUILD_FILE" value: "github/nodejs-vertexai/.kokoro/presubmit/node18/docs.sh" } ================================================ FILE: .kokoro/presubmit/node18/docs.sh ================================================ #!/bin/bash # Copyright 2023 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. # set -eo pipefail if [[ -z "$CREDENTIALS" ]]; then # if CREDENTIALS are explicitly set, assume we're testing locally # and don't set NPM_CONFIG_PREFIX. export NPM_CONFIG_PREFIX=${HOME}/.npm-global export PATH="$PATH:${NPM_CONFIG_PREFIX}/bin" cd $(dirname $0)/../.. fi npm install npm install --no-save @google-cloud/cloud-rad@^0.4.0 # Switch to 'fail at end' to allow tar command to complete before exiting. set +e # publish docs to devsite NO_UPLOAD=1 npx @google-cloud/cloud-rad . cloud-rad tar cvfz docs.tar.gz yaml if [[ $EXIT -ne 0 ]]; then echo -e "\n Generate docs failed: npx returned a non-zero exit code. \n" exit $EXIT fi set -e ================================================ FILE: .kokoro/presubmit/node18/system-test.cfg ================================================ # Download resources for system tests (service account key, etc.) gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/google-cloud-nodejs" env_vars: { key: "TRAMPOLINE_BUILD_FILE" value: "github/nodejs-vertexai/.kokoro/system-test.sh" } ================================================ FILE: .kokoro/presubmit/node22/common.cfg ================================================ # Format: //devtools/kokoro/config/proto/build.proto # Build logs will be here action { define_artifacts { regex: "**/*sponge_log.xml" } } # Download trampoline resources. gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" # Use the trampoline script to run in docker. build_file: "nodejs-vertexai/.kokoro/trampoline_v2.sh" # Configure the docker image for kokoro-trampoline. env_vars: { key: "TRAMPOLINE_IMAGE" value: "gcr.io/cloud-devrel-kokoro-resources/node:22-user" } env_vars: { key: "TRAMPOLINE_BUILD_FILE" value: "github/nodejs-vertexai/.kokoro/test.sh" } ================================================ FILE: .kokoro/presubmit/node22/docs.cfg ================================================ # doc publications use a Python image. env_vars: { key: "TRAMPOLINE_IMAGE" value: "gcr.io/cloud-devrel-kokoro-resources/node:22-user" } # Download trampoline resources. gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" # Use the trampoline script to run in docker. build_file: "nodejs-vertexai/.kokoro/trampoline_v2.sh" env_vars: { key: "TRAMPOLINE_BUILD_FILE" value: "github/nodejs-vertexai/.kokoro/presubmit/node22/docs.sh" } ================================================ FILE: .kokoro/presubmit/node22/docs.sh ================================================ #!/bin/bash # Copyright 2023 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. # set -eo pipefail if [[ -z "$CREDENTIALS" ]]; then # if CREDENTIALS are explicitly set, assume we're testing locally # and don't set NPM_CONFIG_PREFIX. export NPM_CONFIG_PREFIX=${HOME}/.npm-global export PATH="$PATH:${NPM_CONFIG_PREFIX}/bin" cd $(dirname $0)/../.. fi npm install npm install --no-save @google-cloud/cloud-rad@^0.4.0 # Switch to 'fail at end' to allow tar command to complete before exiting. set +e # publish docs to devsite NO_UPLOAD=1 npx @google-cloud/cloud-rad . cloud-rad tar cvfz docs.tar.gz yaml if [[ $EXIT -ne 0 ]]; then echo -e "\n Generate docs failed: npx returned a non-zero exit code. \n" exit $EXIT fi set -e ================================================ FILE: .kokoro/presubmit/node22/system-test.cfg ================================================ # Download resources for system tests (service account key, etc.) gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/google-cloud-nodejs" env_vars: { key: "TRAMPOLINE_BUILD_FILE" value: "github/nodejs-vertexai/.kokoro/system-test.sh" } ================================================ FILE: .kokoro/publish.sh ================================================ #!/bin/bash # Copyright 2018 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. set -eo pipefail export NPM_CONFIG_PREFIX=${HOME}/.npm-global # Start the releasetool reporter python3 -m releasetool publish-reporter-script > /tmp/publisher-script; source /tmp/publisher-script cd $(dirname $0)/.. NPM_TOKEN=$(cat $KOKORO_KEYSTORE_DIR/73713_google-cloud-npm-token-1) echo "//wombat-dressing-room.appspot.com/:_authToken=${NPM_TOKEN}" > ~/.npmrc npm install npm pack . # npm provides no way to specify, observe, or predict the name of the tarball # file it generates. We have to look in the current directory for the freshest # .tgz file. # TARBALL=$(ls -1 -t *.tgz | head -1) npm publish --access=public --registry=https://wombat-dressing-room.appspot.com "$TARBALL" # Kokoro collects *.tgz and package-lock.json files and stores them in Placer # so we can generate SBOMs and attestations. # However, we *don't* want Kokoro to collect package-lock.json and *.tgz files # that happened to be installed with dependencies. find node_modules -name package-lock.json -o -name "*.tgz" | xargs rm -f ================================================ FILE: .kokoro/system-test.sh ================================================ #!/bin/bash # Copyright 2018 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. set -eo pipefail export NPM_CONFIG_PREFIX=${HOME}/.npm-global # Setup service account credentials. export GCLOUD_PROJECT=ucaip-sample-tests cd $(dirname $0)/.. # Run a pre-test hook, if a pre-system-test.sh is in the project # if [ -f .kokoro/pre-system-test.sh ]; then set +x . .kokoro/pre-system-test.sh set -x fi npm install # If tests are running against main branch, configure flakybot # to open issues on failures: if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"continuous"* ]] || [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"nightly"* ]]; then export MOCHA_REPORTER_OUTPUT=test_output_sponge_log.xml export MOCHA_REPORTER=xunit cleanup() { chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot $KOKORO_GFILE_DIR/linux_amd64/flakybot } trap cleanup EXIT HUP fi # Switch to 'fail at end' to allow tar command to complete before exiting. set +e npm run cover:unit && npm run cover:integration EXIT=$? tar cvfz build.tar.gz build npm run cover:report if [ -d "coverage" ]; then tar cvfz coverage.tar.gz coverage fi if [[ $EXIT -ne 0 ]]; then echo -e "\n Testing failed: npm returned a non-zero exit code. \n" exit $EXIT fi set -e ================================================ FILE: .kokoro/test.sh ================================================ #!/bin/bash # Copyright 2018 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. set -eo pipefail export NPM_CONFIG_PREFIX=${HOME}/.npm-global cd $(dirname $0)/.. npm install # If tests are running against main branch, configure flakybot # to open issues on failures: if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"continuous"* ]] || [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"nightly"* ]]; then export MOCHA_REPORTER_OUTPUT=test_output_sponge_log.xml export MOCHA_REPORTER=xunit cleanup() { chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot $KOKORO_GFILE_DIR/linux_amd64/flakybot } trap cleanup EXIT HUP fi # Unit tests exercise the entire API surface, which may include # deprecation warnings: export MOCHA_THROW_DEPRECATION=false npm test # codecov combines coverage across integration and unit tests. Include # the logic below for any environment you wish to collect coverage for: COVERAGE_NODE=22 if npx check-node-version@3.3.0 --silent --node $COVERAGE_NODE; then NYC_BIN=./node_modules/nyc/bin/nyc.js if [ -f "$NYC_BIN" ]; then $NYC_BIN report || true fi bash $KOKORO_GFILE_DIR/codecov.sh else echo "coverage is only reported for Node $COVERAGE_NODE" fi ================================================ FILE: .kokoro/trampoline_v2.sh ================================================ #!/usr/bin/env bash # Copyright 2020 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 # # http://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. # trampoline_v2.sh # # If you want to make a change to this file, consider doing so at: # https://github.com/googlecloudplatform/docker-ci-helper # # This script is for running CI builds. For Kokoro builds, we # set this script to `build_file` field in the Kokoro configuration. # This script does 3 things. # # 1. Prepare the Docker image for the test # 2. Run the Docker with appropriate flags to run the test # 3. Upload the newly built Docker image # # in a way that is somewhat compatible with trampoline_v1. # # These environment variables are required: # TRAMPOLINE_IMAGE: The docker image to use. # TRAMPOLINE_DOCKERFILE: The location of the Dockerfile. # # You can optionally change these environment variables: # TRAMPOLINE_IMAGE_UPLOAD: # (true|false): Whether to upload the Docker image after the # successful builds. # TRAMPOLINE_BUILD_FILE: The script to run in the docker container. # TRAMPOLINE_WORKSPACE: The workspace path in the docker container. # Defaults to /workspace. # Potentially there are some repo specific envvars in .trampolinerc in # the project root. # # Here is an example for running this script. # TRAMPOLINE_IMAGE=gcr.io/cloud-devrel-kokoro-resources/node:10-user \ # TRAMPOLINE_BUILD_FILE=.kokoro/system-test.sh \ # .kokoro/trampoline_v2.sh set -euo pipefail # x-release-please-start-version TRAMPOLINE_VERSION="2.0.10" # x-release-please-end if command -v tput >/dev/null && [[ -n "${TERM:-}" ]]; then readonly IO_COLOR_RED="$(tput setaf 1)" readonly IO_COLOR_GREEN="$(tput setaf 2)" readonly IO_COLOR_YELLOW="$(tput setaf 3)" readonly IO_COLOR_RESET="$(tput sgr0)" else readonly IO_COLOR_RED="" readonly IO_COLOR_GREEN="" readonly IO_COLOR_YELLOW="" readonly IO_COLOR_RESET="" fi function function_exists { [[ "$(LC_ALL=C type -t "$1")" == "function" ]] } # Logs a message using the given color. The first argument must be one # of the IO_COLOR_* variables defined above, such as # "${IO_COLOR_YELLOW}". The remaining arguments will be logged in the # given color. The log message will also have an RFC-3339 timestamp # prepended (in UTC). You can disable the color output by setting # TERM=vt100. function log_impl() { local color="$1" shift local timestamp timestamp="$(date -u "+%Y-%m-%dT%H:%M:%SZ")" echo "================================================================" echo "${color}${timestamp}:" "$@" "${IO_COLOR_RESET}" echo "================================================================" } # Logs the given message with normal coloring and a timestamp. function log() { log_impl "${IO_COLOR_RESET}" "$@" } # Logs the given message in green with a timestamp. function log_green() { log_impl "${IO_COLOR_GREEN}" "$@" } # Logs the given message in yellow with a timestamp. function log_yellow() { log_impl "${IO_COLOR_YELLOW}" "$@" } # Logs the given message in red with a timestamp. function log_red() { log_impl "${IO_COLOR_RED}" "$@" } readonly tmpdir=$(mktemp -d -t ci-XXXXXXXX) readonly tmphome="${tmpdir}/h" mkdir -p "${tmphome}" function cleanup() { rm -rf "${tmpdir}" } trap cleanup EXIT RUNNING_IN_CI="${RUNNING_IN_CI:-false}" # The workspace in the container, defaults to /workspace. TRAMPOLINE_WORKSPACE="${TRAMPOLINE_WORKSPACE:-/workspace}" pass_down_envvars=( # TRAMPOLINE_V2 variables. # Tells scripts whether they are running as part of CI or not. "RUNNING_IN_CI" # Indicates which CI system we're in. "TRAMPOLINE_CI" # Indicates the version of the script. "TRAMPOLINE_VERSION" ) log_yellow "Building with Trampoline ${TRAMPOLINE_VERSION}" # Detect which CI systems we're in. If we're in any of the CI systems # we support, `RUNNING_IN_CI` will be true and `TRAMPOLINE_CI` will be # the name of the CI system. Both envvars will be passing down to the # container for telling which CI system we're in. if [[ -n "${KOKORO_BUILD_ID:-}" ]]; then # descriptive env var for indicating it's on CI. RUNNING_IN_CI="true" TRAMPOLINE_CI="kokoro" if [[ "${TRAMPOLINE_USE_LEGACY_SERVICE_ACCOUNT:-}" == "true" ]]; then if [[ ! -f "${KOKORO_GFILE_DIR}/kokoro-trampoline.service-account.json" ]]; then log_red "${KOKORO_GFILE_DIR}/kokoro-trampoline.service-account.json does not exist. Did you forget to mount cloud-devrel-kokoro-resources/trampoline? Aborting." exit 1 fi # This service account will be activated later. TRAMPOLINE_SERVICE_ACCOUNT="${KOKORO_GFILE_DIR}/kokoro-trampoline.service-account.json" else if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then gcloud auth list fi log_yellow "Configuring Container Registry access" gcloud auth configure-docker --quiet fi pass_down_envvars+=( # KOKORO dynamic variables. "KOKORO_BUILD_NUMBER" "KOKORO_BUILD_ID" "KOKORO_JOB_NAME" "KOKORO_GIT_COMMIT" "KOKORO_GITHUB_COMMIT" "KOKORO_GITHUB_PULL_REQUEST_NUMBER" "KOKORO_GITHUB_PULL_REQUEST_COMMIT" # For Flaky Bot "KOKORO_GITHUB_COMMIT_URL" "KOKORO_GITHUB_PULL_REQUEST_URL" "KOKORO_BUILD_ARTIFACTS_SUBDIR" ) elif [[ "${TRAVIS:-}" == "true" ]]; then RUNNING_IN_CI="true" TRAMPOLINE_CI="travis" pass_down_envvars+=( "TRAVIS_BRANCH" "TRAVIS_BUILD_ID" "TRAVIS_BUILD_NUMBER" "TRAVIS_BUILD_WEB_URL" "TRAVIS_COMMIT" "TRAVIS_COMMIT_MESSAGE" "TRAVIS_COMMIT_RANGE" "TRAVIS_JOB_NAME" "TRAVIS_JOB_NUMBER" "TRAVIS_JOB_WEB_URL" "TRAVIS_PULL_REQUEST" "TRAVIS_PULL_REQUEST_BRANCH" "TRAVIS_PULL_REQUEST_SHA" "TRAVIS_PULL_REQUEST_SLUG" "TRAVIS_REPO_SLUG" "TRAVIS_SECURE_ENV_VARS" "TRAVIS_TAG" ) elif [[ -n "${GITHUB_RUN_ID:-}" ]]; then RUNNING_IN_CI="true" TRAMPOLINE_CI="github-workflow" pass_down_envvars+=( "GITHUB_WORKFLOW" "GITHUB_RUN_ID" "GITHUB_RUN_NUMBER" "GITHUB_ACTION" "GITHUB_ACTIONS" "GITHUB_ACTOR" "GITHUB_REPOSITORY" "GITHUB_EVENT_NAME" "GITHUB_EVENT_PATH" "GITHUB_SHA" "GITHUB_REF" "GITHUB_HEAD_REF" "GITHUB_BASE_REF" ) elif [[ "${CIRCLECI:-}" == "true" ]]; then RUNNING_IN_CI="true" TRAMPOLINE_CI="circleci" pass_down_envvars+=( "CIRCLE_BRANCH" "CIRCLE_BUILD_NUM" "CIRCLE_BUILD_URL" "CIRCLE_COMPARE_URL" "CIRCLE_JOB" "CIRCLE_NODE_INDEX" "CIRCLE_NODE_TOTAL" "CIRCLE_PREVIOUS_BUILD_NUM" "CIRCLE_PROJECT_REPONAME" "CIRCLE_PROJECT_USERNAME" "CIRCLE_REPOSITORY_URL" "CIRCLE_SHA1" "CIRCLE_STAGE" "CIRCLE_USERNAME" "CIRCLE_WORKFLOW_ID" "CIRCLE_WORKFLOW_JOB_ID" "CIRCLE_WORKFLOW_UPSTREAM_JOB_IDS" "CIRCLE_WORKFLOW_WORKSPACE_ID" ) fi # Configure the service account for pulling the docker image. function repo_root() { local dir="$1" while [[ ! -d "${dir}/.git" ]]; do dir="$(dirname "$dir")" done echo "${dir}" } # Detect the project root. In CI builds, we assume the script is in # the git tree and traverse from there, otherwise, traverse from `pwd` # to find `.git` directory. if [[ "${RUNNING_IN_CI:-}" == "true" ]]; then PROGRAM_PATH="$(realpath "$0")" PROGRAM_DIR="$(dirname "${PROGRAM_PATH}")" PROJECT_ROOT="$(repo_root "${PROGRAM_DIR}")" else PROJECT_ROOT="$(repo_root "$(pwd)")" fi log_yellow "Changing to the project root: ${PROJECT_ROOT}." cd "${PROJECT_ROOT}" # To support relative path for `TRAMPOLINE_SERVICE_ACCOUNT`, we need # to use this environment variable in `PROJECT_ROOT`. if [[ -n "${TRAMPOLINE_SERVICE_ACCOUNT:-}" ]]; then mkdir -p "${tmpdir}/gcloud" gcloud_config_dir="${tmpdir}/gcloud" log_yellow "Using isolated gcloud config: ${gcloud_config_dir}." export CLOUDSDK_CONFIG="${gcloud_config_dir}" log_yellow "Using ${TRAMPOLINE_SERVICE_ACCOUNT} for authentication." gcloud auth activate-service-account \ --key-file "${TRAMPOLINE_SERVICE_ACCOUNT}" log_yellow "Configuring Container Registry access" gcloud auth configure-docker --quiet fi required_envvars=( # The basic trampoline configurations. "TRAMPOLINE_IMAGE" "TRAMPOLINE_BUILD_FILE" ) if [[ -f "${PROJECT_ROOT}/.trampolinerc" ]]; then source "${PROJECT_ROOT}/.trampolinerc" fi log_yellow "Checking environment variables." for e in "${required_envvars[@]}" do if [[ -z "${!e:-}" ]]; then log "Missing ${e} env var. Aborting." exit 1 fi done # We want to support legacy style TRAMPOLINE_BUILD_FILE used with V1 # script: e.g. "github/repo-name/.kokoro/run_tests.sh" TRAMPOLINE_BUILD_FILE="${TRAMPOLINE_BUILD_FILE#github/*/}" log_yellow "Using TRAMPOLINE_BUILD_FILE: ${TRAMPOLINE_BUILD_FILE}" # ignore error on docker operations and test execution set +e log_yellow "Preparing Docker image." # We only download the docker image in CI builds. if [[ "${RUNNING_IN_CI:-}" == "true" ]]; then # Download the docker image specified by `TRAMPOLINE_IMAGE` # We may want to add --max-concurrent-downloads flag. log_yellow "Start pulling the Docker image: ${TRAMPOLINE_IMAGE}." if docker pull "${TRAMPOLINE_IMAGE}"; then log_green "Finished pulling the Docker image: ${TRAMPOLINE_IMAGE}." has_image="true" else log_red "Failed pulling the Docker image: ${TRAMPOLINE_IMAGE}." has_image="false" fi else # For local run, check if we have the image. if docker images "${TRAMPOLINE_IMAGE}" | grep "${TRAMPOLINE_IMAGE%:*}"; then has_image="true" else has_image="false" fi fi # The default user for a Docker container has uid 0 (root). To avoid # creating root-owned files in the build directory we tell docker to # use the current user ID. user_uid="$(id -u)" user_gid="$(id -g)" user_name="$(id -un)" # To allow docker in docker, we add the user to the docker group in # the host os. docker_gid=$(cut -d: -f3 < <(getent group docker)) update_cache="false" if [[ "${TRAMPOLINE_DOCKERFILE:-none}" != "none" ]]; then # Build the Docker image from the source. context_dir=$(dirname "${TRAMPOLINE_DOCKERFILE}") docker_build_flags=( "-f" "${TRAMPOLINE_DOCKERFILE}" "-t" "${TRAMPOLINE_IMAGE}" "--build-arg" "UID=${user_uid}" "--build-arg" "USERNAME=${user_name}" ) if [[ "${has_image}" == "true" ]]; then docker_build_flags+=("--cache-from" "${TRAMPOLINE_IMAGE}") fi log_yellow "Start building the docker image." if [[ "${TRAMPOLINE_VERBOSE:-false}" == "true" ]]; then echo "docker build" "${docker_build_flags[@]}" "${context_dir}" fi # ON CI systems, we want to suppress docker build logs, only # output the logs when it fails. if [[ "${RUNNING_IN_CI:-}" == "true" ]]; then if docker build "${docker_build_flags[@]}" "${context_dir}" \ > "${tmpdir}/docker_build.log" 2>&1; then if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then cat "${tmpdir}/docker_build.log" fi log_green "Finished building the docker image." update_cache="true" else log_red "Failed to build the Docker image, aborting." log_yellow "Dumping the build logs:" cat "${tmpdir}/docker_build.log" exit 1 fi else if docker build "${docker_build_flags[@]}" "${context_dir}"; then log_green "Finished building the docker image." update_cache="true" else log_red "Failed to build the Docker image, aborting." exit 1 fi fi else if [[ "${has_image}" != "true" ]]; then log_red "We do not have ${TRAMPOLINE_IMAGE} locally, aborting." exit 1 fi fi # We use an array for the flags so they are easier to document. docker_flags=( # Remove the container after it exists. "--rm" # Use the host network. "--network=host" # Run in privileged mode. We are not using docker for sandboxing or # isolation, just for packaging our dev tools. "--privileged" # Run the docker script with the user id. Because the docker image gets to # write in ${PWD} you typically want this to be your user id. # To allow docker in docker, we need to use docker gid on the host. "--user" "${user_uid}:${docker_gid}" # Pass down the USER. "--env" "USER=${user_name}" # Mount the project directory inside the Docker container. "--volume" "${PROJECT_ROOT}:${TRAMPOLINE_WORKSPACE}" "--workdir" "${TRAMPOLINE_WORKSPACE}" "--env" "PROJECT_ROOT=${TRAMPOLINE_WORKSPACE}" # Mount the temporary home directory. "--volume" "${tmphome}:/h" "--env" "HOME=/h" # Allow docker in docker. "--volume" "/var/run/docker.sock:/var/run/docker.sock" # Mount the /tmp so that docker in docker can mount the files # there correctly. "--volume" "/tmp:/tmp" # Pass down the KOKORO_GFILE_DIR and KOKORO_KEYSTORE_DIR # TODO(tmatsuo): This part is not portable. "--env" "TRAMPOLINE_SECRET_DIR=/secrets" "--volume" "${KOKORO_GFILE_DIR:-/dev/shm}:/secrets/gfile" "--env" "KOKORO_GFILE_DIR=/secrets/gfile" "--volume" "${KOKORO_KEYSTORE_DIR:-/dev/shm}:/secrets/keystore" "--env" "KOKORO_KEYSTORE_DIR=/secrets/keystore" ) # Add an option for nicer output if the build gets a tty. if [[ -t 0 ]]; then docker_flags+=("-it") fi # Passing down env vars for e in "${pass_down_envvars[@]}" do if [[ -n "${!e:-}" ]]; then docker_flags+=("--env" "${e}=${!e}") fi done # If arguments are given, all arguments will become the commands run # in the container, otherwise run TRAMPOLINE_BUILD_FILE. if [[ $# -ge 1 ]]; then log_yellow "Running the given commands '" "${@:1}" "' in the container." readonly commands=("${@:1}") if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then echo docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" "${commands[@]}" fi docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" "${commands[@]}" else log_yellow "Running the tests in a Docker container." docker_flags+=("--entrypoint=${TRAMPOLINE_BUILD_FILE}") if [[ "${TRAMPOLINE_VERBOSE:-}" == "true" ]]; then echo docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" fi docker run "${docker_flags[@]}" "${TRAMPOLINE_IMAGE}" fi test_retval=$? if [[ ${test_retval} -eq 0 ]]; then log_green "Build finished with ${test_retval}" else log_red "Build finished with ${test_retval}" fi # Only upload it when the test passes. if [[ "${update_cache}" == "true" ]] && \ [[ $test_retval == 0 ]] && \ [[ "${TRAMPOLINE_IMAGE_UPLOAD:-false}" == "true" ]]; then log_yellow "Uploading the Docker image." if docker push "${TRAMPOLINE_IMAGE}"; then log_green "Finished uploading the Docker image." else log_red "Failed uploading the Docker image." fi # Call trampoline_after_upload_hook if it's defined. if function_exists trampoline_after_upload_hook; then trampoline_after_upload_hook fi fi exit "${test_retval}" ================================================ FILE: .prettierignore ================================================ **/node_modules build/ docs/ test/ system_test/ sdk_schema_test/ src/**/test/ ================================================ FILE: .prettierrc.js ================================================ /** * @license * Copyright 2023 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. */ module.exports = { ...require('gts/.prettierrc.json') }; ================================================ FILE: .release-please-manifest.json ================================================ { ".": "0.6.0" } ================================================ FILE: .repo-metadata.json ================================================ { "name": "vertexai", "name_pretty": "Google Cloud Vertex AI", "release_level": "preview", "language": "nodejs", "repo": "googleapis/nodejs-vertexai", "distribution_name": "@google-cloud/vertexai", "api_id": "aiplatform.googleapis.com", "api_shortname": "aiplatform", "library_type": "GAPIC_MANUAL", "client_documentation": "https://cloud.google.com/nodejs/docs/reference/vertexai/latest" } ================================================ FILE: .trampolinerc ================================================ # Copyright 2020 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 # # http://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. # Template for .trampolinerc # Add required env vars here. required_envvars+=( ) # Add env vars which are passed down into the container here. pass_down_envvars+=( "AUTORELEASE_PR" "VERSION" ) # Prevent unintentional override on the default image. if [[ "${TRAMPOLINE_IMAGE_UPLOAD:-false}" == "true" ]] && \ [[ -z "${TRAMPOLINE_IMAGE:-}" ]]; then echo "Please set TRAMPOLINE_IMAGE if you want to upload the Docker image." exit 1 fi # Define the default value if it makes sense. if [[ -z "${TRAMPOLINE_IMAGE_UPLOAD:-}" ]]; then TRAMPOLINE_IMAGE_UPLOAD="" fi if [[ -z "${TRAMPOLINE_IMAGE:-}" ]]; then TRAMPOLINE_IMAGE="" fi if [[ -z "${TRAMPOLINE_DOCKERFILE:-}" ]]; then TRAMPOLINE_DOCKERFILE="" fi if [[ -z "${TRAMPOLINE_BUILD_FILE:-}" ]]; then TRAMPOLINE_BUILD_FILE="" fi # Secret Manager secrets. source ${PROJECT_ROOT}/.kokoro/populate-secrets.sh ================================================ FILE: CHANGELOG.md ================================================ # Changelog ## [0.6.0](https://github.com/googleapis/nodejs-vertexai/compare/v0.5.0...v0.6.0) (2026-05-13) ### Features * Update minimum supported Node version to Node 20 ([e2a384e](https://github.com/googleapis/nodejs-vertexai/commit/e2a384e88744914fe8daab01d4ea1f5765cd8700)) * BREAKING CHANGE - Rename the package `@google-cloud/agentplatform` ([adf4388](https://github.com/googleapis/nodejs-vertexai/commit/adf438868e497a4b0118950bc6ed7ba467ec02f6)) ## [1.12.0](https://github.com/googleapis/nodejs-vertexai/compare/v1.11.0...v1.12.0) (2026-04-14) ### Features * Add Agent Engine-level configuration for generation_trigger_config. ([365a14a](https://github.com/googleapis/nodejs-vertexai/commit/365a14ae4b05f81df52fd9fbfe2d3ac3371a2b97)) * Add ingest_events method for Memory Bank. ([365a14a](https://github.com/googleapis/nodejs-vertexai/commit/365a14ae4b05f81df52fd9fbfe2d3ac3371a2b97)) * Add memory_types filter to RetrieveMemories ([90e3f69](https://github.com/googleapis/nodejs-vertexai/commit/90e3f6922caebb65535958081d18b200246cef60)) * Add RetrieveProfiles. ([90e3f69](https://github.com/googleapis/nodejs-vertexai/commit/90e3f6922caebb65535958081d18b200246cef60)) * Add structured data and context to MemoryRevision. ([90e3f69](https://github.com/googleapis/nodejs-vertexai/commit/90e3f6922caebb65535958081d18b200246cef60)) * Add structured data and memory type to Memory. ([90e3f69](https://github.com/googleapis/nodejs-vertexai/commit/90e3f6922caebb65535958081d18b200246cef60)) * Add subset_topics to Memory Bank GenerateMemories ([7932c2b](https://github.com/googleapis/nodejs-vertexai/commit/7932c2b49a05d26c5656bb996cd09709d60670c9)) * Add support for agent gateway in agent engine ([b3ea8e3](https://github.com/googleapis/nodejs-vertexai/commit/b3ea8e3a8fdb90e05c5531e01f4ec1284c105af6)) * add support for keep alive probe in agent engines ([088c5ad](https://github.com/googleapis/nodejs-vertexai/commit/088c5ad3edabb13e49dc520a945ac0f48b145704)) * Adds cancel_query_job to SDK for agent engine long running async tasks. ([bc19f31](https://github.com/googleapis/nodejs-vertexai/commit/bc19f31d0f86bdd9f42572a8d0a4ef94e82684e5)) ## [1.11.0](https://github.com/googleapis/nodejs-vertexai/compare/v1.10.4...v1.11.0) (2026-04-07) ### Features * Add consolidation customization to Memory Bank ([9df74eb](https://github.com/googleapis/nodejs-vertexai/commit/9df74eb4c128084d9746b8cf26570a7a04452178)) * Add session_id to Create Session to allow custom session id ([fed70af](https://github.com/googleapis/nodejs-vertexai/commit/fed70afa92c42331efa5633c80184d27b8d0a1c4)) * In run_query_job, rename gcs_bucket to gcs_uri and allow the case that user sets the filename for the output. ([4a1a387](https://github.com/googleapis/nodejs-vertexai/commit/4a1a3870cb368e574cb51ef7a284b82a3b09f935)) ## [1.10.4](https://github.com/googleapis/nodejs-vertexai/compare/v1.10.3...v1.10.4) (2026-03-31) ### Features * Add memory_id to Create Memory ([73207d3](https://github.com/googleapis/nodejs-vertexai/commit/73207d37f72df9475c8919bbace08e8d531daa7f)) * Add raw_event to Append Event ([73207d3](https://github.com/googleapis/nodejs-vertexai/commit/73207d37f72df9475c8919bbace08e8d531daa7f)) * add support for container_spec in AgentEngines ([274e0ff](https://github.com/googleapis/nodejs-vertexai/commit/274e0ff4861a5d7ec5a157300b4675ca6aa70695)) ### Miscellaneous Chores * release 1.10.4 ([15988b8](https://github.com/googleapis/nodejs-vertexai/commit/15988b8e5810d9faebebfaca2c0963b74dea5b90)) ## [1.10.3](https://github.com/googleapis/nodejs-vertexai/compare/v1.10.2...v1.10.3) (2026-03-24) ### Miscellaneous Chores * release 1.10.3 ([6a68cbe](https://github.com/googleapis/nodejs-vertexai/commit/6a68cbe24119a879f963587646fd9d69fecb9fc2)) ## [1.10.2](https://github.com/googleapis/nodejs-vertexai/compare/v1.10.1...v1.10.2) (2026-03-19) ### Miscellaneous Chores * release 1.10.2 ([431950d](https://github.com/googleapis/nodejs-vertexai/commit/431950d9a41db230b798bc01cfe4ba3d48254584)) ## [1.10.1](https://github.com/googleapis/nodejs-vertexai/compare/v1.10.0...v1.10.1) (2026-03-18) ### Miscellaneous Chores * release 1.10.1 ([3c7a6e6](https://github.com/googleapis/nodejs-vertexai/commit/3c7a6e67184eaf1d9b55058834afa519c7c1ecb4)) ## [1.10.0](https://github.com/googleapis/nodejs-vertexai/compare/v1.9.3...v1.10.0) (2025-04-10) ### Features * Allow labels in GenerateContentRequest ([d210d06](https://github.com/googleapis/nodejs-vertexai/commit/d210d06a2f389911850d6dc6a04b527a8cbdf68e)) * Allow labels in GenerateContentRequest ([#466](https://github.com/googleapis/nodejs-vertexai/issues/466)) ([#501](https://github.com/googleapis/nodejs-vertexai/issues/501)) ([0075baa](https://github.com/googleapis/nodejs-vertexai/commit/0075baae578e34341afdfe3e6ec0086cca98b298)) * enable turn off the safety filter in HarmBlockThreshold enum ([1737c66](https://github.com/googleapis/nodejs-vertexai/commit/1737c6626aed0ef8d9e1904be7a79b50b7da4676)) ### Bug Fixes * aggregate text & functionCall(s) correctly ([5a53266](https://github.com/googleapis/nodejs-vertexai/commit/5a53266835b74e6d165244a67a5cb9427220d7de)) * aggregate text & functionCall(s) correctly ([5a53266](https://github.com/googleapis/nodejs-vertexai/commit/5a53266835b74e6d165244a67a5cb9427220d7de)) * aggregate text & functionCall(s) correctly ([5a53266](https://github.com/googleapis/nodejs-vertexai/commit/5a53266835b74e6d165244a67a5cb9427220d7de)) * aggregate text & functionCall(s) correctly ([#497](https://github.com/googleapis/nodejs-vertexai/issues/497)) ([b62483a](https://github.com/googleapis/nodejs-vertexai/commit/b62483a4891159ac727687ef043f7923a8f7d71d)) ## [1.9.3](https://github.com/googleapis/nodejs-vertexai/compare/v1.9.2...v1.9.3) (2025-01-31) ### Bug Fixes * a typo in chat session and missed toolConfig on chat start ([b552fea](https://github.com/googleapis/nodejs-vertexai/commit/b552fea1aac80a6e471fd082dc35c40598d5d170)) ## [1.9.2](https://github.com/googleapis/nodejs-vertexai/compare/v1.9.0...v1.9.2) (2024-12-13) ### Features * add support for audioTimestamp in GenerationConfig ([#467](https://github.com/googleapis/nodejs-vertexai/issues/467)) ([598d955](https://github.com/googleapis/nodejs-vertexai/commit/598d95580fb8302bced40837b5c4bbebc84946cf)) * enable dynamic retrieval for Google Search Retrieval grounding ([3f9eee6](https://github.com/googleapis/nodejs-vertexai/commit/3f9eee6589967164b8c1b86481468eaa5347afbd)) ### Bug Fixes * a typo in chat session and missed toolConfig on chat start ([b552fea](https://github.com/googleapis/nodejs-vertexai/commit/b552fea1aac80a6e471fd082dc35c40598d5d170)) * Add Context Cache support for ChatSessionPreview class ([#433](https://github.com/googleapis/nodejs-vertexai/issues/433)) ([df6f040](https://github.com/googleapis/nodejs-vertexai/commit/df6f0406fbaa72cd64a8f51015e51fee88518db8)) * Add Context Cache support for ChatSessionPreview class ([#433](https://github.com/googleapis/nodejs-vertexai/issues/433)) ([a3beab1](https://github.com/googleapis/nodejs-vertexai/commit/a3beab1f30540749fbeba40a13327ea078dbed69)) * include cachedContent in generate request ([#469](https://github.com/googleapis/nodejs-vertexai/issues/469)) ([a16b9d4](https://github.com/googleapis/nodejs-vertexai/commit/a16b9d48df1e3d3b8784604de08f28167f3e85bf)) * remove restriction on gsc uri for file data part. ([e694c44](https://github.com/googleapis/nodejs-vertexai/commit/e694c441b456ea7bfb3d09f89c17d71641ef355c)) ### Documentation * update README ([e9705cb](https://github.com/googleapis/nodejs-vertexai/commit/e9705cbd44154435a6ad32979e80005a8eef137d)) * update README ([a052132](https://github.com/googleapis/nodejs-vertexai/commit/a052132b91bad5ee9a42c6fe2057afceab36b542)) ### Miscellaneous Chores * release as 1.9.2 ([d54a91b](https://github.com/googleapis/nodejs-vertexai/commit/d54a91bce84980ddfa90b38318a789787912833a)) ## [1.9.0](https://github.com/googleapis/nodejs-vertexai/compare/v1.8.1...v1.9.0) (2024-10-14) ### Features * Add Context Cache support for ChatSessionPreview class ([#433](https://github.com/googleapis/nodejs-vertexai/issues/433)) ([f8a3bdf](https://github.com/googleapis/nodejs-vertexai/commit/f8a3bdf55b6ee694a8fd41df29bdba54d7f8cdc2)) ### Documentation * update README ([a052132](https://github.com/googleapis/nodejs-vertexai/commit/a052132b91bad5ee9a42c6fe2057afceab36b542)) ## [1.8.1](https://github.com/googleapis/nodejs-vertexai/compare/v1.8.0...v1.8.1) (2024-09-25) ### Bug Fixes * Fix cached contents list url ([2c4b769](https://github.com/googleapis/nodejs-vertexai/commit/2c4b7692e369385e5cd82a9b753d037d31e4e8ce)) ## [1.8.0](https://github.com/googleapis/nodejs-vertexai/compare/v1.7.0...v1.8.0) (2024-09-18) ### Features * Add CachedContent resource to Vertex AI client library. ([8c8963e](https://github.com/googleapis/nodejs-vertexai/commit/8c8963e5c62bf491d5a47f7c5a0db64fafaea0cd)) * Implement cached_content with generateContent methods ([c604b8c](https://github.com/googleapis/nodejs-vertexai/commit/c604b8caf4138537b38bdf9f57e8086d55216981)) ## [1.7.0](https://github.com/googleapis/nodejs-vertexai/compare/v1.6.0...v1.7.0) (2024-08-30) ### Features * Add GoogleApi error in ClientError.cause ([d5c67bd](https://github.com/googleapis/nodejs-vertexai/commit/d5c67bdbb7d40f0c8eecca505c90bac21e4fe36d)) ## [1.6.0](https://github.com/googleapis/nodejs-vertexai/compare/v1.5.0...v1.6.0) (2024-08-26) ### Features * Add responseSchema to GenerateContentRequest. ([d3715da](https://github.com/googleapis/nodejs-vertexai/commit/d3715daa793fda8063b379d16a0bf844a90b4087)) * Add tool config ([f618132](https://github.com/googleapis/nodejs-vertexai/commit/f618132b7b5f9a05ba32b5968ccec14c9c18baaa)) ## [1.5.0](https://github.com/googleapis/nodejs-vertexai/compare/v1.4.1...v1.5.0) (2024-08-21) ### Features * missing property frequencyPenalty in type defintions ([#394](https://github.com/googleapis/nodejs-vertexai/issues/394)) ([7557a83](https://github.com/googleapis/nodejs-vertexai/commit/7557a839b96a9fddc17c6516dd9c8c12772b6c59)) ## [1.4.1](https://github.com/googleapis/nodejs-vertexai/compare/v1.4.0...v1.4.1) (2024-08-09) ### Bug Fixes * Fix docstring order and add node version badge in README ([d330fe3](https://github.com/googleapis/nodejs-vertexai/commit/d330fe3352713226794ac3e8c7a7a21474a32ec1)) ## [1.4.0](https://github.com/googleapis/nodejs-vertexai/compare/v1.3.0...v1.4.0) (2024-07-15) ### Features * support responseMimeType in GenerationConfig to allow users specify output response mimetype of the generated candidate text. ([93f6d70](https://github.com/googleapis/nodejs-vertexai/commit/93f6d70660dbee44f81766544047da7baf427e30)) ### Bug Fixes * handle case when content is undefined in candidate. ([f16f040](https://github.com/googleapis/nodejs-vertexai/commit/f16f0405c0419152119385780ba21b2d9c18dc9b)) ## [1.3.0](https://github.com/googleapis/nodejs-vertexai/compare/v1.2.0...v1.3.0) (2024-06-26) ### Features * infer project ID when user don't specify and throw if inference fails ([6b3e68e](https://github.com/googleapis/nodejs-vertexai/commit/6b3e68e3b869659d17ef584995de7d7bfc1b1f3b)) ### Bug Fixes * improve error message to help with debugging ([8a937d5](https://github.com/googleapis/nodejs-vertexai/commit/8a937d5f534f54867fd62a988dbd84ebafb5b76a)) ## [1.2.0](https://github.com/googleapis/nodejs-vertexai/compare/v1.1.0...v1.2.0) (2024-05-22) ### Features * allow users to pass string as system instruction ([a824162](https://github.com/googleapis/nodejs-vertexai/commit/a824162a29b8c6ba3ccae46c492dd28e9c2baf9c)) * enable inference request to tuned model. ([de9c4c2](https://github.com/googleapis/nodejs-vertexai/commit/de9c4c2f8c63a298bd28ab69dae9b6a5d72c20d7)) * infer location if user doesn't specifies it. ([b8d4af1](https://github.com/googleapis/nodejs-vertexai/commit/b8d4af1bb990e95093f446c808194bfc4fe53287)) * support RAG in public preview ([5ade755](https://github.com/googleapis/nodejs-vertexai/commit/5ade7551fe0dbab54bc56f251c32bf3b7802c2c5)) * update grounding metadata ([d3c0a64](https://github.com/googleapis/nodejs-vertexai/commit/d3c0a647248be6be49b6b93a18aad79c10bae6c4)) ### Bug Fixes * log instead of throw appendHistory errors to avoid unhandled rejection ([2ec9e7d](https://github.com/googleapis/nodejs-vertexai/commit/2ec9e7d5519af438eb03b9f21f90b86f2575ac47)) ## [1.1.0](https://github.com/googleapis/nodejs-vertexai/compare/v1.0.0...v1.1.0) (2024-04-13) ### Features * enable system instruction for GenerativeModel ([590ca5a](https://github.com/googleapis/nodejs-vertexai/commit/590ca5a055e65b493c7d20f3983173dc8a8cbc39)) * enable system instruction in chat experience ([7e71f75](https://github.com/googleapis/nodejs-vertexai/commit/7e71f750104cf14f465bb8091f851b5692f5aea9)) * exposing customHeader in requestOptions to allow users pass in customer headers. ([b47d733](https://github.com/googleapis/nodejs-vertexai/commit/b47d733680837233b4323f4113737421099df02b)) ## [1.0.0](https://github.com/googleapis/nodejs-vertexai/compare/v0.5.0...v1.0.0) (2024-04-04) ### Features * added userAgent option to RequestOptions to allow setting User-Agent header ([ca43e2f](https://github.com/googleapis/nodejs-vertexai/commit/ca43e2f0b4ebef60d3739b10a3707cdfe2e2a4ec)) * include grounding metadata to stream aggregated response. ([d32755e](https://github.com/googleapis/nodejs-vertexai/commit/d32755e41ca36a52bfd55dafd45bf5a1a8835b7b)) * Support functionCalls property in GenerationContentCandidate interface for non streaming mode ([89568a6](https://github.com/googleapis/nodejs-vertexai/commit/89568a654550f51ed7e280eb6108f6bdb13e7a92)) ### Bug Fixes * check optional field in aggregate response ([f7718ae](https://github.com/googleapis/nodejs-vertexai/commit/f7718aec22f2806bfda18cc75d2ba2c47c929efe)) * correct CitationMetadata interface. refactor nested function ([722b7fd](https://github.com/googleapis/nodejs-vertexai/commit/722b7fda23fd03e85b418e71cfacf2206596fc86)) * correct code snippets in README ([bdcc5fd](https://github.com/googleapis/nodejs-vertexai/commit/bdcc5fdda9325c37a2efcfc9c00e8cf90fae1f46)) * correct GenerateContentCandidate interface and GenerateContentResponse interface ([7a366ab](https://github.com/googleapis/nodejs-vertexai/commit/7a366abfc13b87e93bc233e045b8e173ae6357b5)) * correct sys test logic on stream endpoint for funcion calling ([1fd5b72](https://github.com/googleapis/nodejs-vertexai/commit/1fd5b725a6537ddca0b93c34be04a4ad8f9f50b6)) * Fix a bug in the Vertex AI client library. ([8ad7dfb](https://github.com/googleapis/nodejs-vertexai/commit/8ad7dfbd7090868ed89a155aa9519ed220c23451)) * fix bug in safetyRatings handling, fix incomplete content interfaces, and add unit test for stream response handling ([e573ce6](https://github.com/googleapis/nodejs-vertexai/commit/e573ce68bda3fabdc75ffbacc56421215cbe2f70)) * for function call, role should be model. ([3b80dc8](https://github.com/googleapis/nodejs-vertexai/commit/3b80dc86b8c5d1e4be0afe99bca35201fd812abb)) * functionResponse should be user role ([d092ab4](https://github.com/googleapis/nodejs-vertexai/commit/d092ab4bb0862fc8471e663a4fb7084b432baf74)) * Make appendHistory private. ([a1bedcd](https://github.com/googleapis/nodejs-vertexai/commit/a1bedcdb6fe71d73a7601c4fafda699b0b8d1698)) * pass tools from getGenerativeModel and startChat methods to top level functions ([bbaf78a](https://github.com/googleapis/nodejs-vertexai/commit/bbaf78a5286ca39074b72bcce7eb7856fe0bec70)) * pass tools from getGenerativeModel to chatSession. ([907ad74](https://github.com/googleapis/nodejs-vertexai/commit/907ad74aefe24082607431c34027df6ae6d46a08)) * remove any type in token signature ([add084c](https://github.com/googleapis/nodejs-vertexai/commit/add084c6c1657f92a43c102159abceb0b7121b0c)) * remove defaulting value of candidates in unary api. remove unused variables and imports. remove throwing GoogleAIError when candidates undefined or empty. ([6c0c31c](https://github.com/googleapis/nodejs-vertexai/commit/6c0c31c2d798f32739fb0d8b647d4289168cc446)) * replace any type with explicit types in post fetch processing functions ([4099129](https://github.com/googleapis/nodejs-vertexai/commit/4099129d8497ec39fd1410e3edfc7599f2a91db8)) * replace snake_case in docs to camelCase ([5893581](https://github.com/googleapis/nodejs-vertexai/commit/5893581b17b9f1df28410f1315c2fd760acc98b6)) * SDK should be released to 1.0.0 ([4cab5fd](https://github.com/googleapis/nodejs-vertexai/commit/4cab5fd814bb0c47c98b5be2ed250f5a3765cd6e)) * update finish reason enum list to be complete ([f16b2e7](https://github.com/googleapis/nodejs-vertexai/commit/f16b2e778f1c0d250404928d85f12e775fc0f720)) * update prompt feedback interface ([0d3754a](https://github.com/googleapis/nodejs-vertexai/commit/0d3754ac7c51b73281342cdb20b22af5918045fa)) ## [0.5.0](https://github.com/googleapis/nodejs-vertexai/compare/v0.4.0...v0.5.0) (2024-02-29) ### Features * Introduce Request Timeout Configuration ([1b37f40](https://github.com/googleapis/nodejs-vertexai/commit/1b37f4045f604dac10c91ba800b34c6beadd113a)) ### Bug Fixes * correct UsageMetadata schema ([10bc676](https://github.com/googleapis/nodejs-vertexai/commit/10bc67666a64d6ea7dd103c3dae678b8080735c1)) * include usageMetadata in stream aggregated response ([a1154c9](https://github.com/googleapis/nodejs-vertexai/commit/a1154c9a91bb5d9cd988a00be4b462ee013fa704)) ## [0.4.0](https://github.com/googleapis/nodejs-vertexai/compare/v0.3.1...v0.4.0) (2024-02-15) ### Features * Added support for Grounding ([929df39](https://github.com/googleapis/nodejs-vertexai/commit/929df39f19f423bcfaf35ef113ce04886345a6ab)) * enable both GA and preview namespaces. ([1c2aca6](https://github.com/googleapis/nodejs-vertexai/commit/1c2aca6b776784a5b51d1654ffa41dc36f600874)) ### Bug Fixes * throw more details on error message. ([5dba79c](https://github.com/googleapis/nodejs-vertexai/commit/5dba79c3648203b9a66b6098f9f1fa0280e6e67d)) * unary api should only need to `await` once. ([67a2e96](https://github.com/googleapis/nodejs-vertexai/commit/67a2e9649c69a2cf9868a074527efd93d2c800c9)) ## [0.3.1](https://github.com/googleapis/nodejs-vertexai/compare/v0.3.0...v0.3.1) (2024-02-06) ### Bug Fixes * decouple dependency between VertexAI_Preivew and GenerativeModel classes ([6762c99](https://github.com/googleapis/nodejs-vertexai/commit/6762c995bfa1bfdb740ed01a2eb4385126b0e36a)) * Switch NodeJS generateContent to call Unary API endpoint ([e4edb59](https://github.com/googleapis/nodejs-vertexai/commit/e4edb599863c23a896e263ba2639c80481a65543)) ## [0.3.0](https://github.com/googleapis/nodejs-vertexai/compare/v0.2.1...v0.3.0) (2024-01-30) ### Features * add function calling support ([1deb4e9](https://github.com/googleapis/nodejs-vertexai/commit/1deb4e920205d2fff6da780175de6045bd853885)) ### Bug Fixes * throw error when GoogleAuthOptions.scopes doesn't include required scope. ([558aee9](https://github.com/googleapis/nodejs-vertexai/commit/558aee98d76192b4a63b3d28abba3f3d4cda1762)) * throws instructive client side error message when bad request happens for function calling ([c90203d](https://github.com/googleapis/nodejs-vertexai/commit/c90203d153407daa08763c273a827a5e9db54a70)) ## [0.2.1](https://github.com/googleapis/nodejs-vertexai/compare/v0.2.0...v0.2.1) (2024-01-05) ### Bug Fixes * enable passing only a string to generateContent and generateContentStream ([c50811e](https://github.com/googleapis/nodejs-vertexai/commit/c50811e5443848edb8f9ce5d88ae4c6c8b59b65b)) ## [0.2.0](https://github.com/googleapis/nodejs-vertexai/compare/v0.1.3...v0.2.0) (2024-01-03) ### Features * allow user to pass "models/model-ID" to instantiate model ([e94b285](https://github.com/googleapis/nodejs-vertexai/commit/e94b285dac6aaf0c77c6b9c6220b29b8d4aced52)) * include all supported authentication options ([257355c](https://github.com/googleapis/nodejs-vertexai/commit/257355ca09ee298623198404a4f889f5cf7788ee)) ### Bug Fixes * processing of streams, including UTF ([63ce032](https://github.com/googleapis/nodejs-vertexai/commit/63ce032461a32e9e5fdf04d8ce2d4d8628d691b1)) * remove placeholder cache attribute of access token ([3ec92e7](https://github.com/googleapis/nodejs-vertexai/commit/3ec92e71a9f7ef4a55bf64037f363ec6be6a729d)) * update safety return types ([449c7a2](https://github.com/googleapis/nodejs-vertexai/commit/449c7a2af2272add956eb44d8e617878468af344)) * throw ClientError or GoogleGenerativeAIError according to response status so that users can catch them and handle them according to class name. ([ea0dcb7](https://github.com/googleapis/nodejs-vertexai/commit/ea0dcb717be8d22d98916252ccee352e9af4a09f)) ## [0.1.3](https://github.com/googleapis/nodejs-vertexai/compare/v0.1.2...v0.1.3) (2023-12-13) ### Bug Fixes * Add samples link to readme ([3a86e85](https://github.com/googleapis/nodejs-vertexai/commit/3a86e85de034479818813e563cef6badd68074ab)) * update header field ([eab8841](https://github.com/googleapis/nodejs-vertexai/commit/eab8841f42679e976d4b1eca8dc083330380daff)) ## [0.1.2](https://github.com/googleapis/nodejs-vertexai/compare/v0.1.1...v0.1.2) (2023-12-13) ### Bug Fixes * update readme ([b01bd39](https://github.com/googleapis/nodejs-vertexai/commit/b01bd391a34f7b7b65d8e267ca169f52f5a48217)) ## [0.1.1](https://github.com/googleapis/nodejs-vertexai/compare/v0.1.0...v0.1.1) (2023-12-12) ### Bug Fixes * fix stream send message content ([ad1e17e](https://github.com/googleapis/nodejs-vertexai/commit/ad1e17e81c72ce55d395bcae36326d48d595d175)) ## 0.1.0 (2023-12-12) ### Features * add streamGenerateContent method ([6263800](https://github.com/googleapis/nodejs-vertexai/commit/626380039d7bb2fb9af9219f70ad549950b5f490)) * add streamSendMessage method ([598b1dd](https://github.com/googleapis/nodejs-vertexai/commit/598b1dd7ca8d84c9b32e633a65634abea232f7de)) * add generateContent method ([d7f1f0f](https://github.com/googleapis/nodejs-vertexai/commit/d7f1f0f66b7bf22c2cb59a8ef698b426cf7e3b8b)) * add countTokens method ([e0265a3](https://github.com/googleapis/nodejs-vertexai/commit/e0265a36d73b460c66062a0b520b5556d0aa894b)) ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. This Code of Conduct also applies outside the project spaces when the Project Steward has a reasonable belief that an individual's behavior may have a negative impact on the project or its community. ## Conflict Resolution We do not believe that all conflict is bad; healthy debate and disagreement often yield positive results. However, it is never okay to be disrespectful or to engage in behavior that violates the project’s code of conduct. If you see someone violating the code of conduct, you are encouraged to address the behavior directly with those involved. Many issues can be resolved quickly and easily, and this gives people more control over the outcome of their dispute. If you are unable to resolve the matter for any reason, or if the behavior is threatening or harassing, report it. We are dedicated to providing an environment where participants feel welcome and safe. Reports should be directed to *googleapis-stewards@google.com*, the Project Steward(s) for *Google Cloud Client Libraries*. It is the Project Steward’s duty to receive and address reported violations of the code of conduct. They will then work with a committee consisting of representatives from the Open Source Programs Office and the Google Open Source Strategy team. If for any reason you are uncomfortable reaching out to the Project Steward, please email opensource@google.com. We will investigate every complaint, but you may not receive a direct response. We will use our discretion in determining when and how to follow up on reported incidents, which may range from not taking action to permanent expulsion from the project and project-sponsored spaces. We will notify the accused of the report and provide them an opportunity to discuss it before any action is taken. The identity of the reporter will be omitted from the details of the report supplied to the accused. In potentially harmful situations, such as ongoing harassment or threats to anyone's safety, we may take action without notice. ## Attribution This Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html ================================================ FILE: CONTRIBUTING.md ================================================ # How to Contribute We'd love to accept your patches and contributions to this project. There are just a few small guidelines you need to follow. ## Contributor License Agreement Contributions to this project must be accompanied by a Contributor License Agreement. You (or your employer) retain the copyright to your contribution; this simply gives us permission to use and redistribute your contributions as part of the project. Head over to to see your current agreements on file or to sign a new one. You generally only need to submit a CLA once, so if you've already submitted one (even if it was for a different project), you probably don't need to do it again. ## Code Reviews All submissions, including submissions by project members, require review. We use GitHub pull requests for this purpose. Consult [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more information on using pull requests. ## Community Guidelines This project follows [Google's Open Source Community Guidelines](https://opensource.google/conduct/). ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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 http://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. ================================================ FILE: README.md ================================================ # Gemini Enterprise Agent Platform SDK for Node.js quickstart The Agent Platform SDK for Node.js lets you use the Gemini API to build AI-powered features and applications. Both TypeScript and JavaScript are supported. For the latest list of available Gemini models on Agent Platform, see the [Model information](https://cloud.google.com/vertex-ai/docs/generative-ai/learn/models#gemini-models) page in Agent Platform documentation. ## Before you begin 1. Make sure your node.js version is 20 or above. 1. [Select](https://console.cloud.google.com/project) or [create](https://cloud.google.com/resource-manager/docs/creating-managing-projects#creating_a_project) a Google Cloud project. 1. [Enable billing for your project](https://cloud.google.com/billing/docs/how-to/modify-project). 1. [Enable the Agent Platform API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com). 1. [Install the gcloud CLI](https://cloud.google.com/sdk/docs/install). 1. [Initialize the gcloud CLI](https://cloud.google.com/sdk/docs/initializing). 1. Create local authentication credentials for your user account: ```sh gcloud auth application-default login ``` A list of accepted authentication options are listed in [GoogleAuthOptions](https://github.com/googleapis/google-auth-library-nodejs/blob/3ae120d0a45c95e36c59c9ac8286483938781f30/src/auth/googleauth.ts#L87) interface of google-auth-library-node.js GitHub repo. ## Install the SDK Install the Agent Platform SDK for Node.js by running the following command: ```shell npm install @google-cloud/agentplatform ``` ## Instantiate the Agent Platform client First, import the `Client` class: ```typescript import { Client } from '@google-cloud/agentplatform'; ``` Then instantiate a client: ```typescript const client: Client = new Client({ project: 'my-cloud-project', location: 'my-cloud-location', }); ``` ## License The contents of this repository are licensed under the [Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). ================================================ FILE: SECURITY.md ================================================ # Security Policy To report a security issue, please use [g.co/vulnz](https://g.co/vulnz). The Google Security Team will respond within 5 working days of your report on g.co/vulnz. We use g.co/vulnz for our intake, and do coordination and disclosure here using GitHub Security Advisory to privately discuss and fix the issue. ================================================ FILE: package.json ================================================ { "name": "@google-cloud/agentplatform", "description": "Vertex Generative AI client for Node.js", "version": "0.6.0", "license": "Apache-2.0", "author": "Google LLC", "engines": { "node": ">=20.0.0" }, "homepage": "https://github.com/googleapis/nodejs-vertexai", "repository": "googleapis/nodejs-vertexai", "main": "build/src/index.js", "type": "commonjs", "scripts": { "clean": "gts clean", "compile": "tsc -p .", "docs": "jsdoc -c .jsdoc.js", "predocs-test": "npm run docs", "docs-test": "linkinator docs", "compile:oss": "tsc -p tsconfig.json.oss", "fix": "gts fix", "test": "npm run test:unit", "test:unit": "jasmine build/test/unit/*_test.js --reporter=test/spec/reporter.js", "test:system": "jasmine build/system_test/*_test.js --reporter=test/spec/reporter.js", "test:replays": "jasmine build/test/replays/*_test.js --reporter=test/spec/reporter.js", "lint": "ESLINT_USE_FLAT_CONFIG=true eslint src --no-ignore --config src/eslint.config.mjs", "format": "prettier 'src/**/*.ts' 'src/**/*.mjs' --write", "clean-js-files": "find . -type f -name \"*.js\" -exec rm -f {} +", "clean-js-map-files": "find . -type f -name \"*.js.map\" -exec rm -f {} +", "postpack": "if [ \"${CLEAN}\" ]; then npm run clean-after-pack; fi", "cover": "npm run cover:unit && npm run cover:integration && npm run cover:report", "cover:unit": "nyc npm run test", "cover:integration": "nyc --no-clean npm run test:system", "cover:report": "nyc report --reporter=lcov", "prepare": "npm run compile", "pretest": "npm run compile", "posttest": "npm run lint" }, "dependencies": { "@google/genai": "^1.45.0", "google-auth-library": "^9.1.0" }, "devDependencies": { "@eslint/js": "9.20.0", "@types/jasmine": "^5.1.2", "@types/node": "^20.9.0", "eslint": "8.57.0", "gts": "^5.2.0", "jasmine": "^5.1.0", "jasmine-reporters": "^2.4.0", "jsdoc": "^4.0.0", "jsdoc-fresh": "^3.0.0", "jsdoc-region-tag": "^3.0.0", "linkinator": "^4.0.0", "nyc": "^15.1.0", "prettier": "3.3.3", "prettier-plugin-organize-imports": "^4.1.0", "typescript": "~5.4.0", "typescript-eslint": "8.24.1" }, "files": [ "build/src", "!build/**/*.map" ] } ================================================ FILE: release-please-config.json ================================================ { "initial-version": "0.5.0", "release-type": "node", "include-component-in-tag": false, "packages": { ".": { "extra-files": [ "src/client.ts" ] } } } ================================================ FILE: src/.prettierignore ================================================ # Ignore autogenerated files: agentengines.ts _internal_types.ts sessionevents.ts sessions.ts types/** types.ts converters/** # Ignore built files: dist/** ================================================ FILE: src/.prettierrc ================================================ { "printWidth" : 80, "tabWidth" : 2, "useTabs" : false, "semi" : true, "singleQuote" : true, "quoteProps" : "preserve", "bracketSpacing" : false, "trailingComma" : "all", "arrowParens" : "always", "embeddedLanguageFormatting" : "off", "bracketSameLine" : true, "singleAttributePerLine" : false, "htmlWhitespaceSensitivity" : "strict", "plugins": ["prettier-plugin-organize-imports"], } ================================================ FILE: src/_internal_types.ts ================================================ /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ // Code generated by the Google Gen AI SDK generator DO NOT EDIT. ================================================ FILE: src/agentengines.ts ================================================ /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ // Code generated by the Google Gen AI SDK generator DO NOT EDIT. import * as common from '@google/genai/vertex_internal'; import {ApiClient, BaseModule} from '@google/genai/vertex_internal'; import * as converters from './converters/_agentengines_converters.js'; import {Memories} from './memories.js'; import {Sandboxes} from './sandboxes.js'; import {Sessions} from './sessions.js'; import * as types from './types.js'; export class AgentEngines extends BaseModule { public readonly sessions: Sessions; public readonly sandboxes: Sandboxes; public readonly memories: Memories; constructor(private readonly apiClient: ApiClient) { super(); this.sessions = new Sessions(apiClient); this.sandboxes = new Sandboxes(apiClient); this.memories = new Memories(apiClient); } async createInternal( params: types.CreateAgentEngineRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.createAgentEngineRequestParametersToVertex(params); path = common.formatMap( 'reasoningEngines', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'POST', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((apiResponse) => { const resp = converters.agentEngineOperationFromVertex(apiResponse); return resp as types.AgentEngineOperation; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async deleteInternal( params: types.DeleteAgentEngineRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.deleteAgentEngineRequestParametersToVertex(params); path = common.formatMap( '{name}', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'DELETE', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { return resp as types.DeleteAgentEngineOperation; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async getInternal( params: types.GetAgentEngineRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.getAgentEngineRequestParametersToVertex(params); path = common.formatMap( '{name}', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'GET', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((apiResponse) => { const resp = converters.reasoningEngineFromVertex(apiResponse); return resp as types.ReasoningEngine; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async listInternal( params: types.ListAgentEngineRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.listAgentEngineRequestParametersToVertex(params); path = common.formatMap( 'reasoningEngines', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'GET', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((apiResponse) => { const resp = converters.listReasoningEnginesResponseFromVertex(apiResponse); const typedResp = new types.ListReasoningEnginesResponse(); Object.assign(typedResp, resp); return typedResp; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async getAgentOperationInternal( params: types.GetAgentEngineOperationParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.getAgentEngineOperationParametersToVertex(params); path = common.formatMap( '{operationName}', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'GET', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((apiResponse) => { const resp = converters.agentEngineOperationFromVertex(apiResponse); return resp as types.AgentEngineOperation; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async queryInternal( params: types.QueryAgentEngineRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.queryAgentEngineRequestParametersToVertex(params); path = common.formatMap( '{name}:query', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'POST', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { const typedResp = new types.QueryReasoningEngineResponse(); Object.assign(typedResp, resp); return typedResp; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async updateInternal( params: types.UpdateAgentEngineRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.updateAgentEngineRequestParametersToVertex(params); path = common.formatMap( '{name}', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'PATCH', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((apiResponse) => { const resp = converters.agentEngineOperationFromVertex(apiResponse); return resp as types.AgentEngineOperation; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } } ================================================ FILE: src/client.ts ================================================ /** * @license * Copyright 2026 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import {ApiClient, NodeAuth, NodeDownloader, NodeUploader,} from '@google/genai/vertex_internal'; import {AgentEngines} from './agentengines'; import {Skills} from './skills'; export const SDK_VERSION = '0.6.0'; // x-release-please-version let agentEnginesInternalWarned = false; export class Client { protected readonly apiClient: ApiClient; public readonly _agentEnginesInternal: AgentEngines; public readonly skills: Skills; constructor( options: {project?: string; location?: string; apiEndpoint?: string;}) { const auth = new NodeAuth({ googleAuthOptions: { scopes: ['https://www.googleapis.com/auth/cloud-platform'], }, }); const uploader = new NodeUploader(); const downloader = new NodeDownloader(); const nodeVersion = typeof process !== 'undefined' ? process.version : 'unknown'; this.apiClient = new ApiClient({ auth, uploader, downloader, project: options.project, location: options.location, vertexai: true, httpOptions: options.apiEndpoint ? {baseUrl: options.apiEndpoint} : undefined, userAgentExtra: '', }); const headers = this.apiClient.clientOptions.httpOptions?.headers as Record| undefined; if (headers) { const telemetryStr = `+vertex-genai-modules/${SDK_VERSION} gl-node/${nodeVersion}`; if (headers['User-Agent']) { headers['User-Agent'] = headers['User-Agent'].trim() + telemetryStr; } if (headers['x-goog-api-client']) { headers['x-goog-api-client'] = headers['x-goog-api-client'].trim() + telemetryStr; } } this._agentEnginesInternal = new AgentEngines(this.apiClient); this.skills = new Skills(this.apiClient); } /** * Getter for agentEnginesInternal that logs a warning on first use. */ public get agentEnginesInternal(): AgentEngines { if (!agentEnginesInternalWarned) { console.warn( 'The agentEnginesInternal implementation is experimental, and may change in future versions.', ); agentEnginesInternalWarned = true; } return this._agentEnginesInternal; } } ================================================ FILE: src/converters/_agentengines_converters.ts ================================================ /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ // Code generated by the Google Gen AI SDK generator DO NOT EDIT. import * as common from '@google/genai/vertex_internal'; import * as types from '../types.js'; export function agentEngineOperationFromVertex( fromObject: types.AgentEngineOperation, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['name'], fromName); } const fromMetadata = common.getValueByPath(fromObject, ['metadata']); if (fromMetadata != null) { common.setValueByPath(toObject, ['metadata'], fromMetadata); } const fromDone = common.getValueByPath(fromObject, ['done']); if (fromDone != null) { common.setValueByPath(toObject, ['done'], fromDone); } const fromError = common.getValueByPath(fromObject, ['error']); if (fromError != null) { common.setValueByPath(toObject, ['error'], fromError); } const fromResponse = common.getValueByPath(fromObject, ['response']); if (fromResponse != null) { common.setValueByPath( toObject, ['response'], reasoningEngineFromVertex(fromResponse), ); } return toObject; } export function createAgentEngineConfigToVertex( fromObject: types.CreateAgentEngineConfig, parentObject: Record, ): Record { const toObject: Record = {}; const fromDisplayName = common.getValueByPath(fromObject, ['displayName']); if (parentObject !== undefined && fromDisplayName != null) { common.setValueByPath(parentObject, ['displayName'], fromDisplayName); } const fromDescription = common.getValueByPath(fromObject, ['description']); if (parentObject !== undefined && fromDescription != null) { common.setValueByPath(parentObject, ['description'], fromDescription); } const fromSpec = common.getValueByPath(fromObject, ['spec']); if (parentObject !== undefined && fromSpec != null) { common.setValueByPath(parentObject, ['spec'], fromSpec); } const fromContextSpec = common.getValueByPath(fromObject, ['contextSpec']); if (parentObject !== undefined && fromContextSpec != null) { common.setValueByPath( parentObject, ['contextSpec'], reasoningEngineContextSpecToVertex(fromContextSpec), ); } const fromPscInterfaceConfig = common.getValueByPath(fromObject, [ 'pscInterfaceConfig', ]); if (parentObject !== undefined && fromPscInterfaceConfig != null) { common.setValueByPath( parentObject, ['pscInterfaceConfig'], fromPscInterfaceConfig, ); } const fromEncryptionSpec = common.getValueByPath(fromObject, [ 'encryptionSpec', ]); if (parentObject !== undefined && fromEncryptionSpec != null) { common.setValueByPath(parentObject, ['encryptionSpec'], fromEncryptionSpec); } const fromLabels = common.getValueByPath(fromObject, ['labels']); if (parentObject !== undefined && fromLabels != null) { common.setValueByPath(parentObject, ['labels'], fromLabels); } const fromSourcePackages = common.getValueByPath(fromObject, [ 'sourcePackages', ]); if (parentObject !== undefined && fromSourcePackages != null) { common.setValueByPath(parentObject, ['sourcePackages'], fromSourcePackages); } const fromEntrypointModule = common.getValueByPath(fromObject, [ 'entrypointModule', ]); if (parentObject !== undefined && fromEntrypointModule != null) { common.setValueByPath( parentObject, ['entrypointModule'], fromEntrypointModule, ); } const fromEntrypointObject = common.getValueByPath(fromObject, [ 'entrypointObject', ]); if (parentObject !== undefined && fromEntrypointObject != null) { common.setValueByPath( parentObject, ['entrypointObject'], fromEntrypointObject, ); } const fromRequirementsFile = common.getValueByPath(fromObject, [ 'requirementsFile', ]); if (parentObject !== undefined && fromRequirementsFile != null) { common.setValueByPath( parentObject, ['requirementsFile'], fromRequirementsFile, ); } const fromAgentFramework = common.getValueByPath(fromObject, [ 'agentFramework', ]); if (parentObject !== undefined && fromAgentFramework != null) { common.setValueByPath(parentObject, ['agentFramework'], fromAgentFramework); } const fromPythonVersion = common.getValueByPath(fromObject, [ 'pythonVersion', ]); if (parentObject !== undefined && fromPythonVersion != null) { common.setValueByPath(parentObject, ['pythonVersion'], fromPythonVersion); } const fromAgentGatewayConfig = common.getValueByPath(fromObject, [ 'agentGatewayConfig', ]); if (parentObject !== undefined && fromAgentGatewayConfig != null) { common.setValueByPath( parentObject, ['agentGatewayConfig'], fromAgentGatewayConfig, ); } return toObject; } export function createAgentEngineRequestParametersToVertex( fromObject: types.CreateAgentEngineRequestParameters, ): Record { const toObject: Record = {}; const fromConfig = common.getValueByPath(fromObject, ['config']); if (fromConfig != null) { createAgentEngineConfigToVertex(fromConfig, toObject); } return toObject; } export function deleteAgentEngineRequestParametersToVertex( fromObject: types.DeleteAgentEngineRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } const fromForce = common.getValueByPath(fromObject, ['force']); if (fromForce != null) { common.setValueByPath(toObject, ['force'], fromForce); } return toObject; } export function getAgentEngineOperationParametersToVertex( fromObject: types.GetAgentEngineOperationParameters, ): Record { const toObject: Record = {}; const fromOperationName = common.getValueByPath(fromObject, [ 'operationName', ]); if (fromOperationName != null) { common.setValueByPath( toObject, ['_url', 'operationName'], fromOperationName, ); } return toObject; } export function getAgentEngineRequestParametersToVertex( fromObject: types.GetAgentEngineRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } return toObject; } export function listAgentEngineConfigToVertex( fromObject: types.ListAgentEngineConfig, parentObject: Record, ): Record { const toObject: Record = {}; const fromPageSize = common.getValueByPath(fromObject, ['pageSize']); if (parentObject !== undefined && fromPageSize != null) { common.setValueByPath(parentObject, ['_query', 'pageSize'], fromPageSize); } const fromPageToken = common.getValueByPath(fromObject, ['pageToken']); if (parentObject !== undefined && fromPageToken != null) { common.setValueByPath(parentObject, ['_query', 'pageToken'], fromPageToken); } const fromFilter = common.getValueByPath(fromObject, ['filter']); if (parentObject !== undefined && fromFilter != null) { common.setValueByPath(parentObject, ['_query', 'filter'], fromFilter); } return toObject; } export function listAgentEngineRequestParametersToVertex( fromObject: types.ListAgentEngineRequestParameters, ): Record { const toObject: Record = {}; const fromConfig = common.getValueByPath(fromObject, ['config']); if (fromConfig != null) { listAgentEngineConfigToVertex(fromConfig, toObject); } return toObject; } export function listReasoningEnginesResponseFromVertex( fromObject: types.ListReasoningEnginesResponse, ): Record { const toObject: Record = {}; const fromSdkHttpResponse = common.getValueByPath(fromObject, [ 'sdkHttpResponse', ]); if (fromSdkHttpResponse != null) { common.setValueByPath(toObject, ['sdkHttpResponse'], fromSdkHttpResponse); } const fromNextPageToken = common.getValueByPath(fromObject, [ 'nextPageToken', ]); if (fromNextPageToken != null) { common.setValueByPath(toObject, ['nextPageToken'], fromNextPageToken); } const fromReasoningEngines = common.getValueByPath(fromObject, [ 'reasoningEngines', ]); if (fromReasoningEngines != null) { let transformedList = fromReasoningEngines; if (Array.isArray(transformedList)) { transformedList = transformedList.map((item) => { return reasoningEngineFromVertex(item); }); } common.setValueByPath(toObject, ['reasoningEngines'], transformedList); } return toObject; } export function queryAgentEngineConfigToVertex( fromObject: types.QueryAgentEngineConfig, parentObject: Record, ): Record { const toObject: Record = {}; const fromClassMethod = common.getValueByPath(fromObject, ['classMethod']); if (parentObject !== undefined && fromClassMethod != null) { common.setValueByPath(parentObject, ['classMethod'], fromClassMethod); } const fromInput = common.getValueByPath(fromObject, ['input']); if (parentObject !== undefined && fromInput != null) { common.setValueByPath(parentObject, ['input'], fromInput); } const fromIncludeAllFields = common.getValueByPath(fromObject, [ 'includeAllFields', ]); if (fromIncludeAllFields != null) { common.setValueByPath(toObject, ['includeAllFields'], fromIncludeAllFields); } return toObject; } export function queryAgentEngineRequestParametersToVertex( fromObject: types.QueryAgentEngineRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } const fromConfig = common.getValueByPath(fromObject, ['config']); if (fromConfig != null) { queryAgentEngineConfigToVertex(fromConfig, toObject); } return toObject; } export function reasoningEngineContextSpecFromVertex( fromObject: types.ReasoningEngineContextSpec, ): Record { const toObject: Record = {}; const fromMemoryBankConfig = common.getValueByPath(fromObject, [ 'memoryBankConfig', ]); if (fromMemoryBankConfig != null) { common.setValueByPath( toObject, ['memoryBankConfig'], reasoningEngineContextSpecMemoryBankConfigFromVertex( fromMemoryBankConfig, ), ); } return toObject; } export function reasoningEngineContextSpecMemoryBankConfigFromVertex( fromObject: types.ReasoningEngineContextSpecMemoryBankConfig, ): Record { const toObject: Record = {}; const fromCustomizationConfigs = common.getValueByPath(fromObject, [ 'customizationConfigs', ]); if (fromCustomizationConfigs != null) { let transformedList = fromCustomizationConfigs; if (Array.isArray(transformedList)) { transformedList = transformedList.map((item) => { return item; }); } common.setValueByPath(toObject, ['customizationConfigs'], transformedList); } const fromDisableMemoryRevisions = common.getValueByPath(fromObject, [ 'disableMemoryRevisions', ]); if (fromDisableMemoryRevisions != null) { common.setValueByPath( toObject, ['disableMemoryRevisions'], fromDisableMemoryRevisions, ); } const fromGenerationConfig = common.getValueByPath(fromObject, [ 'generationConfig', ]); if (fromGenerationConfig != null) { common.setValueByPath(toObject, ['generationConfig'], fromGenerationConfig); } const fromSimilaritySearchConfig = common.getValueByPath(fromObject, [ 'similaritySearchConfig', ]); if (fromSimilaritySearchConfig != null) { common.setValueByPath( toObject, ['similaritySearchConfig'], fromSimilaritySearchConfig, ); } const fromTtlConfig = common.getValueByPath(fromObject, ['ttlConfig']); if (fromTtlConfig != null) { common.setValueByPath(toObject, ['ttlConfig'], fromTtlConfig); } const fromStructuredMemoryConfigs = common.getValueByPath(fromObject, [ 'structuredMemoryConfigs', ]); if (fromStructuredMemoryConfigs != null) { let transformedList = fromStructuredMemoryConfigs; if (Array.isArray(transformedList)) { transformedList = transformedList.map((item) => { return structuredMemoryConfigFromVertex(item); }); } common.setValueByPath( toObject, ['structuredMemoryConfigs'], transformedList, ); } return toObject; } export function reasoningEngineContextSpecMemoryBankConfigToVertex( fromObject: types.ReasoningEngineContextSpecMemoryBankConfig, ): Record { const toObject: Record = {}; const fromCustomizationConfigs = common.getValueByPath(fromObject, [ 'customizationConfigs', ]); if (fromCustomizationConfigs != null) { let transformedList = fromCustomizationConfigs; if (Array.isArray(transformedList)) { transformedList = transformedList.map((item) => { return item; }); } common.setValueByPath(toObject, ['customizationConfigs'], transformedList); } const fromDisableMemoryRevisions = common.getValueByPath(fromObject, [ 'disableMemoryRevisions', ]); if (fromDisableMemoryRevisions != null) { common.setValueByPath( toObject, ['disableMemoryRevisions'], fromDisableMemoryRevisions, ); } const fromGenerationConfig = common.getValueByPath(fromObject, [ 'generationConfig', ]); if (fromGenerationConfig != null) { common.setValueByPath(toObject, ['generationConfig'], fromGenerationConfig); } const fromSimilaritySearchConfig = common.getValueByPath(fromObject, [ 'similaritySearchConfig', ]); if (fromSimilaritySearchConfig != null) { common.setValueByPath( toObject, ['similaritySearchConfig'], fromSimilaritySearchConfig, ); } const fromTtlConfig = common.getValueByPath(fromObject, ['ttlConfig']); if (fromTtlConfig != null) { common.setValueByPath(toObject, ['ttlConfig'], fromTtlConfig); } const fromStructuredMemoryConfigs = common.getValueByPath(fromObject, [ 'structuredMemoryConfigs', ]); if (fromStructuredMemoryConfigs != null) { let transformedList = fromStructuredMemoryConfigs; if (Array.isArray(transformedList)) { transformedList = transformedList.map((item) => { return structuredMemoryConfigToVertex(item); }); } common.setValueByPath( toObject, ['structuredMemoryConfigs'], transformedList, ); } return toObject; } export function reasoningEngineContextSpecToVertex( fromObject: types.ReasoningEngineContextSpec, ): Record { const toObject: Record = {}; const fromMemoryBankConfig = common.getValueByPath(fromObject, [ 'memoryBankConfig', ]); if (fromMemoryBankConfig != null) { common.setValueByPath( toObject, ['memoryBankConfig'], reasoningEngineContextSpecMemoryBankConfigToVertex(fromMemoryBankConfig), ); } return toObject; } export function reasoningEngineFromVertex( fromObject: types.ReasoningEngine, ): Record { const toObject: Record = {}; const fromEncryptionSpec = common.getValueByPath(fromObject, [ 'encryptionSpec', ]); if (fromEncryptionSpec != null) { common.setValueByPath(toObject, ['encryptionSpec'], fromEncryptionSpec); } const fromContextSpec = common.getValueByPath(fromObject, ['contextSpec']); if (fromContextSpec != null) { common.setValueByPath( toObject, ['contextSpec'], reasoningEngineContextSpecFromVertex(fromContextSpec), ); } const fromCreateTime = common.getValueByPath(fromObject, ['createTime']); if (fromCreateTime != null) { common.setValueByPath(toObject, ['createTime'], fromCreateTime); } const fromDescription = common.getValueByPath(fromObject, ['description']); if (fromDescription != null) { common.setValueByPath(toObject, ['description'], fromDescription); } const fromDisplayName = common.getValueByPath(fromObject, ['displayName']); if (fromDisplayName != null) { common.setValueByPath(toObject, ['displayName'], fromDisplayName); } const fromEtag = common.getValueByPath(fromObject, ['etag']); if (fromEtag != null) { common.setValueByPath(toObject, ['etag'], fromEtag); } const fromLabels = common.getValueByPath(fromObject, ['labels']); if (fromLabels != null) { common.setValueByPath(toObject, ['labels'], fromLabels); } const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['name'], fromName); } const fromSpec = common.getValueByPath(fromObject, ['spec']); if (fromSpec != null) { common.setValueByPath(toObject, ['spec'], fromSpec); } const fromUpdateTime = common.getValueByPath(fromObject, ['updateTime']); if (fromUpdateTime != null) { common.setValueByPath(toObject, ['updateTime'], fromUpdateTime); } const fromTrafficConfig = common.getValueByPath(fromObject, [ 'trafficConfig', ]); if (fromTrafficConfig != null) { common.setValueByPath(toObject, ['trafficConfig'], fromTrafficConfig); } return toObject; } export function structuredMemoryConfigFromVertex( fromObject: types.StructuredMemoryConfig, ): Record { const toObject: Record = {}; const fromSchemaConfigs = common.getValueByPath(fromObject, [ 'schemaConfigs', ]); if (fromSchemaConfigs != null) { let transformedList = fromSchemaConfigs; if (Array.isArray(transformedList)) { transformedList = transformedList.map((item) => { return structuredMemorySchemaConfigFromVertex(item); }); } common.setValueByPath(toObject, ['schemaConfigs'], transformedList); } const fromScopeKeys = common.getValueByPath(fromObject, ['scopeKeys']); if (fromScopeKeys != null) { common.setValueByPath(toObject, ['scopeKeys'], fromScopeKeys); } return toObject; } export function structuredMemoryConfigToVertex( fromObject: types.StructuredMemoryConfig, ): Record { const toObject: Record = {}; const fromSchemaConfigs = common.getValueByPath(fromObject, [ 'schemaConfigs', ]); if (fromSchemaConfigs != null) { let transformedList = fromSchemaConfigs; if (Array.isArray(transformedList)) { transformedList = transformedList.map((item) => { return structuredMemorySchemaConfigToVertex(item); }); } common.setValueByPath(toObject, ['schemaConfigs'], transformedList); } const fromScopeKeys = common.getValueByPath(fromObject, ['scopeKeys']); if (fromScopeKeys != null) { common.setValueByPath(toObject, ['scopeKeys'], fromScopeKeys); } return toObject; } export function structuredMemorySchemaConfigFromVertex( fromObject: types.StructuredMemorySchemaConfig, ): Record { const toObject: Record = {}; const fromMemorySchema = common.getValueByPath(fromObject, ['schema']); if (fromMemorySchema != null) { common.setValueByPath(toObject, ['memorySchema'], fromMemorySchema); } const fromId = common.getValueByPath(fromObject, ['id']); if (fromId != null) { common.setValueByPath(toObject, ['id'], fromId); } const fromMemoryType = common.getValueByPath(fromObject, ['memoryType']); if (fromMemoryType != null) { common.setValueByPath(toObject, ['memoryType'], fromMemoryType); } return toObject; } export function structuredMemorySchemaConfigToVertex( fromObject: types.StructuredMemorySchemaConfig, ): Record { const toObject: Record = {}; const fromMemorySchema = common.getValueByPath(fromObject, ['memorySchema']); if (fromMemorySchema != null) { common.setValueByPath(toObject, ['schema'], fromMemorySchema); } const fromId = common.getValueByPath(fromObject, ['id']); if (fromId != null) { common.setValueByPath(toObject, ['id'], fromId); } const fromMemoryType = common.getValueByPath(fromObject, ['memoryType']); if (fromMemoryType != null) { common.setValueByPath(toObject, ['memoryType'], fromMemoryType); } return toObject; } export function updateAgentEngineConfigToVertex( fromObject: types.UpdateAgentEngineConfig, parentObject: Record, ): Record { const toObject: Record = {}; const fromDisplayName = common.getValueByPath(fromObject, ['displayName']); if (parentObject !== undefined && fromDisplayName != null) { common.setValueByPath(parentObject, ['displayName'], fromDisplayName); } const fromDescription = common.getValueByPath(fromObject, ['description']); if (parentObject !== undefined && fromDescription != null) { common.setValueByPath(parentObject, ['description'], fromDescription); } const fromSpec = common.getValueByPath(fromObject, ['spec']); if (parentObject !== undefined && fromSpec != null) { common.setValueByPath(parentObject, ['spec'], fromSpec); } const fromContextSpec = common.getValueByPath(fromObject, ['contextSpec']); if (parentObject !== undefined && fromContextSpec != null) { common.setValueByPath( parentObject, ['contextSpec'], reasoningEngineContextSpecToVertex(fromContextSpec), ); } const fromPscInterfaceConfig = common.getValueByPath(fromObject, [ 'pscInterfaceConfig', ]); if (parentObject !== undefined && fromPscInterfaceConfig != null) { common.setValueByPath( parentObject, ['pscInterfaceConfig'], fromPscInterfaceConfig, ); } const fromEncryptionSpec = common.getValueByPath(fromObject, [ 'encryptionSpec', ]); if (parentObject !== undefined && fromEncryptionSpec != null) { common.setValueByPath(parentObject, ['encryptionSpec'], fromEncryptionSpec); } const fromLabels = common.getValueByPath(fromObject, ['labels']); if (parentObject !== undefined && fromLabels != null) { common.setValueByPath(parentObject, ['labels'], fromLabels); } const fromSourcePackages = common.getValueByPath(fromObject, [ 'sourcePackages', ]); if (parentObject !== undefined && fromSourcePackages != null) { common.setValueByPath(parentObject, ['sourcePackages'], fromSourcePackages); } const fromEntrypointModule = common.getValueByPath(fromObject, [ 'entrypointModule', ]); if (parentObject !== undefined && fromEntrypointModule != null) { common.setValueByPath( parentObject, ['entrypointModule'], fromEntrypointModule, ); } const fromEntrypointObject = common.getValueByPath(fromObject, [ 'entrypointObject', ]); if (parentObject !== undefined && fromEntrypointObject != null) { common.setValueByPath( parentObject, ['entrypointObject'], fromEntrypointObject, ); } const fromRequirementsFile = common.getValueByPath(fromObject, [ 'requirementsFile', ]); if (parentObject !== undefined && fromRequirementsFile != null) { common.setValueByPath( parentObject, ['requirementsFile'], fromRequirementsFile, ); } const fromAgentFramework = common.getValueByPath(fromObject, [ 'agentFramework', ]); if (parentObject !== undefined && fromAgentFramework != null) { common.setValueByPath(parentObject, ['agentFramework'], fromAgentFramework); } const fromPythonVersion = common.getValueByPath(fromObject, [ 'pythonVersion', ]); if (parentObject !== undefined && fromPythonVersion != null) { common.setValueByPath(parentObject, ['pythonVersion'], fromPythonVersion); } const fromAgentGatewayConfig = common.getValueByPath(fromObject, [ 'agentGatewayConfig', ]); if (parentObject !== undefined && fromAgentGatewayConfig != null) { common.setValueByPath( parentObject, ['agentGatewayConfig'], fromAgentGatewayConfig, ); } const fromUpdateMask = common.getValueByPath(fromObject, ['updateMask']); if (parentObject !== undefined && fromUpdateMask != null) { common.setValueByPath( parentObject, ['_query', 'updateMask'], fromUpdateMask, ); } return toObject; } export function updateAgentEngineRequestParametersToVertex( fromObject: types.UpdateAgentEngineRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } const fromConfig = common.getValueByPath(fromObject, ['config']); if (fromConfig != null) { updateAgentEngineConfigToVertex(fromConfig, toObject); } return toObject; } ================================================ FILE: src/converters/_memories_converters.ts ================================================ /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ // Code generated by the Google Gen AI SDK generator DO NOT EDIT. import * as common from '@google/genai/vertex_internal'; import * as types from '../types.js'; export function agentEngineMemoryConfigToVertex( fromObject: types.AgentEngineMemoryConfig, parentObject: Record, ): Record { const toObject: Record = {}; const fromDisplayName = common.getValueByPath(fromObject, ['displayName']); if (parentObject !== undefined && fromDisplayName != null) { common.setValueByPath(parentObject, ['displayName'], fromDisplayName); } const fromDescription = common.getValueByPath(fromObject, ['description']); if (parentObject !== undefined && fromDescription != null) { common.setValueByPath(parentObject, ['description'], fromDescription); } const fromTtl = common.getValueByPath(fromObject, ['ttl']); if (parentObject !== undefined && fromTtl != null) { common.setValueByPath(parentObject, ['ttl'], fromTtl); } const fromExpireTime = common.getValueByPath(fromObject, ['expireTime']); if (parentObject !== undefined && fromExpireTime != null) { common.setValueByPath(parentObject, ['expireTime'], fromExpireTime); } const fromRevisionExpireTime = common.getValueByPath(fromObject, [ 'revisionExpireTime', ]); if (parentObject !== undefined && fromRevisionExpireTime != null) { common.setValueByPath( parentObject, ['revisionExpireTime'], fromRevisionExpireTime, ); } const fromRevisionTtl = common.getValueByPath(fromObject, ['revisionTtl']); if (parentObject !== undefined && fromRevisionTtl != null) { common.setValueByPath(parentObject, ['revisionTtl'], fromRevisionTtl); } const fromDisableMemoryRevisions = common.getValueByPath(fromObject, [ 'disableMemoryRevisions', ]); if (parentObject !== undefined && fromDisableMemoryRevisions != null) { common.setValueByPath( parentObject, ['disableMemoryRevisions'], fromDisableMemoryRevisions, ); } const fromTopics = common.getValueByPath(fromObject, ['topics']); if (parentObject !== undefined && fromTopics != null) { let transformedList = fromTopics; if (Array.isArray(transformedList)) { transformedList = transformedList.map((item) => { return item; }); } common.setValueByPath(parentObject, ['topics'], transformedList); } const fromMetadata = common.getValueByPath(fromObject, ['metadata']); if (parentObject !== undefined && fromMetadata != null) { common.setValueByPath(parentObject, ['metadata'], fromMetadata); } const fromMemoryId = common.getValueByPath(fromObject, ['memoryId']); if (parentObject !== undefined && fromMemoryId != null) { common.setValueByPath(parentObject, ['_query', 'memoryId'], fromMemoryId); } return toObject; } export function createAgentEngineMemoryRequestParametersToVertex( fromObject: types.CreateAgentEngineMemoryRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } const fromFact = common.getValueByPath(fromObject, ['fact']); if (fromFact != null) { common.setValueByPath(toObject, ['fact'], fromFact); } const fromScope = common.getValueByPath(fromObject, ['scope']); if (fromScope != null) { common.setValueByPath(toObject, ['scope'], fromScope); } const fromConfig = common.getValueByPath(fromObject, ['config']); if (fromConfig != null) { agentEngineMemoryConfigToVertex(fromConfig, toObject); } return toObject; } export function deleteAgentEngineMemoryRequestParametersToVertex( fromObject: types.DeleteAgentEngineMemoryRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } return toObject; } export function generateAgentEngineMemoriesConfigToVertex( fromObject: types.GenerateAgentEngineMemoriesConfig, parentObject: Record, ): Record { const toObject: Record = {}; const fromDisableConsolidation = common.getValueByPath(fromObject, [ 'disableConsolidation', ]); if (parentObject !== undefined && fromDisableConsolidation != null) { common.setValueByPath( parentObject, ['disableConsolidation'], fromDisableConsolidation, ); } const fromRevisionLabels = common.getValueByPath(fromObject, [ 'revisionLabels', ]); if (parentObject !== undefined && fromRevisionLabels != null) { common.setValueByPath(parentObject, ['revisionLabels'], fromRevisionLabels); } const fromRevisionExpireTime = common.getValueByPath(fromObject, [ 'revisionExpireTime', ]); if (parentObject !== undefined && fromRevisionExpireTime != null) { common.setValueByPath( parentObject, ['revisionExpireTime'], fromRevisionExpireTime, ); } const fromRevisionTtl = common.getValueByPath(fromObject, ['revisionTtl']); if (parentObject !== undefined && fromRevisionTtl != null) { common.setValueByPath(parentObject, ['revisionTtl'], fromRevisionTtl); } const fromDisableMemoryRevisions = common.getValueByPath(fromObject, [ 'disableMemoryRevisions', ]); if (parentObject !== undefined && fromDisableMemoryRevisions != null) { common.setValueByPath( parentObject, ['disableMemoryRevisions'], fromDisableMemoryRevisions, ); } const fromMetadata = common.getValueByPath(fromObject, ['metadata']); if (parentObject !== undefined && fromMetadata != null) { common.setValueByPath(parentObject, ['metadata'], fromMetadata); } const fromMetadataMergeStrategy = common.getValueByPath(fromObject, [ 'metadataMergeStrategy', ]); if (parentObject !== undefined && fromMetadataMergeStrategy != null) { common.setValueByPath( parentObject, ['metadataMergeStrategy'], fromMetadataMergeStrategy, ); } const fromAllowedTopics = common.getValueByPath(fromObject, [ 'allowedTopics', ]); if (parentObject !== undefined && fromAllowedTopics != null) { let transformedList = fromAllowedTopics; if (Array.isArray(transformedList)) { transformedList = transformedList.map((item) => { return item; }); } common.setValueByPath(parentObject, ['allowedTopics'], transformedList); } return toObject; } export function generateAgentEngineMemoriesRequestParametersToVertex( fromObject: types.GenerateAgentEngineMemoriesRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } const fromVertexSessionSource = common.getValueByPath(fromObject, [ 'vertexSessionSource', ]); if (fromVertexSessionSource != null) { common.setValueByPath( toObject, ['vertexSessionSource'], fromVertexSessionSource, ); } const fromDirectContentsSource = common.getValueByPath(fromObject, [ 'directContentsSource', ]); if (fromDirectContentsSource != null) { common.setValueByPath( toObject, ['directContentsSource'], fromDirectContentsSource, ); } const fromDirectMemoriesSource = common.getValueByPath(fromObject, [ 'directMemoriesSource', ]); if (fromDirectMemoriesSource != null) { common.setValueByPath( toObject, ['directMemoriesSource'], fromDirectMemoriesSource, ); } const fromScope = common.getValueByPath(fromObject, ['scope']); if (fromScope != null) { common.setValueByPath(toObject, ['scope'], fromScope); } const fromConfig = common.getValueByPath(fromObject, ['config']); if (fromConfig != null) { generateAgentEngineMemoriesConfigToVertex(fromConfig, toObject); } return toObject; } export function getAgentEngineGenerateMemoriesOperationParametersToVertex( fromObject: types.GetAgentEngineGenerateMemoriesOperationParameters, ): Record { const toObject: Record = {}; const fromOperationName = common.getValueByPath(fromObject, [ 'operationName', ]); if (fromOperationName != null) { common.setValueByPath( toObject, ['_url', 'operationName'], fromOperationName, ); } return toObject; } export function getAgentEngineMemoryOperationParametersToVertex( fromObject: types.GetAgentEngineMemoryOperationParameters, ): Record { const toObject: Record = {}; const fromOperationName = common.getValueByPath(fromObject, [ 'operationName', ]); if (fromOperationName != null) { common.setValueByPath( toObject, ['_url', 'operationName'], fromOperationName, ); } return toObject; } export function getAgentEngineMemoryRequestParametersToVertex( fromObject: types.GetAgentEngineMemoryRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } return toObject; } export function ingestEventsConfigToVertex( fromObject: types.IngestEventsConfig, parentObject: Record, ): Record { const toObject: Record = {}; const fromForceFlush = common.getValueByPath(fromObject, ['forceFlush']); if (parentObject !== undefined && fromForceFlush != null) { common.setValueByPath(parentObject, ['forceFlush'], fromForceFlush); } return toObject; } export function ingestEventsRequestParametersToVertex( fromObject: types.IngestEventsRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } const fromStreamId = common.getValueByPath(fromObject, ['streamId']); if (fromStreamId != null) { common.setValueByPath(toObject, ['streamId'], fromStreamId); } const fromDirectContentsSource = common.getValueByPath(fromObject, [ 'directContentsSource', ]); if (fromDirectContentsSource != null) { common.setValueByPath( toObject, ['directContentsSource'], fromDirectContentsSource, ); } const fromScope = common.getValueByPath(fromObject, ['scope']); if (fromScope != null) { common.setValueByPath(toObject, ['scope'], fromScope); } const fromGenerationTriggerConfig = common.getValueByPath(fromObject, [ 'generationTriggerConfig', ]); if (fromGenerationTriggerConfig != null) { common.setValueByPath( toObject, ['generationTriggerConfig'], fromGenerationTriggerConfig, ); } const fromConfig = common.getValueByPath(fromObject, ['config']); if (fromConfig != null) { ingestEventsConfigToVertex(fromConfig, toObject); } return toObject; } export function listAgentEngineMemoryConfigToVertex( fromObject: types.ListAgentEngineMemoryConfig, parentObject: Record, ): Record { const toObject: Record = {}; const fromPageSize = common.getValueByPath(fromObject, ['pageSize']); if (parentObject !== undefined && fromPageSize != null) { common.setValueByPath(parentObject, ['_query', 'pageSize'], fromPageSize); } const fromPageToken = common.getValueByPath(fromObject, ['pageToken']); if (parentObject !== undefined && fromPageToken != null) { common.setValueByPath(parentObject, ['_query', 'pageToken'], fromPageToken); } const fromFilter = common.getValueByPath(fromObject, ['filter']); if (parentObject !== undefined && fromFilter != null) { common.setValueByPath(parentObject, ['_query', 'filter'], fromFilter); } const fromOrderBy = common.getValueByPath(fromObject, ['orderBy']); if (parentObject !== undefined && fromOrderBy != null) { common.setValueByPath(parentObject, ['_query', 'orderBy'], fromOrderBy); } return toObject; } export function listAgentEngineMemoryRequestParametersToVertex( fromObject: types.ListAgentEngineMemoryRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } const fromConfig = common.getValueByPath(fromObject, ['config']); if (fromConfig != null) { listAgentEngineMemoryConfigToVertex(fromConfig, toObject); } return toObject; } export function purgeAgentEngineMemoriesRequestParametersToVertex( fromObject: types.PurgeAgentEngineMemoriesRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } const fromFilter = common.getValueByPath(fromObject, ['filter']); if (fromFilter != null) { common.setValueByPath(toObject, ['filter'], fromFilter); } const fromFilterGroups = common.getValueByPath(fromObject, ['filterGroups']); if (fromFilterGroups != null) { let transformedList = fromFilterGroups; if (Array.isArray(transformedList)) { transformedList = transformedList.map((item) => { return item; }); } common.setValueByPath(toObject, ['filterGroups'], transformedList); } const fromForce = common.getValueByPath(fromObject, ['force']); if (fromForce != null) { common.setValueByPath(toObject, ['force'], fromForce); } return toObject; } export function retrieveAgentEngineMemoriesConfigToVertex( fromObject: types.RetrieveAgentEngineMemoriesConfig, parentObject: Record, ): Record { const toObject: Record = {}; const fromFilter = common.getValueByPath(fromObject, ['filter']); if (parentObject !== undefined && fromFilter != null) { common.setValueByPath(parentObject, ['filter'], fromFilter); } const fromFilterGroups = common.getValueByPath(fromObject, ['filterGroups']); if (parentObject !== undefined && fromFilterGroups != null) { let transformedList = fromFilterGroups; if (Array.isArray(transformedList)) { transformedList = transformedList.map((item) => { return item; }); } common.setValueByPath(parentObject, ['filterGroups'], transformedList); } const fromMemoryTypes = common.getValueByPath(fromObject, ['memoryTypes']); if (parentObject !== undefined && fromMemoryTypes != null) { common.setValueByPath(parentObject, ['memoryTypes'], fromMemoryTypes); } return toObject; } export function retrieveAgentEngineMemoriesRequestParametersToVertex( fromObject: types.RetrieveAgentEngineMemoriesRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } const fromScope = common.getValueByPath(fromObject, ['scope']); if (fromScope != null) { common.setValueByPath(toObject, ['scope'], fromScope); } const fromSimilaritySearchParams = common.getValueByPath(fromObject, [ 'similaritySearchParams', ]); if (fromSimilaritySearchParams != null) { common.setValueByPath( toObject, ['similaritySearchParams'], fromSimilaritySearchParams, ); } const fromSimpleRetrievalParams = common.getValueByPath(fromObject, [ 'simpleRetrievalParams', ]); if (fromSimpleRetrievalParams != null) { common.setValueByPath( toObject, ['simpleRetrievalParams'], fromSimpleRetrievalParams, ); } const fromConfig = common.getValueByPath(fromObject, ['config']); if (fromConfig != null) { retrieveAgentEngineMemoriesConfigToVertex(fromConfig, toObject); } return toObject; } export function retrieveMemoryProfilesRequestParametersToVertex( fromObject: types.RetrieveMemoryProfilesRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } const fromScope = common.getValueByPath(fromObject, ['scope']); if (fromScope != null) { common.setValueByPath(toObject, ['scope'], fromScope); } return toObject; } export function rollbackAgentEngineMemoryRequestParametersToVertex( fromObject: types.RollbackAgentEngineMemoryRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } const fromTargetRevisionId = common.getValueByPath(fromObject, [ 'targetRevisionId', ]); if (fromTargetRevisionId != null) { common.setValueByPath(toObject, ['targetRevisionId'], fromTargetRevisionId); } return toObject; } export function updateAgentEngineMemoryConfigToVertex( fromObject: types.UpdateAgentEngineMemoryConfig, parentObject: Record, ): Record { const toObject: Record = {}; const fromDisplayName = common.getValueByPath(fromObject, ['displayName']); if (parentObject !== undefined && fromDisplayName != null) { common.setValueByPath(parentObject, ['displayName'], fromDisplayName); } const fromDescription = common.getValueByPath(fromObject, ['description']); if (parentObject !== undefined && fromDescription != null) { common.setValueByPath(parentObject, ['description'], fromDescription); } const fromTtl = common.getValueByPath(fromObject, ['ttl']); if (parentObject !== undefined && fromTtl != null) { common.setValueByPath(parentObject, ['ttl'], fromTtl); } const fromExpireTime = common.getValueByPath(fromObject, ['expireTime']); if (parentObject !== undefined && fromExpireTime != null) { common.setValueByPath(parentObject, ['expireTime'], fromExpireTime); } const fromRevisionExpireTime = common.getValueByPath(fromObject, [ 'revisionExpireTime', ]); if (parentObject !== undefined && fromRevisionExpireTime != null) { common.setValueByPath( parentObject, ['revisionExpireTime'], fromRevisionExpireTime, ); } const fromRevisionTtl = common.getValueByPath(fromObject, ['revisionTtl']); if (parentObject !== undefined && fromRevisionTtl != null) { common.setValueByPath(parentObject, ['revisionTtl'], fromRevisionTtl); } const fromDisableMemoryRevisions = common.getValueByPath(fromObject, [ 'disableMemoryRevisions', ]); if (parentObject !== undefined && fromDisableMemoryRevisions != null) { common.setValueByPath( parentObject, ['disableMemoryRevisions'], fromDisableMemoryRevisions, ); } const fromTopics = common.getValueByPath(fromObject, ['topics']); if (parentObject !== undefined && fromTopics != null) { let transformedList = fromTopics; if (Array.isArray(transformedList)) { transformedList = transformedList.map((item) => { return item; }); } common.setValueByPath(parentObject, ['topics'], transformedList); } const fromMetadata = common.getValueByPath(fromObject, ['metadata']); if (parentObject !== undefined && fromMetadata != null) { common.setValueByPath(parentObject, ['metadata'], fromMetadata); } const fromMemoryId = common.getValueByPath(fromObject, ['memoryId']); if (parentObject !== undefined && fromMemoryId != null) { common.setValueByPath(parentObject, ['_query', 'memoryId'], fromMemoryId); } const fromUpdateMask = common.getValueByPath(fromObject, ['updateMask']); if (parentObject !== undefined && fromUpdateMask != null) { common.setValueByPath( parentObject, ['_query', 'updateMask'], fromUpdateMask, ); } return toObject; } export function updateAgentEngineMemoryRequestParametersToVertex( fromObject: types.UpdateAgentEngineMemoryRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } const fromFact = common.getValueByPath(fromObject, ['fact']); if (fromFact != null) { common.setValueByPath(toObject, ['fact'], fromFact); } const fromScope = common.getValueByPath(fromObject, ['scope']); if (fromScope != null) { common.setValueByPath(toObject, ['scope'], fromScope); } const fromConfig = common.getValueByPath(fromObject, ['config']); if (fromConfig != null) { updateAgentEngineMemoryConfigToVertex(fromConfig, toObject); } return toObject; } ================================================ FILE: src/converters/_memoryrevisions_converters.ts ================================================ /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ // Code generated by the Google Gen AI SDK generator DO NOT EDIT. import * as common from '@google/genai/vertex_internal'; import * as types from '../types.js'; export function getAgentEngineMemoryRevisionRequestParametersToVertex( fromObject: types.GetAgentEngineMemoryRevisionRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } return toObject; } export function listAgentEngineMemoryRevisionsConfigToVertex( fromObject: types.ListAgentEngineMemoryRevisionsConfig, parentObject: Record, ): Record { const toObject: Record = {}; const fromPageSize = common.getValueByPath(fromObject, ['pageSize']); if (parentObject !== undefined && fromPageSize != null) { common.setValueByPath(parentObject, ['_query', 'pageSize'], fromPageSize); } const fromPageToken = common.getValueByPath(fromObject, ['pageToken']); if (parentObject !== undefined && fromPageToken != null) { common.setValueByPath(parentObject, ['_query', 'pageToken'], fromPageToken); } const fromFilter = common.getValueByPath(fromObject, ['filter']); if (parentObject !== undefined && fromFilter != null) { common.setValueByPath(parentObject, ['_query', 'filter'], fromFilter); } return toObject; } export function listAgentEngineMemoryRevisionsRequestParametersToVertex( fromObject: types.ListAgentEngineMemoryRevisionsRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } const fromConfig = common.getValueByPath(fromObject, ['config']); if (fromConfig != null) { listAgentEngineMemoryRevisionsConfigToVertex(fromConfig, toObject); } return toObject; } ================================================ FILE: src/converters/_sandboxes_converters.ts ================================================ /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ // Code generated by the Google Gen AI SDK generator DO NOT EDIT. import * as common from '@google/genai/vertex_internal'; import * as types from '../types.js'; export function createAgentEngineSandboxConfigToVertex( fromObject: types.CreateAgentEngineSandboxConfig, parentObject: Record, ): Record { const toObject: Record = {}; const fromDisplayName = common.getValueByPath(fromObject, ['displayName']); if (parentObject !== undefined && fromDisplayName != null) { common.setValueByPath(parentObject, ['displayName'], fromDisplayName); } const fromDescription = common.getValueByPath(fromObject, ['description']); if (parentObject !== undefined && fromDescription != null) { common.setValueByPath(parentObject, ['description'], fromDescription); } const fromTtl = common.getValueByPath(fromObject, ['ttl']); if (parentObject !== undefined && fromTtl != null) { common.setValueByPath(parentObject, ['ttl'], fromTtl); } const fromSandboxEnvironmentTemplate = common.getValueByPath(fromObject, [ 'sandboxEnvironmentTemplate', ]); if (parentObject !== undefined && fromSandboxEnvironmentTemplate != null) { common.setValueByPath( parentObject, ['sandboxEnvironmentTemplate'], fromSandboxEnvironmentTemplate, ); } const fromSandboxEnvironmentSnapshot = common.getValueByPath(fromObject, [ 'sandboxEnvironmentSnapshot', ]); if (parentObject !== undefined && fromSandboxEnvironmentSnapshot != null) { common.setValueByPath( parentObject, ['sandboxEnvironmentSnapshot'], fromSandboxEnvironmentSnapshot, ); } const fromOwner = common.getValueByPath(fromObject, ['owner']); if (parentObject !== undefined && fromOwner != null) { common.setValueByPath(parentObject, ['owner'], fromOwner); } return toObject; } export function createAgentEngineSandboxRequestParametersToVertex( fromObject: types.CreateAgentEngineSandboxRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } const fromSpec = common.getValueByPath(fromObject, ['spec']); if (fromSpec != null) { common.setValueByPath(toObject, ['spec'], fromSpec); } const fromConfig = common.getValueByPath(fromObject, ['config']); if (fromConfig != null) { createAgentEngineSandboxConfigToVertex(fromConfig, toObject); } return toObject; } export function deleteAgentEngineSandboxRequestParametersToVertex( fromObject: types.DeleteAgentEngineSandboxRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } return toObject; } export function executeCodeAgentEngineSandboxRequestParametersToVertex( fromObject: types.ExecuteCodeAgentEngineSandboxRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } const fromInputs = common.getValueByPath(fromObject, ['inputs']); if (fromInputs != null) { let transformedList = fromInputs; if (Array.isArray(transformedList)) { transformedList = transformedList.map((item) => { return item; }); } common.setValueByPath(toObject, ['inputs'], transformedList); } return toObject; } export function getAgentEngineSandboxOperationParametersToVertex( fromObject: types.GetAgentEngineSandboxOperationParameters, ): Record { const toObject: Record = {}; const fromOperationName = common.getValueByPath(fromObject, [ 'operationName', ]); if (fromOperationName != null) { common.setValueByPath( toObject, ['_url', 'operationName'], fromOperationName, ); } return toObject; } export function getAgentEngineSandboxRequestParametersToVertex( fromObject: types.GetAgentEngineSandboxRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } return toObject; } export function listAgentEngineSandboxesConfigToVertex( fromObject: types.ListAgentEngineSandboxesConfig, parentObject: Record, ): Record { const toObject: Record = {}; const fromPageSize = common.getValueByPath(fromObject, ['pageSize']); if (parentObject !== undefined && fromPageSize != null) { common.setValueByPath(parentObject, ['_query', 'pageSize'], fromPageSize); } const fromPageToken = common.getValueByPath(fromObject, ['pageToken']); if (parentObject !== undefined && fromPageToken != null) { common.setValueByPath(parentObject, ['_query', 'pageToken'], fromPageToken); } const fromFilter = common.getValueByPath(fromObject, ['filter']); if (parentObject !== undefined && fromFilter != null) { common.setValueByPath(parentObject, ['_query', 'filter'], fromFilter); } return toObject; } export function listAgentEngineSandboxesRequestParametersToVertex( fromObject: types.ListAgentEngineSandboxesRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } const fromConfig = common.getValueByPath(fromObject, ['config']); if (fromConfig != null) { listAgentEngineSandboxesConfigToVertex(fromConfig, toObject); } return toObject; } ================================================ FILE: src/converters/_sessionevents_converters.ts ================================================ /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ // Code generated by the Google Gen AI SDK generator DO NOT EDIT. import * as common from '@google/genai/vertex_internal'; import * as types from '../types.js'; export function appendAgentEngineSessionEventConfigToVertex( fromObject: types.AppendAgentEngineSessionEventConfig, parentObject: Record, ): Record { const toObject: Record = {}; const fromContent = common.getValueByPath(fromObject, ['content']); if (parentObject !== undefined && fromContent != null) { common.setValueByPath(parentObject, ['content'], fromContent); } const fromActions = common.getValueByPath(fromObject, ['actions']); if (parentObject !== undefined && fromActions != null) { common.setValueByPath(parentObject, ['actions'], fromActions); } const fromErrorCode = common.getValueByPath(fromObject, ['errorCode']); if (parentObject !== undefined && fromErrorCode != null) { common.setValueByPath(parentObject, ['errorCode'], fromErrorCode); } const fromErrorMessage = common.getValueByPath(fromObject, ['errorMessage']); if (parentObject !== undefined && fromErrorMessage != null) { common.setValueByPath(parentObject, ['errorMessage'], fromErrorMessage); } const fromEventMetadata = common.getValueByPath(fromObject, [ 'eventMetadata', ]); if (parentObject !== undefined && fromEventMetadata != null) { common.setValueByPath(parentObject, ['eventMetadata'], fromEventMetadata); } const fromRawEvent = common.getValueByPath(fromObject, ['rawEvent']); if (parentObject !== undefined && fromRawEvent != null) { common.setValueByPath(parentObject, ['rawEvent'], fromRawEvent); } return toObject; } export function appendAgentEngineSessionEventRequestParametersToVertex( fromObject: types.AppendAgentEngineSessionEventRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } const fromAuthor = common.getValueByPath(fromObject, ['author']); if (fromAuthor != null) { common.setValueByPath(toObject, ['author'], fromAuthor); } const fromInvocationId = common.getValueByPath(fromObject, ['invocationId']); if (fromInvocationId != null) { common.setValueByPath(toObject, ['invocationId'], fromInvocationId); } const fromTimestamp = common.getValueByPath(fromObject, ['timestamp']); if (fromTimestamp != null) { common.setValueByPath(toObject, ['timestamp'], fromTimestamp); } const fromConfig = common.getValueByPath(fromObject, ['config']); if (fromConfig != null) { appendAgentEngineSessionEventConfigToVertex(fromConfig, toObject); } return toObject; } export function listAgentEngineSessionEventsConfigToVertex( fromObject: types.ListAgentEngineSessionEventsConfig, parentObject: Record, ): Record { const toObject: Record = {}; const fromPageSize = common.getValueByPath(fromObject, ['pageSize']); if (parentObject !== undefined && fromPageSize != null) { common.setValueByPath(parentObject, ['_query', 'pageSize'], fromPageSize); } const fromPageToken = common.getValueByPath(fromObject, ['pageToken']); if (parentObject !== undefined && fromPageToken != null) { common.setValueByPath(parentObject, ['_query', 'pageToken'], fromPageToken); } const fromFilter = common.getValueByPath(fromObject, ['filter']); if (parentObject !== undefined && fromFilter != null) { common.setValueByPath(parentObject, ['_query', 'filter'], fromFilter); } return toObject; } export function listAgentEngineSessionEventsRequestParametersToVertex( fromObject: types.ListAgentEngineSessionEventsRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } const fromConfig = common.getValueByPath(fromObject, ['config']); if (fromConfig != null) { listAgentEngineSessionEventsConfigToVertex(fromConfig, toObject); } return toObject; } ================================================ FILE: src/converters/_sessions_converters.ts ================================================ /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ // Code generated by the Google Gen AI SDK generator DO NOT EDIT. import * as common from '@google/genai/vertex_internal'; import * as types from '../types.js'; export function createAgentEngineSessionConfigToVertex( fromObject: types.CreateAgentEngineSessionConfig, parentObject: Record, ): Record { const toObject: Record = {}; const fromDisplayName = common.getValueByPath(fromObject, ['displayName']); if (parentObject !== undefined && fromDisplayName != null) { common.setValueByPath(parentObject, ['displayName'], fromDisplayName); } const fromSessionState = common.getValueByPath(fromObject, ['sessionState']); if (parentObject !== undefined && fromSessionState != null) { common.setValueByPath(parentObject, ['sessionState'], fromSessionState); } const fromTtl = common.getValueByPath(fromObject, ['ttl']); if (parentObject !== undefined && fromTtl != null) { common.setValueByPath(parentObject, ['ttl'], fromTtl); } const fromExpireTime = common.getValueByPath(fromObject, ['expireTime']); if (parentObject !== undefined && fromExpireTime != null) { common.setValueByPath(parentObject, ['expireTime'], fromExpireTime); } const fromLabels = common.getValueByPath(fromObject, ['labels']); if (parentObject !== undefined && fromLabels != null) { common.setValueByPath(parentObject, ['labels'], fromLabels); } const fromSessionId = common.getValueByPath(fromObject, ['sessionId']); if (parentObject !== undefined && fromSessionId != null) { common.setValueByPath(parentObject, ['_query', 'sessionId'], fromSessionId); } return toObject; } export function createAgentEngineSessionRequestParametersToVertex( fromObject: types.CreateAgentEngineSessionRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } const fromUserId = common.getValueByPath(fromObject, ['userId']); if (fromUserId != null) { common.setValueByPath(toObject, ['userId'], fromUserId); } const fromConfig = common.getValueByPath(fromObject, ['config']); if (fromConfig != null) { createAgentEngineSessionConfigToVertex(fromConfig, toObject); } return toObject; } export function deleteAgentEngineSessionRequestParametersToVertex( fromObject: types.DeleteAgentEngineSessionRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } return toObject; } export function getAgentEngineSessionOperationParametersToVertex( fromObject: types.GetAgentEngineSessionOperationParameters, ): Record { const toObject: Record = {}; const fromOperationName = common.getValueByPath(fromObject, [ 'operationName', ]); if (fromOperationName != null) { common.setValueByPath( toObject, ['_url', 'operationName'], fromOperationName, ); } return toObject; } export function getAgentEngineSessionRequestParametersToVertex( fromObject: types.GetAgentEngineSessionRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } return toObject; } export function listAgentEngineSessionsConfigToVertex( fromObject: types.ListAgentEngineSessionsConfig, parentObject: Record, ): Record { const toObject: Record = {}; const fromPageSize = common.getValueByPath(fromObject, ['pageSize']); if (parentObject !== undefined && fromPageSize != null) { common.setValueByPath(parentObject, ['_query', 'pageSize'], fromPageSize); } const fromPageToken = common.getValueByPath(fromObject, ['pageToken']); if (parentObject !== undefined && fromPageToken != null) { common.setValueByPath(parentObject, ['_query', 'pageToken'], fromPageToken); } const fromFilter = common.getValueByPath(fromObject, ['filter']); if (parentObject !== undefined && fromFilter != null) { common.setValueByPath(parentObject, ['_query', 'filter'], fromFilter); } return toObject; } export function listAgentEngineSessionsRequestParametersToVertex( fromObject: types.ListAgentEngineSessionsRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } const fromConfig = common.getValueByPath(fromObject, ['config']); if (fromConfig != null) { listAgentEngineSessionsConfigToVertex(fromConfig, toObject); } return toObject; } export function updateAgentEngineSessionConfigToVertex( fromObject: types.UpdateAgentEngineSessionConfig, parentObject: Record, ): Record { const toObject: Record = {}; const fromDisplayName = common.getValueByPath(fromObject, ['displayName']); if (parentObject !== undefined && fromDisplayName != null) { common.setValueByPath(parentObject, ['displayName'], fromDisplayName); } const fromSessionState = common.getValueByPath(fromObject, ['sessionState']); if (parentObject !== undefined && fromSessionState != null) { common.setValueByPath(parentObject, ['sessionState'], fromSessionState); } const fromTtl = common.getValueByPath(fromObject, ['ttl']); if (parentObject !== undefined && fromTtl != null) { common.setValueByPath(parentObject, ['ttl'], fromTtl); } const fromExpireTime = common.getValueByPath(fromObject, ['expireTime']); if (parentObject !== undefined && fromExpireTime != null) { common.setValueByPath(parentObject, ['expireTime'], fromExpireTime); } const fromLabels = common.getValueByPath(fromObject, ['labels']); if (parentObject !== undefined && fromLabels != null) { common.setValueByPath(parentObject, ['labels'], fromLabels); } const fromSessionId = common.getValueByPath(fromObject, ['sessionId']); if (parentObject !== undefined && fromSessionId != null) { common.setValueByPath(parentObject, ['_query', 'sessionId'], fromSessionId); } const fromUpdateMask = common.getValueByPath(fromObject, ['updateMask']); if (parentObject !== undefined && fromUpdateMask != null) { common.setValueByPath( parentObject, ['_query', 'updateMask'], fromUpdateMask, ); } const fromUserId = common.getValueByPath(fromObject, ['userId']); if (parentObject !== undefined && fromUserId != null) { common.setValueByPath(parentObject, ['userId'], fromUserId); } return toObject; } export function updateAgentEngineSessionRequestParametersToVertex( fromObject: types.UpdateAgentEngineSessionRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } const fromConfig = common.getValueByPath(fromObject, ['config']); if (fromConfig != null) { updateAgentEngineSessionConfigToVertex(fromConfig, toObject); } return toObject; } ================================================ FILE: src/converters/_skills_converters.ts ================================================ /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ // Code generated by the Google Gen AI SDK generator DO NOT EDIT. import * as common from '@google/genai/vertex_internal'; import * as types from '../types.js'; export function getSkillRequestParametersToVertex( fromObject: types.GetSkillRequestParameters, ): Record { const toObject: Record = {}; const fromName = common.getValueByPath(fromObject, ['name']); if (fromName != null) { common.setValueByPath(toObject, ['_url', 'name'], fromName); } const fromConfig = common.getValueByPath(fromObject, ['config']); if (fromConfig != null) { common.setValueByPath(toObject, ['config'], fromConfig); } return toObject; } ================================================ FILE: src/eslint.config.mjs ================================================ import eslint from '@eslint/js'; import tseslint from 'typescript-eslint'; export default [ eslint.configs.recommended, ...tseslint.configs.recommended, { ignores: [ // Ignore built files. 'dist/**', ], }, { rules: { '@typescript-eslint/no-unused-vars': [ 'error', { 'argsIgnorePattern': '^_', 'varsIgnorePattern': '^_', }, ], '@typescript-eslint/no-empty-object-type': [ 'error', { 'allowInterfaces': 'always', }, ], }, }, ]; ================================================ FILE: src/index.ts ================================================ /** * @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. */ export {Client} from './client'; export * from './types'; ================================================ FILE: src/memories.ts ================================================ /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ // Code generated by the Google Gen AI SDK generator DO NOT EDIT. import * as common from '@google/genai/vertex_internal'; import {ApiClient, BaseModule} from '@google/genai/vertex_internal'; import * as converters from './converters/_memories_converters.js'; import {MemoryRevisions} from './memoryrevisions.js'; import * as types from './types.js'; export class Memories extends BaseModule { public readonly revisions: MemoryRevisions; constructor(private readonly apiClient: ApiClient) { super(); this.revisions = new MemoryRevisions(apiClient); } async createInternal( params: types.CreateAgentEngineMemoryRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.createAgentEngineMemoryRequestParametersToVertex(params); path = common.formatMap( '{name}/memories', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'POST', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { return resp as types.AgentEngineMemoryOperation; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async delete( params: types.DeleteAgentEngineMemoryRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.deleteAgentEngineMemoryRequestParametersToVertex(params); path = common.formatMap( '{name}', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'DELETE', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { return resp as types.DeleteAgentEngineMemoryOperation; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async generateInternal( params: types.GenerateAgentEngineMemoriesRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.generateAgentEngineMemoriesRequestParametersToVertex(params); path = common.formatMap( '{name}/memories:generate', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'POST', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { return resp as types.AgentEngineGenerateMemoriesOperation; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async get( params: types.GetAgentEngineMemoryRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.getAgentEngineMemoryRequestParametersToVertex(params); path = common.formatMap( '{name}', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'GET', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { return resp as types.Memory; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async ingestEventsInternal( params: types.IngestEventsRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.ingestEventsRequestParametersToVertex(params); path = common.formatMap( '{name}/memories:ingestEvents', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'POST', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { return resp as types.MemoryBankIngestEventsOperation; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async listInternal( params: types.ListAgentEngineMemoryRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.listAgentEngineMemoryRequestParametersToVertex(params); path = common.formatMap( '{name}/memories', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'GET', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { const typedResp = new types.ListReasoningEnginesMemoriesResponse(); Object.assign(typedResp, resp); return typedResp; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async getMemoryOperationInternal( params: types.GetAgentEngineMemoryOperationParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.getAgentEngineMemoryOperationParametersToVertex(params); path = common.formatMap( '{operationName}', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'GET', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { return resp as types.AgentEngineMemoryOperation; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async getGenerateMemoriesOperationInternal( params: types.GetAgentEngineGenerateMemoriesOperationParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.getAgentEngineGenerateMemoriesOperationParametersToVertex( params, ); path = common.formatMap( '{operationName}', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'GET', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { return resp as types.AgentEngineGenerateMemoriesOperation; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async retrieveInternal( params: types.RetrieveAgentEngineMemoriesRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.retrieveAgentEngineMemoriesRequestParametersToVertex(params); path = common.formatMap( '{name}/memories:retrieve', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'POST', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { const typedResp = new types.RetrieveMemoriesResponse(); Object.assign(typedResp, resp); return typedResp; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async retrieveProfiles( params: types.RetrieveMemoryProfilesRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.retrieveMemoryProfilesRequestParametersToVertex(params); path = common.formatMap( '{name}/memories:retrieveProfiles', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'POST', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { const typedResp = new types.RetrieveProfilesResponse(); Object.assign(typedResp, resp); return typedResp; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async rollbackInternal( params: types.RollbackAgentEngineMemoryRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.rollbackAgentEngineMemoryRequestParametersToVertex(params); path = common.formatMap( '{name}:rollback', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'POST', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { return resp as types.AgentEngineRollbackMemoryOperation; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async updateInternal( params: types.UpdateAgentEngineMemoryRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.updateAgentEngineMemoryRequestParametersToVertex(params); path = common.formatMap( '{name}', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'PATCH', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { return resp as types.AgentEngineMemoryOperation; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async purgeInternal( params: types.PurgeAgentEngineMemoriesRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.purgeAgentEngineMemoriesRequestParametersToVertex(params); path = common.formatMap( '{name}/memories:purge', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'POST', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { return resp as types.AgentEnginePurgeMemoriesOperation; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } } ================================================ FILE: src/memoryrevisions.ts ================================================ /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ // Code generated by the Google Gen AI SDK generator DO NOT EDIT. import * as common from '@google/genai/vertex_internal'; import {ApiClient, BaseModule} from '@google/genai/vertex_internal'; import * as converters from './converters/_memoryrevisions_converters.js'; import * as types from './types.js'; export class MemoryRevisions extends BaseModule { constructor(private readonly apiClient: ApiClient) { super(); } async get( params: types.GetAgentEngineMemoryRevisionRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.getAgentEngineMemoryRevisionRequestParametersToVertex( params, ); path = common.formatMap( '{name}', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'GET', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { return resp as types.MemoryRevision; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async listInternal( params: types.ListAgentEngineMemoryRevisionsRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.listAgentEngineMemoryRevisionsRequestParametersToVertex( params, ); path = common.formatMap( '{name}/revisions', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'GET', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { const typedResp = new types.ListAgentEngineMemoryRevisionsResponse(); Object.assign(typedResp, resp); return typedResp; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } } ================================================ FILE: src/releases.txt ================================================ Use this file when you need to force a patch release with release-please. Edit line 4 below with the version for the release. 0.6.0 ================================================ FILE: src/sandboxes.ts ================================================ /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ // Code generated by the Google Gen AI SDK generator DO NOT EDIT. import * as common from '@google/genai/vertex_internal'; import {ApiClient, BaseModule} from '@google/genai/vertex_internal'; import * as converters from './converters/_sandboxes_converters.js'; import * as types from './types.js'; export class Sandboxes extends BaseModule { constructor(private readonly apiClient: ApiClient) { super(); } async createInternal( params: types.CreateAgentEngineSandboxRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.createAgentEngineSandboxRequestParametersToVertex(params); path = common.formatMap( '{name}/sandboxEnvironments', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'POST', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { return resp as types.AgentEngineSandboxOperation; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async deleteInternal( params: types.DeleteAgentEngineSandboxRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.deleteAgentEngineSandboxRequestParametersToVertex(params); path = common.formatMap( '{name}', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'DELETE', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { return resp as types.DeleteAgentEngineSandboxOperation; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async executeCodeInternal( params: types.ExecuteCodeAgentEngineSandboxRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.executeCodeAgentEngineSandboxRequestParametersToVertex( params, ); path = common.formatMap( '{name}/:execute', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'POST', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { const typedResp = new types.ExecuteSandboxEnvironmentResponse(); Object.assign(typedResp, resp); return typedResp; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async getInternal( params: types.GetAgentEngineSandboxRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.getAgentEngineSandboxRequestParametersToVertex(params); path = common.formatMap( '{name}', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'GET', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { return resp as types.SandboxEnvironment; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async listInternal( params: types.ListAgentEngineSandboxesRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.listAgentEngineSandboxesRequestParametersToVertex(params); path = common.formatMap( '{name}/sandboxEnvironments', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'GET', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { const typedResp = new types.ListAgentEngineSandboxesResponse(); Object.assign(typedResp, resp); return typedResp; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async getSandboxOperationInternal( params: types.GetAgentEngineSandboxOperationParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.getAgentEngineSandboxOperationParametersToVertex(params); path = common.formatMap( '{operationName}', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'GET', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { return resp as types.AgentEngineSandboxOperation; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } } ================================================ FILE: src/sessionevents.ts ================================================ /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ // Code generated by the Google Gen AI SDK generator DO NOT EDIT. import * as common from '@google/genai/vertex_internal'; import {ApiClient, BaseModule} from '@google/genai/vertex_internal'; import * as converters from './converters/_sessionevents_converters.js'; import * as types from './types.js'; export class SessionEvents extends BaseModule { constructor(private readonly apiClient: ApiClient) { super(); } async append( params: types.AppendAgentEngineSessionEventRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.appendAgentEngineSessionEventRequestParametersToVertex( params, ); path = common.formatMap( '{name}:appendEvent', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'POST', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { const typedResp = new types.AppendAgentEngineSessionEventResponse(); Object.assign(typedResp, resp); return typedResp; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async listInternal( params: types.ListAgentEngineSessionEventsRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.listAgentEngineSessionEventsRequestParametersToVertex( params, ); path = common.formatMap( '{name}/events', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'GET', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { const typedResp = new types.ListAgentEngineSessionEventsResponse(); Object.assign(typedResp, resp); return typedResp; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } } ================================================ FILE: src/sessions.ts ================================================ /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ // Code generated by the Google Gen AI SDK generator DO NOT EDIT. import * as common from '@google/genai/vertex_internal'; import {ApiClient, BaseModule} from '@google/genai/vertex_internal'; import * as converters from './converters/_sessions_converters.js'; import {SessionEvents} from './sessionevents.js'; import * as types from './types.js'; export class Sessions extends BaseModule { public readonly events: SessionEvents; constructor(private readonly apiClient: ApiClient) { super(); this.events = new SessionEvents(apiClient); } async createInternal( params: types.CreateAgentEngineSessionRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.createAgentEngineSessionRequestParametersToVertex(params); path = common.formatMap( '{name}/sessions', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'POST', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { return resp as types.AgentEngineSessionOperation; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async delete( params: types.DeleteAgentEngineSessionRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.deleteAgentEngineSessionRequestParametersToVertex(params); path = common.formatMap( '{name}', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'DELETE', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { return resp as types.DeleteAgentEngineSessionOperation; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async get( params: types.GetAgentEngineSessionRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.getAgentEngineSessionRequestParametersToVertex(params); path = common.formatMap( '{name}', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'GET', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { return resp as types.Session; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async listInternal( params: types.ListAgentEngineSessionsRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.listAgentEngineSessionsRequestParametersToVertex(params); path = common.formatMap( '{name}/sessions', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'GET', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { const typedResp = new types.ListReasoningEnginesSessionsResponse(); Object.assign(typedResp, resp); return typedResp; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async getSessionOperationInternal( params: types.GetAgentEngineSessionOperationParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.getAgentEngineSessionOperationParametersToVertex(params); path = common.formatMap( '{operationName}', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'GET', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { return resp as types.AgentEngineSessionOperation; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } async updateInternal( params: types.UpdateAgentEngineSessionRequestParameters, ): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.updateAgentEngineSessionRequestParametersToVertex(params); path = common.formatMap( '{name}', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'PATCH', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { return resp as types.AgentEngineSessionOperation; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } } ================================================ FILE: src/skills.ts ================================================ /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ // Code generated by the Google Gen AI SDK generator DO NOT EDIT. import * as common from '@google/genai/vertex_internal'; import {ApiClient, BaseModule} from '@google/genai/vertex_internal'; import * as converters from './converters/_skills_converters.js'; import * as types from './types.js'; export class Skills extends BaseModule { constructor(private readonly apiClient: ApiClient) { super(); } async get(params: types.GetSkillRequestParameters): Promise { let response: Promise; let path: string = ''; let queryParams: Record = {}; if (this.apiClient.isVertexAI()) { const body = converters.getSkillRequestParametersToVertex(params); path = common.formatMap( '{name}', body['_url'] as Record, ); queryParams = body['_query'] as Record; delete body['_url']; delete body['_query']; delete body['config']; response = this.apiClient .request({ path: path, queryParams: queryParams, body: JSON.stringify(body), httpMethod: 'GET', httpOptions: params.config?.httpOptions, abortSignal: params.config?.abortSignal, }) .then((httpResponse) => { return httpResponse.json(); }) as Promise; return response.then((resp) => { return resp as types.Skill; }); } else { throw new Error( 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', ); } } } ================================================ FILE: src/types/common.ts ================================================ /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ // Code generated by the Google Gen AI SDK generator DO NOT EDIT. import * as genaiTypes from '@google/genai'; /** The identity type to use for the Reasoning Engine. If not specified, the `service_account` field will be used if set, otherwise the default Vertex AI Reasoning Engine Service Agent in the project will be used. */ export enum IdentityType { /** * Default value. Use a custom service account if the `service_account` field is set, otherwise use the default Vertex AI Reasoning Engine Service Agent in the project. Same behavior as SERVICE_ACCOUNT. */ IDENTITY_TYPE_UNSPECIFIED = 'IDENTITY_TYPE_UNSPECIFIED', /** * Use a custom service account if the `service_account` field is set, otherwise use the default Vertex AI Reasoning Engine Service Agent in the project. */ SERVICE_ACCOUNT = 'SERVICE_ACCOUNT', /** * Use Agent Identity. The `service_account` field must not be set. */ AGENT_IDENTITY = 'AGENT_IDENTITY', } /** The agent server mode. */ export enum AgentServerMode { /** * Unspecified agent server mode. Do not use. */ AGENT_SERVER_MODE_UNSPECIFIED = 'AGENT_SERVER_MODE_UNSPECIFIED', /** * Stable agent server mode. This mode has everything stable and well-tested features agent engine offers. */ STABLE = 'STABLE', /** * Experimental agent server mode. This mode contains experimental features. */ EXPERIMENTAL = 'EXPERIMENTAL', } /** Represents the managed memory topic. */ export enum ManagedTopicEnum { /** * Represents an unspecified topic. This value should not be used. */ MANAGED_TOPIC_ENUM_UNSPECIFIED = 'MANAGED_TOPIC_ENUM_UNSPECIFIED', /** * Represents significant personal information about the User like first names, relationships, hobbies, important dates. */ USER_PERSONAL_INFO = 'USER_PERSONAL_INFO', /** * Represents stated or implied likes, dislikes, preferred styles, or patterns. */ USER_PREFERENCES = 'USER_PREFERENCES', /** * Represents important milestones or conclusions within the dialogue. */ KEY_CONVERSATION_DETAILS = 'KEY_CONVERSATION_DETAILS', /** * Represents information that the user explicitly requested to remember or forget. */ EXPLICIT_INSTRUCTIONS = 'EXPLICIT_INSTRUCTIONS', } /** The type of the memory. */ export enum MemoryType { /** * Represents an unspecified memory type. This value should not be used. */ MEMORY_TYPE_UNSPECIFIED = 'MEMORY_TYPE_UNSPECIFIED', /** * Indicates belonging to a collection of natural language memories. */ NATURAL_LANGUAGE_COLLECTION = 'NATURAL_LANGUAGE_COLLECTION', /** * Indicates belonging to a structured profile. */ STRUCTURED_PROFILE = 'STRUCTURED_PROFILE', } /** Represents the operator to apply to the filter. If not set, then EQUAL will be used. */ export enum Operator { /** * Represents an unspecified operator. Defaults to EQUAL. */ OPERATOR_UNSPECIFIED = 'OPERATOR_UNSPECIFIED', /** * Equal to. */ EQUAL = 'EQUAL', /** * Greater than. */ GREATER_THAN = 'GREATER_THAN', /** * Less than. */ LESS_THAN = 'LESS_THAN', } /** The coding language supported in this environment. */ export enum Language { /** * The default value. This value is unused. */ LANGUAGE_UNSPECIFIED = 'LANGUAGE_UNSPECIFIED', /** * The coding language is Python. */ LANGUAGE_PYTHON = 'LANGUAGE_PYTHON', /** * The coding language is JavaScript. */ LANGUAGE_JAVASCRIPT = 'LANGUAGE_JAVASCRIPT', } /** The machine config of the code execution environment. */ export enum MachineConfig { /** * The default value: milligcu 2000, memory 1.5Gib */ MACHINE_CONFIG_UNSPECIFIED = 'MACHINE_CONFIG_UNSPECIFIED', /** * The default value: milligcu 4000, memory 4 Gib */ MACHINE_CONFIG_VCPU4_RAM4GIB = 'MACHINE_CONFIG_VCPU4_RAM4GIB', } /** Output only. The runtime state of the SandboxEnvironment. */ export enum SandboxState { /** * The default value. This value is unused. */ STATE_UNSPECIFIED = 'STATE_UNSPECIFIED', /** * Runtime resources are being allocated for the sandbox environment. */ STATE_PROVISIONING = 'STATE_PROVISIONING', /** * Sandbox runtime is ready for serving. */ STATE_RUNNING = 'STATE_RUNNING', /** * Sandbox runtime is halted, performing tear down tasks. */ STATE_DEPROVISIONING = 'STATE_DEPROVISIONING', /** * Sandbox has terminated with underlying runtime failure. */ STATE_TERMINATED = 'STATE_TERMINATED', /** * Sandbox runtime has been deleted. */ STATE_DELETED = 'STATE_DELETED', } /** State of the Skill. */ export enum SkillState { /** * The state of the Skill is unspecified. */ STATE_UNSPECIFIED = 'STATE_UNSPECIFIED', /** * The Skill is active. */ ACTIVE = 'ACTIVE', /** * The Skill is being created. */ CREATING = 'CREATING', /** * The Skill was created, but failed to process. */ FAILED = 'FAILED', /** * The Skill is being deleted. */ DELETING = 'DELETING', } /** Framework used to build the application. */ export enum Framework { /** * Unspecified framework. */ FRAMEWORK_UNSPECIFIED = 'FRAMEWORK_UNSPECIFIED', /** * React framework. */ REACT = 'REACT', /** * Angular framework. */ ANGULAR = 'ANGULAR', } /** Output only. The state of the revision. */ export enum State { /** * The unspecified state. */ STATE_UNSPECIFIED = 'STATE_UNSPECIFIED', /** * Is deployed and ready to be used. */ ACTIVE = 'ACTIVE', /** * Is deprecated, may not be used, only preserved for historical purposes. */ DEPRECATED = 'DEPRECATED', } /** The strategy to use when applying metadata to existing memories during consolidation. */ export enum MemoryMetadataMergeStrategy { /** * The metadata merge strategy is unspecified. */ METADATA_MERGE_STRATEGY_UNSPECIFIED = 'METADATA_MERGE_STRATEGY_UNSPECIFIED', /** * Replace the metadata of the updated memories with the new metadata. */ OVERWRITE = 'OVERWRITE', /** * Append new metadata to the existing metadata. If there are duplicate keys, the existing values will be overwritten. */ MERGE = 'MERGE', /** * Restrict consolidation to memories that have exactly the same metadata as the request. If a memory doesn't have the same metadata, it is not eligible for consolidation. */ REQUIRE_EXACT_MATCH = 'REQUIRE_EXACT_MATCH', } /** The action to take. */ export enum GenerateMemoriesResponseGeneratedMemoryAction { /** * The action is unspecified. */ ACTION_UNSPECIFIED = 'ACTION_UNSPECIFIED', /** * The memory was created. */ CREATED = 'CREATED', /** * The memory was updated. The `fact` field may not be updated if the existing fact is still accurate. */ UPDATED = 'UPDATED', /** * The memory was deleted. */ DELETED = 'DELETED', } /** Represents an environment variable present in a Container or Python Module. */ export declare interface EnvVar { /** Required. Name of the environment variable. Must be a valid C identifier. */ name?: string; /** Required. Variables that reference a $(VAR_NAME) are expanded using the previous defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. The $(VAR_NAME) syntax can be escaped with a double $$, ie: $$(VAR_NAME). Escaped references will never be expanded, regardless of whether the variable exists or not. */ value?: string; } /** DNS peering configuration. These configurations are used to create DNS peering zones in the Vertex tenant project VPC, enabling resolution of records within the specified domain hosted in the target network's Cloud DNS. */ export declare interface DnsPeeringConfig { /** Required. The DNS name suffix of the zone being peered to, e.g., "my-internal-domain.corp.". Must end with a dot. */ domain?: string; /** Required. The VPC network name in the target_project where the DNS zone specified by 'domain' is visible. */ targetNetwork?: string; /** Required. The project ID hosting the Cloud DNS managed zone that contains the 'domain'. The Vertex AI Service Agent requires the dns.peer role on this project. */ targetProject?: string; } /** Configuration for PSC-I. */ export declare interface PscInterfaceConfig { /** Optional. DNS peering configurations. When specified, Vertex AI will attempt to configure DNS peering zones in the tenant project VPC to resolve the specified domains using the target network's Cloud DNS. The user must grant the dns.peer role to the Vertex AI Service Agent on the target project. */ dnsPeeringConfigs?: DnsPeeringConfig[]; /** Optional. The name of the Compute Engine [network attachment](https://cloud.google.com/vpc/docs/about-network-attachments) to attach to the resource within the region and user project. To specify this field, you must have already [created a network attachment] (https://cloud.google.com/vpc/docs/create-manage-network-attachments#create-network-attachments). This field is only used for resources using PSC-I. */ networkAttachment?: string; } /** Reference to a secret stored in the Cloud Secret Manager that will provide the value for this environment variable. */ export declare interface SecretRef { /** Required. The name of the secret in Cloud Secret Manager. Format: {secret_name}. */ secret?: string; /** The Cloud Secret Manager secret version. Can be 'latest' for the latest version, an integer for a specific version, or a version alias. */ version?: string; } /** Represents an environment variable where the value is a secret in Cloud Secret Manager. */ export declare interface SecretEnvVar { /** Required. Name of the secret environment variable. */ name?: string; /** Required. Reference to a secret stored in the Cloud Secret Manager that will provide the value for this environment variable. */ secretRef?: SecretRef; } /** Configuration for traffic originating from a Reasoning Engine. */ export declare interface ReasoningEngineSpecDeploymentSpecAgentGatewayConfigAgentToAnywhereConfig { /** Required. The resource name of the Agent Gateway for outbound traffic. It must be set to a Google-managed gateway whose `governed_access_path` is `AGENT_TO_ANYWHERE`. Format: `projects/{project}/locations/{location}/agentGateways/{agent_gateway}` */ agentGateway?: string; } /** Configuration for traffic targeting a Reasoning Engine. */ export declare interface ReasoningEngineSpecDeploymentSpecAgentGatewayConfigClientToAgentConfig { /** Required. The resource name of the Agent Gateway to use for inbound traffic. It must be set to a Google-managed gateway whose `governed_access_path` is `CLIENT_TO_AGENT`. Format: `projects/{project}/locations/{location}/agentGateways/{agent_gateway}` */ agentGateway?: string; } /** Agent Gateway configuration for a Reasoning Engine deployment. */ export declare interface ReasoningEngineSpecDeploymentSpecAgentGatewayConfig { /** Optional. Configuration for traffic originating from the Reasoning Engine. When unset, outgoing traffic is not routed through an Agent Gateway. */ agentToAnywhereConfig?: ReasoningEngineSpecDeploymentSpecAgentGatewayConfigAgentToAnywhereConfig; /** Optional. Configuration for traffic targeting the Reasoning Engine. When unset, incoming traffic is not routed through an Agent Gateway. */ clientToAgentConfig?: ReasoningEngineSpecDeploymentSpecAgentGatewayConfigClientToAgentConfig; } /** Specifies the HTTP GET configuration for the probe. */ export declare interface KeepAliveProbeHttpGet { /** Required. Specifies the path of the HTTP GET request (e.g., "/is_busy"). */ path?: string; /** Optional. Specifies the port number on the container to which the request is sent. */ port?: number; } /** Represents the configuration for keep-alive probe. Contains configuration on a specified endpoint that a deployment host should use to keep the container alive based on the probe settings. */ export declare interface KeepAliveProbe { /** Optional. Specifies the HTTP GET configuration for the probe. */ httpGet?: KeepAliveProbeHttpGet; /** Optional. Specifies the maximum duration (in seconds) to keep the instance alive via this probe. Can be a maximum of 3600 seconds (1 hour). */ maxSeconds?: number; } /** The specification of a Reasoning Engine deployment. */ export declare interface ReasoningEngineSpecDeploymentSpec { /** The agent server mode. */ agentServerMode?: AgentServerMode; /** Optional. Concurrency for each container and agent server. Recommended value: 2 * cpu + 1. Defaults to 9. */ containerConcurrency?: number; /** Optional. Environment variables to be set with the Reasoning Engine deployment. The environment variables can be updated through the UpdateReasoningEngine API. */ env?: EnvVar[]; /** Optional. The maximum number of application instances that can be launched to handle increased traffic. Defaults to 100. Range: [1, 1000]. If VPC-SC or PSC-I is enabled, the acceptable range is [1, 100]. */ maxInstances?: number; /** Optional. The minimum number of application instances that will be kept running at all times. Defaults to 1. Range: [0, 75]. */ minInstances?: number; /** Optional. Configuration for PSC-I. */ pscInterfaceConfig?: PscInterfaceConfig; /** Optional. Resource limits for each container. Only 'cpu' and 'memory' keys are supported. Defaults to {"cpu": "4", "memory": "4Gi"}. * The only supported values for CPU are '1', '2', '4', '6' and '8'. For more information, go to https://cloud.google.com/run/docs/configuring/cpu. * The only supported values for memory are '1Gi', '2Gi', ... '32 Gi'. * For required cpu on different memory values, go to https://cloud.google.com/run/docs/configuring/memory-limits */ resourceLimits?: Record; /** Optional. Environment variables where the value is a secret in Cloud Secret Manager. To use this feature, add 'Secret Manager Secret Accessor' role (roles/secretmanager.secretAccessor) to AI Platform Reasoning Engine Service Agent. */ secretEnv?: SecretEnvVar[]; /** Optional. Agent Gateway configuration for the Reasoning Engine deployment. */ agentGatewayConfig?: ReasoningEngineSpecDeploymentSpecAgentGatewayConfig; /** Optional. Specifies the configuration for keep-alive probe. Contains configuration on a specified endpoint that a deployment host should use to keep the container alive based on the probe settings. */ keepAliveProbe?: KeepAliveProbe; } /** User-provided package specification, containing pickled object and package requirements. */ export declare interface ReasoningEngineSpecPackageSpec { /** Optional. The Cloud Storage URI of the dependency files in tar.gz format. */ dependencyFilesGcsUri?: string; /** Optional. The Cloud Storage URI of the pickled python object. */ pickleObjectGcsUri?: string; /** Optional. The Python version. Supported values are 3.9, 3.10, 3.11, 3.12, 3.13, 3.14. If not specified, the default value is 3.10. */ pythonVersion?: string; /** Optional. The Cloud Storage URI of the `requirements.txt` file */ requirementsGcsUri?: string; } /** Configuration for the Agent Development Kit (ADK). */ export declare interface ReasoningEngineSpecSourceCodeSpecAgentConfigSourceAdkConfig { /** Required. The value of the ADK config in JSON format. */ jsonConfig?: Record; } /** Specifies source code provided as a byte stream. */ export declare interface ReasoningEngineSpecSourceCodeSpecInlineSource { /** Required. Input only. The application source code archive. It must be a compressed tarball (.tar.gz) file. * @remarks Encoded as base64 string. */ sourceArchive?: string; } /** Specification for the deploying from agent config. */ export declare interface ReasoningEngineSpecSourceCodeSpecAgentConfigSource { /** Required. The ADK configuration. */ adkConfig?: ReasoningEngineSpecSourceCodeSpecAgentConfigSourceAdkConfig; /** Optional. Any additional files needed to interpret the config. If a `requirements.txt` file is present in the `inline_source`, the corresponding packages will be installed. If no `requirements.txt` file is present in `inline_source`, then the latest version of `google-adk` will be installed for interpreting the ADK config. */ inlineSource?: ReasoningEngineSpecSourceCodeSpecInlineSource; } /** Specifies the configuration for fetching source code from a Git repository that is managed by Developer Connect. This includes the repository, revision, and directory to use. */ export declare interface ReasoningEngineSpecSourceCodeSpecDeveloperConnectConfig { /** Required. The Developer Connect Git repository link, formatted as `projects/{project_id}/locations/{location_id}/connections/{connection_id}/gitRepositoryLink/{repository_link_id}`. */ gitRepositoryLink?: string; /** Required. Directory, relative to the source root, in which to run the build. */ dir?: string; /** Required. The revision to fetch from the Git repository such as a branch, a tag, a commit SHA, or any Git ref. */ revision?: string; } /** Specifies source code to be fetched from a Git repository managed through the Developer Connect service. */ export declare interface ReasoningEngineSpecSourceCodeSpecDeveloperConnectSource { /** Required. The Developer Connect configuration that defines the specific repository, revision, and directory to use as the source code root. */ config?: ReasoningEngineSpecSourceCodeSpecDeveloperConnectConfig; } /** The image spec for building an image (within a single build step), based on the config file (i.e. Dockerfile) in the source directory. */ export declare interface ReasoningEngineSpecSourceCodeSpecImageSpec { /** Optional. Build arguments to be used. They will be passed through --build-arg flags. */ buildArgs?: Record; } /** Specification for running a Python application from source. */ export declare interface ReasoningEngineSpecSourceCodeSpecPythonSpec { /** Optional. The Python module to load as the entrypoint, specified as a fully qualified module name. For example: path.to.agent. If not specified, defaults to "agent". The project root will be added to Python sys.path, allowing imports to be specified relative to the root. This field should not be set if the source is `agent_config_source`. */ entrypointModule?: string; /** Optional. The name of the callable object within the `entrypoint_module` to use as the application If not specified, defaults to "root_agent". This field should not be set if the source is `agent_config_source`. */ entrypointObject?: string; /** Optional. The path to the requirements file, relative to the source root. If not specified, defaults to "requirements.txt". */ requirementsFile?: string; /** Optional. The version of Python to use. Support version includes 3.9, 3.10, 3.11, 3.12, 3.13, 3.14. If not specified, default value is 3.10. */ version?: string; } /** Specification for deploying from source code. */ export declare interface ReasoningEngineSpecSourceCodeSpec { /** Source code is generated from the agent config. */ agentConfigSource?: ReasoningEngineSpecSourceCodeSpecAgentConfigSource; /** Source code is in a Git repository managed by Developer Connect. */ developerConnectSource?: ReasoningEngineSpecSourceCodeSpecDeveloperConnectSource; /** Optional. Configuration for building an image with custom config file. */ imageSpec?: ReasoningEngineSpecSourceCodeSpecImageSpec; /** Source code is provided directly in the request. */ inlineSource?: ReasoningEngineSpecSourceCodeSpecInlineSource; /** Configuration for a Python application. */ pythonSpec?: ReasoningEngineSpecSourceCodeSpecPythonSpec; } /** Specification for deploying from a container image. */ export declare interface ReasoningEngineSpecContainerSpec { /** Required. The Artifact Registry Docker image URI (e.g., us-central1-docker.pkg.dev/my-project/my-repo/my-image:tag) of the container image that is to be run on each worker replica. */ imageUri?: string; } /** The specification of an agent engine. */ export declare interface ReasoningEngineSpec { /** Optional. The A2A Agent Card for the agent (if available). It follows the specification at https://a2a-protocol.org/latest/specification/#5-agent-discovery-the-agent-card. */ agentCard?: Record; /** Optional. The OSS agent framework used to develop the agent. Currently supported values: "google-adk", "langchain", "langgraph", "ag2", "llama-index", "custom". */ agentFramework?: string; /** Optional. Declarations for object class methods in OpenAPI specification format. */ classMethods?: Record[]; /** Optional. The specification of a Reasoning Engine deployment. */ deploymentSpec?: ReasoningEngineSpecDeploymentSpec; /** Output only. The identity to use for the Reasoning Engine. It can contain one of the following values: * service-{project}@gcp-sa-aiplatform-re.googleapis.com (for SERVICE_AGENT identity type) * {name}@{project}.gserviceaccount.com (for SERVICE_ACCOUNT identity type) * agents.global.{org}.system.id.goog/resources/aiplatform/projects/{project}/locations/{location}/reasoningEngines/{reasoning_engine} (for AGENT_IDENTITY identity type) */ effectiveIdentity?: string; /** Optional. The identity type to use for the Reasoning Engine. If not specified, the `service_account` field will be used if set, otherwise the default Vertex AI Reasoning Engine Service Agent in the project will be used. */ identityType?: IdentityType; /** Optional. User provided package spec of the ReasoningEngine. Ignored when users directly specify a deployment image through `deployment_spec.first_party_image_override`, but keeping the field_behavior to avoid introducing breaking changes. The `deployment_source` field should not be set if `package_spec` is specified. */ packageSpec?: ReasoningEngineSpecPackageSpec; /** Optional. The service account that the Reasoning Engine artifact runs as. It should have "roles/storage.objectViewer" for reading the user project's Cloud Storage and "roles/aiplatform.user" for using Vertex extensions. If not specified, the Vertex AI Reasoning Engine Service Agent in the project will be used. */ serviceAccount?: string; /** Deploy from source code files with a defined entrypoint. */ sourceCodeSpec?: ReasoningEngineSpecSourceCodeSpec; /** Deploy from a container image with a defined entrypoint and commands. */ containerSpec?: ReasoningEngineSpecContainerSpec; } /** The conversation source event for generating memories. */ export declare interface MemoryBankCustomizationConfigGenerateMemoriesExampleConversationSourceEvent { /** Required. Represents the content of the event. */ content?: genaiTypes.Content; } /** A conversation source for the example. This is similar to `DirectContentsSource`. */ export declare interface MemoryBankCustomizationConfigGenerateMemoriesExampleConversationSource { /** Optional. Represents the input conversation events for the example. */ events?: MemoryBankCustomizationConfigGenerateMemoriesExampleConversationSourceEvent[]; } /** The topic ID for a memory. */ export declare interface MemoryTopicId { /** Optional. Represents the custom memory topic label. */ customMemoryTopicLabel?: string; /** Optional. Represents the managed memory topic. */ managedMemoryTopic?: ManagedTopicEnum; } /** A memory generated by the operation. */ export declare interface MemoryBankCustomizationConfigGenerateMemoriesExampleGeneratedMemory { /** Required. Represents the fact to generate a memory from. */ fact?: string; /** Optional. Represents the list of topics that the memory should be associated with. For example, use `custom_memory_topic_label = "jargon"` if the extracted memory is an example of memory extraction for the custom topic `jargon`. */ topics?: MemoryTopicId[]; } /** An example of how to generate memories for a particular scope. */ export declare interface MemoryBankCustomizationConfigGenerateMemoriesExample { /** A conversation source for the example. */ conversationSource?: MemoryBankCustomizationConfigGenerateMemoriesExampleConversationSource; /** Optional. Represents the memories that are expected to be generated from the input conversation. An empty list indicates that no memories are expected to be generated for the input conversation. */ generatedMemories?: MemoryBankCustomizationConfigGenerateMemoriesExampleGeneratedMemory[]; } /** A custom memory topic defined by the developer. */ export declare interface MemoryBankCustomizationConfigMemoryTopicCustomMemoryTopic { /** Required. Represents the label of the topic. */ label?: string; /** Required. Represents the description of the memory topic. This should explain what information should be extracted for this topic. */ description?: string; } /** A managed memory topic defined by the system. */ export declare interface MemoryBankCustomizationConfigMemoryTopicManagedMemoryTopic { /** Required. Represents the managed topic. */ managedTopicEnum?: ManagedTopicEnum; } /** A topic of information that should be extracted from conversations and stored as memories. */ export declare interface MemoryBankCustomizationConfigMemoryTopic { /** A custom memory topic defined by the developer. */ customMemoryTopic?: MemoryBankCustomizationConfigMemoryTopicCustomMemoryTopic; /** A managed memory topic defined by Memory Bank. */ managedMemoryTopic?: MemoryBankCustomizationConfigMemoryTopicManagedMemoryTopic; } /** Represents configuration for customizing how memories are consolidated. */ export declare interface MemoryBankCustomizationConfigConsolidationConfig { /** Optional. Represents the maximum number of revisions to consider for each candidate memory. If not set, then the default value (1) will be used, which means that only the latest revision will be considered. */ revisionsPerCandidateCount?: number; } /** Represents configuration for organizing natural language memories for a particular scope. */ export declare interface MemoryBankCustomizationConfig { /** Optional. Indicates whether the memories will be generated in the third person (i.e. "The user generates memories with Memory Bank."). By default, the memories will be generated in the first person (i.e. "I generate memories with Memory Bank.") */ enableThirdPersonMemories?: boolean; /** Optional. Provides examples of how to generate memories for a particular scope. */ generateMemoriesExamples?: MemoryBankCustomizationConfigGenerateMemoriesExample[]; /** Optional. Represents topics of information that should be extracted from conversations and stored as memories. If not set, then Memory Bank's default topics will be used. */ memoryTopics?: MemoryBankCustomizationConfigMemoryTopic[]; /** Optional. Represents the scope keys (i.e. 'user_id') for which to use this config. A request's scope must include all of the provided keys for the config to be used (order does not matter). If empty, then the config will be used for all requests that do not have a more specific config. Only one default config is allowed per Memory Bank. */ scopeKeys?: string[]; /** Optional. Represents configuration for customizing how memories are consolidated together. */ consolidationConfig?: MemoryBankCustomizationConfigConsolidationConfig; /** Optional. Indicates whether natural language memory generation should be disabled for all requests. By default, natural language memory generation is enabled. Set this to `true` when you only want to generate structured memories. */ disableNaturalLanguageMemories?: boolean; } /** Represents the active rule that determines when to flush the buffer. */ export declare interface MemoryGenerationTriggerConfigGenerationTriggerRule { /** Specifies to trigger generation when the event count reaches this limit. */ eventCount?: number; /** Specifies to trigger generation at a fixed interval. The duration must have a minute-level granularity. */ fixedInterval?: string; /** Specifies to trigger generation if the stream is inactive for the specified duration after the most recent event. The duration must have a minute-level granularity. */ idleDuration?: string; } /** The configuration for triggering memory generation for ingested events. */ export declare interface MemoryGenerationTriggerConfig { /** Optional. Represents the active rule that determines when to flush the buffer. If not set, then the stream will be force flushed immediately. */ generationRule?: MemoryGenerationTriggerConfigGenerationTriggerRule; } /** Configuration for how to generate memories. */ export declare interface ReasoningEngineContextSpecMemoryBankConfigGenerationConfig { /** Optional. The model used to generate memories. Format: `projects/{project}/locations/{location}/publishers/google/models/{model}`. */ model?: string; /** Optional. Specifies the default trigger configuration for generating memories using `IngestEvents`. */ generationTriggerConfig?: MemoryGenerationTriggerConfig; } /** Configuration for how to perform similarity search on memories. */ export declare interface ReasoningEngineContextSpecMemoryBankConfigSimilaritySearchConfig { /** Required. The model used to generate embeddings to lookup similar memories. Format: `projects/{project}/locations/{location}/publishers/google/models/{model}`. */ embeddingModel?: string; } /** Configuration for TTL of the memories in the Memory Bank based on the action that created or updated the memory. */ export declare interface ReasoningEngineContextSpecMemoryBankConfigTtlConfigGranularTtlConfig { /** Optional. The TTL duration for memories uploaded via CreateMemory. */ createTtl?: string; /** Optional. The TTL duration for memories newly generated via GenerateMemories (GenerateMemoriesResponse.GeneratedMemory.Action.CREATED). */ generateCreatedTtl?: string; /** Optional. The TTL duration for memories updated via GenerateMemories (GenerateMemoriesResponse.GeneratedMemory.Action.UPDATED). In the case of an UPDATE action, the `expire_time` of the existing memory will be updated to the new value (now + TTL). */ generateUpdatedTtl?: string; } /** Configuration for automatically setting the TTL ("time-to-live") of the memories in the Memory Bank. */ export declare interface ReasoningEngineContextSpecMemoryBankConfigTtlConfig { /** Optional. The default TTL duration of the memories in the Memory Bank. This applies to all operations that create or update a memory. */ defaultTtl?: string; /** Optional. The granular TTL configuration of the memories in the Memory Bank. */ granularTtlConfig?: ReasoningEngineContextSpecMemoryBankConfigTtlConfigGranularTtlConfig; /** Optional. The default TTL duration of the memory revisions in the Memory Bank. This applies to all operations that create a memory revision. If not set, a default TTL of 365 days will be used. */ memoryRevisionDefaultTtl?: string; } /** Represents the OpenAPI schema of the structured memories. */ export declare interface StructuredMemorySchemaConfig { /** Required. Represents the OpenAPI schema of the structured memories. */ memorySchema?: genaiTypes.Schema; /** Required. Represents the ID of the schema. Must be 1-63 characters, start with a lowercase letter, and consist of lowercase letters, numbers, and hyphens. */ id?: string; /** Optional. Represents the type of the structured memories associated with the schema. If not set, then `STRUCTURED_PROFILE` will be used. */ memoryType?: MemoryType; } /** Configuration for organizing structured memories within a scope. */ export declare interface StructuredMemoryConfig { /** Optional. Represents configuration of the structured memories' schemas. */ schemaConfigs?: StructuredMemorySchemaConfig[]; /** Optional. Represents the scope keys (i.e. 'user_id') for which to use this config. A request's scope must include all of the provided keys for the config to be used (order does not matter). If empty, then the config will be used for all requests that do not have a more specific config. Only one default config is allowed per Memory Bank. */ scopeKeys?: string[]; } /** Specification for a Memory Bank. */ export declare interface ReasoningEngineContextSpecMemoryBankConfig { /** Optional. Configuration for how to customize Memory Bank behavior for a particular scope. */ customizationConfigs?: MemoryBankCustomizationConfig[]; /** If true, no memory revisions will be created for any requests to the Memory Bank. */ disableMemoryRevisions?: boolean; /** Optional. Configuration for how to generate memories for the Memory Bank. */ generationConfig?: ReasoningEngineContextSpecMemoryBankConfigGenerationConfig; /** Optional. Configuration for how to perform similarity search on memories. If not set, the Memory Bank will use the default embedding model `text-embedding-005`. */ similaritySearchConfig?: ReasoningEngineContextSpecMemoryBankConfigSimilaritySearchConfig; /** Optional. Configuration for automatic TTL ("time-to-live") of the memories in the Memory Bank. If not set, TTL will not be applied automatically. The TTL can be explicitly set by modifying the `expire_time` of each Memory resource. */ ttlConfig?: ReasoningEngineContextSpecMemoryBankConfigTtlConfig; /** Optional. Configuration for organizing structured memories for a particular scope. */ structuredMemoryConfigs?: StructuredMemoryConfig[]; } /** Configuration for how Agent Engine sub-resources should manage context. */ export declare interface ReasoningEngineContextSpec { /** Optional. Specification for a Memory Bank, which manages memories for the Agent Engine. */ memoryBankConfig?: ReasoningEngineContextSpecMemoryBankConfig; } /** Config for create agent engine. */ export declare interface CreateAgentEngineConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; /** The user-defined name of the Agent Engine. The display name can be up to 128 characters long and can comprise any UTF-8 characters. */ displayName?: string; /** The description of the Agent Engine. */ description?: string; /** Optional. Configurations of the Agent Engine. */ spec?: ReasoningEngineSpec; /** Optional. The context spec to be used for the Agent Engine. */ contextSpec?: ReasoningEngineContextSpec; /** Optional. The PSC interface config for PSC-I to be used for the Agent Engine. */ pscInterfaceConfig?: PscInterfaceConfig; /** The minimum number of instances to run for the Agent Engine. Defaults to 1. Range: [0, 10]. */ minInstances?: number; /** The maximum number of instances to run for the Agent Engine. Defaults to 100. Range: [1, 1000]. If VPC-SC or PSC-I is enabled, the acceptable range is [1, 100]. */ maxInstances?: number; /** The resource limits to be applied to the Agent Engine. Required keys: 'cpu' and 'memory'. Supported values for 'cpu': '1', '2', '4', '6', '8'. Supported values for 'memory': '1Gi', '2Gi', ..., '32Gi'. */ resourceLimits?: Record; /** The container concurrency to be used for the Agent Engine. Recommended value: 2 * cpu + 1. Defaults to 9. */ containerConcurrency?: number; /** The encryption spec to be used for the Agent Engine. */ encryptionSpec?: genaiTypes.EncryptionSpec; /** The labels to be used for the Agent Engine. */ labels?: Record; /** The class methods to be used for the Agent Engine. If specified, they'll override the class methods that are autogenerated by default. By default, methods are generated by inspecting the agent object and generating a corresponding method for each method defined on the agent class. */ classMethods?: Record[]; /** The user-provided paths to the source packages (if any). If specified, the files in the source packages will be packed into a a tarball file, uploaded to Agent Engine's API, and deployed to the Agent Engine. The following fields will be ignored: - agent - extra_packages - staging_bucket - requirements The following fields will be used to install and use the agent from the source packages: - entrypoint_module (required) - entrypoint_object (required) - requirements_file (optional) - class_methods (required) */ sourcePackages?: string[]; /** Specifies the configuration for fetching source code from a Git repository that is managed by Developer Connect. This includes the repository, revision, and directory to use. */ developerConnectSource?: ReasoningEngineSpecSourceCodeSpecDeveloperConnectConfig; /** The entrypoint module to be used for the Agent Engine This field only used when source_packages is specified. */ entrypointModule?: string; /** The entrypoint object to be used for the Agent Engine. This field only used when source_packages is specified. */ entrypointObject?: string; /** The user-provided path to the requirements file (if any). This field is only used when source_packages is specified. If not specified, agent engine will find and use the `requirements.txt` in the source package. */ requirementsFile?: string; /** The agent framework to be used for the Agent Engine. The OSS agent framework used to develop the agent. Currently supported values: "google-adk", "langchain", "langgraph", "ag2", "llama-index", "custom". If not specified: - If `agent` is specified, the agent framework will be auto-detected. - If `source_packages` is specified, the agent framework will default to "custom". */ agentFramework?: | 'google-adk' | 'langchain' | 'langgraph' | 'ag2' | 'llama-index' | 'custom'; /** The Python version to be used for the Agent Engine. If not specified, it will use the current Python version of the environment. Supported versions: "3.10", "3.11", "3.12", "3.13", "3.14". */ pythonVersion?: '3.10' | '3.11' | '3.12' | '3.13' | '3.14'; /** The build options for the Agent Engine. The following keys are supported: - installation_scripts: Optional. The paths to the installation scripts to be executed in the Docker image. The scripts must be located in the `installation_scripts` subdirectory and the path must be added to `extra_packages`. */ buildOptions?: Record; /** Agent Gateway configuration for a Reasoning Engine deployment. */ agentGatewayConfig?: ReasoningEngineSpecDeploymentSpecAgentGatewayConfig; /** Optional. Specifies the configuration for keep-alive probe. Contains configuration on a specified endpoint that a deployment host should use to keep the container alive based on the probe settings. */ keepAliveProbe?: KeepAliveProbe; } /** Parameters for creating agent engines. */ export declare interface CreateAgentEngineRequestParameters { config?: CreateAgentEngineConfig; } /** Traffic distribution configuration, where all traffic is sent to the latest Runtime Revision. */ export declare interface ReasoningEngineTrafficConfigTrafficSplitAlwaysLatest {} /** A single target for the traffic split, specifying a Runtime Revision and the percentage of traffic to send to it. */ export declare interface ReasoningEngineTrafficConfigTrafficSplitManualTarget { /** Required. Specifies percent of the traffic to this Runtime Revision. */ percent?: number; /** Required. The Runtime Revision name to which to send this portion of traffic, if traffic allocation is by Runtime Revision. */ runtimeRevisionName?: string; } /** Manual traffic distribution configuration, where the user specifies the Runtime Revision IDs and the percentage of traffic to send to each. */ export declare interface ReasoningEngineTrafficConfigTrafficSplitManual { /** A list of traffic targets for the Runtimes Revisions. The sum of percentages must equal to 100. */ targets?: ReasoningEngineTrafficConfigTrafficSplitManualTarget[]; } /** Traffic distribution configuration. */ export declare interface ReasoningEngineTrafficConfig { /** Optional. Traffic distribution configuration, where all traffic is sent to the latest Runtime Revision. */ trafficSplitAlwaysLatest?: ReasoningEngineTrafficConfigTrafficSplitAlwaysLatest; /** Optional. Manual traffic distribution configuration, where the user specifies the Runtime Revision IDs and the percentage of traffic to send to each. */ trafficSplitManual?: ReasoningEngineTrafficConfigTrafficSplitManual; } /** An agent engine. */ export declare interface ReasoningEngine { /** Customer-managed encryption key spec for a ReasoningEngine. If set, this ReasoningEngine and all sub-resources of this ReasoningEngine will be secured by this key. */ encryptionSpec?: genaiTypes.EncryptionSpec; /** Optional. Configuration for how Agent Engine sub-resources should manage context. */ contextSpec?: ReasoningEngineContextSpec; /** Output only. Timestamp when this ReasoningEngine was created. */ createTime?: string; /** Optional. The description of the ReasoningEngine. */ description?: string; /** Required. The display name of the ReasoningEngine. */ displayName?: string; /** Optional. Used to perform consistent read-modify-write updates. If not set, a blind "overwrite" update happens. */ etag?: string; /** Labels for the ReasoningEngine. */ labels?: Record; /** Identifier. The resource name of the ReasoningEngine. Format: `projects/{project}/locations/{location}/reasoningEngines/{reasoning_engine}` */ name?: string; /** Optional. Configurations of the ReasoningEngine */ spec?: ReasoningEngineSpec; /** Output only. Timestamp when this ReasoningEngine was most recently updated. */ updateTime?: string; /** Optional. Traffic distribution configuration for the Reasoning Engine. */ trafficConfig?: ReasoningEngineTrafficConfig; } /** Operation that has an agent engine as a response. */ export declare interface AgentEngineOperation { /** The server-assigned name, which is only unique within the same service that originally returns it. If you use the default HTTP mapping, the `name` should be a resource name ending with `operations/{unique_id}`. */ name?: string; /** Service-specific metadata associated with the operation. It typically contains progress information and common metadata such as create time. Some services might not provide such metadata. Any method that returns a long-running operation should document the metadata type, if any. */ metadata?: Record; /** If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed, and either `error` or `response` is available. */ done?: boolean; /** The error result of the operation in case of failure or cancellation. */ error?: Record; /** The created Agent Engine. */ response?: ReasoningEngine; } /** Config for deleting agent engine. */ export declare interface DeleteAgentEngineConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; } /** Parameters for deleting agent engines. */ export declare interface DeleteAgentEngineRequestParameters { /** Name of the agent engine. */ name: string; /** If set to true, any child resources will also be deleted. */ force?: boolean; config?: DeleteAgentEngineConfig; } /** Operation for deleting agent engines. */ export declare interface DeleteAgentEngineOperation { /** The server-assigned name, which is only unique within the same service that originally returns it. If you use the default HTTP mapping, the `name` should be a resource name ending with `operations/{unique_id}`. */ name?: string; /** Service-specific metadata associated with the operation. It typically contains progress information and common metadata such as create time. Some services might not provide such metadata. Any method that returns a long-running operation should document the metadata type, if any. */ metadata?: Record; /** If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed, and either `error` or `response` is available. */ done?: boolean; /** The error result of the operation in case of failure or cancellation. */ error?: Record; } /** Config for create agent engine. */ export declare interface GetAgentEngineConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; } /** Parameters for getting agent engines. */ export declare interface GetAgentEngineRequestParameters { /** Name of the agent engine. */ name: string; config?: GetAgentEngineConfig; } /** Config for listing agent engines. */ export declare interface ListAgentEngineConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; pageSize?: number; pageToken?: string; /** An expression for filtering the results of the request. For field names both snake_case and camelCase are supported. */ filter?: string; } /** Parameters for listing agent engines. */ export declare interface ListAgentEngineRequestParameters { config?: ListAgentEngineConfig; } /** Response for listing agent engines. */ export class ListReasoningEnginesResponse { /** Used to retain the full HTTP response. */ sdkHttpResponse?: genaiTypes.HttpResponse; nextPageToken?: string; /** List of agent engines. */ reasoningEngines?: ReasoningEngine[]; } export declare interface GetAgentEngineOperationConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; } /** Parameters for getting an operation with an agent engine as a response. */ export declare interface GetAgentEngineOperationParameters { /** The server-assigned name for the operation. */ operationName: string; /** Used to override the default configuration. */ config?: GetAgentEngineOperationConfig; } /** Config for querying agent engines. */ export declare interface QueryAgentEngineConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; /** The class method to call. */ classMethod?: string; /** The input to the class method. */ input?: Record; includeAllFields?: boolean; } /** Parameters for querying agent engines. */ export declare interface QueryAgentEngineRequestParameters { /** Name of the agent engine. */ name: string; config?: QueryAgentEngineConfig; } /** The response for querying an agent engine. */ export class QueryReasoningEngineResponse { /** Response provided by users in JSON object format. */ output?: unknown; } /** Config for updating agent engine. */ export declare interface UpdateAgentEngineConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; /** The user-defined name of the Agent Engine. The display name can be up to 128 characters long and can comprise any UTF-8 characters. */ displayName?: string; /** The description of the Agent Engine. */ description?: string; /** Optional. Configurations of the Agent Engine. */ spec?: ReasoningEngineSpec; /** Optional. The context spec to be used for the Agent Engine. */ contextSpec?: ReasoningEngineContextSpec; /** Optional. The PSC interface config for PSC-I to be used for the Agent Engine. */ pscInterfaceConfig?: PscInterfaceConfig; /** The minimum number of instances to run for the Agent Engine. Defaults to 1. Range: [0, 10]. */ minInstances?: number; /** The maximum number of instances to run for the Agent Engine. Defaults to 100. Range: [1, 1000]. If VPC-SC or PSC-I is enabled, the acceptable range is [1, 100]. */ maxInstances?: number; /** The resource limits to be applied to the Agent Engine. Required keys: 'cpu' and 'memory'. Supported values for 'cpu': '1', '2', '4', '6', '8'. Supported values for 'memory': '1Gi', '2Gi', ..., '32Gi'. */ resourceLimits?: Record; /** The container concurrency to be used for the Agent Engine. Recommended value: 2 * cpu + 1. Defaults to 9. */ containerConcurrency?: number; /** The encryption spec to be used for the Agent Engine. */ encryptionSpec?: genaiTypes.EncryptionSpec; /** The labels to be used for the Agent Engine. */ labels?: Record; /** The class methods to be used for the Agent Engine. If specified, they'll override the class methods that are autogenerated by default. By default, methods are generated by inspecting the agent object and generating a corresponding method for each method defined on the agent class. */ classMethods?: Record[]; /** The user-provided paths to the source packages (if any). If specified, the files in the source packages will be packed into a a tarball file, uploaded to Agent Engine's API, and deployed to the Agent Engine. The following fields will be ignored: - agent - extra_packages - staging_bucket - requirements The following fields will be used to install and use the agent from the source packages: - entrypoint_module (required) - entrypoint_object (required) - requirements_file (optional) - class_methods (required) */ sourcePackages?: string[]; /** Specifies the configuration for fetching source code from a Git repository that is managed by Developer Connect. This includes the repository, revision, and directory to use. */ developerConnectSource?: ReasoningEngineSpecSourceCodeSpecDeveloperConnectConfig; /** The entrypoint module to be used for the Agent Engine This field only used when source_packages is specified. */ entrypointModule?: string; /** The entrypoint object to be used for the Agent Engine. This field only used when source_packages is specified. */ entrypointObject?: string; /** The user-provided path to the requirements file (if any). This field is only used when source_packages is specified. If not specified, agent engine will find and use the `requirements.txt` in the source package. */ requirementsFile?: string; /** The agent framework to be used for the Agent Engine. The OSS agent framework used to develop the agent. Currently supported values: "google-adk", "langchain", "langgraph", "ag2", "llama-index", "custom". If not specified: - If `agent` is specified, the agent framework will be auto-detected. - If `source_packages` is specified, the agent framework will default to "custom". */ agentFramework?: | 'google-adk' | 'langchain' | 'langgraph' | 'ag2' | 'llama-index' | 'custom'; /** The Python version to be used for the Agent Engine. If not specified, it will use the current Python version of the environment. Supported versions: "3.10", "3.11", "3.12", "3.13", "3.14". */ pythonVersion?: '3.10' | '3.11' | '3.12' | '3.13' | '3.14'; /** The build options for the Agent Engine. The following keys are supported: - installation_scripts: Optional. The paths to the installation scripts to be executed in the Docker image. The scripts must be located in the `installation_scripts` subdirectory and the path must be added to `extra_packages`. */ buildOptions?: Record; /** Agent Gateway configuration for a Reasoning Engine deployment. */ agentGatewayConfig?: ReasoningEngineSpecDeploymentSpecAgentGatewayConfig; /** Optional. Specifies the configuration for keep-alive probe. Contains configuration on a specified endpoint that a deployment host should use to keep the container alive based on the probe settings. */ keepAliveProbe?: KeepAliveProbe; /** The update mask to apply. For the `FieldMask` definition, see https://protobuf.dev/reference/protobuf/google.protobuf/#field-mask. */ updateMask?: string; } /** Parameters for updating agent engines. */ export declare interface UpdateAgentEngineRequestParameters { /** Name of the agent engine. */ name: string; config?: UpdateAgentEngineConfig; } /** The metadata values for memories. */ export declare interface MemoryMetadataValue { /** Represents a boolean value. */ boolValue?: boolean; /** Represents a double value. */ doubleValue?: number; /** Represents a string value. */ stringValue?: string; /** Represents a timestamp value. When filtering on timestamp values, only the seconds field will be compared. */ timestampValue?: string; } /** Config for creating a Memory. */ export declare interface AgentEngineMemoryConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; /** The display name of the memory. */ displayName?: string; /** The description of the memory. */ description?: string; /** Waits for the operation to complete before returning. */ waitForCompletion?: boolean; /** Optional. Input only. The TTL for this resource. The expiration time is computed: now + TTL. */ ttl?: string; /** Optional. Timestamp of when this resource is considered expired. This is *always* provided on output, regardless of what `expiration` was sent on input. */ expireTime?: string; /** Optional. Input only. Timestamp of when the revision is considered expired. If not set, the memory revision will be kept until manually deleted. */ revisionExpireTime?: string; /** Optional. Input only. The TTL for the revision. The expiration time is computed: now + TTL. */ revisionTtl?: string; /** Optional. Input only. If true, no revision will be created for this request. */ disableMemoryRevisions?: boolean; /** Optional. The topics of the memory. */ topics?: MemoryTopicId[]; /** Optional. User-provided metadata for the Memory. This information was provided when creating, updating, or generating the Memory. It was not generated by Memory Bank. */ metadata?: Record; /** Optional. The user defined ID to use for memory, which will become the final component of the memory resource name. If not provided, Vertex AI will generate a value for this ID. This value may be up to 63 characters, and valid characters are `[a-z0-9-]`. The first character must be a letter, and the last character must be a letter or number. */ memoryId?: string; } /** Parameters for creating Agent Engine Memories. */ export declare interface CreateAgentEngineMemoryRequestParameters { /** Name of the agent engine to create the memory under. */ name: string; /** The fact of the memory. This is the semantic knowledge extracted from the source content). */ fact: string; /** The scope of the memory. Memories are isolated within their scope. The scope is defined when creating or generating memories. Up to 5 key-value pairs are accepted, andscope values cannot contain the wildcard character '*'. */ scope: Record; config?: AgentEngineMemoryConfig; } /** Represents the structured value of the memory. */ export declare interface MemoryStructuredContent { /** Required. Represents the structured value of the memory. */ data?: Record; /** Required. Represents the schema ID for which this structured memory belongs to. */ schemaId?: string; } /** A memory. */ export declare interface Memory { /** Output only. Represents the timestamp when this Memory was created. */ createTime?: string; /** Optional. Represents the description of the Memory. */ description?: string; /** Optional. Input only. Indicates whether no revision will be created for this request. */ disableMemoryRevisions?: boolean; /** Optional. Represents the display name of the Memory. */ displayName?: string; /** Optional. Represents the timestamp of when this resource is considered expired. This is *always* provided on output when `expiration` is set on input, regardless of whether `expire_time` or `ttl` was provided. */ expireTime?: string; /** Optional. Represents semantic knowledge extracted from the source content. */ fact?: string; /** Optional. Represents user-provided metadata for the Memory. This information was provided when creating, updating, or generating the Memory. It was not generated by Memory Bank. */ metadata?: Record; /** Identifier. Represents the resource name of the Memory. Format: `projects/{project}/locations/{location}/reasoningEngines/{reasoning_engine}/memories/{memory}` */ name?: string; /** Optional. Input only. Represents the timestamp of when the revision is considered expired. If not set, the memory revision will be kept until manually deleted. */ revisionExpireTime?: string; /** Optional. Input only. Represents the labels to apply to the Memory Revision created as a result of this request. */ revisionLabels?: Record; /** Optional. Input only. Represents the TTL for the revision. The expiration time is computed: now + TTL. */ revisionTtl?: string; /** Required. Immutable. Represents the scope of the Memory. Memories are isolated within their scope. The scope is defined when creating or generating memories. Scope values cannot contain the wildcard character '*'. */ scope?: Record; /** Optional. Represents the Topics of the Memory. */ topics?: MemoryTopicId[]; /** Optional. Input only. Represents the TTL for this resource. The expiration time is computed: now + TTL. */ ttl?: string; /** Output only. Represents the timestamp when this Memory was most recently updated. */ updateTime?: string; /** Optional. Represents the type of the memory. If not set, the `NATURAL_LANGUAGE_COLLECTION` type is used. If `STRUCTURED_COLLECTION` or `STRUCTURED_PROFILE` is used, then `structured_data` must be provided. */ memoryType?: MemoryType; /** Optional. Represents the structured content of the memory. */ structuredContent?: MemoryStructuredContent; } /** Operation that has an agent engine memory as a response. */ export declare interface AgentEngineMemoryOperation { /** The server-assigned name, which is only unique within the same service that originally returns it. If you use the default HTTP mapping, the `name` should be a resource name ending with `operations/{unique_id}`. */ name?: string; /** Service-specific metadata associated with the operation. It typically contains progress information and common metadata such as create time. Some services might not provide such metadata. Any method that returns a long-running operation should document the metadata type, if any. */ metadata?: Record; /** If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed, and either `error` or `response` is available. */ done?: boolean; /** The error result of the operation in case of failure or cancellation. */ error?: Record; /** The Agent Engine Memory. */ response?: Memory; } /** Config for deleting an Agent Engine Memory. */ export declare interface DeleteAgentEngineMemoryConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; } /** Parameters for deleting agent engines. */ export declare interface DeleteAgentEngineMemoryRequestParameters { /** Name of the agent engine memory to delete. */ name: string; config?: DeleteAgentEngineMemoryConfig; } /** Operation for deleting agent engines. */ export declare interface DeleteAgentEngineMemoryOperation { /** The server-assigned name, which is only unique within the same service that originally returns it. If you use the default HTTP mapping, the `name` should be a resource name ending with `operations/{unique_id}`. */ name?: string; /** Service-specific metadata associated with the operation. It typically contains progress information and common metadata such as create time. Some services might not provide such metadata. Any method that returns a long-running operation should document the metadata type, if any. */ metadata?: Record; /** If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed, and either `error` or `response` is available. */ done?: boolean; /** The error result of the operation in case of failure or cancellation. */ error?: Record; } /** The vertex session source for generating memories. */ export declare interface GenerateMemoriesRequestVertexSessionSource { /** Optional. End time (exclusive) of the time range. If not set, the end time is unbounded. */ endTime?: string; /** Required. The resource name of the Session to generate memories for. Format: `projects/{project}/locations/{location}/reasoningEngines/{reasoning_engine}/sessions/{session}` */ session?: string; /** Optional. Time range to define which session events should be used to generate memories. Start time (inclusive) of the time range. If not set, the start time is unbounded. */ startTime?: string; } export declare interface GenerateMemoriesRequestDirectContentsSourceEvent { /** Required. A single piece of content from which to generate memories. */ content?: genaiTypes.Content; } /** The direct contents source for generating memories. */ export declare interface GenerateMemoriesRequestDirectContentsSource { /** Required. The source content (i.e. chat history) to generate memories from. */ events?: GenerateMemoriesRequestDirectContentsSourceEvent[]; } /** A direct memory to upload to Memory Bank. */ export declare interface GenerateMemoriesRequestDirectMemoriesSourceDirectMemory { /** Required. The fact to consolidate with existing memories. */ fact?: string; /** Optional. The topics that the consolidated memories should be associated with. */ topics?: MemoryTopicId[]; } /** The direct memories source for generating memories. */ export declare interface GenerateMemoriesRequestDirectMemoriesSource { /** Required. The direct memories to upload to Memory Bank. At most 5 direct memories are allowed per request. */ directMemories?: GenerateMemoriesRequestDirectMemoriesSourceDirectMemory[]; } /** Config for generating memories. */ export declare interface GenerateAgentEngineMemoriesConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; /** Whether to disable consolidation of memories. If true, generated memories will not be consolidated with existing memories; all generated memories will be added as new memories regardless of whether they are duplicates of or contradictory to existing memories. By default, memory consolidation is enabled. */ disableConsolidation?: boolean; /** Waits for the operation to complete before returning. */ waitForCompletion?: boolean; /** Labels to apply to the memory revision. For example, you can use this to label a revision with its data source. */ revisionLabels?: Record; /** Optional. Input only. Timestamp of when the revision is considered expired. If not set, the memory revision will be kept until manually deleted. */ revisionExpireTime?: string; /** Optional. Input only. The TTL for the revision. The expiration time is computed: now + TTL. */ revisionTtl?: string; /** Optional. Input only. If true, no revisions will be created for this request. */ disableMemoryRevisions?: boolean; /** Optional. User-provided metadata for the generated memories. This is not generated by Memory Bank. */ metadata?: Record; /** Optional. The strategy to use when applying metadata to existing memories. */ metadataMergeStrategy?: MemoryMetadataMergeStrategy; /** Optional. Restricts memory generation to a subset of memory topics. */ allowedTopics?: MemoryTopicId[]; } /** Parameters for generating agent engine memories. */ export declare interface GenerateAgentEngineMemoriesRequestParameters { /** Name of the agent engine to generate memories for. */ name: string; /** The vertex session source of the memories that should be generated. */ vertexSessionSource?: GenerateMemoriesRequestVertexSessionSource; /** The direct contents source of the memories that should be generated. */ directContentsSource?: GenerateMemoriesRequestDirectContentsSource; /** The direct memories source of the memories that should be generated. */ directMemoriesSource?: GenerateMemoriesRequestDirectMemoriesSource; /** The scope of the memories that should be generated. Memories will be consolidated across memories with the same scope. Must be provided unless the scope is defined in the source content. If `scope` is provided, it will override the scope defined in the source content. Scope values cannot contain the wildcard character '*'. */ scope?: Record; config?: GenerateAgentEngineMemoriesConfig; } /** A memory that was generated. */ export class GenerateMemoriesResponseGeneratedMemory { /** The generated memory. */ memory?: Memory; /** The action to take. */ action?: GenerateMemoriesResponseGeneratedMemoryAction; /** The previous revision of the Memory before the action was performed. This field is only set if the action is `UPDATED` or `DELETED`. You can use this to rollback the Memory to the previous revision, undoing the action. Format: `projects/{project}/locations/{location}/reasoningEngines/{reasoning_engine}/memories/{memory}/revisions/{revision}` */ previousRevision?: string; } /** The response for generating memories. */ export class GenerateMemoriesResponse { /** The generated memories. */ generatedMemories?: GenerateMemoriesResponseGeneratedMemory[]; } /** Operation that generates memories for an agent engine. */ export declare interface AgentEngineGenerateMemoriesOperation { /** The server-assigned name, which is only unique within the same service that originally returns it. If you use the default HTTP mapping, the `name` should be a resource name ending with `operations/{unique_id}`. */ name?: string; /** Service-specific metadata associated with the operation. It typically contains progress information and common metadata such as create time. Some services might not provide such metadata. Any method that returns a long-running operation should document the metadata type, if any. */ metadata?: Record; /** If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed, and either `error` or `response` is available. */ done?: boolean; /** The error result of the operation in case of failure or cancellation. */ error?: Record; /** The response for generating memories. */ response?: GenerateMemoriesResponse; } /** Config for getting an Agent Engine Memory. */ export declare interface GetAgentEngineMemoryConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; } /** Parameters for getting an agent engine. */ export declare interface GetAgentEngineMemoryRequestParameters { /** Name of the agent engine. */ name: string; config?: GetAgentEngineMemoryConfig; } /** The direct contents source event for ingesting events. */ export declare interface IngestionDirectContentsSourceEvent { /** Required. The content of the event. */ content?: genaiTypes.Content; /** Optional. A unique identifier for the event. If an event with the same event_id is ingested multiple times, it will be de-duplicated. */ eventId?: string; /** Optional. The time at which the event occurred. If provided, this timestamp will be used for ordering events within a stream. If not provided, the server-side ingestion time will be used. */ eventTime?: string; } /** The direct contents source for ingesting events. */ export declare interface IngestionDirectContentsSource { /** Required. The events to ingest. */ events?: IngestionDirectContentsSourceEvent[]; } /** Config for ingesting events. */ export declare interface IngestEventsConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; /** Waits for the underlying memory generation operation to complete before returning. Defaults to false. */ waitForCompletion?: boolean; /** Optional. Forces a flush of all pending events in the stream and triggers memory generation immediately bypassing any conditions configured in the `generation_trigger_config`. */ forceFlush?: boolean; } /** Parameters for purging agent engine memories. */ export declare interface IngestEventsRequestParameters { /** Name of the Agent Engine to ingest events into. */ name: string; /** The ID of the stream to ingest events into. */ streamId?: string; /** The direct memories source of the events that should be ingested. */ directContentsSource?: IngestionDirectContentsSource; /** The scope of the memories that should be generated from the stream. Memories will be consolidated across memories with the same scope. Scope values cannot contain the wildcard character '*'. */ scope?: Record; /** The configuration for the memory generation trigger. */ generationTriggerConfig?: MemoryGenerationTriggerConfig; config?: IngestEventsConfig; } /** Operation that ingests events into a memory bank. */ export declare interface MemoryBankIngestEventsOperation { /** The server-assigned name, which is only unique within the same service that originally returns it. If you use the default HTTP mapping, the `name` should be a resource name ending with `operations/{unique_id}`. */ name?: string; /** Service-specific metadata associated with the operation. It typically contains progress information and common metadata such as create time. Some services might not provide such metadata. Any method that returns a long-running operation should document the metadata type, if any. */ metadata?: Record; /** If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed, and either `error` or `response` is available. */ done?: boolean; /** The error result of the operation in case of failure or cancellation. */ error?: Record; } /** Config for listing agent engine memories. */ export declare interface ListAgentEngineMemoryConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; pageSize?: number; pageToken?: string; /** An expression for filtering the results of the request. For field names both snake_case and camelCase are supported. */ filter?: string; /** The standard list order by string. If not specified, the default order is `create_time desc`. If specified, the default sorting order of provided fields is ascending. More detail in [AIP-132](https://google.aip.dev/132). Supported fields: * `create_time` * `update_time` */ orderBy?: string; } /** Parameters for listing agent engines. */ export declare interface ListAgentEngineMemoryRequestParameters { /** Name of the agent engine. */ name: string; config?: ListAgentEngineMemoryConfig; } /** Response for listing agent engine memories. */ export class ListReasoningEnginesMemoriesResponse { /** Used to retain the full HTTP response. */ sdkHttpResponse?: genaiTypes.HttpResponse; nextPageToken?: string; /** List of agent engine memories. */ memories?: Memory[]; } /** Parameters for getting an operation with a memory as a response. */ export declare interface GetAgentEngineMemoryOperationParameters { /** The server-assigned name for the operation. */ operationName: string; /** Used to override the default configuration. */ config?: GetAgentEngineOperationConfig; } /** Parameters for getting an operation with generated memories as a response. */ export declare interface GetAgentEngineGenerateMemoriesOperationParameters { /** The server-assigned name for the operation. */ operationName: string; /** Used to override the default configuration. */ config?: GetAgentEngineOperationConfig; } /** The parameters for semantic similarity search based retrieval. */ export declare interface RetrieveMemoriesRequestSimilaritySearchParams { /** Required. Query to use for similarity search retrieval. If provided, then the parent ReasoningEngine must have ReasoningEngineContextSpec.MemoryBankConfig.SimilaritySearchConfig set. */ searchQuery?: string; /** Optional. The maximum number of memories to return. The service may return fewer than this value. If unspecified, at most 3 memories will be returned. The maximum value is 100; values above 100 will be coerced to 100. */ topK?: number; } /** The parameters for simple (non-similarity search) retrieval. */ export declare interface RetrieveMemoriesRequestSimpleRetrievalParams { /** Optional. The maximum number of memories to return. The service may return fewer than this value. If unspecified, at most 3 memories will be returned. The maximum value is 100; values above 100 will be coerced to 100. */ pageSize?: number; /** Optional. A page token, received from a previous `RetrieveMemories` call. Provide this to retrieve the subsequent page. */ pageToken?: string; } /** Filter to apply when retrieving memories. */ export declare interface MemoryFilter { /** Represents the key of the filter. For example, "author" would apply to `metadata` entries with the key "author". */ key?: string; /** Indicates whether the filter will be negated. */ negate?: boolean; /** Represents the operator to apply to the filter. If not set, then EQUAL will be used. */ op?: Operator; /** Represents the value to compare to. */ value?: MemoryMetadataValue; } /** The conjunction filter for memories. */ export declare interface MemoryConjunctionFilter { /** Represents filters that will be combined using AND logic. */ filters?: MemoryFilter[]; } /** Config for retrieving memories. */ export declare interface RetrieveAgentEngineMemoriesConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; /** The standard list filter that will be applied to the retrieved memories. More detail in [AIP-160](https://google.aip.dev/160). Supported fields: * `fact` * `create_time` * `update_time` */ filter?: string; /** Metadata filters that will be applied to the retrieved memories' `metadata` using OR logic. Filters are defined using disjunctive normal form (OR of ANDs). For example: `filter_groups: [{filters: [{key: "author", value: {string_value: "agent `123"}, op: EQUAL}]}, {filters: [{key: "label", value: {string_value: "travel"}, op: EQUAL}, {key: "author", value: {string_value: "agent 321"}, op: EQUAL}]}]` would be equivalent to the logical expression: `(metadata.author = "agent 123" OR (metadata.label = "travel" AND metadata.author = "agent 321"))`. */ filterGroups?: MemoryConjunctionFilter[]; /** Specifies the types of memories to retrieve. If this field is empty or not provided, the request will default to retrieving only memories of type `NATURAL_LANGUAGE_COLLECTION`. If populated, the request will retrieve memories matching any of the specified `MemoryType` values. */ memoryTypes?: MemoryType[]; } /** Parameters for retrieving agent engine memories. */ export declare interface RetrieveAgentEngineMemoriesRequestParameters { /** Name of the agent engine to retrieve memories from. */ name: string; /** The scope of the memories to retrieve. A memory must have exactly the same scope as the scope provided here to be retrieved (i.e. same keys and values). Order does not matter, but it is case-sensitive. */ scope: Record; /** Parameters for semantic similarity search based retrieval. */ similaritySearchParams?: RetrieveMemoriesRequestSimilaritySearchParams; /** Parameters for simple (non-similarity search) retrieval. */ simpleRetrievalParams?: RetrieveMemoriesRequestSimpleRetrievalParams; config?: RetrieveAgentEngineMemoriesConfig; } /** A retrieved memory. */ export class RetrieveMemoriesResponseRetrievedMemory { /** The distance between the query and the retrieved Memory. Smaller values indicate more similar memories. This is only set if similarity search was used for retrieval. */ distance?: number; /** The retrieved Memory. */ memory?: Memory; } /** The response for retrieving memories. */ export class RetrieveMemoriesResponse { /** A token that can be sent as `page_token` to retrieve the next page. If this field is omitted, there are no subsequent pages. This token is not set if similarity search was used for retrieval. */ nextPageToken?: string; /** The retrieved memories. */ retrievedMemories?: RetrieveMemoriesResponseRetrievedMemory[]; } /** Config for retrieving memory profiles. */ export declare interface RetrieveMemoryProfilesConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; } /** Parameters for retrieving agent engine memory profiles. */ export declare interface RetrieveMemoryProfilesRequestParameters { /** Name of the agent engine to retrieve memory profiles from. */ name: string; /** The scope of the memories to retrieve. A memory must have exactly the same scope as the scope provided here to be retrieved (i.e. same keys and values). Order does not matter, but it is case-sensitive. */ scope: Record; config?: RetrieveMemoryProfilesConfig; } /** A memory profile. */ export declare interface MemoryProfile { /** Represents the ID of the schema. This ID corresponds to the `schema_id` defined inside the SchemaConfig, under StructuredMemoryCustomizationConfig. */ schemaId?: string; /** Represents the profile data. */ profile?: Record; } /** The response for retrieving memory profiles. */ export class RetrieveProfilesResponse { /** The retrieved structured profiles, which match the schemas under the requested scope. The key is the ID of the schema that the profile is linked with, which corresponds to the `schema_id` defined inside the `SchemaConfig`, under `StructuredMemoryCustomizationConfig`. */ profiles?: Record; } /** Config for rolling back a memory. */ export declare interface RollbackAgentEngineMemoryConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; /** Waits for the operation to complete before returning. */ waitForCompletion?: boolean; } /** Parameters for generating agent engine memories. */ export declare interface RollbackAgentEngineMemoryRequestParameters { /** Name of the agent engine memory to rollback. */ name: string; /** The ID of the revision to rollback to. */ targetRevisionId: string; config?: RollbackAgentEngineMemoryConfig; } /** Operation that rolls back a memory. */ export declare interface AgentEngineRollbackMemoryOperation { /** The server-assigned name, which is only unique within the same service that originally returns it. If you use the default HTTP mapping, the `name` should be a resource name ending with `operations/{unique_id}`. */ name?: string; /** Service-specific metadata associated with the operation. It typically contains progress information and common metadata such as create time. Some services might not provide such metadata. Any method that returns a long-running operation should document the metadata type, if any. */ metadata?: Record; /** If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed, and either `error` or `response` is available. */ done?: boolean; /** The error result of the operation in case of failure or cancellation. */ error?: Record; } /** Config for updating agent engine memory. */ export declare interface UpdateAgentEngineMemoryConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; /** The display name of the memory. */ displayName?: string; /** The description of the memory. */ description?: string; /** Waits for the operation to complete before returning. */ waitForCompletion?: boolean; /** Optional. Input only. The TTL for this resource. The expiration time is computed: now + TTL. */ ttl?: string; /** Optional. Timestamp of when this resource is considered expired. This is *always* provided on output, regardless of what `expiration` was sent on input. */ expireTime?: string; /** Optional. Input only. Timestamp of when the revision is considered expired. If not set, the memory revision will be kept until manually deleted. */ revisionExpireTime?: string; /** Optional. Input only. The TTL for the revision. The expiration time is computed: now + TTL. */ revisionTtl?: string; /** Optional. Input only. If true, no revision will be created for this request. */ disableMemoryRevisions?: boolean; /** Optional. The topics of the memory. */ topics?: MemoryTopicId[]; /** Optional. User-provided metadata for the Memory. This information was provided when creating, updating, or generating the Memory. It was not generated by Memory Bank. */ metadata?: Record; /** Optional. The user defined ID to use for memory, which will become the final component of the memory resource name. If not provided, Vertex AI will generate a value for this ID. This value may be up to 63 characters, and valid characters are `[a-z0-9-]`. The first character must be a letter, and the last character must be a letter or number. */ memoryId?: string; /** The update mask to apply. For the `FieldMask` definition, see https://protobuf.dev/reference/protobuf/google.protobuf/#field-mask. */ updateMask?: string; } /** Parameters for updating agent engine memories. */ export declare interface UpdateAgentEngineMemoryRequestParameters { /** Name of the agent engine memory to update. */ name: string; /** The updated fact of the memory. This is the semantic knowledge extracted from the source content. */ fact?: string; /** The updated scope of the memory. Memories are isolated within their scope. The scope is defined when creating or generating memories. Up to 5 key-value pairs are accepted, and scope values cannot contain the wildcard character '*'. */ scope?: Record; config?: UpdateAgentEngineMemoryConfig; } /** Config for purging memories. */ export declare interface PurgeAgentEngineMemoriesConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; /** Waits for the operation to complete before returning. */ waitForCompletion?: boolean; } /** Parameters for purging agent engine memories. */ export declare interface PurgeAgentEngineMemoriesRequestParameters { /** Name of the Agent Engine to purge memories from. */ name: string; /** The standard list filter to determine which memories to purge. More detail in [AIP-160](https://google.aip.dev/160). */ filter?: string; /** Metadata filters that will be applied to the memories' `metadata` using OR logic. Filters are defined using disjunctive normal form (OR of ANDs). For example: `filter_groups: [{filters: [{key: "author", value: {string_value: "agent `123"}, op: EQUAL}]}, {filters: [{key: "label", value: {string_value: "travel"}, op: EQUAL}, {key: "author", value: {string_value: "agent 321"}, op: EQUAL}]}]` would be equivalent to the logical expression: `(metadata.author = "agent 123" OR (metadata.label = "travel" AND metadata.author = "agent 321"))`. */ filterGroups?: MemoryConjunctionFilter[]; /** If true, the memories will actually be purged. If false, the purge request will be validated but not executed. */ force?: boolean; config?: PurgeAgentEngineMemoriesConfig; } /** The response for purging memories. */ export class PurgeMemoriesResponse { /** The number of memories that were purged. */ purgeCount?: number; } /** Operation that purges memories from an agent engine. */ export declare interface AgentEnginePurgeMemoriesOperation { /** The server-assigned name, which is only unique within the same service that originally returns it. If you use the default HTTP mapping, the `name` should be a resource name ending with `operations/{unique_id}`. */ name?: string; /** Service-specific metadata associated with the operation. It typically contains progress information and common metadata such as create time. Some services might not provide such metadata. Any method that returns a long-running operation should document the metadata type, if any. */ metadata?: Record; /** If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed, and either `error` or `response` is available. */ done?: boolean; /** The error result of the operation in case of failure or cancellation. */ error?: Record; /** The response for purging memories. */ response?: PurgeMemoriesResponse; } /** Config for getting an Agent Engine Memory Revision. */ export declare interface GetAgentEngineMemoryRevisionConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; } /** Parameters for getting an Agent Engine memory revision. */ export declare interface GetAgentEngineMemoryRevisionRequestParameters { /** Name of the agent engine. */ name: string; config?: GetAgentEngineMemoryRevisionConfig; } /** An extracted memory that is the intermediate result before consolidation. */ export declare interface IntermediateExtractedMemory { /** Output only. Represents the fact of the extracted memory. */ fact?: string; /** Output only. Represents the explanation of why the information was extracted from the source content. */ context?: string; /** Output only. Represents the structured value of the extracted memory. */ structuredData?: Record; } /** A memory revision. */ export declare interface MemoryRevision { /** Output only. Represents the timestamp when this Memory Revision was created. */ createTime?: string; /** Output only. Represents the timestamp of when this resource is considered expired. */ expireTime?: string; /** Output only. Represents the extracted memories from the source content before consolidation when the memory was updated via GenerateMemories. This information was used to modify an existing Memory via Consolidation. */ extractedMemories?: IntermediateExtractedMemory[]; /** Output only. Represents the fact of the Memory Revision. This corresponds to the `fact` field of the parent Memory at the time of revision creation. */ fact?: string; /** Output only. Represents the labels of the Memory Revision. These labels are applied to the MemoryRevision when it is created based on `GenerateMemoriesRequest.revision_labels`. */ labels?: Record; /** Identifier. Represents the resource name of the Memory Revision. Format: `projects/{project}/locations/{location}/reasoningEngines/{reasoning_engine}/memories/{memory}/revisions/{memory_revision}` */ name?: string; /** Output only. Represents the structured value of the memory at the time of revision creation. */ structuredData?: Record; } /** Config for listing Agent Engine memory revisions. */ export declare interface ListAgentEngineMemoryRevisionsConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; pageSize?: number; pageToken?: string; /** An expression for filtering the results of the request. For field names both snake_case and camelCase are supported. */ filter?: string; } /** Parameters for listing Agent Engine memory revisions. */ export declare interface ListAgentEngineMemoryRevisionsRequestParameters { /** Name of the Agent Engine memory */ name: string; config?: ListAgentEngineMemoryRevisionsConfig; } /** Response for listing agent engine memory revisions. */ export class ListAgentEngineMemoryRevisionsResponse { /** Used to retain the full HTTP response. */ sdkHttpResponse?: genaiTypes.HttpResponse; nextPageToken?: string; /** List of memory revisions. */ memoryRevisions?: MemoryRevision[]; } /** The code execution environment with customized settings. */ export declare interface SandboxEnvironmentSpecCodeExecutionEnvironment { /** The coding language supported in this environment. */ codeLanguage?: Language; /** The machine config of the code execution environment. */ machineConfig?: MachineConfig; } /** The computer use environment with customized settings. */ export declare interface SandboxEnvironmentSpecComputerUseEnvironment {} /** The specification of a sandbox environment. */ export declare interface SandboxEnvironmentSpec { /** Optional. The code execution environment. */ codeExecutionEnvironment?: SandboxEnvironmentSpecCodeExecutionEnvironment; /** Optional. The computer use environment. */ computerUseEnvironment?: SandboxEnvironmentSpecComputerUseEnvironment; } /** Config for creating a Sandbox. */ export declare interface CreateAgentEngineSandboxConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; /** The display name of the sandbox. */ displayName?: string; /** The description of the sandbox. */ description?: string; /** Waits for the operation to complete before returning. */ waitForCompletion?: boolean; /** The TTL for this resource. The expiration time is computed: now + TTL. */ ttl?: string; /** The name of the sandbox environment template to create the sandbox from. The sandbox environment template should be in the format: projects/{project}/locations/{location}/agentEngines/{agent_engine}/sandboxEnvironmentTemplates/{sandbox_environment_template} */ sandboxEnvironmentTemplate?: string; /** The name of the sandbox environment snapshot to restore the sandbox from. The sandbox environment snapshot should be in the format: projects/{project}/locations/{location}/agentEngines/{agent_engine}/sandboxEnvironmentSnapshots/{sandbox_environment_snapshot} */ sandboxEnvironmentSnapshot?: string; /** Owner information for this sandbox environment. A sandbox can only be restored from a snapshot belonging to the same owner. */ owner?: string; } /** Parameters for creating Agent Engine Sandboxes. */ export declare interface CreateAgentEngineSandboxRequestParameters { /** Name of the agent engine to create the sandbox under. */ name: string; /** The specification of the sandbox. */ spec?: SandboxEnvironmentSpec; config?: CreateAgentEngineSandboxConfig; } /** The connection information of the SandboxEnvironment. */ export declare interface SandboxEnvironmentConnectionInfo { /** Output only. The hostname of the load balancer. */ loadBalancerHostname?: string; /** Output only. The IP address of the load balancer. */ loadBalancerIp?: string; /** Output only. The internal IP address of the SandboxEnvironment. */ sandboxInternalIp?: string; /** Output only. The hostname of the SandboxEnvironment. */ sandboxHostname?: string; /** Output only. The routing token for the SandboxEnvironment. */ routingToken?: string; } /** A sandbox environment. */ export declare interface SandboxEnvironment { /** Expiration time of the sandbox environment. */ expireTime?: string; /** Output only. The connection information of the SandboxEnvironment. */ connectionInfo?: SandboxEnvironmentConnectionInfo; /** Output only. The timestamp when this SandboxEnvironment was created. */ createTime?: string; /** Required. The display name of the SandboxEnvironment. */ displayName?: string; /** Identifier. The name of the SandboxEnvironment. */ name?: string; /** Optional. The configuration of the SandboxEnvironment. */ spec?: SandboxEnvironmentSpec; /** Output only. The runtime state of the SandboxEnvironment. */ state?: SandboxState; /** Optional. Input only. The TTL for the sandbox environment. The expiration time is computed: now + TTL. */ ttl?: string; /** Output only. The timestamp when this SandboxEnvironment was most recently updated. */ updateTime?: string; /** Output only. The resource name of the latest snapshot taken for this SandboxEnvironment. */ latestSandboxEnvironmentSnapshot?: string; /** Optional. Owner information for this sandbox environment. A Sandbox can only be restored from a snapshot that belongs to the same owner. If not set, sandbox will be created as the default owner. */ owner?: string; /** Optional. The resource name of the SandboxEnvironmentSnapshot to use for creating this SandboxEnvironment. Format: `projects/{project}/locations/{location}/reasoningEngines/{reasoning_engine}/sandboxEnvironmentSnapshots/{sandbox_environment_snapshot}` */ sandboxEnvironmentSnapshot?: string; /** Optional. The name of the SandboxEnvironmentTemplate specified in the parent Agent Engine resource that this SandboxEnvironment is created from. Only one of `sandbox_environment_template` and `spec` should be set. */ sandboxEnvironmentTemplate?: string; } /** Operation that has an agent engine sandbox as a response. */ export declare interface AgentEngineSandboxOperation { /** The server-assigned name, which is only unique within the same service that originally returns it. If you use the default HTTP mapping, the `name` should be a resource name ending with `operations/{unique_id}`. */ name?: string; /** Service-specific metadata associated with the operation. It typically contains progress information and common metadata such as create time. Some services might not provide such metadata. Any method that returns a long-running operation should document the metadata type, if any. */ metadata?: Record; /** If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed, and either `error` or `response` is available. */ done?: boolean; /** The error result of the operation in case of failure or cancellation. */ error?: Record; /** The Agent Engine Sandbox. */ response?: SandboxEnvironment; } /** Config for deleting an Agent Engine Sandbox. */ export declare interface DeleteAgentEngineSandboxConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; } /** Parameters for deleting agent engines. */ export declare interface DeleteAgentEngineSandboxRequestParameters { /** Name of the agent engine sandbox to delete. */ name: string; config?: DeleteAgentEngineSandboxConfig; } /** Operation for deleting agent engines. */ export declare interface DeleteAgentEngineSandboxOperation { /** The server-assigned name, which is only unique within the same service that originally returns it. If you use the default HTTP mapping, the `name` should be a resource name ending with `operations/{unique_id}`. */ name?: string; /** Service-specific metadata associated with the operation. It typically contains progress information and common metadata such as create time. Some services might not provide such metadata. Any method that returns a long-running operation should document the metadata type, if any. */ metadata?: Record; /** If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed, and either `error` or `response` is available. */ done?: boolean; /** The error result of the operation in case of failure or cancellation. */ error?: Record; } /** Metadata for a chunk. */ export declare interface Metadata { /** Optional. Attributes attached to the data. The keys have semantic conventions and the consumers of the attributes should know how to deserialize the value bytes based on the keys. */ attributes?: Record; } /** A chunk of data. */ export declare interface Chunk { /** Required. The data in the chunk. * @remarks Encoded as base64 string. */ data?: string; /** Optional. Metadata that is associated with the data in the payload. */ metadata?: Metadata; /** Required. Mime type of the chunk data. See https://www.iana.org/assignments/media-types/media-types.xhtml for the full list. */ mimeType?: string; } /** Config for executing code in an Agent Engine sandbox. */ export declare interface ExecuteCodeAgentEngineSandboxConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; } /** Parameters for executing code in an agent engine sandbox. */ export declare interface ExecuteCodeAgentEngineSandboxRequestParameters { /** Name of the agent engine sandbox to execute code in. */ name: string; /** Inputs to the code execution. */ inputs?: Chunk[]; config?: ExecuteCodeAgentEngineSandboxConfig; } /** The response for executing a sandbox environment. */ export class ExecuteSandboxEnvironmentResponse { /** The outputs from the sandbox environment. */ outputs?: Chunk[]; } /** Config for getting an Agent Engine Memory. */ export declare interface GetAgentEngineSandboxConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; } /** Parameters for getting an agent engine sandbox. */ export declare interface GetAgentEngineSandboxRequestParameters { /** Name of the agent engine sandbox. */ name: string; config?: GetAgentEngineSandboxConfig; } /** Config for listing agent engine sandboxes. */ export declare interface ListAgentEngineSandboxesConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; pageSize?: number; pageToken?: string; /** An expression for filtering the results of the request. For field names both snake_case and camelCase are supported. */ filter?: string; } /** Parameters for listing agent engine sandboxes. */ export declare interface ListAgentEngineSandboxesRequestParameters { /** Name of the agent engine. */ name: string; config?: ListAgentEngineSandboxesConfig; } /** Response for listing agent engine sandboxes. */ export class ListAgentEngineSandboxesResponse { /** Used to retain the full HTTP response. */ sdkHttpResponse?: genaiTypes.HttpResponse; nextPageToken?: string; /** List of agent engine sandboxes. */ sandboxEnvironments?: SandboxEnvironment[]; } /** Parameters for getting an operation with a sandbox as a response. */ export declare interface GetAgentEngineSandboxOperationParameters { /** The server-assigned name for the operation. */ operationName: string; /** Used to override the default configuration. */ config?: GetAgentEngineOperationConfig; } /** Config for creating a Session. */ export declare interface CreateAgentEngineSessionConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; /** The display name of the session. */ displayName?: string; /** Session state which stores key conversation points. */ sessionState?: Record; /** Waits for the operation to complete before returning. */ waitForCompletion?: boolean; /** Optional. Input only. The TTL for this resource. The expiration time is computed: now + TTL. */ ttl?: string; /** Optional. Timestamp of when this resource is considered expired. This is *always* provided on output, regardless of what `expiration` was sent on input. */ expireTime?: string; /** Optional. The labels with user-defined metadata to organize your Sessions. Label keys and values can be no longer than 64 characters (Unicode codepoints), can only contain lowercase letters, numeric characters, underscores and dashes. International characters are allowed. See https://goo.gl/xmQnxf for more information and examples of labels. */ labels?: Record; /** Optional. The user defined ID to use for session, which will become the final component of the session resource name. If not provided, Vertex AI will generate a value for this ID. This value may be up to 63 characters, and valid characters are `[a-z0-9-]`. The first character must be a letter, and the last character must be a letter or number. */ sessionId?: string; } /** Parameters for creating Agent Engine Sessions. */ export declare interface CreateAgentEngineSessionRequestParameters { /** Name of the agent engine to create the session under. */ name: string; /** The user ID of the session. */ userId: string; config?: CreateAgentEngineSessionConfig; } /** A session. */ export declare interface Session { /** Output only. Timestamp when the session was created. */ createTime?: string; /** Optional. The display name of the session. */ displayName?: string; /** Optional. Timestamp of when this session is considered expired. This is *always* provided on output, regardless of what was sent on input. The minimum value is 24 hours from the time of creation. */ expireTime?: string; /** The labels with user-defined metadata to organize your Sessions. Label keys and values can be no longer than 64 characters (Unicode codepoints), can only contain lowercase letters, numeric characters, underscores and dashes. International characters are allowed. See https://goo.gl/xmQnxf for more information and examples of labels. */ labels?: Record; /** Identifier. The resource name of the session. Format: 'projects/{project}/locations/{location}/reasoningEngines/{reasoning_engine}/sessions/{session}'. */ name?: string; /** Optional. Session specific memory which stores key conversation points. */ sessionState?: Record; /** Optional. Input only. The TTL for this session. The minimum value is 24 hours. */ ttl?: string; /** Output only. Timestamp when the session was updated. */ updateTime?: string; /** Required. Immutable. String id provided by the user */ userId?: string; } /** Operation that has an agent engine session as a response. */ export declare interface AgentEngineSessionOperation { /** The server-assigned name, which is only unique within the same service that originally returns it. If you use the default HTTP mapping, the `name` should be a resource name ending with `operations/{unique_id}`. */ name?: string; /** Service-specific metadata associated with the operation. It typically contains progress information and common metadata such as create time. Some services might not provide such metadata. Any method that returns a long-running operation should document the metadata type, if any. */ metadata?: Record; /** If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed, and either `error` or `response` is available. */ done?: boolean; /** The error result of the operation in case of failure or cancellation. */ error?: Record; /** The Agent Engine Session. */ response?: Session; } /** Config for deleting an Agent Engine Session. */ export declare interface DeleteAgentEngineSessionConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; } /** Parameters for deleting agent engine sessions. */ export declare interface DeleteAgentEngineSessionRequestParameters { /** Name of the agent engine session to delete. */ name: string; config?: DeleteAgentEngineSessionConfig; } /** Operation for deleting agent engine sessions. */ export declare interface DeleteAgentEngineSessionOperation { /** The server-assigned name, which is only unique within the same service that originally returns it. If you use the default HTTP mapping, the `name` should be a resource name ending with `operations/{unique_id}`. */ name?: string; /** Service-specific metadata associated with the operation. It typically contains progress information and common metadata such as create time. Some services might not provide such metadata. Any method that returns a long-running operation should document the metadata type, if any. */ metadata?: Record; /** If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed, and either `error` or `response` is available. */ done?: boolean; /** The error result of the operation in case of failure or cancellation. */ error?: Record; } /** Config for getting an Agent Engine Session. */ export declare interface GetAgentEngineSessionConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; } /** Parameters for getting an agent engine session. */ export declare interface GetAgentEngineSessionRequestParameters { /** Name of the agent engine session. */ name: string; config?: GetAgentEngineSessionConfig; } /** Config for listing agent engine sessions. */ export declare interface ListAgentEngineSessionsConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; pageSize?: number; pageToken?: string; /** An expression for filtering the results of the request. For field names both snake_case and camelCase are supported. */ filter?: string; } /** Parameters for listing agent engines. */ export declare interface ListAgentEngineSessionsRequestParameters { /** Name of the agent engine. */ name: string; config?: ListAgentEngineSessionsConfig; } /** Response for listing agent engine sessions. */ export class ListReasoningEnginesSessionsResponse { /** Used to retain the full HTTP response. */ sdkHttpResponse?: genaiTypes.HttpResponse; nextPageToken?: string; /** List of agent engine sessions. */ sessions?: Session[]; } /** Parameters for getting an operation with a session as a response. */ export declare interface GetAgentEngineSessionOperationParameters { /** The server-assigned name for the operation. */ operationName: string; /** Used to override the default configuration. */ config?: GetAgentEngineOperationConfig; } /** Config for updating agent engine session. */ export declare interface UpdateAgentEngineSessionConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; /** The display name of the session. */ displayName?: string; /** Session state which stores key conversation points. */ sessionState?: Record; /** Waits for the operation to complete before returning. */ waitForCompletion?: boolean; /** Optional. Input only. The TTL for this resource. The expiration time is computed: now + TTL. */ ttl?: string; /** Optional. Timestamp of when this resource is considered expired. This is *always* provided on output, regardless of what `expiration` was sent on input. */ expireTime?: string; /** Optional. The labels with user-defined metadata to organize your Sessions. Label keys and values can be no longer than 64 characters (Unicode codepoints), can only contain lowercase letters, numeric characters, underscores and dashes. International characters are allowed. See https://goo.gl/xmQnxf for more information and examples of labels. */ labels?: Record; /** Optional. The user defined ID to use for session, which will become the final component of the session resource name. If not provided, Vertex AI will generate a value for this ID. This value may be up to 63 characters, and valid characters are `[a-z0-9-]`. The first character must be a letter, and the last character must be a letter or number. */ sessionId?: string; /** The update mask to apply. For the `FieldMask` definition, see https://protobuf.dev/reference/protobuf/google.protobuf/#field-mask. */ updateMask?: string; /** User ID of the agent engine session to update. */ userId?: string; } /** Parameters for updating agent engine sessions. */ export declare interface UpdateAgentEngineSessionRequestParameters { /** Name of the agent engine session to update. */ name: string; config?: UpdateAgentEngineSessionConfig; } /** Actions are parts of events that are executed by the agent. */ export declare interface EventActions { /** Optional. Indicates that the event is updating an artifact. key is the filename, value is the version. */ artifactDelta?: Record; /** Optional. The agent is escalating to a higher level agent. */ escalate?: boolean; /** Optional. Will only be set by a tool response indicating tool request euc. Struct key is the function call id since one function call response (from model) could correspond to multiple function calls. Struct value is the required auth config, which can be another struct. */ requestedAuthConfigs?: Record; /** Optional. If true, it won't call model to summarize function response. Only used for function_response event. */ skipSummarization?: boolean; /** Optional. Indicates that the event is updating the state with the given delta. */ stateDelta?: Record; /** Optional. If set, the event transfers to the specified agent. */ transferAgent?: string; } /** Metadata relating to a LLM response event. */ export declare interface EventMetadata { /** Optional. Metadata returned to client when grounding is enabled. */ groundingMetadata?: genaiTypes.GroundingMetadata; /** Optional. The branch of the event. The format is like agent_1.agent_2.agent_3, where agent_1 is the parent of agent_2, and agent_2 is the parent of agent_3. Branch is used when multiple child agents shouldn't see their siblings' conversation history. */ branch?: string; /** The custom metadata of the LlmResponse. */ customMetadata?: Record; /** Optional. Flag indicating that LLM was interrupted when generating the content. Usually it's due to user interruption during a bidi streaming. */ interrupted?: boolean; /** Optional. Set of ids of the long running function calls. Agent client will know from this field about which function call is long running. Only valid for function call event. */ longRunningToolIds?: string[]; /** Optional. Indicates whether the text content is part of a unfinished text stream. Only used for streaming mode and when the content is plain text. */ partial?: boolean; /** Optional. Indicates whether the response from the model is complete. Only used for streaming mode. */ turnComplete?: boolean; /** Optional. Audio transcription of user input. */ inputTranscription?: genaiTypes.Transcription; /** Optional. Audio transcription of model output. */ outputTranscription?: genaiTypes.Transcription; } /** Config for appending agent engine session event. */ export declare interface AppendAgentEngineSessionEventConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; /** The content of the session event. */ content?: genaiTypes.Content; /** Actions are parts of events that are related to the session event. */ actions?: EventActions; /** The error code of the session event. */ errorCode?: string; /** The error message of the session event. */ errorMessage?: string; /** Metadata relating to the session event. */ eventMetadata?: EventMetadata; /** Weakly typed raw event data in proto struct format. */ rawEvent?: Record; } /** Parameters for appending agent engines. */ export declare interface AppendAgentEngineSessionEventRequestParameters { /** Name of the agent engine session. */ name: string; /** Author of the agent engine session event. */ author: string; /** Invocation ID of the agent engine. */ invocationId: string; /** Timestamp indicating when the event was created. */ timestamp: string; config?: AppendAgentEngineSessionEventConfig; } /** Response for appending agent engine session event. */ export class AppendAgentEngineSessionEventResponse {} /** Config for listing agent engine session events. */ export declare interface ListAgentEngineSessionEventsConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; pageSize?: number; pageToken?: string; /** An expression for filtering the results of the request. For field names both snake_case and camelCase are supported. */ filter?: string; } /** Parameters for listing agent engine session events. */ export declare interface ListAgentEngineSessionEventsRequestParameters { /** Name of the agent engine session. */ name: string; config?: ListAgentEngineSessionEventsConfig; } /** A session event. */ export declare interface SessionEvent { /** Optional. Content of the event provided by the author. */ content?: genaiTypes.Content; /** Optional. Actions executed by the agent. */ actions?: EventActions; /** Required. The name of the agent that sent the event, or user. */ author?: string; /** Optional. Error code if the response is an error. Code varies by model. */ errorCode?: string; /** Optional. Error message if the response is an error. */ errorMessage?: string; /** Optional. Metadata relating to this event. */ eventMetadata?: EventMetadata; /** Required. The invocation id of the event, multiple events can have the same invocation id. */ invocationId?: string; /** Identifier. The resource name of the event. Format:`projects/{project}/locations/{location}/reasoningEngines/{reasoning_engine}/sessions/{session}/events/{event}`. */ name?: string; /** Required. Timestamp when the event was created on client side. */ timestamp?: string; /** Optional. Weakly typed raw event data in proto struct format. */ rawEvent?: Record; } /** Response for listing agent engine session events. */ export class ListAgentEngineSessionEventsResponse { /** Used to retain the full HTTP response. */ sdkHttpResponse?: genaiTypes.HttpResponse; nextPageToken?: string; /** List of session events. */ sessionEvents?: SessionEvent[]; } /** Config for getting a skill. */ export declare interface GetSkillConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; } /** Parameters for GetSkillRequest. */ export declare interface GetSkillRequestParameters { /** The resource name of the Skill to retrieve. Format: projects/{project}/locations/{location}/skills/{skill} */ name: string; config?: GetSkillConfig; } /** Represents a Skill resource. Patches the type from the discovery document. */ export declare interface Skill { /** Required. Provides the zipped filesystem of the Skill. This should contain the `SKILL.md` file at the root of the zip and optional directories for scripts, references, and assets. Directory should align with the directory structure specified at https://agentskills.io/specification#directory-structure. */ zippedFilesystem?: string; /** Output only. The state of the Skill. */ state?: SkillState; /** Identifier. The resource name of the Skill. Format: `projects/{project}/locations/{location}/skills/{skill}` */ name?: string; /** Output only. Timestamp when this Skill was created. */ createTime?: string; /** Output only. Timestamp when this Skill was most recently updated. */ updateTime?: string; /** Required. Provides the display name of the Skill. This should align with `name` in the `SKILL.md` file. */ displayName?: string; /** Required. Describes the Skill. Should describe both what the skill does and when to use it. Should include specific keywords that help agents identify relevant tasks. This should align with `description` in the `SKILL.md` file. */ description?: string; /** Optional. Specifies the license of the Skill. This should be an SPDX license identifier (e.g., "MIT", "Apache-2.0"). See https://spdx.org/licenses/. This should align with `license` in the `SKILL.md` file. */ license?: string; /** Optional. Specifies the compatibility of the Skill. Indicates environment requirements (intended product, system packages, network access, etc.). This should align with `compatibility` in the `SKILL.md` file. */ compatibility?: string; } /** An agent engine instance. */ export declare interface AgentEngine { /** The underlying API client. */ apiClient?: unknown; /** The underlying API client for asynchronous operations. */ apiAsyncClient?: unknown; /** The underlying API resource (i.e. ReasoningEngine). */ apiResource?: ReasoningEngine; } /** Config for agent engine methods. */ export declare interface AgentEngineConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; /** The GCS bucket to use for staging the artifacts needed. It must be a valid GCS bucket name, e.g. "gs://bucket-name". It is required if `agent_engine` is specified. */ stagingBucket?: string; /** The set of PyPI dependencies needed. It can either be the path to a single file (requirements.txt), or an ordered list of strings corresponding to each line of the requirements file. */ requirements?: unknown; /** The user-defined name of the Agent Engine. The name can be up to 128 characters long and can comprise any UTF-8 character. */ displayName?: string; /** The description of the Agent Engine. */ description?: string; /** The GCS bucket directory under `staging_bucket` to use for staging the artifacts needed. */ gcsDirName?: string; /** The set of extra user-provided packages (if any). */ extraPackages?: string[]; /** The environment variables to be set when running the Agent Engine. If it is a dictionary, the keys are the environment variable names, and the values are the corresponding values. */ envVars?: unknown; /** The service account to be used for the Agent Engine. If not specified, the default Reasoning Engine P6SA service agent will be used. */ serviceAccount?: string; /** The identity type to use for the Agent Engine. */ identityType?: IdentityType; /** The context spec to be used for the Agent Engine. */ contextSpec?: ReasoningEngineContextSpec; /** The PSC interface config for PSC-I to be used for the Agent Engine. */ pscInterfaceConfig?: PscInterfaceConfig; /** The minimum number of instances to run for the Agent Engine. Defaults to 1. Range: [0, 10]. */ minInstances?: number; /** The maximum number of instances to run for the Agent Engine. Defaults to 100. Range: [1, 1000]. If VPC-SC or PSC-I is enabled, the acceptable range is [1, 100]. */ maxInstances?: number; /** The resource limits to be applied to the Agent Engine. Required keys: 'cpu' and 'memory'. Supported values for 'cpu': '1', '2', '4', '6', '8'. Supported values for 'memory': '1Gi', '2Gi', ..., '32Gi'. */ resourceLimits?: Record; /** The container concurrency to be used for the Agent Engine. Recommended value: 2 * cpu + 1. Defaults to 9. */ containerConcurrency?: number; /** The encryption spec to be used for the Agent Engine. */ encryptionSpec?: genaiTypes.EncryptionSpec; /** The labels to be used for the Agent Engine. */ labels?: Record; /** The class methods to be used for the Agent Engine. If specified, they'll override the class methods that are autogenerated by default. By default, methods are generated by inspecting the agent object and generating a corresponding method for each method defined on the agent class. */ classMethods?: Record[]; /** The user-provided paths to the source packages (if any). If specified, the files in the source packages will be packed into a a tarball file, uploaded to Agent Engine's API, and deployed to the Agent Engine. The following fields will be ignored: - agent - extra_packages - staging_bucket - requirements The following fields will be used to install and use the agent from the source packages: - entrypoint_module (required) - entrypoint_object (required) - requirements_file (optional) - class_methods (required) */ sourcePackages?: string[]; /** Specifies the configuration for fetching source code from a Git repository that is managed by Developer Connect. This includes the repository, revision, and directory to use. */ developerConnectSource?: ReasoningEngineSpecSourceCodeSpecDeveloperConnectConfig; /** The entrypoint module to be used for the Agent Engine This field only used when source_packages is specified. */ entrypointModule?: string; /** The entrypoint object to be used for the Agent Engine. This field only used when source_packages is specified. */ entrypointObject?: string; /** The user-provided path to the requirements file (if any). This field is only used when source_packages is specified. If not specified, agent engine will find and use the `requirements.txt` in the source package. */ requirementsFile?: string; /** The agent framework to be used for the Agent Engine. The OSS agent framework used to develop the agent. Currently supported values: "google-adk", "langchain", "langgraph", "ag2", "llama-index", "custom". If not specified: - If `agent` is specified, the agent framework will be auto-detected. - If `source_packages` is specified, the agent framework will default to "custom". */ agentFramework?: | 'google-adk' | 'langchain' | 'langgraph' | 'ag2' | 'llama-index' | 'custom'; /** The Python version to be used for the Agent Engine. If not specified, it will use the current Python version of the environment. Supported versions: "3.10", "3.11", "3.12", "3.13", "3.14". */ pythonVersion?: '3.10' | '3.11' | '3.12' | '3.13' | '3.14'; /** The build options for the Agent Engine. The following keys are supported: - installation_scripts: Optional. The paths to the installation scripts to be executed in the Docker image. The scripts must be located in the `installation_scripts` subdirectory and the path must be added to `extra_packages`. */ buildOptions?: Record; /** The image spec for the Agent Engine. */ imageSpec?: ReasoningEngineSpecSourceCodeSpecImageSpec; /** The agent config source for the Agent Engine. */ agentConfigSource?: ReasoningEngineSpecSourceCodeSpecAgentConfigSource; /** The container spec for the Agent Engine. */ containerSpec?: ReasoningEngineSpecContainerSpec; /** Agent Gateway configuration for a Reasoning Engine deployment. */ agentGatewayConfig?: ReasoningEngineSpecDeploymentSpecAgentGatewayConfig; /** Optional. Specifies the configuration for keep-alive probe. Contains configuration on a specified endpoint that a deployment host should use to keep the container alive based on the probe settings. */ keepAliveProbe?: KeepAliveProbe; } /** Config for checking a query job on an agent engine. */ export declare interface RunQueryJobAgentEngineConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; /** The query to send to the agent engine. */ query?: string; /** The GCS URI to use for the output. If it is a file, the system use this file to store the response. If it represents a directory, the system automatically generate a file for the response. In both cases, the input query will be stored in the same directory under the same file name prefix as the output file. */ outputGcsUri?: string; } /** Result of running a query job. */ export declare interface RunQueryJobResult { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; /** Name of the agent engine operation to later check for status. */ jobName?: string; /** The GCS URI of the input file. */ inputGcsUri?: string; /** The GCS URI of the output file. */ outputGcsUri?: string; } /** Config for canceling async querying agent engines. */ export declare interface CancelQueryJobAgentEngineConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; /** Name of the longrunning operation returned from run_query_job. */ operationName?: string; } /** Result of canceling a query job. */ export declare interface CancelQueryJobResult { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; } /** Config for async querying agent engines. */ export declare interface CheckQueryJobAgentEngineConfig { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; /** Whether to retrieve the results of the query job. */ retrieveResult?: boolean; } /** Result of checking a query job. */ export declare interface CheckQueryJobResult { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; /** Name of the agent engine operation. */ operationName?: string; /** The GCS URI of the output file. */ outputGcsUri?: string; /** Status of the operation. */ status?: string; /** JSON result of the operation. */ result?: string; } /** Response from LRO. */ export class CheckQueryJobResponse { /** Used to override HTTP request options. */ httpOptions?: genaiTypes.HttpOptions; /** Abort signal which can be used to cancel the request. NOTE: AbortSignal is a client-only operation. Using it to cancel an operation will not cancel the request in the service. You will still be charged usage for any applicable operations. */ abortSignal?: AbortSignal; /** The GCS URI of the output file. */ outputGcsUri?: string; } /** A linked resource attached to the application by the user. */ export declare interface SchemaPromptSpecAppBuilderDataLinkedResource { /** A user-friendly name for the data source shown in the UI. */ displayName?: string; /** The unique resource name of the data source. The format is determined by the 'type' field. For type "SAVED_PROMPT": projects/{project}/locations/{location}/datasets/{dataset} For type "AI_AGENT": projects/{project}/locations/{location}/agents/{agent} */ name?: string; /** The type of the linked resource. e.g., "SAVED_PROMPT", "AI_AGENT" This string corresponds to the name of the LinkedResourceType enum member. See: google3/cloud/console/web/ai/platform/llm/prompts/build/services/specs_repository_service/linked_resources/linked_resource.ts */ type?: string; } /** Defines data for an application builder. */ export declare interface SchemaPromptSpecAppBuilderData { /** Serialized state of the code repository. This string will typically contain a JSON representation of the UI's CodeRepositoryService state (files, folders, content, and any metadata). The UI is responsible for serialization and deserialization. */ codeRepositoryState?: string; /** Optional. Framework used to build the application. */ framework?: Framework; /** Linked resources attached to the application by the user. */ linkedResources?: SchemaPromptSpecAppBuilderDataLinkedResource[]; } ================================================ FILE: src/types.ts ================================================ /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ // Code generated by the Google Gen AI SDK generator DO NOT EDIT. export * from './types/common.js'; ================================================ FILE: system_test/agent_engine_e2e_test.ts ================================================ /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import {Client} from '../src/client'; const PROJECT = process.env['GCLOUD_PROJECT']; const LOCATION = 'us-central1'; async function pollOperation(client: Client, operationName: string) { let isDone = false; let pollCount = 0; while (!isDone && pollCount < 120) { const status = await client.agentEnginesInternal.getAgentOperationInternal({ operationName, }); if (status.done) { return status; } pollCount++; await new Promise((resolve) => setTimeout(resolve, 5000)); } throw new Error( `Operation ${operationName} did not complete within the timeout.`, ); } describe('agentEnginesInternal', () => { let client: Client; let agentEngineName: string|undefined; let createOperationName: string|undefined; let updateOperationName: string|undefined; beforeAll(async () => { jasmine.DEFAULT_TIMEOUT_INTERVAL = 600000; client = new Client({ project: PROJECT as string, location: LOCATION, }); const createOp = await client.agentEnginesInternal.createInternal({ config: { displayName: 'test-agent-engine-sample', description: 'Created from the Vertex JS SDK system tests', labels: {'test-label': 'test-value'}, }, }); createOperationName = createOp.name; const status = await pollOperation(client, createOperationName!); agentEngineName = status.response?.name; }, 600000); afterAll(async () => { // If the test failed during the create operation, try to recover // the resource name from the operation to cleanup. if (!agentEngineName && createOperationName) { try { const status = await client.agentEnginesInternal.getAgentOperationInternal({ operationName: createOperationName, }); if (status.done && status.response?.name) { agentEngineName = status.response.name; } } catch (e) { console.error('Failed to recover Agent Engine name from operation:', e); } } if (agentEngineName) { try { await client.agentEnginesInternal.deleteInternal({ name: agentEngineName, }); } catch (e) { console.error('Failed to delete Agent Engine during cleanup:', e); } } }); it('should create an Agent Engine', async () => { // The create operation is tested in the beforeAll hook, so we just // need to check that the resource name is defined. expect(agentEngineName).toBeDefined(); }); it('should get and update an Agent Engine', async () => { const agentEngine = await client.agentEnginesInternal.getInternal({ name: agentEngineName!, }); expect(agentEngine.name).toBeDefined(); expect(agentEngine.displayName).toEqual('test-agent-engine-sample'); expect(agentEngine.labels).toEqual({'test-label': 'test-value'}); const updateOp = await client.agentEnginesInternal.updateInternal({ name: agentEngineName!, config: { displayName: 'test-agent-engine-updated', description: 'Updated from the Vertex JS SDK system tests', updateMask: 'displayName,description', }, }); expect(updateOp.name).toBeDefined(); updateOperationName = updateOp.name; const status = await pollOperation(client, updateOperationName!); if (status.response) { expect(status.response.displayName).toEqual('test-agent-engine-updated'); } }); }); ================================================ FILE: test/replays/_replay_client.ts ================================================ /** * @license * Copyright 2026 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import {Pager} from '@google/genai'; import * as fs from 'fs'; import * as path from 'path'; import {Client} from '../../src/client.js'; /** * Bypass real credential fetching during replay. */ class FakeAuth { async addAuthHeaders(headers: Headers): Promise { if (headers.get('Authorization')) return; headers.append('Authorization', 'Bearer fake-replay-token'); } } /** * ReplayClient extends the Vertex AI SDK Client to support replay * testing with request and response verification against recorded JSON files. */ export class ReplayClient extends Client { private replayData: any; private interactionIndex = 0; constructor(options: {project: string; location: string}) { super(options); } /** * Loads a replay JSON file and sets up the fetch spy. */ setupReplay(replayFileName: string): jasmine.Spy { const fakeAuth = new FakeAuth(); const auth = this.apiClient.clientOptions.auth; spyOn(auth, 'addAuthHeaders').and.callFake(async (headers: Headers) => { await fakeAuth.addAuthHeaders(headers); }); const replaysDir = process.env['GOOGLE_GENAI_REPLAYS_DIRECTORY']; if (!replaysDir) { throw new Error('Set GOOGLE_GENAI_REPLAYS_DIRECTORY env var.'); } const replayFilePath = path.join(replaysDir, replayFileName); const rawData = fs.readFileSync(replayFilePath, 'utf8'); this.replayData = JSON.parse(rawData); return spyOn(global, 'fetch') .and.callFake(async (url: any, init?: RequestInit) => { if (this.interactionIndex >= this.replayData.interactions.length) { throw new Error(`Unexpected fetch call to ${url.toString()}`); } const interaction = this.replayData.interactions[this.interactionIndex++]; const responseStatus = interaction.response.status_code || 200; const bodySegments = interaction.response.body_segments || []; const responseBody = bodySegments.length === 1 ? JSON.stringify(bodySegments[0]) : ''; return new Response(responseBody, { status: responseStatus, headers: new Headers( interaction.response.headers as Record), }); }); } /** * Verifies the actual request sent matches the expected request in the * replay. */ verifyInteraction(index: number, actualArgs: any[]) { const expectedRequest = this.replayData.interactions[index].request; const expectedRequestCamel: any = JSON.parse(snakeToCamel(JSON.stringify(expectedRequest))); if (expectedRequestCamel.headers) { expectedRequestCamel.headers = normalizeHeaders(expectedRequestCamel.headers); } const [url, init] = actualArgs; const actualHeaders = new Headers(init?.headers || {}); const xGoogApiClient = actualHeaders.get('x-goog-api-client') || ''; const userAgent = actualHeaders.get('user-agent') || ''; // Validate that user-agent is set correctly. expect(xGoogApiClient).toContain('vertex-genai-modules/'); expect(xGoogApiClient).toContain('gl-node/'); expect(userAgent).toContain('vertex-genai-modules/'); expect(userAgent).toContain('gl-node/'); const normalizedActual = normalizeRequest(init || {}, url.toString()); assertMessagesEqual(normalizedActual, expectedRequestCamel); } /** * Verifies the SDK response matches the expected response in the replay. */ verifyResponse(index: number, actualResponse: any) { const expectedInteraction = this.replayData.interactions[index]; const expectedResponse = expectedInteraction.response.sdk_response_segments?.[0] || expectedInteraction.response.body_segments?.[0]; const actualNormalized = JSON.parse( snakeToCamel(JSON.stringify(extractResponseFromPager(actualResponse)))); const expectedNormalized = JSON.parse(snakeToCamel(JSON.stringify(expectedResponse))); assertMessagesEqual(actualNormalized, expectedNormalized); } verifyAllInteractions() { if (this.interactionIndex < this.replayData.interactions.length) { throw new Error(`Expected ${ this.replayData.interactions.length} interactions but only ${ this.interactionIndex} were executed.`); } } } function extractResponseFromPager(sdkResponse: any): any { if (!(sdkResponse instanceof Pager)) return sdkResponse; const response: Record = {}; response[sdkResponse.name] = sdkResponse.page; return response; } function snakeToCamel(str: string): string { return str.replace(/_([a-z])/g, (g) => g[1].toUpperCase()); } function normalizeRequest(request: RequestInit, url: string) { return { method: request.method?.toLowerCase(), url: redactUrl(url), headers: normalizeHeaders(request.headers as Headers), bodySegments: normalizeBody(request.body as string), }; } function redactUrl(url: string) { return url .replace( /.*\/projects\/[^/]+\/locations\/[^/]+\//, '{VERTEX_URL_PREFIX}/') .replace(/\*/g, '%2A'); } function normalizeHeaderName(headerName: string): string { if (!headerName) return ''; return headerName.split('-') .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) .join('-'); } function normalizeHeaders(headers: any) { const obj: Record = {}; const entries = headers instanceof Headers ? Array.from(headers.entries()) : Object.entries(headers || {}); for (const [k, v] of entries) { const key = k.toLowerCase(); // Temporarily skip these checks until replay file headers match across // languages if (key === 'authorization' || key === 'user-agent' || key === 'x-goog-api-client') { continue; } const normalizedKey = normalizeHeaderName(key); obj[normalizedKey] = v as string; } return obj; } function normalizeBody(body: string) { try { if (!body) return body; const parsed = JSON.parse(snakeToCamel(body)); return Array.isArray(parsed) ? parsed : [parsed]; } catch { return body; } } function isObjectEmpty(obj: unknown): boolean { if (obj == null) return true; if (typeof obj !== 'object') return false; for (const key of Object.keys(obj as object)) { const val = (obj as any)[key]; if (typeof val === 'object') { if (!isObjectEmpty(val)) return false; } else if (val !== undefined && val !== null) { return false; } } return true; } /** * Message comparison. This treats undefined and empty objects/arrays as equal. */ function assertMessagesEqual(actual: unknown, expected: unknown) { function isObjectEmpty(obj: unknown): boolean { if (obj == null) return true; if (typeof obj !== 'object') return false; for (const key of Object.keys(obj as object)) { const val = (obj as any)[key]; if (typeof val === 'object') { if (!isObjectEmpty(val)) return false; } else if (val !== undefined && val !== null) { return false; } } return true; } function assertDeepEqual(a: any, b: any, path: string = '$') { if (a === b) return; if (a === undefined && typeof b === 'object') { if (!isObjectEmpty(b)) { throw new Error(`Mismatch at ${ path}: Expected undefined to match empty object, but got ${ JSON.stringify(b)}`); } return; } if (typeof a === 'object' && typeof b === 'object' && a && b) { const aKeys = Object.keys(a); const bKeys = Object.keys(b); for (const key of bKeys) { assertDeepEqual(a[key], b[key], `${path}.${key}`); } for (const key of aKeys) { if (!bKeys.includes(key) && !isObjectEmpty(a[key])) { throw new Error( `Mismatch at ${path}: Actual has extra non-empty key "${key}"`); } } return; } if (a !== b) { expect(a).withContext(`Path: ${path}`).toEqual(b); } } assertDeepEqual(actual, expected); } ================================================ FILE: test/replays/agentengines_memories_test.ts ================================================ /** * @license * Copyright 2026 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import 'jasmine'; import {NodeAuth} from '@google/genai/vertex_internal'; import {ReplayClient} from './_replay_client.js'; describe('Memories', () => { let client: ReplayClient; beforeEach(() => { client = new ReplayClient({ project: 'test-project', location: 'us-central1', }); }); it('creates a memory in an agent engine', async () => { const fetchSpy = client.setupReplay( 'ae_memories_private_create/test_private_create_memory.vertex.json'); const createOp = await client.agentEnginesInternal.memories.createInternal({ name: 'projects/964831358985/locations/us-central1/reasoningEngines/2886612747586371584', fact: 'memory_fact', scope: {'user_id': '123'} }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(createOp.name).toBeDefined(); client.verifyAllInteractions(); }); it('deletes an agent engine memory', async () => { const fetchSpy = client.setupReplay('ae_memories_delete/test_delete_memory.vertex.json'); const deleteOp = await client.agentEnginesInternal.memories.delete({ name: 'projects/964831358985/locations/us-central1/reasoningEngines/2886612747586371584/memories/5605466683931099136', }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(deleteOp.name).toBeDefined(); client.verifyAllInteractions(); }); it('generates an agent engine memory', async () => { const fetchSpy = client.setupReplay( 'ae_memories_private_generate/test_private_generate_memory.vertex.json'); const aeName = 'projects/964831358985/locations/us-central1/reasoningEngines/2886612747586371584'; const generateOp = await client.agentEnginesInternal.memories.generateInternal({ name: aeName, vertexSessionSource: { session: '{PROJECT_AND_LOCATION_PATH}/reasoningEngines/2886612747586371584/sessions/6922431337672474624' }, }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(generateOp.name).toBeDefined(); client.verifyAllInteractions(); }); it('gets an agent engine memory', async () => { const fetchSpy = client.setupReplay('ae_memories_get/test_get_memory.vertex.json'); const memoryName = 'projects/964831358985/locations/us-central1/reasoningEngines/2886612747586371584/memories/3858070028511346688'; const memory = await client.agentEnginesInternal.memories.get({ name: memoryName, }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(memory.name).toBeDefined(); client.verifyAllInteractions(); }); it('gets an agent engine memory operation', async () => { const fetchSpy = client.setupReplay( 'ae_memories_private_get_memory_operation/test_private_get_memory_operation.vertex.json'); const opName = 'projects/964831358985/locations/us-central1/reasoningEngines/2886612747586371584/memories/3858070028511346688/operations/1044963283964002304'; const memoryOperation = await client.agentEnginesInternal.memories.getMemoryOperationInternal({ operationName: opName, }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(memoryOperation.name).toBeDefined(); client.verifyAllInteractions(); }); it('gets an agent engine generate memory operation', async () => { const fetchSpy = client.setupReplay( 'ae_memories_private_get_generate_memories_operation/test_private_get_generate_memories_operation.vertex.json'); const opName = 'projects/964831358985/locations/us-central1/reasoningEngines/2886612747586371584/operations/5669315676343369728'; const generateMemoriesOperation = await client.agentEnginesInternal.memories .getGenerateMemoriesOperationInternal({ operationName: opName, }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(generateMemoriesOperation.name).toBeDefined(); client.verifyAllInteractions(); }); it('lists agent engine memories', async () => { const fetchSpy = client.setupReplay( 'ae_memories_private_list/test_private_list_memory.vertex.json'); const aeName = 'projects/964831358985/locations/us-central1/reasoningEngines/2886612747586371584'; const memoryList = await client.agentEnginesInternal.memories.listInternal({ name: aeName, }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(memoryList.memories![0].name) .toEqual( 'projects/964831358985/locations/us-central1/reasoningEngines/2886612747586371584/memories/3858070028511346688'); client.verifyAllInteractions(); }); it('retrieves an agent engine memory', async () => { const fetchSpy = client.setupReplay( 'ae_memories_private_retrieve/test_private_retrieve.vertex.json'); const aeName = 'projects/964831358985/locations/us-central1/reasoningEngines/2886612747586371584'; const retrievedMemories = await client.agentEnginesInternal.memories.retrieveInternal({ name: aeName, scope: {'user_id': '123'}, }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); if (retrievedMemories?.retrievedMemories && retrievedMemories.retrievedMemories.length > 0) { expect(retrievedMemories.retrievedMemories[0].memory?.name).toBeDefined(); } client.verifyAllInteractions(); }); it('rolls back an agent engine memory', async () => { const fetchSpy = client.setupReplay( 'ae_memories_private_rollback/test_private_rollback.vertex.json'); const rollbackOperation = await client.agentEnginesInternal.memories.rollbackInternal({ name: 'projects/964831358985/locations/us-central1/reasoningEngines/2886612747586371584/memories/3858070028511346688', targetRevisionId: '3001207491565453312', }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(rollbackOperation.name).toBeDefined(); client.verifyAllInteractions(); }); it('updates an agent engine memory', async () => { const fetchSpy = client.setupReplay( 'ae_memories_private_update/test_private_update_memory.vertex.json'); const memoryName = 'projects/964831358985/locations/us-central1/reasoningEngines/2886612747586371584/memories/3858070028511346688'; const updateOp = await client.agentEnginesInternal.memories.updateInternal({ name: memoryName, fact: 'memory_fact_updated', scope: {'user_id': '123'}, }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(updateOp.name).toBeDefined(); client.verifyAllInteractions(); }); it('purges an agent engine memory', async () => { const fetchSpy = client.setupReplay( 'ae_memories_private_purge/test_private_purge.vertex.json'); const purgeOp = await client.agentEnginesInternal.memories.purgeInternal({ name: 'projects/964831358985/locations/us-central1/reasoningEngines/6086402690647064576', filter: 'scope.user_id=123', }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(purgeOp.name).toBeDefined(); client.verifyAllInteractions(); }); it('gets an agent engine memory revision', async () => { const fetchSpy = client.setupReplay( 'ae_memory_revisions_get/test_get_memory_revisions.vertex.json'); const memoryRevisionName = 'projects/964831358985/locations/us-central1/reasoningEngines/2886612747586371584/memories/3858070028511346688/revisions/516064922187071488' const revision = await client.agentEnginesInternal.memories.revisions.get({ name: memoryRevisionName, }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(revision.name).toEqual(memoryRevisionName); client.verifyAllInteractions(); }); it('lists agent engine memory revisions', async () => { const fetchSpy = client.setupReplay( 'ae_memory_revisions_private_list/test_private_list_memory_revisions.vertex.json'); const aeName = 'projects/964831358985/locations/us-central1/reasoningEngines/2886612747586371584/memories/3858070028511346688'; const revisionList = await client.agentEnginesInternal.memories.revisions.listInternal({ name: aeName, }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(revisionList.memoryRevisions![0].name) .toEqual( 'projects/964831358985/locations/us-central1/reasoningEngines/2886612747586371584/memories/3858070028511346688/revisions/516064922187071488'); client.verifyAllInteractions(); }); }); ================================================ FILE: test/replays/agentengines_sandboxes_test.ts ================================================ /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import 'jasmine'; import {NodeAuth} from '@google/genai/vertex_internal'; import * as types from '../../src/types.js'; import {ReplayClient} from './_replay_client.js'; describe('AgentEnginesSandboxes', () => { let client: ReplayClient; beforeEach(() => { client = new ReplayClient({ project: 'test-project', location: 'us-central1', }); }); it('creates an agent engine sandbox', async () => { const fetchSpy = client.setupReplay( 'ae_sandboxes_private_create/test_private_create.vertex.json'); const createSandboxOp = await client.agentEnginesInternal.sandboxes.createInternal({ name: `projects/964831358985/locations/us-central1/reasoningEngines/2886612747586371584`, spec: { codeExecutionEnvironment: { machineConfig: types.MachineConfig.MACHINE_CONFIG_VCPU4_RAM4GIB, }, }, }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(createSandboxOp.name).toBeDefined(); client.verifyAllInteractions(); }); it('deletes an agent engine sandbox', async () => { const fetchSpy = client.setupReplay( 'ae_sandboxes_private_delete/test_private_delete.vertex.json'); const deleteSandboxOp = await client.agentEnginesInternal.sandboxes.deleteInternal({ name: `reasoningEngines/2886612747586371584/sandboxEnvironments/6068475153556176896`, }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(deleteSandboxOp.name).toBeDefined(); client.verifyAllInteractions(); }); it('executes code in an agent engine sandbox', async () => { const fetchSpy = client.setupReplay( 'ae_sandboxes_private_execute_code/test_private_execute_code.vertex.json'); const code = ` with open("test.txt", "r") as input: with open("output.txt", "w") as output_txt: for line in input: output_txt.write(line) `; // Need this to match recorded json file. const jsonWithSpace = JSON.stringify({code}).replace('{"code":', '{"code": '); const executeCodeResponse = await client.agentEnginesInternal.sandboxes.executeCodeInternal({ name: `reasoningEngines/2886612747586371584/sandboxEnvironments/6068475153556176896`, inputs: [ { mimeType: 'application/json', data: Buffer.from(jsonWithSpace).toString('base64'), }, { mimeType: 'text/plain', data: Buffer.from('Hello, world!').toString('base64'), metadata: { attributes: { file_name: Buffer.from('test.txt').toString('base64'), }, }, }, ], }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(executeCodeResponse.outputs).toBeDefined(); client.verifyAllInteractions(); }); it('gets an agent engine sandbox', async () => { const fetchSpy = client.setupReplay( 'ae_sandboxes_private_get/test_private_get.vertex.json'); const sandboxName = `projects/964831358985/locations/us-central1/reasoningEngines/2886612747586371584/sandboxEnvironments/3186171392039059456`; const sandbox = await client.agentEnginesInternal.sandboxes.getInternal({ name: sandboxName, }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(sandbox.name).toEqual(sandboxName); client.verifyAllInteractions(); }); it('gets an agent engine sandbox operation', async () => { const fetchSpy = client.setupReplay( 'ae_sandboxes_private_get_sandbox_operation/test_private_get_operation.vertex.json'); const operationName = `projects/964831358985/locations/us-central1/operations/4799455193970245632`; const sandbox = await client.agentEnginesInternal.sandboxes.getSandboxOperationInternal( { operationName: operationName, }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(sandbox.name).toEqual(operationName); client.verifyAllInteractions(); }); it('lists sandboxes for an agent engine', async () => { const fetchSpy = client.setupReplay( 'ae_sandboxes_private_list/test_private_list.vertex.json'); const aeName = `reasoningEngines/2886612747586371584`; const listSandboxesResponse = await client.agentEnginesInternal.sandboxes.listInternal({ name: aeName, }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(listSandboxesResponse.sandboxEnvironments).toHaveSize(2); client.verifyAllInteractions(); }); }); ================================================ FILE: test/replays/agentengines_sessions_test.ts ================================================ /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import 'jasmine'; import {NodeAuth} from '@google/genai/vertex_internal'; import {ReplayClient} from './_replay_client.js'; describe('AgentEnginesSessions', () => { let client: ReplayClient; beforeEach(() => { client = new ReplayClient({ project: 'test-project', location: 'us-central1', }); }); it('creates an agent engine session', async () => { const fetchSpy = client.setupReplay( 'ae_session_private_create/test_private_create_session.vertex.json'); const createSessionOp = await client.agentEnginesInternal.sessions.createInternal({ name: `projects/964831358985/locations/us-central1/reasoningEngines/2886612747586371584`, userId: 'test-user-id', }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(createSessionOp.name).toBeDefined(); client.verifyAllInteractions(); }); it('updates an agent engine session', async () => { const fetchSpy = client.setupReplay( 'ae_session_private_update/test_private_update_session.vertex.json'); const updateSessionOp = await client.agentEnginesInternal.sessions.updateInternal({ name: `reasoningEngines/2886612747586371584/sessions/3080649749292908544`, config: { displayName: 'test-agent-engine-session-updated', userId: 'test-user-id' } }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(updateSessionOp.name).toBeDefined(); client.verifyAllInteractions(); }); it('gets an agent engine session operation', async () => { const fetchSpy = client.setupReplay( 'ae_session_private_get/test_private_get_session_operation.vertex.json'); const getSessionOp = await client.agentEnginesInternal.sessions.getSessionOperationInternal({ operationName: `reasoningEngines/2886612747586371584/sessions/3080649749292908544/operations/758783840595476480` }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(getSessionOp.name).toBeDefined(); client.verifyAllInteractions(); }); it('deletes an agent engine session', async () => { const fetchSpy = client.setupReplay( 'ae_session_delete/test_delete_session_non_blocking.vertex.json'); const deleteSessionOp = await client.agentEnginesInternal.sessions.delete({ name: `reasoningEngines/2886612747586371584/sessions/8521561049109889024` }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(deleteSessionOp.name).toBeDefined(); client.verifyAllInteractions(); }); }); ================================================ FILE: test/replays/agentengines_test.ts ================================================ /** * @license * Copyright 2026 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import 'jasmine'; import {NodeAuth} from '@google/genai/vertex_internal'; import {ReplayClient} from './_replay_client.js'; describe('AgentEngines', () => { let client: ReplayClient; beforeEach(() => { client = new ReplayClient({ project: 'test-project', location: 'us-central1', }); }); it('creates an agent engine', async () => { const fetchSpy = client.setupReplay( 'agent_engine_private_create/test_private_create_with_labels.vertex.json'); const createOp = await client.agentEnginesInternal.createInternal( {config: {labels: {'test-label': 'test-value'}}}); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(createOp.name).toBeDefined(); client.verifyAllInteractions(); }); it('udpates an agent engine', async () => { const fetchSpy = client.setupReplay( 'agent_engine_private_update/test_private_update.vertex.json'); const updateOp = await client.agentEnginesInternal.updateInternal({ name: 'reasoningEngines/2886612747586371584', config: {displayName: 'test-agent-engine-updated'} }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(updateOp.name).toBeDefined(); client.verifyAllInteractions(); }); it('gets an agent engine resource', async () => { const fetchSpy = client.setupReplay( 'agent_engine_private_get/test_private_get.vertex.json'); const reasoningEngine = await client.agentEnginesInternal.getInternal({ name: 'reasoningEngines/2886612747586371584', }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(reasoningEngine.name).toBeDefined(); client.verifyAllInteractions(); }); it('deletes an agent engine resource', async () => { const fetchSpy = client.setupReplay( 'agent_engine_private_delete/test_private_delete.vertex.json'); const reasoningEngine = await client.agentEnginesInternal.deleteInternal({ name: 'reasoningEngines/7571341522470174720', }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(reasoningEngine.name).toBeDefined(); client.verifyAllInteractions(); }); it('logs an experimental warning only once when agentEnginesInternal is accessed', () => { const warnSpy = spyOn(console, 'warn'); const aeClient1 = client.agentEnginesInternal; const firstAccessCount = warnSpy.calls.count(); expect(firstAccessCount).toBeLessThanOrEqual(1); if (firstAccessCount === 1) { expect(warnSpy).toHaveBeenCalledWith(jasmine.stringMatching( /agentEnginesInternal module is experimental/)); } const aeClient2 = client.agentEnginesInternal; expect(warnSpy.calls.count()).toBe(firstAccessCount); }); }); ================================================ FILE: test/replays/run_replay_tests.sh ================================================ #!/bin/bash # This script runs replay tests for the Vertex SDK JS GenAI modules. # It is intended to be used from the google3 directory of a CitC client. # # Example: # ./third_party/javascript/node_modules/vertexai/test/genai/run_replay_tests.sh START_DIR=$(pwd) if [[ "$START_DIR" != */google3 ]]; then echo "Error: This script must be run from your client's '/google3' directory." echo "Your current directory is: $START_DIR" exit 1 fi export GOOGLE_GENAI_REPLAYS_DIRECTORY="$START_DIR/google/cloud/aiplatform/sdk/genai/replays/tests/vertex_sdk_genai_replays/" if [ ! -d "$GOOGLE_GENAI_REPLAYS_DIRECTORY" ]; then echo "Error: Replays directory not found at $GOOGLE_GENAI_REPLAYS_DIRECTORY" exit 1 fi PARSED_ARGS=$(getopt -o "" -l "mode:" -- "$@") if [ $? -ne 0 ]; then echo "Error: Failed to parse command line arguments." >&2 exit 1 fi eval set -- "$PARSED_ARGS" MODE_VALUE="replay" while true; do case "$1" in --mode) MODE_VALUE="$2" shift 2 ;; --) shift break ;; *) echo "Internal error: Unrecognized arg option: '$1'" >&2 exit 1 ;; esac done if [ "$MODE_VALUE" != "replay" ]; then echo "Error: The JS SDK currently only supports --mode replay." exit 1 fi echo "Running JS GenAI replay tests via blaze..." blaze test --test_strategy=local \ --test_env=GOOGLE_GENAI_REPLAYS_DIRECTORY="$GOOGLE_GENAI_REPLAYS_DIRECTORY" \ --test_output=errors \ //third_party/javascript/node_modules/vertexai/test:genai_modules_replay_tests EXIT_CODE=$? echo "Tests completed with exit code: $EXIT_CODE." exit $EXIT_CODE ================================================ FILE: test/replays/sessionevents_test.ts ================================================ /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import 'jasmine'; import {NodeAuth} from '@google/genai/vertex_internal'; import {ReplayClient} from './_replay_client.js'; describe('SessionEvents', () => { let client: ReplayClient; beforeEach(() => { client = new ReplayClient({ project: 'test-project', location: 'us-central1', }); }); it('appends an agent engine session event', async () => { const fetchSpy = client.setupReplay( 'ae_session_events_append/test_append_session_event.vertex.json'); const createEventOp = await client.agentEnginesInternal.sessions.events.append({ name: 'reasoningEngines/2886612747586371584/sessions/6922431337672474624', author: 'test-user-123', invocationId: 'test-invocation-id', timestamp: '2009-02-13T23:31:00+00:00', }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); client.verifyAllInteractions(); }); it('lists session events', async () => { const fetchSpy = client.setupReplay( 'ae_session_events_private_list/test_private_list_session_events.vertex.json'); const listSessionEventsResponse = await client.agentEnginesInternal.sessions.events.listInternal({ name: 'reasoningEngines/2886612747586371584/sessions/6922431337672474624', }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(listSessionEventsResponse.sessionEvents).toBeDefined(); expect(listSessionEventsResponse.sessionEvents!.length).toBeGreaterThan(0); expect(listSessionEventsResponse.sessionEvents![0].name) .toContain('events/2517327301947949056'); client.verifyAllInteractions(); }); }); ================================================ FILE: test/replays/skills_test.ts ================================================ /** * @license * Copyright 2026 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import 'jasmine'; import {ReplayClient} from './_replay_client.js'; describe('Skills', () => { let client: ReplayClient; beforeEach(() => { client = new ReplayClient({ project: 'test-project', location: 'us-central1', }); }); it('gets a skill resource', async () => { const fetchSpy = client.setupReplay( 'skills_get/test_get_skill.vertex.json'); const skill = await client.skills.get({ name: 'projects/demo-project/locations/us-central1/skills/7184367305562783744', }); client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); expect(skill.name).toBeDefined(); client.verifyAllInteractions(); }); }); ================================================ FILE: test/replays/test_env.js ================================================ /** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ const path = require('path'); module.exports = { beforeJasmine: () => { process.env['GOOGLE_CLOUD_PROJECT'] = 'vertex-sdk-dev'; process.env['GOOGLE_CLOUD_LOCATION'] = 'us-central1'; if (process.env['RUNFILES']) { process.env['GOOGLE_GENAI_REPLAYS_DIRECTORY'] = path.join( process.env['RUNFILES'], 'google3/google/cloud/aiplatform/sdk/genai/replays/tests/vertex_sdk_genai_replays' ); } return Promise.resolve(); }, afterJasmine: (failureReason) => Promise.resolve(failureReason), }; ================================================ FILE: test/spec/reporter.js ================================================ /** * @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. */ const reporters = require('jasmine-reporters'); function TSJUnitXmlReporter() { const junitReporter = new reporters.JUnitXmlReporter({ savePath: __dirname, consolidateAll: true, filePrefix: 'sponge_log' }); return junitReporter; } module.exports = exports = TSJUnitXmlReporter; ================================================ FILE: test/unit/client_test.ts ================================================ import {AgentEngines} from '../../src/agentengines'; import {Client} from '../../src/client'; describe('GenAI Client Instantiation', () => { const options = { project: 'test-project', location: 'us-central1', }; it('should initialize with provided project and location', () => { const client = new Client(options); expect(client).toBeDefined(); }); it('should expose agentEnginesInternal as an instance of AgentEngines', () => { const client = new Client(options); // This will log an experimental warning. expect(client.agentEnginesInternal).toBeDefined(); expect(client.agentEnginesInternal instanceof AgentEngines).toBe(true); }); it('should correctly initialize AgentEngines submodules', () => { const client = new Client(options); const ae = client.agentEnginesInternal; expect(ae.sessions).toBeDefined(); expect(ae.sandboxes).toBeDefined(); expect(ae.memories).toBeDefined(); }); }); ================================================ FILE: tsconfig.json ================================================ { "extends": "./node_modules/gts/tsconfig-google.json", "compilerOptions": { "module": "commonjs", "moduleResolution": "node", "baseUrl": ".", "paths": { "@google/genai": ["./node_modules/@google/genai/dist/genai.d.ts"], "@google/genai/vertex_internal": ["./node_modules/@google/genai/dist/vertex_internal/index.d.ts"] }, "rootDir": ".", "outDir": "build", "resolveJsonModule": true, "lib": [ "es2022", "dom", "dom.iterable" ], "skipLibCheck": true }, "include": [ "src/**/*.ts", "test/**/*.ts", "system_test/**/*.ts", "vertexai/src/**/*.ts", "vertexai/test/**/*.ts", "vertexai/system_test/**/*.ts" ], "exclude": [ "build", "node_modules", "dist" ] } ================================================ FILE: vertexai/.eslintrc.json ================================================ { "extends": "./node_modules/gts" } ================================================ FILE: vertexai/README.md ================================================ [![NPM Downloads](https://img.shields.io/npm/dm/%40google-cloud%2Fvertexai)](https://www.npmjs.com/package/@google-cloud/vertexai) [![Node Current](https://img.shields.io/node/v/%40google-cloud%2Fvertexai)](https://www.npmjs.com/package/@google-cloud/vertexai) > [!NOTE] The `VertexAI` class and all its dependencies in the Vertex AI SDK are > deprecated as of June 24, 2025 and will be removed on June 24, 2026. Please > use the [Google Gen AI SDK](https://www.npmjs.com/package/@google/genai) to > access Gemini features. See > [the migration guide](https://cloud.google.com/vertex-ai/generative-ai/docs/deprecations/genai-vertexai-sdk) > for details. > Vertex AI is now the Gemini Enterprise Agent Platform. # Vertex AI SDK for Node.js quickstart The Vertex AI SDK for Node.js lets you use the Vertex AI Gemini API to build AI-powered features and applications. Both TypeScript and JavaScript are supported. The sample code in this document is written in JavaScript only. For detailed samples using the Vertex AI Node.js SDK, see the [samples repository](https://github.com/GoogleCloudPlatform/nodejs-docs-samples/tree/main/generative-ai/snippets) on GitHub. For the latest list of available Gemini models on Vertex AI, see the [Model information](https://cloud.google.com/vertex-ai/docs/generative-ai/learn/models#gemini-models) page in Vertex AI documentation. ## Before you begin 1. Make sure your node.js version is 20 or above. 1. [Select](https://console.cloud.google.com/project) or [create](https://cloud.google.com/resource-manager/docs/creating-managing-projects#creating_a_project) a Google Cloud project. 1. [Enable billing for your project](https://cloud.google.com/billing/docs/how-to/modify-project). 1. [Enable the Vertex AI API](https://console.cloud.google.com/flows/enableapi?apiid=aiplatform.googleapis.com). 1. [Install the gcloud CLI](https://cloud.google.com/sdk/docs/install). 1. [Initialize the gcloud CLI](https://cloud.google.com/sdk/docs/initializing). 1. Create local authentication credentials for your user account: ```sh gcloud auth application-default login ``` A list of accepted authentication options are listed in [GoogleAuthOptions](https://github.com/googleapis/google-auth-library-nodejs/blob/3ae120d0a45c95e36c59c9ac8286483938781f30/src/auth/googleauth.ts#L87) interface of google-auth-library-node.js GitHub repo. 1. Official documentation is available in the [Vertex AI SDK Overview](https://cloud.google.com/vertex-ai/generative-ai/docs/reference/nodejs/latest/overview) page. From here, a complete list of documentation on classes, interfaces, and enums are available. ## Install the SDK Install the Vertex AI SDK for Node.js by running the following command: ```shell npm install @google-cloud/vertexai ``` ## Initialize the `VertexAI` class To use the Vertex AI SDK for Node.js, create an instance of `VertexAI` by passing it your Google Cloud project ID and location. Then create an instance of the GenerativeModel class using the VertexAI class methods. ```javascript const { FunctionDeclarationSchemaType, HarmBlockThreshold, HarmCategory, VertexAI } = require('@google-cloud/vertexai'); const project = 'your-cloud-project'; const location = 'us-central1'; const textModel = 'gemini-1.5-flash'; const visionModel = 'gemini-1.5-flash'; const vertexAI = new VertexAI({project: project, location: location}); // Instantiate Gemini models const generativeModel = vertexAI.getGenerativeModel({ model: textModel, // The following parameters are optional // They can also be passed to individual content generation requests safetySettings: [{category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE}], generationConfig: {maxOutputTokens: 256}, systemInstruction: { role: 'system', parts: [{"text": `For example, you are a helpful customer service agent.`}] }, }); const generativeVisionModel = vertexAI.getGenerativeModel({ model: visionModel, }); const generativeModelPreview = vertexAI.preview.getGenerativeModel({ model: textModel, }); ``` ## Send text prompt requests You can send text prompt requests by using `generateContentStream` for streamed responses, or `generateContent` for nonstreamed responses. ### Get streamed text responses The response is returned in chunks as it's being generated to reduce the perception of latency to a human reader. ```typescript async function streamGenerateContent() { const request = { contents: [{role: 'user', parts: [{text: 'How are you doing today?'}]}], }; const streamingResult = await generativeModel.generateContentStream(request); for await (const item of streamingResult.stream) { console.log('stream chunk: ', JSON.stringify(item)); } const aggregatedResponse = await streamingResult.response; console.log('aggregated response: ', JSON.stringify(aggregatedResponse)); }; streamGenerateContent(); ``` ### Get nonstreamed text responses The response is returned all at once. ```javascript async function generateContent() { const request = { contents: [{role: 'user', parts: [{text: 'How are you doing today?'}]}], }; const result = await generativeModel.generateContent(request); const response = result.response; console.log('Response: ', JSON.stringify(response)); }; generateContent(); ``` ## Send multiturn chat requests Chat requests use previous messages as context when responding to new prompts. To send multiturn chat requests, use `sendMessageStream` for streamed responses, or `sendMessage` for nonstreamed responses. ### Get streamed chat responses The response is returned in chunks as it's being generated to reduce the perception of latency to a human reader. ```javascript async function streamChat() { const chat = generativeModel.startChat(); const chatInput = "How can I learn more about Node.js?"; const result = await chat.sendMessageStream(chatInput); for await (const item of result.stream) { console.log("Stream chunk: ", item.candidates[0].content.parts[0].text); } const aggregatedResponse = await result.response; console.log('Aggregated response: ', JSON.stringify(aggregatedResponse)); } streamChat(); ``` ### Get nonstreamed chat responses The response is returned all at once. ```javascript async function sendChat() { const chat = generativeModel.startChat(); const chatInput = "How can I learn more about Node.js?"; const result = await chat.sendMessage(chatInput); const response = result.response; console.log('response: ', JSON.stringify(response)); } sendChat(); ``` ## Include images or videos in your prompt request Prompt requests can include either an image or video in addition to text. For more information, see [Send multimodal prompt requests](https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/send-multimodal-prompts) in the Vertex AI documentation. ### Include an image You can include images in the prompt either by specifying the Cloud Storage URI where the image is located or by including a base64 encoding of the image. #### Specify a Cloud Storage URI of the image You can specify the Cloud Storage URI of the image in `fileUri`. ```javascript async function multiPartContent() { const filePart = {fileData: {fileUri: "gs://generativeai-downloads/images/scones.jpg", mimeType: "image/jpeg"}}; const textPart = {text: 'What is this picture about?'}; const request = { contents: [{role: 'user', parts: [textPart, filePart]}], }; const streamingResult = await generativeVisionModel.generateContentStream(request); for await (const item of streamingResult.stream) { console.log('stream chunk: ', JSON.stringify(item)); } const aggregatedResponse = await streamingResult.response; console.log(aggregatedResponse.candidates[0].content); } multiPartContent(); ``` #### Specify a base64 image encoding string You can specify the base64 image encoding string in `data`. ```javascript async function multiPartContentImageString() { // Replace this with your own base64 image string const base64Image = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg=='; const filePart = {inline_data: {data: base64Image, mimeType: 'image/jpeg'}}; const textPart = {text: 'What is this picture about?'}; const request = { contents: [{role: 'user', parts: [textPart, filePart]}], }; const streamingResult = await generativeVisionModel.generateContentStream(request); const contentResponse = await streamingResult.response; console.log(contentResponse.candidates[0].content.parts[0].text); } multiPartContentImageString(); ``` ### Include a video You can include videos in the prompt by specifying the Cloud Storage URI where the video is located in `fileUri`. ```javascript async function multiPartContentVideo() { const filePart = {fileData: {fileUri: 'gs://cloud-samples-data/video/animals.mp4', mimeType: 'video/mp4'}}; const textPart = {text: 'What is in the video?'}; const request = { contents: [{role: 'user', parts: [textPart, filePart]}], }; const streamingResult = await generativeVisionModel.generateContentStream(request); for await (const item of streamingResult.stream) { console.log('stream chunk: ', JSON.stringify(item)); } const aggregatedResponse = await streamingResult.response; console.log(aggregatedResponse.candidates[0].content); } multiPartContentVideo(); ``` ## Function calling The Vertex AI SDK for Node.js supports [function calling](https://cloud.google.com/vertex-ai/docs/generative-ai/multimodal/function-calling) in the `sendMessage`, `sendMessageStream`, `generateContent`, and `generateContentStream` methods. We recommend using it through the chat methods (`sendMessage` or `sendMessageStream`) but have included examples of both approaches below. ### Declare a function The following examples show you how to declare a function. ```javascript const functionDeclarations = [ { functionDeclarations: [ { name: "get_current_weather", description: 'get weather in a given location', parameters: { type: FunctionDeclarationSchemaType.OBJECT, properties: { location: {type: FunctionDeclarationSchemaType.STRING}, unit: { type: FunctionDeclarationSchemaType.STRING, enum: ['celsius', 'fahrenheit'], }, }, required: ['location'], }, }, ], }, ]; const functionResponseParts = [ { functionResponse: { name: "get_current_weather", response: {name: "get_current_weather", content: {weather: "super nice"}}, }, }, ]; ``` ### Function calling using `sendMessageStream` After the function is declared, you can pass it to the model in the `tools` parameter of the prompt request. ```javascript async function functionCallingChat() { // Create a chat session and pass your function declarations const chat = generativeModel.startChat({ tools: functionDeclarations, }); const chatInput1 = 'What is the weather in Boston?'; // This should include a functionCall response from the model const streamingResult1 = await chat.sendMessageStream(chatInput1); for await (const item of streamingResult1.stream) { console.log(item.candidates[0]); } const response1 = await streamingResult1.response; console.log("first aggregated response: ", JSON.stringify(response1)); // Send a follow up message with a FunctionResponse const streamingResult2 = await chat.sendMessageStream(functionResponseParts); for await (const item of streamingResult2.stream) { console.log(item.candidates[0]); } // This should include a text response from the model using the response content // provided above const response2 = await streamingResult2.response; console.log("second aggregated response: ", JSON.stringify(response2)); } functionCallingChat(); ``` ### Function calling using `generateContentStream` ```javascript async function functionCallingGenerateContentStream() { const request = { contents: [ {role: 'user', parts: [{text: 'What is the weather in Boston?'}]}, {role: 'model', parts: [{functionCall: {name: 'get_current_weather', args: {'location': 'Boston'}}}]}, {role: 'user', parts: functionResponseParts} ], tools: functionDeclarations, }; const streamingResult = await generativeModel.generateContentStream(request); for await (const item of streamingResult.stream) { console.log(item.candidates[0]); } } functionCallingGenerateContentStream(); ``` ## Counting tokens ```javascript async function countTokens() { const request = { contents: [{role: 'user', parts: [{text: 'How are you doing today?'}]}], }; const response = await generativeModel.countTokens(request); console.log('count tokens response: ', JSON.stringify(response)); } countTokens(); ``` ## Grounding (Preview) Grounding is preview only feature. Grounding lets you connect model output to verifiable sources of information to reduce hallucination. You can specify Google Search or Vertex AI search as the data source for grounding. ### Grounding using Google Search (Preview) ```javascript async function generateContentWithGoogleSearchGrounding() { const generativeModelPreview = vertexAI.preview.getGenerativeModel({ model: textModel, // The following parameters are optional // They can also be passed to individual content generation requests safetySettings: [{category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE}], generationConfig: {maxOutputTokens: 256}, }); const googleSearchRetrievalTool = { googleSearchRetrieval: { disableAttribution: false, }, }; const result = await generativeModelPreview.generateContent({ contents: [{role: 'user', parts: [{text: 'Why is the sky blue?'}]}], tools: [googleSearchRetrievalTool], }) const response = result.response; const groundingMetadata = response.candidates[0].groundingMetadata; console.log("GroundingMetadata is: ", JSON.stringify(groundingMetadata)); } generateContentWithGoogleSearchGrounding(); ``` ### Grounding using Vertex AI Search (Preview) ```javascript async function generateContentWithVertexAISearchGrounding() { const generativeModelPreview = vertexAI.preview.getGenerativeModel({ model: textModel, // The following parameters are optional // They can also be passed to individual content generation requests safetySettings: [{category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE}], generationConfig: {maxOutputTokens: 256}, }); const vertexAIRetrievalTool = { retrieval: { vertexAiSearch: { datastore: 'projects/.../locations/.../collections/.../dataStores/...', }, disableAttribution: false, }, }; const result = await generativeModelPreview.generateContent({ contents: [{role: 'user', parts: [{text: 'Why is the sky blue?'}]}], tools: [vertexAIRetrievalTool], }) const response = result.response; const groundingMetadata = response.candidates[0].groundingMetadata; console.log("Grounding metadata is: ", JSON.stringify(groundingMetadata)); } generateContentWithVertexAISearchGrounding(); ``` ## System Instruction You can include an optional system instruction when instantiating a generative model to provide additional context to the model. The system instruction can also be passed to individual text prompt requests. ### Include system instruction in generative model instantiation ```javascript const generativeModel = vertexAI.getGenerativeModel({ model: textModel, // The following parameter is optional. systemInstruction: { role: 'system', parts: [{"text": `For example, you are a helpful customer service agent.`}] }, }); ``` ### Include system instruction in text prompt request ```javascript async function generateContent() { const request = { contents: [{role: 'user', parts: [{text: 'How are you doing today?'}]}], systemInstruction: { role: 'system', parts: [{ text: `For example, you are a helpful customer service agent.` }] }, }; const result = await generativeModel.generateContent(request); const response = result.response; console.log('Response: ', JSON.stringify(response)); }; generateContent(); ``` ## FAQ ### What if I want to specify authentication options instead of using default options? **Step1**: Find a list of accepted authentication options in [GoogleAuthOptions](https://github.com/googleapis/google-auth-library-nodejs/blob/3ae120d0a45c95e36c59c9ac8286483938781f30/src/auth/googleauth.ts#L87) interface of google-auth-library-node.js GitHub repo. **Step2:** Instantiate the `VertexAI` class by passing in the `GoogleAuthOptions` interface as follows: ```javascript const { VertexAI } = require('@google-cloud/vertexai'); const { GoogleAuthOptions } = require('google-auth-library'); const vertexAI = new VertexAI( { googleAuthOptions: { // your GoogleAuthOptions interface } } ) ``` ## License The contents of this repository are licensed under the [Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). ================================================ FILE: vertexai/package.json ================================================ { "name": "@google-cloud/vertexai", "description": "Vertex Generative AI client for Node.js", "version": "1.12.0", "license": "Apache-2.0", "author": "Google LLC", "engines": { "node": ">=20.0.0" }, "homepage": "https://github.com/googleapis/nodejs-vertexai", "repository": "googleapis/nodejs-vertexai", "main": "build/src/index.js", "type": "commonjs", "scripts": { "clean": "gts clean", "compile": "tsc -p .", "docs": "jsdoc -c .jsdoc.js", "predocs-test": "npm run docs", "docs-test": "linkinator docs", "compile:oss": "tsc -p tsconfig.json.oss", "fix": "gts fix", "test": "npm run test:unit", "test:unit": "jasmine build/test/unit/*_test.js --reporter=test/spec/reporter.js", "test:system": "jasmine build/system_test/*_test.js --reporter=test/spec/reporter.js", "test:replays": "jasmine build/test/replays/*_test.js --reporter=test/spec/reporter.js", "lint": "ESLINT_USE_FLAT_CONFIG=true eslint src --no-ignore --config src/eslint.config.mjs", "format": "prettier 'src/**/*.ts' 'src/**/*.mjs' --write", "clean-js-files": "find . -type f -name \"*.js\" -exec rm -f {} +", "clean-js-map-files": "find . -type f -name \"*.js.map\" -exec rm -f {} +", "postpack": "if [ \"${CLEAN}\" ]; then npm run clean-after-pack; fi", "cover": "npm run cover:unit && npm run cover:integration && npm run cover:report", "cover:unit": "nyc npm run test", "cover:integration": "nyc --no-clean npm run test:system", "cover:report": "nyc report --reporter=lcov", "prepare": "npm run compile", "pretest": "npm run compile", "posttest": "npm run lint" }, "dependencies": { "@google/genai": "^1.45.0", "google-auth-library": "^9.1.0" }, "devDependencies": { "@eslint/js": "9.20.0", "@types/jasmine": "^5.1.2", "@types/node": "^20.9.0", "eslint": "8.57.0", "gts": "^5.2.0", "jasmine": "^5.1.0", "jasmine-reporters": "^2.4.0", "jsdoc": "^4.0.0", "jsdoc-fresh": "^3.0.0", "jsdoc-region-tag": "^3.0.0", "linkinator": "^4.0.0", "nyc": "^15.1.0", "prettier": "3.3.3", "prettier-plugin-organize-imports": "^4.1.0", "typescript": "~5.4.0", "typescript-eslint": "8.24.1" }, "files": [ "build/src", "build/vertexai/src", "!build/**/*.map" ] } ================================================ FILE: vertexai/src/functions/count_tokens.ts ================================================ /** * @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. */ import { CountTokensRequest, CountTokensResponse, RequestOptions, } from '../types/content'; import {GoogleGenerativeAIError} from '../types/errors'; import * as constants from '../util/constants'; import { throwErrorIfNotOK, processCountTokenResponse, } from './post_fetch_processing'; import {postRequest} from './post_request'; /** * Make a async request to count tokens. * @param request A CountTokensRequest object with the request contents. * @returns The CountTokensResponse object with the token count. */ export async function countTokens( location: string, resourcePath: string, token: Promise, request: CountTokensRequest, apiEndpoint?: string, requestOptions?: RequestOptions ): Promise { const response: Response | undefined = await postRequest({ region: location, resourcePath: resourcePath, resourceMethod: constants.COUNT_TOKENS_METHOD, token: await token, data: request, apiEndpoint: apiEndpoint, requestOptions: requestOptions, }).catch(e => { throw new GoogleGenerativeAIError('exception posting request', e); }); await throwErrorIfNotOK(response).catch(e => { throw e; }); return processCountTokenResponse(response); } ================================================ FILE: vertexai/src/functions/generate_content.ts ================================================ /** * @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. */ import { GenerateContentRequest, GenerateContentResult, GenerationConfig, RequestOptions, SafetySetting, StreamGenerateContentResult, Tool, } from '../types/content'; import {GoogleGenerativeAIError} from '../types/errors'; import {ToolConfig} from '../types/tool'; import * as constants from '../util/constants'; import { processUnary, processStream, throwErrorIfNotOK, } from './post_fetch_processing'; import {postRequest} from './post_request'; import { formatContentRequest, validateGenerateContentRequest, validateGenerationConfig, hasVertexRagStore, getApiVersion, } from './pre_fetch_processing'; /** * Make a async call to generate content. * @param request A GenerateContentRequest object with the request contents. * @returns The GenerateContentResponse object with the response candidates. */ export async function generateContent( location: string, resourcePath: string, token: Promise, request: GenerateContentRequest | string, apiEndpoint?: string, generationConfig?: GenerationConfig, safetySettings?: SafetySetting[], tools?: Tool[], toolConfig?: ToolConfig, requestOptions?: RequestOptions ): Promise { request = formatContentRequest(request, generationConfig, safetySettings); validateGenerateContentRequest(request); if (request.generationConfig) { request.generationConfig = validateGenerationConfig( request.generationConfig ); } const generateContentRequest: GenerateContentRequest = { contents: request.contents, systemInstruction: request.systemInstruction, cachedContent: request.cachedContent, generationConfig: request.generationConfig ?? generationConfig, safetySettings: request.safetySettings ?? safetySettings, tools: request.tools ?? tools, toolConfig: request.toolConfig ?? toolConfig, labels: request.labels, }; const response: Response | undefined = await postRequest({ region: location, resourcePath, resourceMethod: constants.GENERATE_CONTENT_METHOD, token: await token, data: generateContentRequest, apiEndpoint, requestOptions, apiVersion: getApiVersion(request), }).catch(e => { throw new GoogleGenerativeAIError('exception posting request to model', e); }); await throwErrorIfNotOK(response).catch(e => { throw e; }); return processUnary(response); } /** * Make an async stream request to generate content. The response will be * returned in stream. * @param {GenerateContentRequest} request - {@link GenerateContentRequest} * @returns {Promise} Promise of {@link * StreamGenerateContentResult} */ export async function generateContentStream( location: string, resourcePath: string, token: Promise, request: GenerateContentRequest | string, apiEndpoint?: string, generationConfig?: GenerationConfig, safetySettings?: SafetySetting[], tools?: Tool[], toolConfig?: ToolConfig, requestOptions?: RequestOptions ): Promise { request = formatContentRequest(request, generationConfig, safetySettings); validateGenerateContentRequest(request); if (request.generationConfig) { request.generationConfig = validateGenerationConfig( request.generationConfig ); } const generateContentRequest: GenerateContentRequest = { contents: request.contents, systemInstruction: request.systemInstruction, cachedContent: request.cachedContent, generationConfig: request.generationConfig ?? generationConfig, safetySettings: request.safetySettings ?? safetySettings, tools: request.tools ?? tools, toolConfig: request.toolConfig ?? toolConfig, labels: request.labels, }; const response = await postRequest({ region: location, resourcePath, resourceMethod: constants.STREAMING_GENERATE_CONTENT_METHOD, token: await token, data: generateContentRequest, apiEndpoint, requestOptions, apiVersion: getApiVersion(request), }).catch(e => { throw new GoogleGenerativeAIError('exception posting request', e); }); await throwErrorIfNotOK(response).catch(e => { throw e; }); return processStream(response); } ================================================ FILE: vertexai/src/functions/index.ts ================================================ /** * @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. */ export {countTokens} from './count_tokens'; export {postRequest} from './post_request'; export {generateContent, generateContentStream} from './generate_content'; ================================================ FILE: vertexai/src/functions/post_fetch_processing.ts ================================================ /** * @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. */ import { CitationMetadata, Content, CountTokensResponse, GenerateContentCandidate, GenerateContentResponse, GenerateContentResult, GroundingMetadata, StreamGenerateContentResult, } from '../types/content'; import {constants} from '../util'; import { ClientError, GoogleApiError, GoogleGenerativeAIError, } from '../types/errors'; export async function throwErrorIfNotOK(response: Response | undefined) { if (response === undefined) { throw new GoogleGenerativeAIError('response is undefined'); } if (!response.ok) { const status: number = response.status; const statusText: string = response.statusText; const errorBody = await response.json(); const errorMessage = `got status: ${status} ${statusText}. ${JSON.stringify( errorBody )}`; if (status >= 400 && status < 500) { const error = new ClientError( errorMessage, new GoogleApiError( errorBody.error.message, errorBody.error.code, errorBody.error.status, errorBody.error.details ) ); throw error; } throw new GoogleGenerativeAIError(errorMessage); } } const responseLineRE = /^data: (.*)(?:\n\n|\r\r|\r\n\r\n)/; async function* generateResponseSequence( stream: ReadableStream ): AsyncGenerator { const reader = stream.getReader(); while (true) { const {value, done} = await reader.read(); if (done) { break; } yield addMissingIndexAndRole(value); } } /** * Process a response.body stream from the backend and return an * iterator that provides one complete GenerateContentResponse at a time * and a promise that resolves with a single aggregated * GenerateContentResponse. * * @param response - Response from a fetch call * @ignore */ export async function processStream( response: Response | undefined ): Promise { if (response === undefined) { throw new GoogleGenerativeAIError( 'Error processing stream because response === undefined' ); } if (!response.body) { throw new GoogleGenerativeAIError( 'Error processing stream because response.body not found' ); } const inputStream = response.body!.pipeThrough( new TextDecoderStream('utf8', {fatal: true}) ); const responseStream = getResponseStream( inputStream ) as ReadableStream; const [stream1, stream2] = responseStream.tee(); return Promise.resolve({ stream: generateResponseSequence(stream1), response: getResponsePromise(stream2), }); } async function getResponsePromise( stream: ReadableStream ): Promise { const allResponses: GenerateContentResponse[] = []; const reader = stream.getReader(); // eslint-disable-next-line no-constant-condition while (true) { const {done, value} = await reader.read(); if (done) { return aggregateResponses(allResponses); } allResponses.push(value); } } /** * Reads a raw stream from the fetch response and join incomplete * chunks, returning a new stream that provides a single complete * GenerateContentResponse in each iteration. * @ignore */ function getResponseStream( inputStream: ReadableStream ): ReadableStream { const reader = inputStream.getReader(); const stream = new ReadableStream({ start(controller) { let currentText = ''; return pump(); function pump(): Promise<(() => Promise) | undefined> { return reader.read().then(({value, done}) => { if (done) { if (currentText.trim()) { controller.error( new GoogleGenerativeAIError( `Failed to parse final chunk of stream: ${currentText}` ) ); return; } controller.close(); return; } currentText += value; let match = currentText.match(responseLineRE); let parsedResponse: unknown; while (match) { try { parsedResponse = JSON.parse(match[1]); } catch (e) { controller.error( new GoogleGenerativeAIError( `Error parsing JSON response from stream chunk: "${match[1]}"` ) ); return; } controller.enqueue(parsedResponse); currentText = currentText.substring(match[0].length); match = currentText.match(responseLineRE); } return pump(); }); } }, }); return stream; } /** * Aggregates an array of `GenerateContentResponse`s into a single * GenerateContentResponse. * @ignore * @VisibleForTesting */ export function aggregateResponses( responses: GenerateContentResponse[] ): GenerateContentResponse { const lastResponse = responses[responses.length - 1]; if (lastResponse === undefined) { throw new GoogleGenerativeAIError( 'Error aggregating stream chunks because the final response in stream chunk is undefined' ); } const aggregatedResponse: GenerateContentResponse = {}; if (lastResponse.promptFeedback) { aggregatedResponse.promptFeedback = lastResponse.promptFeedback; } if (lastResponse.usageMetadata) { aggregatedResponse.usageMetadata = lastResponse.usageMetadata; } for (const response of responses) { if (!response.candidates || response.candidates.length === 0) { continue; } for (let i = 0; i < response.candidates.length; i++) { if (!aggregatedResponse.candidates) { aggregatedResponse.candidates = []; } if (!aggregatedResponse.candidates[i]) { aggregatedResponse.candidates[i] = { index: response.candidates[i].index ?? i, content: { role: response.candidates[i].content?.role ?? constants.MODEL_ROLE, parts: [{text: ''}], }, } as GenerateContentCandidate; } const citationMetadataAggregated: CitationMetadata | undefined = aggregateCitationMetadataForCandidate( response.candidates[i], aggregatedResponse.candidates[i] ); if (citationMetadataAggregated) { aggregatedResponse.candidates[i].citationMetadata = citationMetadataAggregated; } const finishResonOfChunk = response.candidates[i].finishReason; if (finishResonOfChunk) { aggregatedResponse.candidates[i].finishReason = response.candidates[i].finishReason; } const finishMessageOfChunk = response.candidates[i].finishMessage; if (finishMessageOfChunk) { aggregatedResponse.candidates[i].finishMessage = finishMessageOfChunk; } const safetyRatingsOfChunk = response.candidates[i].safetyRatings; if (safetyRatingsOfChunk) { aggregatedResponse.candidates[i].safetyRatings = safetyRatingsOfChunk; } if ( response.candidates[i].content && response.candidates[i].content.parts && response.candidates[i].content.parts.length > 0 ) { const {parts} = aggregatedResponse.candidates[i].content; for (const part of response.candidates[i].content.parts) { // NOTE: cannot have text and functionCall both in the same part. // add functionCall(s) to new parts. if (part.text) { parts[0].text += part.text; } if (part.functionCall) { parts.push({functionCall: part.functionCall}); } } } const groundingMetadataAggregated: GroundingMetadata | undefined = aggregateGroundingMetadataForCandidate( response.candidates[i], aggregatedResponse.candidates[i] ); if (groundingMetadataAggregated) { aggregatedResponse.candidates[i].groundingMetadata = groundingMetadataAggregated; } } } if (aggregatedResponse.candidates?.length) { aggregatedResponse.candidates.forEach(candidate => { if ( candidate.content.parts.length > 1 && candidate.content.parts[0].text === '' ) { candidate.content.parts.shift(); // remove empty text parameter } }); } return aggregatedResponse; } function aggregateCitationMetadataForCandidate( candidateChunk: GenerateContentCandidate, aggregatedCandidate: GenerateContentCandidate ): CitationMetadata | undefined { if (!candidateChunk.citationMetadata) { return; } const emptyCitationMetadata: CitationMetadata = { citations: [], }; const citationMetadataAggregated: CitationMetadata = aggregatedCandidate.citationMetadata ?? emptyCitationMetadata; const citationMetadataChunk: CitationMetadata = candidateChunk.citationMetadata!; if (citationMetadataChunk.citations) { citationMetadataAggregated.citations = citationMetadataAggregated.citations!.concat( citationMetadataChunk.citations ); } return citationMetadataAggregated; } function aggregateGroundingMetadataForCandidate( candidateChunk: GenerateContentCandidate, aggregatedCandidate: GenerateContentCandidate ): GroundingMetadata | undefined { if (!candidateChunk.groundingMetadata) { return; } const emptyGroundingMetadata: GroundingMetadata = { webSearchQueries: [], retrievalQueries: [], groundingChunks: [], groundingSupports: [], }; const groundingMetadataAggregated: GroundingMetadata = aggregatedCandidate.groundingMetadata ?? emptyGroundingMetadata; const groundingMetadataChunk: GroundingMetadata = candidateChunk.groundingMetadata!; if (groundingMetadataChunk.webSearchQueries) { groundingMetadataAggregated.webSearchQueries = groundingMetadataAggregated.webSearchQueries!.concat( groundingMetadataChunk.webSearchQueries ); } if (groundingMetadataChunk.retrievalQueries) { groundingMetadataAggregated.retrievalQueries = groundingMetadataAggregated.retrievalQueries!.concat( groundingMetadataChunk.retrievalQueries ); } if (groundingMetadataChunk.groundingChunks) { groundingMetadataAggregated.groundingChunks = groundingMetadataAggregated.groundingChunks!.concat( groundingMetadataChunk.groundingChunks ); } if (groundingMetadataChunk.groundingSupports) { groundingMetadataAggregated.groundingSupports = groundingMetadataAggregated.groundingSupports!.concat( groundingMetadataChunk.groundingSupports ); } if (groundingMetadataChunk.searchEntryPoint) { groundingMetadataAggregated.searchEntryPoint = groundingMetadataChunk.searchEntryPoint; } return groundingMetadataAggregated; } function addMissingIndexAndRole( response: GenerateContentResponse ): GenerateContentResponse { const generateContentResponse = response as GenerateContentResponse; if ( generateContentResponse.candidates && generateContentResponse.candidates.length > 0 ) { generateContentResponse.candidates.forEach((candidate, index) => { if (candidate.index === undefined) { generateContentResponse.candidates![index].index = index; } if (candidate.content === undefined) { generateContentResponse.candidates![index].content = {} as Content; } if (candidate.content.role === undefined) { generateContentResponse.candidates![index].content.role = constants.MODEL_ROLE; } }); } return generateContentResponse; } /** * Process model responses from generateContent * @ignore */ export async function processUnary( response: Response | undefined ): Promise { if (response !== undefined) { // ts-ignore const responseJson = await response.json(); const generateContentResponse = addMissingIndexAndRole(responseJson); return Promise.resolve({ response: generateContentResponse, }); } return Promise.resolve({ response: {} as GenerateContentResponse, }); } /** * Process model responses from countTokens * @ignore */ export async function processCountTokenResponse( response: Response | undefined ): Promise { if (response) { // ts-ignore return response.json(); } return Promise.resolve({} as CountTokensResponse); } ================================================ FILE: vertexai/src/functions/post_request.ts ================================================ /** * @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. */ const API_BASE_PATH = 'aiplatform.googleapis.com'; const GOOGLE_INTERNAL_ENDPOINT = 'googleapis.com'; const AUTHORIZATION_HEADER = 'Authorization'; const CONTENT_TYPE_HEADER = 'Content-Type'; const USER_AGENT_HEADER = 'User-Agent'; const X_GOOG_API_CLIENT_HEADER = 'X-Goog-Api-Client'; const SERVER_RESERVED_HEADERS = [AUTHORIZATION_HEADER, CONTENT_TYPE_HEADER]; import { GenerateContentRequest, CountTokensRequest, RequestOptions, } from '../types/content'; import {ClientError} from '../types/errors'; import * as constants from '../util/constants'; /** * Makes a POST request to a Vertex service * @ignore */ export async function postRequest({ region, resourcePath, resourceMethod, token, data, apiEndpoint, requestOptions, apiVersion = 'v1', }: { region: string; resourcePath: string; resourceMethod: string; token: string | null | undefined; data: GenerateContentRequest | CountTokensRequest; apiEndpoint?: string; requestOptions?: RequestOptions; apiVersion?: string; }): Promise { const vertexBaseEndpoint = apiEndpoint ?? `${region}-${API_BASE_PATH}`; let vertexEndpoint = `https://${vertexBaseEndpoint}/${apiVersion}/${resourcePath}:${resourceMethod}`; // Use server sent events for streamGenerateContent if (resourceMethod === constants.STREAMING_GENERATE_CONTENT_METHOD) { vertexEndpoint += '?alt=sse'; } const necessaryHeaders = new Headers({ [AUTHORIZATION_HEADER]: `Bearer ${token}`, [CONTENT_TYPE_HEADER]: 'application/json', [USER_AGENT_HEADER]: constants.USER_AGENT, }); const totalHeaders: Headers = getExtraHeaders( vertexBaseEndpoint, necessaryHeaders, requestOptions ); return fetch(vertexEndpoint, { ...getFetchOptions(requestOptions), method: 'POST', headers: totalHeaders, body: JSON.stringify(data), }); } function getFetchOptions(requestOptions?: RequestOptions): RequestInit { const fetchOptions = {} as RequestInit; if ( !requestOptions || requestOptions.timeout === undefined || requestOptions.timeout < 0 ) { return fetchOptions; } const abortController = new AbortController(); const signal = abortController.signal; setTimeout(() => abortController.abort(), requestOptions.timeout); fetchOptions.signal = signal; return fetchOptions; } function stringHasLineBreak(header?: string | null): boolean { if (header === null || header === undefined) { return false; } return header.includes('\n') || header.includes('\r'); } function headersHasLineBreak(customHeaders?: Headers): boolean { if (!customHeaders) { return false; } for (const [key, value] of customHeaders.entries()) { if (stringHasLineBreak(key) || stringHasLineBreak(value)) { return true; } } return false; } function getExtraHeaders( vertexBaseEndpoint: string, necessaryHeaders: Headers, requestOptions?: RequestOptions ): Headers { if (stringHasLineBreak(requestOptions?.apiClient)) { throw new ClientError( 'Found line break in apiClient request option field, please remove ' + 'the line break and try again.' ); } if (headersHasLineBreak(requestOptions?.customHeaders)) { throw new ClientError( 'Found line break in customerHeaders request option field, please remove ' + 'the line break and try again.' ); } const totalHeaders: Headers = new Headers(necessaryHeaders); const customHeaders = requestOptions?.customHeaders ?? new Headers(); for (const [key, val] of customHeaders.entries()) { totalHeaders.append(key, val); } if (requestOptions?.apiClient) { totalHeaders.append(X_GOOG_API_CLIENT_HEADER, requestOptions?.apiClient); } // Resolve header conflicts. let goldenHeaders: Headers; if (vertexBaseEndpoint.endsWith(GOOGLE_INTERNAL_ENDPOINT)) { goldenHeaders = necessaryHeaders; } else { goldenHeaders = customHeaders; } for (const header of SERVER_RESERVED_HEADERS) { if (goldenHeaders.has(header)) { totalHeaders.set(header, goldenHeaders.get(header)!); } } return totalHeaders; } ================================================ FILE: vertexai/src/functions/pre_fetch_processing.ts ================================================ /** * @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. */ import { GenerateContentRequest, GenerationConfig, RetrievalTool, SafetySetting, Tool, } from '../types/content'; import {ClientError} from '../types/errors'; import * as constants from '../util/constants'; export function formatContentRequest( request: GenerateContentRequest | string, generationConfig?: GenerationConfig, safetySettings?: SafetySetting[] ): GenerateContentRequest { if (typeof request === 'string') { return { contents: [{role: constants.USER_ROLE, parts: [{text: request}]}], generationConfig: generationConfig, safetySettings: safetySettings, }; } else { return request; } } export function validateGenerateContentRequest( request: GenerateContentRequest ) { if (hasVertexAISearch(request) && hasVertexRagStore(request)) { throw new ClientError( 'Found both vertexAiSearch and vertexRagStore field are set in tool. Either set vertexAiSearch or vertexRagStore.' ); } } export function validateGenerationConfig( generationConfig: GenerationConfig ): GenerationConfig { if ('topK' in generationConfig) { if (!(generationConfig.topK! > 0) || !(generationConfig.topK! <= 40)) { delete generationConfig.topK; } } return generationConfig; } export function getApiVersion( request: GenerateContentRequest ): 'v1' | 'v1beta1' { return hasVertexRagStore(request) || hasCachedContent(request) ? 'v1beta1' : 'v1'; } export function hasVertexRagStore(request: GenerateContentRequest): boolean { for (const tool of request?.tools ?? []) { const retrieval = (tool as RetrievalTool).retrieval; if (!retrieval) continue; if (retrieval.vertexRagStore) { return true; } } return false; } function hasCachedContent(request: GenerateContentRequest): boolean { return !!request.cachedContent; } export function hasVertexAISearch(request: GenerateContentRequest): boolean { for (const tool of request?.tools ?? []) { const retrieval = (tool as RetrievalTool).retrieval; if (!retrieval) continue; if (retrieval.vertexAiSearch) { return true; } } return false; } ================================================ FILE: vertexai/src/functions/test/functions_test.ts ================================================ /** * @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. */ import { ClientError, CountTokensRequest, FinishReason, FunctionDeclarationSchemaType, GenerateContentRequest, GenerateContentResponse, GenerateContentResponseHandler, GenerateContentResult, GoogleApiError, HarmBlockThreshold, HarmCategory, HarmProbability, RequestOptions, SafetyRating, SafetySetting, StreamGenerateContentResult, Tool, ToolConfig, } from '../../types'; import {constants} from '../../util'; import {countTokens} from '../count_tokens'; import {generateContent, generateContentStream} from '../generate_content'; import * as StreamFunctions from '../post_fetch_processing'; const TEST_LOCATION = 'test-location'; const TEST_RESOURCE_PATH = 'test-resource-path'; const TEST_TOKEN = 'testtoken'; const TEST_TOKEN_PROMISE = Promise.resolve(TEST_TOKEN); const TEST_API_ENDPOINT = 'test-api-endpoint'; const TEST_CHAT_MESSAGE_TEXT = 'How are you doing today?'; const TEST_USER_CHAT_MESSAGE = [ {role: constants.USER_ROLE, parts: [{text: TEST_CHAT_MESSAGE_TEXT}]}, ]; const CONTENTS = [ { role: 'user', parts: [{text: 'What is the weater like in Boston?'}], }, ]; const TEST_USER_CHAT_MESSAGE_WITH_GCS_FILE = [ { role: constants.USER_ROLE, parts: [ {text: TEST_CHAT_MESSAGE_TEXT}, { fileData: { fileUri: 'gs://test_bucket/test_image.jpeg', mimeType: 'image/jpeg', }, }, ], }, ]; const TEST_USER_CHAT_MESSAGE_WITH_INVALID_GCS_FILE = [ { role: constants.USER_ROLE, parts: [ {text: TEST_CHAT_MESSAGE_TEXT}, {fileData: {fileUri: 'test_image.jpeg', mimeType: 'image/jpeg'}}, ], }, ]; const TEST_SAFETY_SETTINGS: SafetySetting[] = [ { category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH, }, ]; const TEST_REQUEST_OPTIONS: RequestOptions = { timeout: 0, }; const TEST_SAFETY_RATINGS: SafetyRating[] = [ { category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, probability: HarmProbability.NEGLIGIBLE, }, ]; const TEST_GENERATION_CONFIG = { candidateCount: 1, stopSequences: ['hello'], }; const TEST_CANDIDATES = [ { index: 1, content: { role: constants.MODEL_ROLE, parts: [{text: 'Im doing great! How are you?'}], }, finishReason: 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_MODEL_RESPONSE = { candidates: TEST_CANDIDATES, usageMetadata: {promptTokenCount: 0, candidatesTokenCount: 0}, }; const TEST_CANDIDATE_WITH_INVALID_DATA = [ { index: 1, content: { role: constants.MODEL_ROLE, parts: [], }, }, ]; const TEST_MODEL_RESPONSE_WITH_INVALID_DATA = { candidates: TEST_CANDIDATE_WITH_INVALID_DATA, }; 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: constants.MODEL_ROLE, parts: [TEST_FUNCTION_CALL_RESPONSE], }, finishReason: FinishReason.STOP, finishMessage: '', safetyRatings: TEST_SAFETY_RATINGS, }, ]; const TEST_MODEL_RESPONSE_WITH_FUNCTION_CALL = { candidates: TEST_CANDIDATES_WITH_FUNCTION_CALL, }; const TEST_ENDPOINT_BASE_PATH = 'test.googleapis.com'; const TEST_GCS_FILENAME = 'gs://test_bucket/test_image.jpeg'; const TEST_MULTIPART_MESSAGE = [ { role: 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: constants.USER_ROLE, parts: [{text: 'What is in this picture?'}, INLINE_DATA_FILE_PART], }, ]; const TEST_EMPTY_TOOLS: Tool[] = []; const TEST_EMPTY_TOOL_CONFIG: ToolConfig = {}; const TEST_TOOLS_WITH_FUNCTION_DECLARATION: Tool[] = [ { functionDeclarations: [ { name: 'get_current_weather', description: 'get weather in a given location', parameters: { type: FunctionDeclarationSchemaType.OBJECT, properties: { location: {type: FunctionDeclarationSchemaType.STRING}, unit: { type: FunctionDeclarationSchemaType.STRING, enum: ['celsius', 'fahrenheit'], }, }, required: ['location'], }, }, ], }, ]; const TEST_TOOLS_WITH_RAG: Tool[] = [ { retrieval: {vertexRagStore: {ragResources: [{ragCorpus: 'ragCorpus'}]}}, }, ]; const TEST_LABELS: Record = { test_key: 'test_value', }; const fetchResponseObj = { status: 200, statusText: 'OK', ok: true, headers: {'Content-Type': 'application/json'}, url: 'url', }; /** * Returns a generator, used to mock the generateContentStream response * @ignore */ export async function* testGenerator(): AsyncGenerator { yield { candidates: TEST_CANDIDATES, }; } function buildFetchResponse(body: any): Response { return new Response(JSON.stringify(body), fetchResponseObj); } describe('countTokens', () => { const req: CountTokensRequest = { contents: TEST_USER_CHAT_MESSAGE, }; let fetchSpy: jasmine.Spy; it('return expected response when OK', async () => { const expectedResponseBody = { totalTokens: 1, }; const response = new Response( JSON.stringify(expectedResponseBody), fetchResponseObj ); fetchSpy = spyOn(global, 'fetch').and.resolveTo(response); const resp = await countTokens( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, req, TEST_API_ENDPOINT ); expect(resp).toEqual(expectedResponseBody); }); it('request rejected when timeout', async () => { fetchSpy = spyOn(global, 'fetch').and.resolveTo({ ok: false, status: 500, statusText: 'AbortError', } as Response); await expectAsync( countTokens( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, req, TEST_API_ENDPOINT, TEST_REQUEST_OPTIONS ) ).toBeRejected(); expect(fetchSpy.calls.allArgs()[0][1].signal).toBeInstanceOf(AbortSignal); }); it('throw GoogleGenerativeError when not OK and not 4XX', async () => { 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); spyOn(global, 'fetch').and.resolveTo(response); await expectAsync( countTokens( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, req, TEST_API_ENDPOINT ) ).toBeRejected(); }); it('throw ClientError when not OK and 4XX', async () => { const fetch400Obj = { status: 400, statusText: 'Bad Request', ok: false, }; const body = { error: { code: 400, message: 'request is invalid', status: 'INVALID_ARGUMENT', }, }; const response = new Response(JSON.stringify(body), fetch400Obj); spyOn(global, 'fetch').and.resolveTo(response); let error: any; try { await countTokens( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, req, TEST_API_ENDPOINT ); } catch (e) { error = e; } expect(error).toBeInstanceOf(ClientError); expect(error.cause).toBeInstanceOf(GoogleApiError); expect(error.cause.code).toBe(400); expect(error.cause.status).toEqual('INVALID_ARGUMENT'); }); }); describe('generateContent', () => { let fetchSpy: jasmine.Spy; beforeEach(() => { fetchSpy = spyOn(global, 'fetch'); }); it('request rejected when timeout', async () => { const req: GenerateContentRequest = { contents: TEST_USER_CHAT_MESSAGE, }; fetchSpy.and.resolveTo({ ok: false, status: 500, statusText: 'AbortError', } as Response); await expectAsync( generateContent( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, req, TEST_API_ENDPOINT, TEST_GENERATION_CONFIG, TEST_SAFETY_SETTINGS, TEST_EMPTY_TOOLS, TEST_EMPTY_TOOL_CONFIG, TEST_REQUEST_OPTIONS ) ).toBeRejected(); expect(fetchSpy.calls.allArgs()[0][1].signal).toBeInstanceOf(AbortSignal); }); it('returns a GenerateContentResponse', async () => { const req: GenerateContentRequest = { contents: TEST_USER_CHAT_MESSAGE, }; const expectedResult: GenerateContentResult = { response: TEST_MODEL_RESPONSE, }; fetchSpy.and.resolveTo(buildFetchResponse(TEST_MODEL_RESPONSE)); const resp = await generateContent( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, req, TEST_API_ENDPOINT ); expect(resp).toEqual(expectedResult); }); it('returns a GenerateContentResponse when passed a string', async () => { const expectedResult: GenerateContentResult = { response: TEST_MODEL_RESPONSE, }; fetchSpy.and.resolveTo(buildFetchResponse(TEST_MODEL_RESPONSE)); const resp = await generateContent( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, TEST_CHAT_MESSAGE_TEXT, TEST_API_ENDPOINT ); expect(resp).toEqual(expectedResult); }); it('returns a GenerateContentResponse when passed a GCS URI', async () => { const req: GenerateContentRequest = { contents: TEST_USER_CHAT_MESSAGE_WITH_GCS_FILE, }; const expectedResult: GenerateContentResult = { response: TEST_MODEL_RESPONSE, }; fetchSpy.and.resolveTo(buildFetchResponse(TEST_MODEL_RESPONSE)); const resp = await generateContent( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, req, TEST_API_ENDPOINT ); expect(resp).toEqual(expectedResult); }); it('returns a GenerateContentResponse when passed safetySettings and generationConfig', async () => { const req: GenerateContentRequest = { contents: TEST_USER_CHAT_MESSAGE, safetySettings: TEST_SAFETY_SETTINGS, generationConfig: TEST_GENERATION_CONFIG, }; const expectedResult: GenerateContentResult = { response: TEST_MODEL_RESPONSE, }; fetchSpy.and.resolveTo(buildFetchResponse(TEST_MODEL_RESPONSE)); const resp = await generateContent( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, req, TEST_API_ENDPOINT ); expect(resp).toEqual(expectedResult); }); it('updates the base API endpoint when provided', async () => { const req: GenerateContentRequest = { contents: TEST_USER_CHAT_MESSAGE, }; fetchSpy.and.resolveTo(buildFetchResponse(TEST_MODEL_RESPONSE)); await generateContent( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, req, TEST_ENDPOINT_BASE_PATH ); expect(fetchSpy.calls.allArgs()[0][0].toString()).toContain( TEST_ENDPOINT_BASE_PATH ); }); it('removes topK when it is set to 0', async () => { const reqWithEmptyConfigs: GenerateContentRequest = { contents: TEST_USER_CHAT_MESSAGE_WITH_GCS_FILE, generationConfig: {topK: 0}, safetySettings: [], }; fetchSpy.and.resolveTo(buildFetchResponse(TEST_MODEL_RESPONSE)); await generateContent( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, reqWithEmptyConfigs, TEST_API_ENDPOINT ); 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: GenerateContentRequest = { contents: TEST_USER_CHAT_MESSAGE_WITH_GCS_FILE, generationConfig: {topK: 1}, safetySettings: [], }; fetchSpy.and.resolveTo(buildFetchResponse(TEST_MODEL_RESPONSE)); await generateContent( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, reqWithEmptyConfigs, TEST_API_ENDPOINT ); const requestArgs = fetchSpy.calls.allArgs()[0][1]; if (typeof requestArgs === 'object' && requestArgs) { expect(JSON.stringify(requestArgs['body'])).toContain('topK'); } }); it('aggregates citation metadata', async () => { const req: GenerateContentRequest = { contents: TEST_USER_CHAT_MESSAGE, }; fetchSpy.and.resolveTo(buildFetchResponse(TEST_MODEL_RESPONSE)); const resp = await generateContent( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, req, TEST_API_ENDPOINT ); expect( resp.response.candidates![0].citationMetadata?.citations.length ).toEqual( TEST_MODEL_RESPONSE.candidates[0].citationMetadata.citations.length ); }); it('returns a FunctionCall when passed a FunctionDeclaration', async () => { const req: GenerateContentRequest = { contents: CONTENTS, tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION, }; const expectedResult: GenerateContentResult = { response: TEST_MODEL_RESPONSE_WITH_FUNCTION_CALL, }; fetchSpy.and.resolveTo( new Response( JSON.stringify(TEST_MODEL_RESPONSE_WITH_FUNCTION_CALL), fetchResponseObj ) ); const actualResult = await generateContent( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, req, TEST_API_ENDPOINT ); expect(actualResult).toEqual(expectedResult); expect( GenerateContentResponseHandler.getFunctionCallsFromCandidate( actualResult.response.candidates![0] ) ).toHaveSize(1); expect( GenerateContentResponseHandler.getFunctionCallsFromCandidate( actualResult.response.candidates![0] ) ).toEqual([ expectedResult.response.candidates![0].content.parts[0].functionCall!, ]); }); it('returns a empty FunctionCall list when response contains invalid data', async () => { const req: GenerateContentRequest = { contents: CONTENTS, tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION, }; const expectedResult: GenerateContentResult = { response: TEST_MODEL_RESPONSE_WITH_INVALID_DATA, }; fetchSpy.and.resolveTo( new Response( JSON.stringify(TEST_MODEL_RESPONSE_WITH_INVALID_DATA), fetchResponseObj ) ); const actualResult = await generateContent( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, req, TEST_API_ENDPOINT ); expect(actualResult).toEqual(expectedResult); expect( GenerateContentResponseHandler.getFunctionCallsFromCandidate( actualResult.response.candidates?.[0] ) ).toHaveSize(0); }); it('returns empty candidates when response is empty', async () => { const req: GenerateContentRequest = { contents: CONTENTS, tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION, }; fetchSpy.and.resolveTo(new Response(JSON.stringify({}), fetchResponseObj)); const actualResult: GenerateContentResult = await generateContent( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, req, TEST_API_ENDPOINT ); expect(actualResult.response.candidates).not.toBeDefined(); }); it('should use v1 apiVersion', async () => { const request: GenerateContentRequest = { contents: CONTENTS, }; fetchSpy.and.resolveTo(buildFetchResponse(TEST_MODEL_RESPONSE)); await generateContent( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, request, TEST_API_ENDPOINT ); const vertexEndpoint = fetchSpy.calls.allArgs()[0][0]; expect(vertexEndpoint).toContain('/v1/'); }); it('should use v1beta1 apiVersion when set RAG in tools', async () => { const request: GenerateContentRequest = { contents: CONTENTS, tools: TEST_TOOLS_WITH_RAG, }; fetchSpy.and.resolveTo(buildFetchResponse(TEST_MODEL_RESPONSE)); await generateContent( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, request, TEST_API_ENDPOINT ); const vertexEndpoint = fetchSpy.calls.allArgs()[0][0]; expect(vertexEndpoint).toContain('/v1beta1/'); }); it('provides labels to the vertex endpoint', async () => { const request: GenerateContentRequest = { contents: CONTENTS, labels: TEST_LABELS, }; fetchSpy.and.resolveTo(buildFetchResponse(TEST_MODEL_RESPONSE)); await generateContent( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, request, TEST_API_ENDPOINT ); const httpRequest = fetchSpy.calls.allArgs()[0][1]; const body = JSON.parse(httpRequest.body); // @ts-ignore expect(body.labels).toEqual(TEST_LABELS); }); }); describe('generateContentStream', () => { let expectedStreamResult: StreamGenerateContentResult; let fetchSpy: jasmine.Spy; let fetchResult: Response; beforeEach(() => { expectedStreamResult = { response: Promise.resolve(TEST_MODEL_RESPONSE), stream: testGenerator(), }; fetchResult = new Response( JSON.stringify(expectedStreamResult), fetchResponseObj ); }); it('request rejected when timeout', async () => { const req: GenerateContentRequest = { contents: TEST_USER_CHAT_MESSAGE, }; fetchSpy = spyOn(global, 'fetch').and.resolveTo({ ok: false, status: 500, statusText: 'AbortError', } as Response); await expectAsync( generateContentStream( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, req, TEST_API_ENDPOINT, TEST_GENERATION_CONFIG, TEST_SAFETY_SETTINGS, TEST_EMPTY_TOOLS, TEST_EMPTY_TOOL_CONFIG, TEST_REQUEST_OPTIONS ) ).toBeRejected(); expect(fetchSpy.calls.allArgs()[0][1].signal).toBeInstanceOf(AbortSignal); }); it('returns a GenerateContentResponse when passed text content', async () => { const req: GenerateContentRequest = { contents: TEST_USER_CHAT_MESSAGE, }; const expectedResult: StreamGenerateContentResult = { response: Promise.resolve(TEST_MODEL_RESPONSE), stream: testGenerator(), }; fetchSpy = spyOn(global, 'fetch').and.resolveTo(fetchResult); spyOn(StreamFunctions, 'processStream').and.resolveTo(expectedResult); const resp = await generateContentStream( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, req, TEST_API_ENDPOINT ); expect(resp).toEqual(expectedResult); }); it('returns a GenerateContentResponse when passed a string', async () => { const expectedResult: StreamGenerateContentResult = { response: Promise.resolve(TEST_MODEL_RESPONSE), stream: testGenerator(), }; fetchSpy = spyOn(global, 'fetch').and.resolveTo(fetchResult); spyOn(StreamFunctions, 'processStream').and.resolveTo(expectedResult); const resp = await generateContentStream( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, TEST_API_ENDPOINT, TEST_CHAT_MESSAGE_TEXT ); expect(resp).toEqual(expectedResult); }); it('returns a GenerateContentResponse when passed multi-part content with a GCS URI', async () => { const req: GenerateContentRequest = { contents: TEST_MULTIPART_MESSAGE, }; const expectedResult: StreamGenerateContentResult = { response: Promise.resolve(TEST_MODEL_RESPONSE), stream: testGenerator(), }; fetchSpy = spyOn(global, 'fetch').and.resolveTo(fetchResult); spyOn(StreamFunctions, 'processStream').and.resolveTo(expectedResult); const resp = await generateContentStream( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, req, TEST_API_ENDPOINT ); expect(resp).toEqual(expectedResult); }); it('returns a GenerateContentResponse when passed multi-part content with base64 data', async () => { const req: GenerateContentRequest = { contents: TEST_MULTIPART_MESSAGE_BASE64, }; const expectedResult: StreamGenerateContentResult = { response: Promise.resolve(TEST_MODEL_RESPONSE), stream: testGenerator(), }; fetchSpy = spyOn(global, 'fetch').and.resolveTo(fetchResult); spyOn(StreamFunctions, 'processStream').and.resolveTo(expectedResult); const resp = await generateContentStream( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, req, TEST_API_ENDPOINT ); expect(resp).toEqual(expectedResult); }); it('returns a FunctionCall when passed a FunctionDeclaration', async () => { const req: GenerateContentRequest = { contents: [ {role: 'user', parts: [{text: 'What is the weater like in Boston?'}]}, ], tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION, }; const expectedStreamResult: StreamGenerateContentResult = { response: Promise.resolve(TEST_MODEL_RESPONSE_WITH_FUNCTION_CALL), stream: testGenerator(), }; fetchSpy = spyOn(global, 'fetch').and.resolveTo(fetchResult); spyOn(StreamFunctions, 'processStream').and.resolveTo(expectedStreamResult); const result = await generateContentStream( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, req, TEST_API_ENDPOINT ); expect(result).toEqual(expectedStreamResult); const response = await result.response; expect( GenerateContentResponseHandler.getFunctionCallsFromCandidate( response.candidates![0] ) ).toHaveSize(1); expect( GenerateContentResponseHandler.getFunctionCallsFromCandidate( response.candidates![0] ) ).toEqual([response.candidates![0].content.parts[0].functionCall!]); }); it('returns an empty FunctionCall list when response contains invalid data', async () => { const req: GenerateContentRequest = { contents: [ {role: 'user', parts: [{text: 'What is the weater like in Boston?'}]}, ], tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION, }; const expectedStreamResult: StreamGenerateContentResult = { response: Promise.resolve(TEST_MODEL_RESPONSE_WITH_INVALID_DATA), stream: testGenerator(), }; fetchSpy = spyOn(global, 'fetch').and.resolveTo(fetchResult); spyOn(StreamFunctions, 'processStream').and.resolveTo(expectedStreamResult); const actualResult = await generateContentStream( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, req, TEST_API_ENDPOINT ); expect(actualResult).toEqual(expectedStreamResult); const response = await actualResult.response; expect( GenerateContentResponseHandler.getFunctionCallsFromCandidate( response.candidates?.[0] ) ).toHaveSize(0); }); it('provides labels to the vertex endpoint', async () => { const request: GenerateContentRequest = { contents: CONTENTS, labels: TEST_LABELS, }; const expectedStreamResult: StreamGenerateContentResult = { response: Promise.resolve(TEST_MODEL_RESPONSE_WITH_INVALID_DATA), stream: testGenerator(), }; fetchSpy = spyOn(global, 'fetch').and.resolveTo(fetchResult); spyOn(StreamFunctions, 'processStream').and.resolveTo(expectedStreamResult); await generateContentStream( TEST_LOCATION, TEST_RESOURCE_PATH, TEST_TOKEN_PROMISE, request, TEST_API_ENDPOINT ); const httpRequest = fetchSpy.calls.allArgs()[0][1]; const body = JSON.parse(httpRequest.body); // @ts-ignore expect(body.labels).toEqual(TEST_LABELS); }); }); ================================================ FILE: vertexai/src/functions/test/post_fetch_processing_test.ts ================================================ /** * @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. */ import { AGGREGATED_RESPONSE_STREAM_RESPONSE_CHUNKS_1, AGGREGATED_RESPONSE_STREAM_RESPONSE_CHUNKS_2, AGGREGATED_RESPONSE_STREAM_RESPONSE_CHUNKS_3, AGGREGATED_RESPONSE_STREAM_RESPONSE_CHUNKS_4, AGGREGATED_RESPONSE_STREAM_RESPONSE_CHUNKS_5, AGGREGATED_RESPONSE_STREAM_RESPONSE_CHUNKS_6, COUNT_TOKENS_RESPONSE_1, STREAM_RESPONSE_CHUNKS_1, STREAM_RESPONSE_CHUNKS_2, STREAM_RESPONSE_CHUNKS_3, STREAM_RESPONSE_CHUNKS_4, STREAM_RESPONSE_CHUNKS_5, STREAM_RESPONSE_CHUNKS_6, UNARY_RESPONSE_1, UNARY_RESPONSE_MISSING_ROLE_INDEX, } from './test_data'; import * as PostFetchFunctions from '../post_fetch_processing'; import {aggregateResponses} from '../post_fetch_processing'; import {generateContent, generateContentStream} from '../generate_content'; import {countTokens} from '../count_tokens'; const fetchResponseObj = { status: 200, statusText: 'OK', ok: true, headers: {'Content-Type': 'application/json'}, url: 'url', }; const LOCATION = 'location'; const RESOURCE_PATH = 'RESOURCE_PATH'; const TOKEN = Promise.resolve('token'); const GENERATE_CONTENT_REQUEST = 'generate_content_request'; const COUNT_TOKEN_REQUEST = { contents: [{role: 'user', parts: [{text: 'text'}]}], }; describe('aggregateResponses', () => { it('grounding metadata in multiple chunks for multiple candidates, should aggregate accordingly', () => { const actualResult = aggregateResponses(STREAM_RESPONSE_CHUNKS_1); expect(JSON.stringify(actualResult)).toEqual( JSON.stringify(AGGREGATED_RESPONSE_STREAM_RESPONSE_CHUNKS_1) ); }); it('citation metadata in multiple chunks for multiple candidates, should aggregate accordingly', () => { const actualResult = aggregateResponses(STREAM_RESPONSE_CHUNKS_2); expect(JSON.stringify(actualResult)).toEqual( JSON.stringify(AGGREGATED_RESPONSE_STREAM_RESPONSE_CHUNKS_2) ); }); it('missing candidates, should return {}', () => { expect(aggregateResponses([{}, {}])).toEqual({}); }); it('missing role and index, should add role and index', () => { const actualResult = aggregateResponses(STREAM_RESPONSE_CHUNKS_3); expect(JSON.stringify(actualResult)).toEqual( JSON.stringify(AGGREGATED_RESPONSE_STREAM_RESPONSE_CHUNKS_3) ); }); it('missing content, should add role and return empty content', () => { const actualResult = aggregateResponses(STREAM_RESPONSE_CHUNKS_4); expect(JSON.stringify(actualResult)).toEqual( JSON.stringify(AGGREGATED_RESPONSE_STREAM_RESPONSE_CHUNKS_4) ); }); it('should aggregate text and functionCalls to separate parts', () => { const actualResult = aggregateResponses(STREAM_RESPONSE_CHUNKS_5); expect(JSON.stringify(actualResult)).toEqual( JSON.stringify(AGGREGATED_RESPONSE_STREAM_RESPONSE_CHUNKS_5) ); }); it('should aggregate functionCalls with the empty text removed', () => { const actualResult = aggregateResponses(STREAM_RESPONSE_CHUNKS_6); expect(JSON.stringify(actualResult)).toEqual( JSON.stringify(AGGREGATED_RESPONSE_STREAM_RESPONSE_CHUNKS_6) ); }); }); describe('processUnary', () => { it('grounding metadata in multiple candidates, processUnary should return faithful response', async () => { const fetchResult = new Response( JSON.stringify(UNARY_RESPONSE_1), fetchResponseObj ); spyOn(global, 'fetch').and.resolveTo(fetchResult); const actualResult = await generateContent( LOCATION, RESOURCE_PATH, TOKEN, GENERATE_CONTENT_REQUEST ); const actualResponse = actualResult.response; expect(actualResponse).toEqual(UNARY_RESPONSE_1); }); it('response missing role and index, should add role and index', async () => { const fetchResult = new Response( JSON.stringify(UNARY_RESPONSE_MISSING_ROLE_INDEX), fetchResponseObj ); const expectedResult = UNARY_RESPONSE_1; spyOn(global, 'fetch').and.resolveTo(fetchResult); const actualResult = await generateContent( LOCATION, RESOURCE_PATH, TOKEN, GENERATE_CONTENT_REQUEST ); const actualResponse = actualResult.response; expect(actualResponse).toEqual(expectedResult); }); it('candidate undefined, should return empty response', async () => { spyOn(global, 'fetch').and.resolveTo( new Response(JSON.stringify({}), fetchResponseObj) ); const actualResult = await generateContent( LOCATION, RESOURCE_PATH, TOKEN, GENERATE_CONTENT_REQUEST ); const actualResponse = actualResult.response; expect(actualResponse).toEqual({}); }); }); describe('processStream', () => { it('grounding metadata in multiple chunks for multiple candidates, processStream should return faithful response', async () => { const fetchResult = new Response( JSON.stringify(STREAM_RESPONSE_CHUNKS_1), fetchResponseObj ); spyOn(global, 'fetch').and.resolveTo(fetchResult); const processStreamSpy = spyOn(PostFetchFunctions, 'processStream'); await generateContentStream( LOCATION, RESOURCE_PATH, TOKEN, GENERATE_CONTENT_REQUEST ); const actualArg = processStreamSpy.calls.allArgs()[0][0]; expect(actualArg).toBeDefined(); const actualResponseToProcessStream = await actualArg!.json(); expect(actualResponseToProcessStream).toEqual(STREAM_RESPONSE_CHUNKS_1); }); }); describe('processCountTokenResponse', () => { it('multiple contents, processCountTokenResponse should return faithful response', async () => { const fetchResult = new Response( JSON.stringify(COUNT_TOKENS_RESPONSE_1), fetchResponseObj ); spyOn(global, 'fetch').and.resolveTo(fetchResult); const actualResponse = await countTokens( LOCATION, RESOURCE_PATH, TOKEN, COUNT_TOKEN_REQUEST ); expect(actualResponse).toEqual(COUNT_TOKENS_RESPONSE_1); }); }); ================================================ FILE: vertexai/src/functions/test/post_request_test.ts ================================================ /** * @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. */ import {GenerateContentRequest, RequestOptions} from '../../types'; import {postRequest} from '../post_request'; describe('postRequest', () => { const REGION = 'us-central1'; const RESOURCE_PATH = 'resource-path'; const RESOURCE_METHOD = 'resource-method'; const TOKEN = 'token'; const API_ENDPOINT = 'api-endpoint.googleapis.com'; const API_ENDPOINT_EXTERNAL = 'api-endpoint.external.com'; const data = {} as GenerateContentRequest; let fetchSpy: jasmine.Spy; beforeEach(() => { fetchSpy = spyOn(global, 'fetch').and.resolveTo({} as Response); }); it('apiClient header contains line break type 1, should throw', async () => { const requestOptions: RequestOptions = { apiClient: 'apiClient\n', }; const expectedErrorMessage = '[VertexAI.ClientError]: Found line break in apiClient request option field, please remove ' + 'the line break and try again.'; await postRequest({ region: REGION, resourcePath: RESOURCE_PATH, resourceMethod: RESOURCE_METHOD, token: TOKEN, apiEndpoint: API_ENDPOINT, data: data, requestOptions: requestOptions, }).catch(e => { expect(e.message).toEqual(expectedErrorMessage); }); }); it('apiClient header contains line break type 2, should throw', async () => { const requestOptions: RequestOptions = { apiClient: 'apiClient\r', }; const expectedErrorMessage = '[VertexAI.ClientError]: Found line break in apiClient request option field, please remove ' + 'the line break and try again.'; await postRequest({ region: REGION, resourcePath: RESOURCE_PATH, resourceMethod: RESOURCE_METHOD, token: TOKEN, apiEndpoint: API_ENDPOINT, data: data, requestOptions: requestOptions, }).catch(e => { expect(e.message).toEqual(expectedErrorMessage); }); }); it('apiClient header correct, should call through', async () => { const requestOptions: RequestOptions = { apiClient: 'apiClient', }; await postRequest({ region: REGION, resourcePath: RESOURCE_PATH, resourceMethod: RESOURCE_METHOD, token: TOKEN, apiEndpoint: API_ENDPOINT, data: data, requestOptions: requestOptions, }); const actualHeaders = fetchSpy.calls.mostRecent().args[1].headers; expect(actualHeaders.get('X-Goog-Api-Client')).toEqual('apiClient'); }); it('customer object header contains line break type 1, should throw', async () => { const requestOptions: RequestOptions = { customHeaders: new Headers({customerHeader: 'apiClient\n'}), } as RequestOptions; const expectedErrorMessage = '[VertexAI.ClientError]: Found line break in customerHeaders request option field, please remove ' + 'the line break and try again.'; await postRequest({ region: REGION, resourcePath: RESOURCE_PATH, resourceMethod: RESOURCE_METHOD, token: TOKEN, apiEndpoint: API_ENDPOINT, data: data, requestOptions: requestOptions, }).catch(e => { expect(e.message).toEqual(expectedErrorMessage); }); }); it('customer object header contains line break type 2, should throw', async () => { const requestOptions: RequestOptions = { customHeaders: new Headers({customerHeader: 'apiClient\r'}), } as RequestOptions; const expectedErrorMessage = '[VertexAI.ClientError]: Found line break in customerHeaders request option field, please remove ' + 'the line break and try again.'; await postRequest({ region: REGION, resourcePath: RESOURCE_PATH, resourceMethod: RESOURCE_METHOD, token: TOKEN, apiEndpoint: API_ENDPOINT, data: data, requestOptions: requestOptions, }).catch(e => { expect(e.message).toEqual(expectedErrorMessage); }); }); it('set customer header correctly should call through', async () => { const requestOptions: RequestOptions = { customHeaders: new Headers({customerHeader: 'customerHeaderValue'}), } as RequestOptions; await postRequest({ region: REGION, resourcePath: RESOURCE_PATH, resourceMethod: RESOURCE_METHOD, token: TOKEN, apiEndpoint: API_ENDPOINT, data: data, requestOptions: requestOptions, }); const actualHeaders = fetchSpy.calls.mostRecent().args[1].headers; expect(actualHeaders.get('customerHeader')).toEqual('customerHeaderValue'); }); it('set both custom header and apiClient, should prioritize apiClient and SDK headers if sent to internal endpoint', async () => { const requestOptions: RequestOptions = { customHeaders: new Headers({ 'User-Agent': 'user-agent-value', 'X-Goog-Api-Client': 'apiClient1', 'Content-Type': 'other-content-type', }), apiClient: 'apiClient2', } as RequestOptions; await postRequest({ region: REGION, resourcePath: RESOURCE_PATH, resourceMethod: RESOURCE_METHOD, token: TOKEN, apiEndpoint: API_ENDPOINT, data: data, requestOptions: requestOptions, }); const actualHeaders = fetchSpy.calls.mostRecent().args[1].headers; expect(actualHeaders.get('X-Goog-Api-Client')).toEqual( 'apiClient1, apiClient2' ); expect(actualHeaders.get('User-Agent')).toContain('model-builder'); expect(actualHeaders.get('User-Agent')).toContain('user-agent-value'); expect(actualHeaders.get('Content-Type')).toEqual('application/json'); }); it('set both custom header and apiClient, should prioritize custom headers if sent to external endpoint', async () => { const requestOptions: RequestOptions = { customHeaders: new Headers({ 'User-Agent': 'user-agent-value', 'X-Goog-Api-Client': 'apiClient1', 'Content-Type': 'other-content-type', }), apiClient: 'apiClient2', } as RequestOptions; await postRequest({ region: REGION, resourcePath: RESOURCE_PATH, resourceMethod: RESOURCE_METHOD, token: TOKEN, apiEndpoint: API_ENDPOINT_EXTERNAL, data: data, requestOptions: requestOptions, }); const actualHeaders = fetchSpy.calls.mostRecent().args[1].headers; expect(actualHeaders.get('X-Goog-Api-Client')).toEqual( 'apiClient1, apiClient2' ); expect(actualHeaders.get('User-Agent')).toContain('model-builder'); expect(actualHeaders.get('User-Agent')).toContain('user-agent-value'); expect(actualHeaders.get('Content-Type')).toEqual('other-content-type'); }); }); ================================================ FILE: vertexai/src/functions/test/pre_fetch_processing_test.ts ================================================ /** * @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. */ import {Tool} from '../../types/content'; import { getApiVersion, validateGenerateContentRequest, } from '../pre_fetch_processing'; const TOOL1 = {retrieval: {vertexAiSearch: {datastore: 'datastore'}}} as Tool; const TOOL2 = { retrieval: {vertexRagStore: {ragResources: [{ragCorpus: 'ragCorpus'}]}}, } as Tool; const TOOL3 = { retrieval: { vertexAiSearch: {datastore: 'datastore'}, vertexRagStore: {ragResources: [{ragCorpus: 'ragCorpus'}]}, }, } as Tool; const VALID_TOOL_ERROR_MESSAGE = '[VertexAI.ClientError]: Found both vertexAiSearch and vertexRagStore field are set in tool. Either set vertexAiSearch or vertexRagStore.'; describe('validateTools', () => { it('should pass validation when set tool correctly', () => { expect(() => validateGenerateContentRequest({tools: [TOOL1], contents: []}) ).not.toThrow(); expect(() => validateGenerateContentRequest({tools: [TOOL2], contents: []}) ).not.toThrow(); }); it('should throw error when set VertexAiSearch and VertexRagStore in two tools in request', () => { expect(() => validateGenerateContentRequest({tools: [TOOL1, TOOL2], contents: []}) ).toThrowError(VALID_TOOL_ERROR_MESSAGE); }); it('should throw error when set VertexAiSearch and VertexRagStore in a single tool in request', () => { expect(() => validateGenerateContentRequest({tools: [TOOL3], contents: []}) ).toThrowError(VALID_TOOL_ERROR_MESSAGE); }); }); describe('getApiVersion', () => { it('should return v1', () => { expect(getApiVersion({contents: [], tools: [TOOL1]})).toEqual('v1'); }); it('should return v1beta1', () => { expect(getApiVersion({contents: [], tools: [TOOL2]})).toEqual('v1beta1'); expect(getApiVersion({contents: [], tools: [TOOL1, TOOL2]})).toEqual( 'v1beta1' ); }); }); ================================================ FILE: vertexai/src/functions/test/test_data.ts ================================================ /** * @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. */ import { CountTokensResponse, GenerateContentResponse, } from '../../types/content'; export const STREAM_RESPONSE_CHUNKS_1: GenerateContentResponse[] = [ { candidates: [ { content: { role: 'model', parts: [ { text: 'chunk1Candidate1', }, ], }, safetyRatings: [ { category: 'HARM_CATEGORY_HATE_SPEECH', probability: 'NEGLIGIBLE', probabilityScore: 0.448547, severity: 'HARM_SEVERITY_MEDIUM', severityScore: 0.40221596, }, { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', probability: 'NEGLIGIBLE', probabilityScore: 0.41935068, severity: 'HARM_SEVERITY_LOW', severityScore: 0.27067295, }, { category: 'HARM_CATEGORY_HARASSMENT', probability: 'NEGLIGIBLE', probabilityScore: 0.40703878, severity: 'HARM_SEVERITY_LOW', severityScore: 0.26095408, }, { category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT', probability: 'NEGLIGIBLE', probabilityScore: 0.24220563, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.15140383, }, ], }, { content: { role: 'model', parts: [ { text: 'chunk1Candidate2', }, ], }, safetyRatings: [ { category: 'HARM_CATEGORY_HATE_SPEECH', probability: 'NEGLIGIBLE', probabilityScore: 0.448547, severity: 'HARM_SEVERITY_MEDIUM', severityScore: 0.40221596, }, { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', probability: 'NEGLIGIBLE', probabilityScore: 0.41935068, severity: 'HARM_SEVERITY_LOW', severityScore: 0.27067295, }, { category: 'HARM_CATEGORY_HARASSMENT', probability: 'NEGLIGIBLE', probabilityScore: 0.40703878, severity: 'HARM_SEVERITY_LOW', severityScore: 0.26095408, }, { category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT', probability: 'NEGLIGIBLE', probabilityScore: 0.24220563, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.15140383, }, ], }, ], }, { candidates: [ { content: { role: 'model', parts: [ { text: 'chunk2Candidate1', }, ], }, safetyRatings: [ { category: 'HARM_CATEGORY_HATE_SPEECH', probability: 'NEGLIGIBLE', probabilityScore: 0.32594952, severity: 'HARM_SEVERITY_LOW', severityScore: 0.20481865, }, { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', probability: 'NEGLIGIBLE', probabilityScore: 0.32498476, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.18728127, }, { category: 'HARM_CATEGORY_HARASSMENT', probability: 'NEGLIGIBLE', probabilityScore: 0.31742626, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.12940271, }, { category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT', probability: 'NEGLIGIBLE', probabilityScore: 0.14175598, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.12252322, }, ], }, { content: { role: 'model', parts: [ { text: 'chunk2Candidate2', }, ], }, safetyRatings: [ { category: 'HARM_CATEGORY_HATE_SPEECH', probability: 'NEGLIGIBLE', probabilityScore: 0.32594952, severity: 'HARM_SEVERITY_LOW', severityScore: 0.20481865, }, { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', probability: 'NEGLIGIBLE', probabilityScore: 0.32498476, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.18728127, }, { category: 'HARM_CATEGORY_HARASSMENT', probability: 'NEGLIGIBLE', probabilityScore: 0.31742626, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.12940271, }, { category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT', probability: 'NEGLIGIBLE', probabilityScore: 0.14175598, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.12252322, }, ], }, ], }, { candidates: [ { content: { role: 'model', parts: [ { text: 'chunk3Candidate1', }, ], }, groundingMetadata: { webSearchQueries: ['query for former chunk for first candidate'], groundingChunks: [ { web: { uri: 'url for former chunk for first candidate', title: 'title for former chunk for first candidate', }, }, ], groundingSupports: [ { segment: { startIndex: 0, endIndex: 421, text: 'grounding support for former chunk for first candidate', }, }, ], }, safetyRatings: [ { category: 'HARM_CATEGORY_HATE_SPEECH', probability: 'NEGLIGIBLE', probabilityScore: 0.32402143, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.18892181, }, { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', probability: 'NEGLIGIBLE', probabilityScore: 0.32028955, severity: 'HARM_SEVERITY_LOW', severityScore: 0.21783626, }, { category: 'HARM_CATEGORY_HARASSMENT', probability: 'NEGLIGIBLE', probabilityScore: 0.32124704, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.13568956, }, { category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT', probability: 'NEGLIGIBLE', probabilityScore: 0.16344544, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.11516222, }, ], }, { content: { role: 'model', parts: [ { text: 'chunk3Candidate2', }, ], }, groundingMetadata: { webSearchQueries: ['query for former chunk for second candidate'], groundingChunks: [ { web: { uri: 'url for former chunk for second candidate', title: 'title for former chunk for second candidate', }, }, ], groundingSupports: [ { segment: { startIndex: 0, endIndex: 421, text: 'grounding support for former chunk for second candidate', }, }, ], }, safetyRatings: [ { category: 'HARM_CATEGORY_HATE_SPEECH', probability: 'NEGLIGIBLE', probabilityScore: 0.32402143, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.18892181, }, { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', probability: 'NEGLIGIBLE', probabilityScore: 0.32028955, severity: 'HARM_SEVERITY_LOW', severityScore: 0.21783626, }, { category: 'HARM_CATEGORY_HARASSMENT', probability: 'NEGLIGIBLE', probabilityScore: 0.32124704, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.13568956, }, { category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT', probability: 'NEGLIGIBLE', probabilityScore: 0.16344544, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.11516222, }, ], }, ], }, { candidates: [ { content: { role: 'model', }, finishReason: 'STOP', groundingMetadata: { webSearchQueries: ['query for later chunk for first candidate'], groundingChunks: [ { web: { uri: 'url for later chunk for first candidate', title: 'title for later chunk for first candidate', }, }, ], groundingSupports: [ { segment: { startIndex: 0, endIndex: 421, text: 'grounding support for later chunk for first candidate', }, }, ], searchEntryPoint: { renderedContent: 'rendered content for later chunk for first candidate', }, }, }, { content: { role: 'model', }, finishReason: 'STOP', groundingMetadata: { webSearchQueries: ['query for later chunk for second candidate'], groundingChunks: [ { web: { uri: 'url for later chunk for second candidate', title: 'title for later chunk for second candidate', }, }, ], groundingSupports: [ { segment: { startIndex: 0, endIndex: 421, text: 'grounding support for later chunk for second candidate', }, }, ], searchEntryPoint: { renderedContent: 'rendered content for later chunk for second candidate', }, }, }, ], usageMetadata: { promptTokenCount: 6, candidatesTokenCount: 91, totalTokenCount: 97, }, }, ] as GenerateContentResponse[]; export const AGGREGATED_RESPONSE_STREAM_RESPONSE_CHUNKS_1: GenerateContentResponse = { usageMetadata: { promptTokenCount: 6, candidatesTokenCount: 91, totalTokenCount: 97, }, candidates: [ { index: 0, content: { role: 'model', parts: [{text: 'chunk1Candidate1chunk2Candidate1chunk3Candidate1'}], }, safetyRatings: [ { category: 'HARM_CATEGORY_HATE_SPEECH', probability: 'NEGLIGIBLE', probabilityScore: 0.32402143, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.18892181, }, { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', probability: 'NEGLIGIBLE', probabilityScore: 0.32028955, severity: 'HARM_SEVERITY_LOW', severityScore: 0.21783626, }, { category: 'HARM_CATEGORY_HARASSMENT', probability: 'NEGLIGIBLE', probabilityScore: 0.32124704, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.13568956, }, { category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT', probability: 'NEGLIGIBLE', probabilityScore: 0.16344544, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.11516222, }, ], groundingMetadata: { webSearchQueries: [ 'query for former chunk for first candidate', 'query for later chunk for first candidate', ], retrievalQueries: [], groundingChunks: [ { web: { uri: 'url for former chunk for first candidate', title: 'title for former chunk for first candidate', }, }, { web: { uri: 'url for later chunk for first candidate', title: 'title for later chunk for first candidate', }, }, ], groundingSupports: [ { segment: { startIndex: 0, endIndex: 421, text: 'grounding support for former chunk for first candidate', }, }, { segment: { startIndex: 0, endIndex: 421, text: 'grounding support for later chunk for first candidate', }, }, ], searchEntryPoint: { renderedContent: 'rendered content for later chunk for first candidate', }, }, finishReason: 'STOP', }, { index: 1, content: { role: 'model', parts: [{text: 'chunk1Candidate2chunk2Candidate2chunk3Candidate2'}], }, safetyRatings: [ { category: 'HARM_CATEGORY_HATE_SPEECH', probability: 'NEGLIGIBLE', probabilityScore: 0.32402143, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.18892181, }, { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', probability: 'NEGLIGIBLE', probabilityScore: 0.32028955, severity: 'HARM_SEVERITY_LOW', severityScore: 0.21783626, }, { category: 'HARM_CATEGORY_HARASSMENT', probability: 'NEGLIGIBLE', probabilityScore: 0.32124704, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.13568956, }, { category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT', probability: 'NEGLIGIBLE', probabilityScore: 0.16344544, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.11516222, }, ], groundingMetadata: { webSearchQueries: [ 'query for former chunk for second candidate', 'query for later chunk for second candidate', ], retrievalQueries: [], groundingChunks: [ { web: { uri: 'url for former chunk for second candidate', title: 'title for former chunk for second candidate', }, }, { web: { uri: 'url for later chunk for second candidate', title: 'title for later chunk for second candidate', }, }, ], groundingSupports: [ { segment: { startIndex: 0, endIndex: 421, text: 'grounding support for former chunk for second candidate', }, }, { segment: { startIndex: 0, endIndex: 421, text: 'grounding support for later chunk for second candidate', }, }, ], searchEntryPoint: { renderedContent: 'rendered content for later chunk for second candidate', }, }, finishReason: 'STOP', }, ], } as GenerateContentResponse; export const STREAM_RESPONSE_CHUNKS_2: GenerateContentResponse[] = [ { candidates: [ { content: { role: 'model', parts: [ { text: 'chunk1Candidate1', }, ], }, citationMetadata: { citations: [ { startIndex: 1, endIndex: 42, uri: '1st url for former chunk for first candidate', title: '1st title for former chunk for first candidate', license: '1st license for former chunk for first candidate', }, { startIndex: 2, endIndex: 67, uri: '2nd url for former chunk for first candidate', title: '2nd title for former chunk for first candidate', license: '2nd license for former chunk for first candidate', }, ], }, }, { content: { role: 'model', parts: [ { text: 'chunk1Candidate2', }, ], }, citationMetadata: { citations: [ { startIndex: 5, endIndex: 921, uri: '1st url for former chunk for second candidate', title: '1st title for former chunk for second candidate', license: '1st license for former chunk for second candidate', }, ], }, }, ], }, { candidates: [ { content: { role: 'model', parts: [ { text: 'chunk2Candidate1', }, ], }, }, { content: { role: 'model', parts: [ { text: 'chunk2Candidate2', }, ], }, safetyRatings: [ { category: 'HARM_CATEGORY_HATE_SPEECH', probability: 'NEGLIGIBLE', probabilityScore: 0.32594952, severity: 'HARM_SEVERITY_LOW', severityScore: 0.20481865, }, { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', probability: 'NEGLIGIBLE', probabilityScore: 0.32498476, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.18728127, }, { category: 'HARM_CATEGORY_HARASSMENT', probability: 'NEGLIGIBLE', probabilityScore: 0.31742626, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.12940271, }, { category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT', probability: 'NEGLIGIBLE', probabilityScore: 0.14175598, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.12252322, }, ], }, ], }, { candidates: [ { content: { role: 'model', parts: [ { text: 'chunk3Candidate1', }, ], }, citationMetadata: { citations: [ { startIndex: 1, endIndex: 42, uri: '1st url for later chunk for first candidate', title: '1st title for later chunk for first candidate', license: '1st license for later chunk for first candidate', }, { startIndex: 2, endIndex: 67, uri: '2nd url for later chunk for first candidate', title: '2nd title for later chunk for first candidate', license: '2nd license for later chunk for first candidate', }, ], }, }, { content: { role: 'model', parts: [ { text: 'chunk3Candidate2', }, ], }, citationMetadata: { citations: [ { startIndex: 6, endIndex: 432, uri: '1st url for later chunk for second candidate', title: '1st title for later chunk for second candidate', license: '1st license for later chunk for second candidate', }, ], }, }, ], }, { candidates: [ { content: { role: 'model', }, finishReason: 'STOP', }, { content: { role: 'model', }, finishReason: 'STOP', }, ], usageMetadata: { promptTokenCount: 6, candidatesTokenCount: 91, totalTokenCount: 97, }, }, ] as GenerateContentResponse[]; export const AGGREGATED_RESPONSE_STREAM_RESPONSE_CHUNKS_2: GenerateContentResponse = { usageMetadata: { promptTokenCount: 6, candidatesTokenCount: 91, totalTokenCount: 97, }, candidates: [ { index: 0, content: { role: 'model', parts: [ { text: 'chunk1Candidate1chunk2Candidate1chunk3Candidate1', }, ], }, citationMetadata: { citations: [ { startIndex: 1, endIndex: 42, uri: '1st url for former chunk for first candidate', title: '1st title for former chunk for first candidate', license: '1st license for former chunk for first candidate', }, { startIndex: 2, endIndex: 67, uri: '2nd url for former chunk for first candidate', title: '2nd title for former chunk for first candidate', license: '2nd license for former chunk for first candidate', }, { startIndex: 1, endIndex: 42, uri: '1st url for later chunk for first candidate', title: '1st title for later chunk for first candidate', license: '1st license for later chunk for first candidate', }, { startIndex: 2, endIndex: 67, uri: '2nd url for later chunk for first candidate', title: '2nd title for later chunk for first candidate', license: '2nd license for later chunk for first candidate', }, ], }, finishReason: 'STOP', }, { index: 1, content: { role: 'model', parts: [ { text: 'chunk1Candidate2chunk2Candidate2chunk3Candidate2', }, ], }, citationMetadata: { citations: [ { startIndex: 5, endIndex: 921, uri: '1st url for former chunk for second candidate', title: '1st title for former chunk for second candidate', license: '1st license for former chunk for second candidate', }, { startIndex: 6, endIndex: 432, uri: '1st url for later chunk for second candidate', title: '1st title for later chunk for second candidate', license: '1st license for later chunk for second candidate', }, ], }, safetyRatings: [ { category: 'HARM_CATEGORY_HATE_SPEECH', probability: 'NEGLIGIBLE', probabilityScore: 0.32594952, severity: 'HARM_SEVERITY_LOW', severityScore: 0.20481865, }, { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', probability: 'NEGLIGIBLE', probabilityScore: 0.32498476, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.18728127, }, { category: 'HARM_CATEGORY_HARASSMENT', probability: 'NEGLIGIBLE', probabilityScore: 0.31742626, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.12940271, }, { category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT', probability: 'NEGLIGIBLE', probabilityScore: 0.14175598, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.12252322, }, ], finishReason: 'STOP', }, ], } as GenerateContentResponse; export const STREAM_RESPONSE_CHUNKS_3: GenerateContentResponse[] = [ { candidates: [ {content: {parts: [{text: 'chunk1Candidate1'}]}}, {content: {parts: [{text: 'chunk1Candidate2'}]}}, ], }, { candidates: [ {content: {parts: [{text: 'chunk2Candidate1'}]}}, {content: {parts: [{text: 'chunk2Candidate2'}]}}, ], }, ] as GenerateContentResponse[]; export const AGGREGATED_RESPONSE_STREAM_RESPONSE_CHUNKS_3: GenerateContentResponse = { candidates: [ { index: 0, content: { role: 'model', parts: [{text: 'chunk1Candidate1chunk2Candidate1'}], }, }, { index: 1, content: { role: 'model', parts: [{text: 'chunk1Candidate2chunk2Candidate2'}], }, }, ], } as GenerateContentResponse; export const STREAM_RESPONSE_CHUNKS_4: GenerateContentResponse[] = [ { candidates: [{}], }, ] as GenerateContentResponse[]; export const AGGREGATED_RESPONSE_STREAM_RESPONSE_CHUNKS_4: GenerateContentResponse = { candidates: [ { index: 0, content: { role: 'model', parts: [{text: ''}], }, }, ], } as GenerateContentResponse; export const STREAM_RESPONSE_CHUNKS_5: GenerateContentResponse[] = [ { candidates: [ { content: { parts: [ {functionCall: {name: 'fn', args: {a: 1}}}, {text: 'chunk1Text1'}, ], }, }, ], }, { candidates: [ { content: { parts: [{text: 'chunk2Text1'}], }, }, ], }, ] as GenerateContentResponse[]; export const AGGREGATED_RESPONSE_STREAM_RESPONSE_CHUNKS_5: GenerateContentResponse = { candidates: [ { index: 0, content: { role: 'model', parts: [ {text: 'chunk1Text1chunk2Text1'}, {functionCall: {name: 'fn', args: {a: 1}}}, ], }, }, ], } as GenerateContentResponse; export const STREAM_RESPONSE_CHUNKS_6: GenerateContentResponse[] = [ { candidates: [ { content: { parts: [{functionCall: {name: 'fn', args: {a: 1}}}], }, }, ], }, ] as GenerateContentResponse[]; export const AGGREGATED_RESPONSE_STREAM_RESPONSE_CHUNKS_6: GenerateContentResponse = { candidates: [ { index: 0, content: { role: 'model', parts: [{functionCall: {name: 'fn', args: {a: 1}}}], }, }, ], } as GenerateContentResponse; export const UNARY_RESPONSE_1: GenerateContentResponse = { candidates: [ { content: { role: 'model', parts: [ { text: 'candidate1', }, ], }, index: 0, safetyRatings: [ { category: 'HARM_CATEGORY_HATE_SPEECH', probability: 'NEGLIGIBLE', probabilityScore: 0.448547, severity: 'HARM_SEVERITY_MEDIUM', severityScore: 0.40221596, }, { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', probability: 'NEGLIGIBLE', probabilityScore: 0.41935068, severity: 'HARM_SEVERITY_LOW', severityScore: 0.27067295, }, { category: 'HARM_CATEGORY_HARASSMENT', probability: 'NEGLIGIBLE', probabilityScore: 0.40703878, severity: 'HARM_SEVERITY_LOW', severityScore: 0.26095408, }, { category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT', probability: 'NEGLIGIBLE', probabilityScore: 0.24220563, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.15140383, }, ], }, { content: { role: 'model', parts: [ { text: 'candidate2', }, ], }, index: 1, safetyRatings: [ { category: 'HARM_CATEGORY_HATE_SPEECH', probability: 'NEGLIGIBLE', probabilityScore: 0.448547, severity: 'HARM_SEVERITY_MEDIUM', severityScore: 0.40221596, }, { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', probability: 'NEGLIGIBLE', probabilityScore: 0.41935068, severity: 'HARM_SEVERITY_LOW', severityScore: 0.27067295, }, { category: 'HARM_CATEGORY_HARASSMENT', probability: 'NEGLIGIBLE', probabilityScore: 0.40703878, severity: 'HARM_SEVERITY_LOW', severityScore: 0.26095408, }, { category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT', probability: 'NEGLIGIBLE', probabilityScore: 0.24220563, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.15140383, }, ], }, ], promptFeedback: { blockReason: 'BLOCK_REASON_UNSPECIFIED', safetyRatings: [ { category: 'HARM_CATEGORY_HATE_SPEECH', probability: 'NEGLIGIBLE', probabilityScore: 0.448547, severity: 'HARM_SEVERITY_MEDIUM', severityScore: 0.40221596, }, ], blockReasonMessage: 'block reason message', }, usageMetadata: { promptTokenCount: 6, candidatesTokenCount: 91, totalTokenCount: 97, }, } as GenerateContentResponse; export const UNARY_RESPONSE_MISSING_ROLE_INDEX: GenerateContentResponse = { candidates: [ { content: { parts: [ { text: 'candidate1', }, ], }, index: 0, safetyRatings: [ { category: 'HARM_CATEGORY_HATE_SPEECH', probability: 'NEGLIGIBLE', probabilityScore: 0.448547, severity: 'HARM_SEVERITY_MEDIUM', severityScore: 0.40221596, }, { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', probability: 'NEGLIGIBLE', probabilityScore: 0.41935068, severity: 'HARM_SEVERITY_LOW', severityScore: 0.27067295, }, { category: 'HARM_CATEGORY_HARASSMENT', probability: 'NEGLIGIBLE', probabilityScore: 0.40703878, severity: 'HARM_SEVERITY_LOW', severityScore: 0.26095408, }, { category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT', probability: 'NEGLIGIBLE', probabilityScore: 0.24220563, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.15140383, }, ], }, { content: { parts: [ { text: 'candidate2', }, ], }, safetyRatings: [ { category: 'HARM_CATEGORY_HATE_SPEECH', probability: 'NEGLIGIBLE', probabilityScore: 0.448547, severity: 'HARM_SEVERITY_MEDIUM', severityScore: 0.40221596, }, { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', probability: 'NEGLIGIBLE', probabilityScore: 0.41935068, severity: 'HARM_SEVERITY_LOW', severityScore: 0.27067295, }, { category: 'HARM_CATEGORY_HARASSMENT', probability: 'NEGLIGIBLE', probabilityScore: 0.40703878, severity: 'HARM_SEVERITY_LOW', severityScore: 0.26095408, }, { category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT', probability: 'NEGLIGIBLE', probabilityScore: 0.24220563, severity: 'HARM_SEVERITY_NEGLIGIBLE', severityScore: 0.15140383, }, ], }, ], promptFeedback: { blockReason: 'BLOCK_REASON_UNSPECIFIED', safetyRatings: [ { category: 'HARM_CATEGORY_HATE_SPEECH', probability: 'NEGLIGIBLE', probabilityScore: 0.448547, severity: 'HARM_SEVERITY_MEDIUM', severityScore: 0.40221596, }, ], blockReasonMessage: 'block reason message', }, usageMetadata: { promptTokenCount: 6, candidatesTokenCount: 91, totalTokenCount: 97, }, } as GenerateContentResponse; export const COUNT_TOKENS_RESPONSE_1: CountTokensResponse = { totalTokens: 6, totalBillableCharacters: 20, }; ================================================ FILE: vertexai/src/functions/util.ts ================================================ /** * @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. */ import {Content} from '../types/content'; import {constants} from '../util'; export function formulateSystemInstructionIntoContent( systemInstruction: string | Content ): Content { if (typeof systemInstruction === 'string') { return { role: constants.SYSTEM_ROLE, parts: [{text: systemInstruction}], } as Content; } systemInstruction.role = constants.SYSTEM_ROLE; return systemInstruction; } ================================================ FILE: vertexai/src/index.ts ================================================ /** * @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. */ export {VertexAI} from './vertex_ai'; export * from './types'; export * from './models'; ================================================ FILE: vertexai/src/models/chat_session.ts ================================================ /** * @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. */ /* tslint:disable */ import {GoogleAuth} from 'google-auth-library'; import {formulateSystemInstructionIntoContent} from '../functions/util'; import { generateContent, generateContentStream, } from '../functions/generate_content'; import { Content, GenerateContentRequest, GenerateContentResult, GenerationConfig, Part, RequestOptions, SafetySetting, StartChatSessionRequest, StreamGenerateContentResult, Tool, } from '../types/content'; import {ToolConfig} from '../types'; import {ClientError, GoogleAuthError} from '../types/errors'; import {constants} from '../util'; /** * The `ChatSession` class is used to make multiturn send message requests. You * can instantiate this class by using the `startChat` method in the * `GenerativeModel` class. The `sendMessage` method makes an async call to get * the response of a chat message at at once. The `sendMessageStream` method * makes an async call to stream the response of a chat message as it's being * generated. */ export class ChatSession { private readonly project: string; private readonly location: string; private historyInternal: Content[]; private sendStreamPromise: Promise = Promise.resolve(); private readonly resourcePath: string; private readonly googleAuth: GoogleAuth; protected readonly requestOptions?: RequestOptions; private readonly generationConfig?: GenerationConfig; private readonly safetySettings?: SafetySetting[]; private readonly tools?: Tool[]; private readonly toolConfig?: ToolConfig; private readonly apiEndpoint?: string; private readonly systemInstruction?: Content; async getHistory(): Promise { return Promise.resolve(this.historyInternal); } /** * @constructor * @param request - {@link StartChatSessionRequest} */ constructor( request: StartChatSessionRequest, requestOptions?: RequestOptions ) { this.project = request.project; this.location = request.location; this.googleAuth = request.googleAuth; this.resourcePath = request.resourcePath; this.historyInternal = request.history ?? []; this.generationConfig = request.generationConfig; this.safetySettings = request.safetySettings; this.tools = request.tools; this.toolConfig = request.toolConfig; this.apiEndpoint = request.apiEndpoint; this.requestOptions = requestOptions ?? {}; if (request.systemInstruction) { this.systemInstruction = formulateSystemInstructionIntoContent( request.systemInstruction ); } } /** * Gets access token from GoogleAuth. Throws {@link GoogleAuthError} when * fails. * @returns Promise of token. */ private fetchToken(): Promise { const tokenPromise = this.googleAuth.getAccessToken().catch(e => { throw new GoogleAuthError(constants.CREDENTIAL_ERROR_MESSAGE, e); }); return tokenPromise; } /** * Makes an async call to send chat message. * * The response is returned in {@link * GenerateContentResult.response}. * * @example * ``` * const chat = generativeModel.startChat(); * const result1 = await chat.sendMessage("How can I learn more about Node.js?"); * console.log('Response: ', JSON.stringify(result1.response)); * * const result2 = await chat.sendMessage("What about python?"); * console.log('Response: ', JSON.stringify(result2.response)); * ``` * * @param request - send message request. * @returns Promise of {@link GenerateContentResult}. */ async sendMessage( request: string | Array ): Promise { const newContent: Content[] = formulateNewContentFromSendMessageRequest(request); const generateContentRequest: GenerateContentRequest = { contents: this.historyInternal.concat(newContent), safetySettings: this.safetySettings, generationConfig: this.generationConfig, tools: this.tools, toolConfig: this.toolConfig, systemInstruction: this.systemInstruction, }; const generateContentResult: GenerateContentResult = await generateContent( this.location, this.resourcePath, this.fetchToken(), generateContentRequest, this.apiEndpoint, this.generationConfig, this.safetySettings, this.tools, this.toolConfig, this.requestOptions ).catch(e => { throw e; }); const generateContentResponse = await generateContentResult.response; // Only push the latest message to history if the response returns a result if ( generateContentResponse.candidates && generateContentResponse.candidates.length !== 0 ) { this.historyInternal = this.historyInternal.concat(newContent); const contentFromModel = generateContentResponse.candidates[0].content; this.historyInternal.push(contentFromModel); } return Promise.resolve(generateContentResult); } private async appendHistory( streamGenerateContentResultPromise: Promise, newContent: Content[] ): Promise { const streamGenerateContentResult = await streamGenerateContentResultPromise; const streamGenerateContentResponse = await streamGenerateContentResult.response; // Only push the latest message to history if the response returned a result if ( streamGenerateContentResponse.candidates && streamGenerateContentResponse.candidates.length !== 0 ) { this.historyInternal = this.historyInternal.concat(newContent); const contentFromModel = streamGenerateContentResponse.candidates[0].content; this.historyInternal.push(contentFromModel); } } /** * Makes an async call to stream send message. * * The response is streamed chunk by chunk in * {@link StreamGenerateContentResult.stream}. The aggregated response is * avaliable in {@link StreamGenerateContentResult.response} after all chunks * are returned. * * @example * ``` * const chat = generativeModel.startChat(); * const chatInput = "How can I learn more about Node.js?"; * const result = await chat.sendMessageStream(chatInput); * for await (const item of result.stream) { * console.log(item.candidates[0].content.parts[0].text); * } * const response = await result.response; * console.log('aggregated response: ', JSON.stringify(result.response)); * ``` * * @param request - send message request. * @returns Promise of {@link StreamGenerateContentResult}. */ async sendMessageStream( request: string | Array ): Promise { const newContent: Content[] = formulateNewContentFromSendMessageRequest(request); const generateContentrequest: GenerateContentRequest = { contents: this.historyInternal.concat(newContent), safetySettings: this.safetySettings, generationConfig: this.generationConfig, tools: this.tools, toolConfig: this.toolConfig, systemInstruction: this.systemInstruction, }; const streamGenerateContentResultPromise = generateContentStream( this.location, this.resourcePath, this.fetchToken(), generateContentrequest, this.apiEndpoint, this.generationConfig, this.safetySettings, this.tools, this.toolConfig, this.requestOptions ).catch(e => { throw e; }); this.sendStreamPromise = this.appendHistory( streamGenerateContentResultPromise, newContent ).catch(e => { // Errors from remote endpoint will be catchable by user from streamGenerateContentResultPromise // Errors in appendHistory should not throw to cause user's programe exit with code 1 console.error(e); }); return streamGenerateContentResultPromise; } } /** * The `ChatSessionPreview` class is used to make multiturn send message requests. You * can instantiate this class by using the `startChat` method in the * `GenerativeModelPreview` class. The `sendMessage` method makes an async call to get * the response of a chat message at at once. The `sendMessageStream` method * makes an async call to stream the response of a chat message as it's being * generated. */ export class ChatSessionPreview { private readonly project: string; private readonly location: string; private historyInternal: Content[]; private sendStreamPromise: Promise = Promise.resolve(); private readonly resourcePath: string; private readonly googleAuth: GoogleAuth; protected readonly requestOptions?: RequestOptions; private readonly generationConfig?: GenerationConfig; private readonly safetySettings?: SafetySetting[]; private readonly tools?: Tool[]; private readonly toolConfig?: ToolConfig; private readonly apiEndpoint?: string; private readonly systemInstruction?: Content; private readonly cachedContent?: string; async getHistory(): Promise { return Promise.resolve(this.historyInternal); } /** * @constructor * @param request - {@link StartChatSessionRequest} */ constructor( request: StartChatSessionRequest, requestOptions?: RequestOptions ) { this.project = request.project; this.location = request.location; this.googleAuth = request.googleAuth; this.resourcePath = request.resourcePath; this.historyInternal = request.history ?? []; this.generationConfig = request.generationConfig; this.safetySettings = request.safetySettings; this.tools = request.tools; this.toolConfig = request.toolConfig; this.apiEndpoint = request.apiEndpoint; this.requestOptions = requestOptions ?? {}; this.cachedContent = request.cachedContent; if (request.systemInstruction) { this.systemInstruction = formulateSystemInstructionIntoContent( request.systemInstruction ); } } /** * Gets access token from GoogleAuth. Throws GoogleAuthError when fails. * @returns Promise of token. */ private fetchToken(): Promise { const tokenPromise = this.googleAuth.getAccessToken().catch(e => { throw new GoogleAuthError(constants.CREDENTIAL_ERROR_MESSAGE, e); }); return tokenPromise; } /** * Makes an async call to send chat message. * * The response is returned in {@link * GenerateContentResult.response}. * * @example * ``` * const chat = generativeModelPreview.startChat(); * const result1 = await chat.sendMessage("How can I learn more about Node.js?"); * console.log('Response: ', JSON.stringify(result1.response)); * * const result2 = await chat.sendMessage("What about python?"); * console.log('Response: ', JSON.stringify(result2.response)); * ``` * * @param request - send message request. * @returns Promise of {@link GenerateContentResult}. */ async sendMessage( request: string | Array ): Promise { const newContent: Content[] = formulateNewContentFromSendMessageRequest(request); const generateContentRequest: GenerateContentRequest = { contents: this.historyInternal.concat(newContent), safetySettings: this.safetySettings, generationConfig: this.generationConfig, tools: this.tools, toolConfig: this.toolConfig, systemInstruction: this.systemInstruction, cachedContent: this.cachedContent, }; const generateContentResult: GenerateContentResult = await generateContent( this.location, this.resourcePath, this.fetchToken(), generateContentRequest, this.apiEndpoint, this.generationConfig, this.safetySettings, this.tools, this.toolConfig, this.requestOptions ).catch(e => { throw e; }); const generateContentResponse = await generateContentResult.response; // Only push the latest message to history if the response returned a result if ( generateContentResponse.candidates && generateContentResponse.candidates.length !== 0 ) { this.historyInternal = this.historyInternal.concat(newContent); const contentFromAssistant = generateContentResponse.candidates[0].content; this.historyInternal.push(contentFromAssistant); } return Promise.resolve(generateContentResult); } private async appendHistory( streamGenerateContentResultPromise: Promise, newContent: Content[] ): Promise { const streamGenerateContentResult = await streamGenerateContentResultPromise; const streamGenerateContentResponse = await streamGenerateContentResult.response; // Only push the latest message to history if the response returned a result if ( streamGenerateContentResponse.candidates && streamGenerateContentResponse.candidates.length !== 0 ) { this.historyInternal = this.historyInternal.concat(newContent); const contentFromAssistant = streamGenerateContentResponse.candidates[0].content; this.historyInternal.push(contentFromAssistant); } } /** * Makes an async call to stream send message. * * The response is streamed chunk by chunk in * {@link StreamGenerateContentResult.stream}. The aggregated response is * avaliable in {@link StreamGenerateContentResult.response} after all chunks * are returned. * * @example * ``` * const chat = generativeModel.startChat(); * const chatInput = "How can I learn more about Node.js?"; * const result = await chat.sendMessageStream(chatInput); * for await (const item of result.stream) { * console.log(item.candidates[0].content.parts[0].text); * } * const response = await result.response; * console.log('aggregated response: ', JSON.stringify(result.response)); * ``` * * @param request - send message request. * @returns Promise of {@link StreamGenerateContentResult}. */ async sendMessageStream( request: string | Array ): Promise { const newContent: Content[] = formulateNewContentFromSendMessageRequest(request); const generateContentRequest: GenerateContentRequest = { contents: this.historyInternal.concat(newContent), safetySettings: this.safetySettings, generationConfig: this.generationConfig, tools: this.tools, toolConfig: this.toolConfig, systemInstruction: this.systemInstruction, cachedContent: this.cachedContent, }; const streamGenerateContentResultPromise = generateContentStream( this.location, this.resourcePath, this.fetchToken(), generateContentRequest, this.apiEndpoint, this.generationConfig, this.safetySettings, this.tools, this.toolConfig, this.requestOptions ).catch(e => { throw e; }); this.sendStreamPromise = this.appendHistory( streamGenerateContentResultPromise, newContent ).catch(e => { // Errors from remote endpoint will be catchable by user from streamGenerateContentResultPromise // Errors in appendHistory should not throw to cause user's programe exit with code 1 console.error(e); }); return streamGenerateContentResultPromise; } } function formulateNewContentFromSendMessageRequest( request: string | Array ): Content[] { let newParts: Part[] = []; if (typeof request === 'string') { newParts = [{text: request}]; } else if (Array.isArray(request)) { for (const item of request) { if (typeof item === 'string') { newParts.push({text: item}); } else { newParts.push(item); } } } return assignRoleToPartsAndValidateSendMessageRequest(newParts); } /** * When multiple Part types (i.e. FunctionResponsePart and TextPart) are * passed in a single Part array, we may need to assign different roles to each * part. Currently only FunctionResponsePart requires a role other than 'user'. * @ignore * @param parts Array of parts to pass to the model * @returns Array of content items */ function assignRoleToPartsAndValidateSendMessageRequest( parts: Array ): Content[] { const userContent: Content = {role: constants.USER_ROLE, parts: []}; const functionContent: Content = {role: constants.USER_ROLE, parts: []}; let hasUserContent = false; let hasFunctionContent = false; for (const part of parts) { if ('functionResponse' in part) { functionContent.parts.push(part); hasFunctionContent = true; } else { userContent.parts.push(part); hasUserContent = true; } } if (hasUserContent && hasFunctionContent) { throw new ClientError( 'Within a single message, FunctionResponse cannot be mixed with other type of part in the request for sending chat message.' ); } if (!hasUserContent && !hasFunctionContent) { throw new ClientError('No content is provided for sending chat message.'); } if (hasUserContent) { return [userContent]; } return [functionContent]; } ================================================ FILE: vertexai/src/models/generative_models.ts ================================================ /** * @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. */ /* tslint:disable */ import {GoogleAuth} from 'google-auth-library'; import {formulateSystemInstructionIntoContent} from '../functions/util'; import {countTokens} from '../functions/count_tokens'; import { generateContent, generateContentStream, } from '../functions/generate_content'; import { CachedContent, Content, CountTokensRequest, CountTokensResponse, GenerateContentRequest, GenerateContentResult, GenerationConfig, GetGenerativeModelParams, RequestOptions, SafetySetting, StartChatParams, StartChatSessionRequest, StreamGenerateContentResult, Tool, } from '../types/content'; import {ToolConfig} from '../types/tool'; import {ClientError, GoogleAuthError} from '../types/errors'; import {constants} from '../util'; import {ChatSession, ChatSessionPreview} from './chat_session'; /** * The `GenerativeModel` class is the base class for the generative models on * Vertex AI. * NOTE: Don't instantiate this class directly. Use * `vertexai.getGenerativeModel()` instead. */ export class GenerativeModel { private readonly model: string; private readonly generationConfig?: GenerationConfig; private readonly safetySettings?: SafetySetting[]; private readonly tools?: Tool[]; private readonly toolConfig?: ToolConfig; private readonly requestOptions?: RequestOptions; private readonly systemInstruction?: Content; private readonly project: string; private readonly location: string; private readonly googleAuth: GoogleAuth; private readonly publisherModelEndpoint: string; private readonly resourcePath: string; private readonly apiEndpoint?: string; /** * @constructor * @param getGenerativeModelParams - {@link GetGenerativeModelParams} */ constructor(getGenerativeModelParams: GetGenerativeModelParams) { this.project = getGenerativeModelParams.project; this.location = getGenerativeModelParams.location; this.apiEndpoint = getGenerativeModelParams.apiEndpoint; this.googleAuth = getGenerativeModelParams.googleAuth; this.model = getGenerativeModelParams.model; this.generationConfig = getGenerativeModelParams.generationConfig; this.safetySettings = getGenerativeModelParams.safetySettings; this.tools = getGenerativeModelParams.tools; this.toolConfig = getGenerativeModelParams.toolConfig; this.requestOptions = getGenerativeModelParams.requestOptions ?? {}; if (getGenerativeModelParams.systemInstruction) { this.systemInstruction = formulateSystemInstructionIntoContent( getGenerativeModelParams.systemInstruction ); } this.resourcePath = formulateResourcePathFromModel( this.model, this.project, this.location ); // publisherModelEndpoint is deprecated this.publisherModelEndpoint = this.resourcePath; } /** * Gets access token from GoogleAuth. Throws {@link GoogleAuthError} when * fails. * @returns Promise of token string. */ private fetchToken(): Promise { const tokenPromise = this.googleAuth.getAccessToken().catch(e => { throw new GoogleAuthError(constants.CREDENTIAL_ERROR_MESSAGE, e); }); return tokenPromise; } /** * Makes an async call to generate content. * * The response will be returned in {@link * GenerateContentResult.response}. * * @example * ``` * const request = { * contents: [{role: 'user', parts: [{text: 'How are you doing today?'}]}], * }; * const result = await generativeModel.generateContent(request); * console.log('Response: ', JSON.stringify(result.response)); * ``` * * @param request - A GenerateContentRequest object with the request contents. * @returns The GenerateContentResponse object with the response candidates. */ async generateContent( request: GenerateContentRequest | string ): Promise { request = formulateRequestToGenerateContentRequest(request); const formulatedRequest = formulateSystemInstructionIntoGenerateContentRequest( request, this.systemInstruction ); return generateContent( this.location, this.resourcePath, this.fetchToken(), formulatedRequest, this.apiEndpoint, this.generationConfig, this.safetySettings, this.tools, this.toolConfig, this.requestOptions ); } /** * Makes an async stream request to generate content. * * The response is returned chunk by chunk as it's being generated in {@link * StreamGenerateContentResult.stream}. After all chunks of the response are * returned, the aggregated response is available in * {@link StreamGenerateContentResult.response}. * * @example * ``` * const request = { * contents: [{role: 'user', parts: [{text: 'How are you doing today?'}]}], * }; * const streamingResult = await generativeModel.generateContentStream(request); * for await (const item of streamingResult.stream) { * console.log('stream chunk: ', JSON.stringify(item)); * } * const aggregatedResponse = await streamingResult.response; * console.log('aggregated response: ', JSON.stringify(aggregatedResponse)); * ``` * * @param request - {@link GenerateContentRequest} * @returns Promise of {@link StreamGenerateContentResult} */ async generateContentStream( request: GenerateContentRequest | string ): Promise { request = formulateRequestToGenerateContentRequest(request); const formulatedRequest = formulateSystemInstructionIntoGenerateContentRequest( request, this.systemInstruction ); return generateContentStream( this.location, this.resourcePath, this.fetchToken(), formulatedRequest, this.apiEndpoint, this.generationConfig, this.safetySettings, this.tools, this.toolConfig, this.requestOptions ); } /** * Makes an async request to count tokens. * * The `countTokens` function returns the token count and the number of * billable characters for a prompt. * * @example * ``` * const request = { * contents: [{role: 'user', parts: [{text: 'How are you doing today?'}]}], * }; * const resp = await generativeModel.countTokens(request); * console.log('count tokens response: ', resp); * ``` * * @param request - A CountTokensRequest object with the request contents. * @returns The CountTokensResponse object with the token count. */ async countTokens(request: CountTokensRequest): Promise { return countTokens( this.location, this.resourcePath, this.fetchToken(), request, this.apiEndpoint, this.requestOptions ); } /** * Instantiates a {@link ChatSession}. * * The {@link ChatSession} class is a stateful class that holds the state of * the conversation with the model and provides methods to interact with the * model in chat mode. Calling this method doesn't make any calls to a remote * endpoint. To make remote call, use {@link ChatSession.sendMessage} or * @link ChatSession.sendMessageStream}. * * @example * ``` * const chat = generativeModel.startChat(); * const result1 = await chat.sendMessage("How can I learn more about Node.js?"); * const response1 = await result1.response; * console.log('Response: ', JSON.stringify(response1)); * * const result2 = await chat.sendMessageStream("What about python?"); * const response2 = await result2.response; * console.log('Response: ', JSON.stringify(await response2)); * ``` * * @param request - {@link StartChatParams} * @returns {@link ChatSession} */ startChat(request?: StartChatParams): ChatSession { const startChatRequest: StartChatSessionRequest = { project: this.project, location: this.location, googleAuth: this.googleAuth, publisherModelEndpoint: this.publisherModelEndpoint, resourcePath: this.resourcePath, tools: this.tools, toolConfig: this.toolConfig, systemInstruction: this.systemInstruction, }; if (request) { startChatRequest.history = request.history; startChatRequest.generationConfig = request.generationConfig ?? this.generationConfig; startChatRequest.safetySettings = request.safetySettings ?? this.safetySettings; startChatRequest.tools = request.tools ?? this.tools; startChatRequest.toolConfig = request.toolConfig ?? this.toolConfig; startChatRequest.apiEndpoint = request.apiEndpoint ?? this.apiEndpoint; startChatRequest.systemInstruction = request.systemInstruction ?? this.systemInstruction; } return new ChatSession(startChatRequest, this.requestOptions); } } /** * The `GenerativeModelPreview` class is the base class for the generative models * that are in preview. * NOTE: Don't instantiate this class directly. Use * `vertexai.preview.getGenerativeModel()` instead. */ export class GenerativeModelPreview { private readonly model: string; private readonly generationConfig?: GenerationConfig; private readonly safetySettings?: SafetySetting[]; private readonly tools?: Tool[]; private readonly toolConfig?: ToolConfig; private readonly requestOptions?: RequestOptions; private readonly systemInstruction?: Content; private readonly project: string; private readonly location: string; private readonly googleAuth: GoogleAuth; private readonly publisherModelEndpoint: string; private readonly resourcePath: string; private readonly apiEndpoint?: string; private readonly cachedContent?: CachedContent; /** * @constructor * @param getGenerativeModelParams - {@link GetGenerativeModelParams} */ constructor(getGenerativeModelParams: GetGenerativeModelParams) { this.project = getGenerativeModelParams.project; this.location = getGenerativeModelParams.location; this.apiEndpoint = getGenerativeModelParams.apiEndpoint; this.googleAuth = getGenerativeModelParams.googleAuth; this.model = getGenerativeModelParams.model; this.generationConfig = getGenerativeModelParams.generationConfig; this.safetySettings = getGenerativeModelParams.safetySettings; this.tools = getGenerativeModelParams.tools; this.toolConfig = getGenerativeModelParams.toolConfig; this.cachedContent = getGenerativeModelParams.cachedContent; this.requestOptions = getGenerativeModelParams.requestOptions ?? {}; if (getGenerativeModelParams.systemInstruction) { this.systemInstruction = formulateSystemInstructionIntoContent( getGenerativeModelParams.systemInstruction ); } this.resourcePath = formulateResourcePathFromModel( this.model, this.project, this.location ); // publisherModelEndpoint is deprecated this.publisherModelEndpoint = this.resourcePath; } /** * Gets access token from GoogleAuth. Throws {@link GoogleAuthError} when * fails. * @returns Promise of token string. */ private fetchToken(): Promise { const tokenPromise = this.googleAuth.getAccessToken().catch(e => { throw new GoogleAuthError(constants.CREDENTIAL_ERROR_MESSAGE, e); }); return tokenPromise; } /** * Makes an async call to generate content. * * The response will be returned in {@link GenerateContentResult.response}. * * @example * ``` * const request = { * contents: [{role: 'user', parts: [{text: 'How are you doing today?'}]}], * }; * const result = await generativeModelPreview.generateContent(request); * console.log('Response: ', JSON.stringify(result.response)); * ``` * * @param request - A GenerateContentRequest object with the request contents. * @returns The GenerateContentResponse object with the response candidates. */ async generateContent( request: GenerateContentRequest | string ): Promise { request = formulateRequestToGenerateContentRequest(request); const formulatedRequest = { ...formulateSystemInstructionIntoGenerateContentRequest( request, this.systemInstruction ), cachedContent: this.cachedContent?.name, }; return generateContent( this.location, this.resourcePath, this.fetchToken(), formulatedRequest, this.apiEndpoint, this.generationConfig, this.safetySettings, this.tools, this.toolConfig, this.requestOptions ); } /** * Makes an async stream request to generate content. * * The response is returned chunk by chunk as it's being generated in {@link * StreamGenerateContentResult.stream}. After all chunks of the response are * returned, the aggregated response is available in * {@link StreamGenerateContentResult.response}. * * @example * ``` * const request = { * contents: [{role: 'user', parts: [{text: 'How are you doing today?'}]}], * }; * const streamingResult = await generativeModelPreview.generateContentStream(request); * for await (const item of streamingResult.stream) { * console.log('stream chunk: ', JSON.stringify(item)); * } * const aggregatedResponse = await streamingResult.response; * console.log('aggregated response: ', JSON.stringify(aggregatedResponse)); * ``` * * @param request - {@link GenerateContentRequest} * @returns Promise of {@link StreamGenerateContentResult} */ async generateContentStream( request: GenerateContentRequest | string ): Promise { request = formulateRequestToGenerateContentRequest(request); const formulatedRequest = { ...formulateSystemInstructionIntoGenerateContentRequest( request, this.systemInstruction ), cachedContent: this.cachedContent?.name, }; return generateContentStream( this.location, this.resourcePath, this.fetchToken(), formulatedRequest, this.apiEndpoint, this.generationConfig, this.safetySettings, this.tools, this.toolConfig, this.requestOptions ); } /** * Makes an async request to count tokens. * * The `countTokens` function returns the token count and the number of * billable characters for a prompt. * * @example * ``` * const request = { * contents: [{role: 'user', parts: [{text: 'How are you doing today?'}]}], * }; * const resp = await generativeModelPreview.countTokens(request); * console.log('count tokens response: ', resp); * ``` * * @param request - A CountTokensRequest object with the request contents. * @returns The CountTokensResponse object with the token count. */ async countTokens(request: CountTokensRequest): Promise { return countTokens( this.location, this.resourcePath, this.fetchToken(), request, this.apiEndpoint, this.requestOptions ); } /** * Instantiates a {@link ChatSessionPreview}. * * The {@link ChatSessionPreview} class is a stateful class that holds the state of * the conversation with the model and provides methods to interact with the * model in chat mode. Calling this method doesn't make any calls to a remote * endpoint. To make remote call, use {@link ChatSessionPreview.sendMessage} or * {@link ChatSessionPreview.sendMessageStream}. * * @example * ``` * const chat = generativeModelPreview.startChat(); * const result1 = await chat.sendMessage("How can I learn more about Node.js?"); * const response1 = await result1.response; * console.log('Response: ', JSON.stringify(response1)); * * const result2 = await chat.sendMessageStream("What about python?"); * const response2 = await result2.response; * console.log('Response: ', JSON.stringify(await response2)); * ``` * * @param request - {@link StartChatParams} * @returns {@link ChatSessionPreview} */ startChat(request?: StartChatParams): ChatSessionPreview { const startChatRequest: StartChatSessionRequest = { project: this.project, location: this.location, googleAuth: this.googleAuth, publisherModelEndpoint: this.publisherModelEndpoint, resourcePath: this.resourcePath, tools: this.tools, toolConfig: this.toolConfig, systemInstruction: this.systemInstruction, cachedContent: this.cachedContent?.name, }; if (request) { startChatRequest.history = request.history; startChatRequest.generationConfig = request.generationConfig ?? this.generationConfig; startChatRequest.safetySettings = request.safetySettings ?? this.safetySettings; startChatRequest.tools = request.tools ?? this.tools; startChatRequest.toolConfig = request.toolConfig ?? this.toolConfig; startChatRequest.systemInstruction = request.systemInstruction ?? this.systemInstruction; startChatRequest.cachedContent = request.cachedContent ?? this.cachedContent?.name; } return new ChatSessionPreview(startChatRequest, this.requestOptions); } getModelName(): string { return this.model; } getCachedContent(): CachedContent | undefined { return this.cachedContent; } getSystemInstruction(): Content | undefined { return this.systemInstruction; } } function formulateResourcePathFromModel( model: string, project: string, location: string ): string { let resourcePath: string; if (!model) { throw new ClientError('model parameter must not be empty.'); } if (!model.includes('/')) { // example 'gemini-1.0-pro' resourcePath = `projects/${project}/locations/${location}/publishers/google/models/${model}`; } else if (model.startsWith('models/')) { // example 'models/gemini-1.0-pro' resourcePath = `projects/${project}/locations/${location}/publishers/google/${model}`; } else if (model.startsWith('projects/')) { // example 'projects/my-project/locations/my-location/models/my-tuned-model' resourcePath = model; } else { throw new ClientError( 'model parameter must be either a Model Garden model ID or a full resource name.' ); } return resourcePath; } function formulateRequestToGenerateContentRequest( request: GenerateContentRequest | string ): GenerateContentRequest { if (typeof request === 'string') { return { contents: [{role: constants.USER_ROLE, parts: [{text: request}]}], } as GenerateContentRequest; } return request; } function formulateSystemInstructionIntoGenerateContentRequest( methodRequest: GenerateContentRequest, classSystemInstruction?: Content ): GenerateContentRequest { if (methodRequest.systemInstruction) { methodRequest.systemInstruction = formulateSystemInstructionIntoContent( methodRequest.systemInstruction ); return methodRequest; } if (classSystemInstruction) { methodRequest.systemInstruction = classSystemInstruction; } return methodRequest; } ================================================ FILE: vertexai/src/models/index.ts ================================================ /** * @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. */ export {ChatSession, ChatSessionPreview} from './chat_session'; export {GenerativeModel, GenerativeModelPreview} from './generative_models'; ================================================ FILE: vertexai/src/models/test/chat_session_test.ts ================================================ /** * @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. */ import {constants} from '../../util'; import {ChatSession, ChatSessionPreview} from '../chat_session'; import { Content, FunctionDeclarationSchemaType, GenerateContentCandidate, GenerateContentRequest, GenerateContentResponse, HarmBlockThreshold, HarmCategory, RequestOptions, SafetySetting, StartChatSessionRequest, Tool, } from '../../types'; import * as GenerateContentFunctions from '../../functions/generate_content'; import {createFakeGoogleAuth} from '../../testing/fake_google_auth'; const PROJECT = 'test_project'; const LOCATION = 'test_location'; const TEST_TOKEN = 'testtoken'; const FAKE_GOOGLE_AUTH = createFakeGoogleAuth({ scopes: 'https://www.googleapis.com/auth/cloud-platform', accessToken: TEST_TOKEN, }); const TEST_SAFETY_SETTINGS: SafetySetting[] = [ { category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH, }, ]; const TEST_GENERATION_CONFIG = { candidateCount: 1, stopSequences: ['hello'], }; const TEST_ENDPOINT_BASE_PATH = 'test.googleapis.com'; const TEST_TOOLS_WITH_FUNCTION_DECLARATION: Tool[] = [ { functionDeclarations: [ { name: 'get_current_weather', description: 'get weather in a given location', parameters: { type: FunctionDeclarationSchemaType.OBJECT, properties: { location: {type: FunctionDeclarationSchemaType.STRING}, unit: { type: FunctionDeclarationSchemaType.STRING, enum: ['celsius', 'fahrenheit'], }, }, required: ['location'], }, }, ], }, ]; const TEST_REQUEST_OPTIONS = { timeout: 0, }; const TEST_SYSTEM_INSTRUCTION_TEXT = 'system instruction'; const TEST_SYSTEM_INSTRUCTION = { role: constants.SYSTEM_ROLE, parts: [{text: TEST_SYSTEM_INSTRUCTION_TEXT}], }; const MODEL_NAME = 'test_model'; const RESOURCE_PATH = `projects/${PROJECT}/locations/${LOCATION}/publishers/google/models/${MODEL_NAME}`; const TEST_CHAT_MESSSAGE_TEXT_ROUND_1 = "what's the weather today?"; const TEST_CHAT_MESSSAGE_TEXT_ROUND_2 = [ 'how about tomorrow?', 'Will it rain?', ]; const TEST_CHAT_MESSSAGE_CONTENT_ROUND_1 = { index: 0, content: {parts: [{text: TEST_CHAT_MESSSAGE_TEXT_ROUND_1}], role: 'user'}, } as GenerateContentCandidate; const TEST_CHAT_MESSSAGE_CONTENT_ROUND_2 = { index: 0, content: { parts: TEST_CHAT_MESSSAGE_TEXT_ROUND_2.map(text => ({text})), role: 'user', }, } as GenerateContentCandidate; const TEST_MODEL_RESPONSE_ROUND_1 = { response: { candidates: [ { index: 0, content: {parts: [{text: "it's sunny today"}], role: 'model'}, }, ], } as GenerateContentResponse, }; const TEST_MODEL_RESPONSE_ROUND_2 = { response: { candidates: [ { index: 0, content: {parts: [{text: "it's rainy tomorrow"}], role: 'model'}, }, ], } as GenerateContentResponse, }; describe('ChatSession', () => { const chatSessionTestCases = [ (request: StartChatSessionRequest, requestOptions?: RequestOptions) => new ChatSession(request, requestOptions), (request: StartChatSessionRequest, requestOptions?: RequestOptions) => new ChatSessionPreview(request, requestOptions), ]; describe('sendMessage should call internal functions and append response to history', () => { const testCases = [ { name: 'when passed a string prompt in round 1 and list of strings in round 2', request: { resourcePath: RESOURCE_PATH, project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }, requestOptions: TEST_REQUEST_OPTIONS, sendMessageInputs: [ TEST_CHAT_MESSSAGE_TEXT_ROUND_1, TEST_CHAT_MESSSAGE_TEXT_ROUND_2, ], generateContentCalledParams: [ Object.values({ location: LOCATION, resourcePath: RESOURCE_PATH, token: jasmine.any(Promise), request: jasmine.objectContaining({ contents: [TEST_CHAT_MESSSAGE_CONTENT_ROUND_1.content], } as GenerateContentRequest), apiEndpoint: undefined, generationConfig: undefined, safetySettings: undefined, tools: undefined, toolConfig: undefined, requestOptions: TEST_REQUEST_OPTIONS, }), Object.values({ location: LOCATION, resourcePath: RESOURCE_PATH, token: jasmine.any(Promise), request: jasmine.objectContaining({ contents: [ TEST_CHAT_MESSSAGE_CONTENT_ROUND_1.content, TEST_MODEL_RESPONSE_ROUND_1.response!.candidates![0].content, TEST_CHAT_MESSSAGE_CONTENT_ROUND_2.content, ], } as GenerateContentRequest), apiEndpoint: undefined, generationConfig: undefined, safetySettings: undefined, tools: undefined, toolConfig: undefined, requestOptions: TEST_REQUEST_OPTIONS, }), ], generateContentReturns: [ TEST_MODEL_RESPONSE_ROUND_1, TEST_MODEL_RESPONSE_ROUND_2, ], }, { name: 'when pass params at class constructor level', request: { resourcePath: RESOURCE_PATH, project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, systemInstruction: TEST_SYSTEM_INSTRUCTION, history: [] as Content[], safetySettings: TEST_SAFETY_SETTINGS, generationConfig: TEST_GENERATION_CONFIG, tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION, toolConfig: {}, apiEndpoint: TEST_ENDPOINT_BASE_PATH, } as StartChatSessionRequest, requestOptions: TEST_REQUEST_OPTIONS, sendMessageInputs: [TEST_CHAT_MESSSAGE_TEXT_ROUND_1], generateContentCalledParams: [ Object.values({ location: LOCATION, resourcePath: RESOURCE_PATH, token: jasmine.any(Promise), request: jasmine.objectContaining({ contents: [TEST_CHAT_MESSSAGE_CONTENT_ROUND_1.content], } as GenerateContentRequest), apiEndpoint: TEST_ENDPOINT_BASE_PATH, generationConfig: TEST_GENERATION_CONFIG, safetySettings: TEST_SAFETY_SETTINGS, tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION, toolConfig: {}, requestOptions: TEST_REQUEST_OPTIONS, }), ], generateContentReturns: [TEST_MODEL_RESPONSE_ROUND_1], }, { name: 'when passed a string prompt and set history at class constructor level', request: { resourcePath: RESOURCE_PATH, project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, history: [TEST_CHAT_MESSSAGE_CONTENT_ROUND_1.content], }, requestOptions: TEST_REQUEST_OPTIONS, sendMessageInputs: [TEST_CHAT_MESSSAGE_TEXT_ROUND_1], generateContentCalledParams: [ Object.values({ location: LOCATION, resourcePath: RESOURCE_PATH, token: jasmine.any(Promise), request: jasmine.objectContaining({ contents: [ TEST_CHAT_MESSSAGE_CONTENT_ROUND_1.content, TEST_CHAT_MESSSAGE_CONTENT_ROUND_1.content, ], } as GenerateContentRequest), apiEndpoint: undefined, generationConfig: undefined, safetySettings: undefined, tools: undefined, toolConfig: undefined, requestOptions: TEST_REQUEST_OPTIONS, }), ], generateContentReturns: [TEST_MODEL_RESPONSE_ROUND_1], }, ].flatMap(testCase => chatSessionTestCases.map(createChatSession => ({ createChatSession, ...testCase, })) ); testCases.forEach((testCase: any) => { it(`${testCase.name} when call sendMessage`, async () => { const chatSession = testCase.createChatSession( testCase.request, testCase.requestOptions ); const generateContentSpy: jasmine.Spy = spyOn( GenerateContentFunctions, 'generateContent' ); generateContentSpy.and.returnValues( Promise.resolve(testCase.generateContentReturns[0]), Promise.resolve(testCase.generateContentReturns[1]) ); // Round 1. const round1Result = await chatSession.sendMessage( testCase.sendMessageInputs[0] ); expect(generateContentSpy).toHaveBeenCalledWith( ...testCase.generateContentCalledParams[0] ); expect(round1Result).toEqual(testCase.generateContentReturns[0]); let expectedHistory; if (testCase.request.history) { expectedHistory = [ ...(testCase.request.history ?? []), TEST_CHAT_MESSSAGE_CONTENT_ROUND_1.content, testCase.generateContentReturns[0].response.candidates[0].content, ]; } else { expectedHistory = [ TEST_CHAT_MESSSAGE_CONTENT_ROUND_1.content, testCase.generateContentReturns[0].response.candidates[0].content, ]; } expect(await chatSession.getHistory()).toEqual(expectedHistory); if (testCase.sendMessageInputs.length > 1) { // Round 2. const round2Result = await chatSession.sendMessage( testCase.sendMessageInputs[1] ); expect(generateContentSpy).toHaveBeenCalledWith( ...testCase.generateContentCalledParams[1] ); expect(round2Result).toEqual(testCase.generateContentReturns[1]); expect(await chatSession.getHistory()).toEqual([ TEST_CHAT_MESSSAGE_CONTENT_ROUND_1.content, testCase.generateContentReturns[0].response.candidates[0].content, TEST_CHAT_MESSSAGE_CONTENT_ROUND_2.content, testCase.generateContentReturns[1].response.candidates[0].content, ]); } }); it(`${testCase.name} when call sendMessageStream`, async () => { const chatSession = testCase.createChatSession( testCase.request, testCase.requestOptions ); const generateContentSpy: jasmine.Spy = spyOn( GenerateContentFunctions, 'generateContentStream' ); generateContentSpy.and.returnValues( Promise.resolve(testCase.generateContentReturns[0]), Promise.resolve(testCase.generateContentReturns[1]) ); // Round 1. const round1Result = await chatSession.sendMessageStream( testCase.sendMessageInputs[0] ); expect(generateContentSpy).toHaveBeenCalledWith( ...testCase.generateContentCalledParams[0] ); expect(round1Result).toEqual(testCase.generateContentReturns[0]); let expectedHistory; if (testCase.request.history) { expectedHistory = [ ...(testCase.request.history ?? []), TEST_CHAT_MESSSAGE_CONTENT_ROUND_1.content, testCase.generateContentReturns[0].response.candidates[0].content, ]; } else { expectedHistory = [ TEST_CHAT_MESSSAGE_CONTENT_ROUND_1.content, testCase.generateContentReturns[0].response.candidates[0].content, ]; } expect(await chatSession.getHistory()).toEqual(expectedHistory); if (testCase.sendMessageInputs.length > 1) { // Round 2. const round2Result = await chatSession.sendMessageStream( testCase.sendMessageInputs[1] ); expect(generateContentSpy).toHaveBeenCalledWith( ...testCase.generateContentCalledParams[1] ); expect(round2Result).toEqual(testCase.generateContentReturns[1]); expect((await chatSession.getHistory()).slice(-4)).toEqual([ TEST_CHAT_MESSSAGE_CONTENT_ROUND_1.content, testCase.generateContentReturns[0].response.candidates[0].content, TEST_CHAT_MESSSAGE_CONTENT_ROUND_2.content, testCase.generateContentReturns[1].response.candidates[0].content, ]); } }); }); }); }); ================================================ FILE: vertexai/src/models/test/generative_models_test.ts ================================================ /** * @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. */ import {constants} from '../../util'; import {GenerativeModel, GenerativeModelPreview} from '../generative_models'; import { FunctionDeclarationSchemaType, GenerateContentRequest, HarmBlockThreshold, HarmCategory, SafetySetting, Tool, GetGenerativeModelParams, ToolConfig, FunctionCallingMode, StartChatSessionRequest, } from '../../types'; import * as GenerateContentFunctions from '../../functions/generate_content'; import * as CountTokensFunctions from '../../functions/count_tokens'; import * as models from '../../models'; import {createFakeGoogleAuth} from '../../testing/fake_google_auth'; import {RequestOptions} from 'https'; import {ChatSession} from '../chat_session'; const PROJECT = 'test_project'; const LOCATION = 'test_location'; const MODEL_NAME = 'model-name'; const RESOURCE_PATH = `projects/${PROJECT}/locations/${LOCATION}/publishers/google/models/${MODEL_NAME}`; const TEST_TOKEN = 'testtoken'; const FAKE_GOOGLE_AUTH = 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_CONTENT_MESSAGE: GenerateContentRequest = { contents: [ {role: constants.USER_ROLE, parts: [{text: TEST_CHAT_MESSSAGE_TEXT}]}, ], }; const TEST_SAFETY_SETTINGS: SafetySetting[] = [ { category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_ONLY_HIGH, }, ]; const TEST_GENERATION_CONFIG = { candidateCount: 1, stopSequences: ['hello'], }; const TEST_ENDPOINT_BASE_PATH = 'test.googleapis.com'; const TEST_TOOLS_WITH_FUNCTION_DECLARATION: Tool[] = [ { functionDeclarations: [ { name: 'get_current_weather', description: 'get weather in a given location', parameters: { type: FunctionDeclarationSchemaType.OBJECT, properties: { location: {type: FunctionDeclarationSchemaType.STRING}, unit: { type: FunctionDeclarationSchemaType.STRING, enum: ['celsius', 'fahrenheit'], }, }, required: ['location'], }, }, ], }, ]; const TEST_TOOLS_CONFIG: ToolConfig = { functionCallingConfig: { mode: FunctionCallingMode.ANY, allowedFunctionNames: ['get_current_weather'], }, }; const TEST_REQUEST_OPTIONS = { timeout: 0, }; const TEST_SYSTEM_INSTRUCTION = { role: constants.SYSTEM_ROLE, parts: [{text: 'system instruction'}], }; const TEST_SYSTEM_INSTRUCTION_WRONG_ROLE = { role: 'WRONG_ROLE', parts: [{text: 'system instruction'}], }; const BASE_MODEL_PARAMS = { project: PROJECT, location: LOCATION, auth: FAKE_GOOGLE_AUTH, }; describe('', () => { const modelTestCases = [ { createModel: (param: GetGenerativeModelParams) => new GenerativeModel(param), isPreviewModel: false, }, { createModel: (param: GetGenerativeModelParams) => new GenerativeModelPreview(param), isPreviewModel: true, }, ]; describe('generate method should call internal function', () => { const testCases = [ { name: 'when passed a string prompt', previewOnly: false, modelParams: { ...BASE_MODEL_PARAMS, model: MODEL_NAME, googleAuth: FAKE_GOOGLE_AUTH, }, generateContentParams: TEST_CHAT_MESSSAGE_TEXT, expectedParams: Object.values({ location: LOCATION, resourcePath: RESOURCE_PATH, token: jasmine.any(Promise), request: jasmine.objectContaining(TEST_USER_CONTENT_MESSAGE), apiEndpoint: undefined, generationConfig: undefined, safetySettings: undefined, tools: undefined, toolConfig: undefined, requestOptions: {}, }), }, { name: 'when passed a object prompt', previewOnly: false, modelParams: { ...BASE_MODEL_PARAMS, model: MODEL_NAME, googleAuth: FAKE_GOOGLE_AUTH, }, generateContentParams: TEST_USER_CONTENT_MESSAGE, expectedParams: Object.values({ location: LOCATION, resourcePath: RESOURCE_PATH, token: jasmine.any(Promise), request: jasmine.objectContaining(TEST_USER_CONTENT_MESSAGE), apiEndpoint: undefined, generationConfig: undefined, safetySettings: undefined, tools: undefined, toolConfig: undefined, requestOptions: {}, }), }, { name: 'when the model name has `models` prefix', previewOnly: false, modelParams: { ...BASE_MODEL_PARAMS, model: 'models/model-name', googleAuth: FAKE_GOOGLE_AUTH, }, generateContentParams: TEST_CHAT_MESSSAGE_TEXT, expectedParams: Object.values({ location: LOCATION, resourcePath: RESOURCE_PATH, token: jasmine.any(Promise), request: jasmine.objectContaining(TEST_USER_CONTENT_MESSAGE), apiEndpoint: undefined, generationConfig: undefined, safetySettings: undefined, tools: undefined, toolConfig: undefined, requestOptions: {}, }), }, { name: 'when the model name has `project` prefix', previewOnly: false, modelParams: { ...BASE_MODEL_PARAMS, model: 'projects/my-project/locations/my-location/models/my-tuned-model', googleAuth: FAKE_GOOGLE_AUTH, }, generateContentParams: TEST_CHAT_MESSSAGE_TEXT, expectedParams: Object.values({ location: LOCATION, resourcePath: 'projects/my-project/locations/my-location/models/my-tuned-model', token: jasmine.any(Promise), request: jasmine.objectContaining(TEST_USER_CONTENT_MESSAGE), apiEndpoint: undefined, generationConfig: undefined, safetySettings: undefined, tools: undefined, toolConfig: undefined, requestOptions: {}, }), }, { name: 'when pass params at model constructor level', previewOnly: false, modelParams: { ...BASE_MODEL_PARAMS, model: MODEL_NAME, googleAuth: FAKE_GOOGLE_AUTH, apiEndpoint: TEST_ENDPOINT_BASE_PATH, generationConfig: TEST_GENERATION_CONFIG, systemInstruction: TEST_SYSTEM_INSTRUCTION, tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION, toolConfig: TEST_TOOLS_CONFIG, safetySettings: TEST_SAFETY_SETTINGS, requestOptions: TEST_REQUEST_OPTIONS, }, generateContentParams: TEST_CHAT_MESSSAGE_TEXT, expectedParams: Object.values({ location: LOCATION, resourcePath: RESOURCE_PATH, token: jasmine.any(Promise), request: jasmine.objectContaining({ systemInstruction: TEST_SYSTEM_INSTRUCTION, ...TEST_USER_CONTENT_MESSAGE, }), apiEndpoint: TEST_ENDPOINT_BASE_PATH, generationConfig: TEST_GENERATION_CONFIG, safetySettings: TEST_SAFETY_SETTINGS, tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION, toolConfig: TEST_TOOLS_CONFIG, requestOptions: TEST_REQUEST_OPTIONS, }), }, { name: 'when pass params at model constructor level', previewOnly: true, modelParams: { ...BASE_MODEL_PARAMS, model: MODEL_NAME, googleAuth: FAKE_GOOGLE_AUTH, apiEndpoint: TEST_ENDPOINT_BASE_PATH, generationConfig: TEST_GENERATION_CONFIG, systemInstruction: TEST_SYSTEM_INSTRUCTION, tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION, toolConfig: TEST_TOOLS_CONFIG, safetySettings: TEST_SAFETY_SETTINGS, requestOptions: TEST_REQUEST_OPTIONS, cachedContent: {name: 'cachedContentName'}, }, generateContentParams: TEST_CHAT_MESSSAGE_TEXT, expectedParams: Object.values({ location: LOCATION, resourcePath: RESOURCE_PATH, token: jasmine.any(Promise), request: jasmine.objectContaining({ systemInstruction: TEST_SYSTEM_INSTRUCTION, ...TEST_USER_CONTENT_MESSAGE, cachedContent: 'cachedContentName', }), apiEndpoint: TEST_ENDPOINT_BASE_PATH, generationConfig: TEST_GENERATION_CONFIG, safetySettings: TEST_SAFETY_SETTINGS, tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION, toolConfig: TEST_TOOLS_CONFIG, requestOptions: TEST_REQUEST_OPTIONS, }), }, { name: 'when pass params at model method level', previewOnly: false, modelParams: { ...BASE_MODEL_PARAMS, model: MODEL_NAME, googleAuth: FAKE_GOOGLE_AUTH, apiEndpoint: TEST_ENDPOINT_BASE_PATH, generationConfig: undefined, systemInstruction: undefined, tools: undefined, toolConfig: undefined, safetySettings: undefined, requestOptions: TEST_REQUEST_OPTIONS, }, generateContentParams: { ...TEST_USER_CONTENT_MESSAGE, generationConfig: TEST_GENERATION_CONFIG, systemInstruction: TEST_SYSTEM_INSTRUCTION, tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION, toolConfig: TEST_TOOLS_CONFIG, safetySettings: TEST_SAFETY_SETTINGS, }, expectedParams: Object.values({ location: LOCATION, resourcePath: RESOURCE_PATH, token: jasmine.any(Promise), request: jasmine.objectContaining({ ...TEST_USER_CONTENT_MESSAGE, systemInstruction: TEST_SYSTEM_INSTRUCTION, generationConfig: TEST_GENERATION_CONFIG, tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION, toolConfig: TEST_TOOLS_CONFIG, safetySettings: TEST_SAFETY_SETTINGS, }), apiEndpoint: TEST_ENDPOINT_BASE_PATH, generationConfig: undefined, tools: undefined, toolConfig: undefined, safetySettings: undefined, requestOptions: TEST_REQUEST_OPTIONS, }), }, { name: 'when set system instruction(wrong role) in model constructor', previewOnly: false, modelParams: { ...BASE_MODEL_PARAMS, model: MODEL_NAME, googleAuth: FAKE_GOOGLE_AUTH, systemInstruction: TEST_SYSTEM_INSTRUCTION_WRONG_ROLE, }, generateContentParams: TEST_CHAT_MESSSAGE_TEXT, expectedParams: Object.values({ location: LOCATION, resourcePath: RESOURCE_PATH, token: jasmine.any(Promise), request: jasmine.objectContaining({ systemInstruction: TEST_SYSTEM_INSTRUCTION_WRONG_ROLE, ...TEST_USER_CONTENT_MESSAGE, }), apiEndpoint: undefined, generationConfig: undefined, safetySettings: undefined, tools: undefined, toolConfig: undefined, requestOptions: {}, }), }, { name: 'when set system instruction(wrong role) in model method level', previewOnly: false, modelParams: { ...BASE_MODEL_PARAMS, model: MODEL_NAME, googleAuth: FAKE_GOOGLE_AUTH, }, generateContentParams: { ...TEST_USER_CONTENT_MESSAGE, systemInstruction: TEST_SYSTEM_INSTRUCTION_WRONG_ROLE, }, expectedParams: Object.values({ location: LOCATION, resourcePath: RESOURCE_PATH, token: jasmine.any(Promise), request: jasmine.objectContaining({ ...TEST_USER_CONTENT_MESSAGE, systemInstruction: TEST_SYSTEM_INSTRUCTION_WRONG_ROLE, }), apiEndpoint: undefined, generationConfig: undefined, safetySettings: undefined, tools: undefined, toolConfig: undefined, requestOptions: {}, }), }, ] .flatMap(testCase => modelTestCases.map((modelTestCase: any) => ({ createModel: modelTestCase.createModel, isPreviewModel: modelTestCase.isPreviewModel, ...testCase, })) ) .filter( (testCase: any) => !testCase.previewOnly || (testCase.previewOnly && testCase.isPreviewModel) ); testCases.forEach((testCase: any) => { it(`${testCase.name} when call generateContent (isPreviewModel=${testCase.isPreviewModel})`, async () => { const model = testCase.createModel(testCase.modelParams); const generateContentSpy: jasmine.Spy = spyOn( GenerateContentFunctions, 'generateContent' ); await model.generateContent(testCase.generateContentParams); const expectedParams = testCase.expectedParams; expect(generateContentSpy).toHaveBeenCalledWith(...expectedParams); }); }); testCases .filter( (testCase: any) => !testCase.previewOnly || (testCase.previewOnly && testCase.isPreviewModel) ) .forEach((testCase: any) => { it(`${testCase.name} when call generateContentStream (isPreviewModel=${testCase.isPreviewModel})`, async () => { const model = testCase.createModel(testCase.modelParams); const generateContentSpy: jasmine.Spy = spyOn( GenerateContentFunctions, 'generateContentStream' ); await model.generateContentStream(testCase.generateContentParams); const expectedParams = testCase.expectedParams; expect(generateContentSpy).toHaveBeenCalledWith(...expectedParams); }); }); }); describe('countTokens method should call internal function', () => { const testCases = [ { name: 'call internal countTokens when passed a object prompt', modelParams: { ...BASE_MODEL_PARAMS, model: MODEL_NAME, googleAuth: FAKE_GOOGLE_AUTH, }, countTokensRequest: TEST_USER_CONTENT_MESSAGE, expectedParams: Object.values({ location: LOCATION, resourcePath: RESOURCE_PATH, token: jasmine.any(Promise), request: TEST_USER_CONTENT_MESSAGE, apiEndpoint: undefined, requestOptions: {}, }), }, { name: 'call internal counTokens when set timeout request option', modelParams: { ...BASE_MODEL_PARAMS, model: MODEL_NAME, googleAuth: FAKE_GOOGLE_AUTH, requestOptions: TEST_REQUEST_OPTIONS, }, countTokensRequest: TEST_USER_CONTENT_MESSAGE, expectedParams: Object.values({ location: LOCATION, resourcePath: RESOURCE_PATH, token: jasmine.any(Promise), request: TEST_USER_CONTENT_MESSAGE, apiEndpoint: undefined, requestOptions: TEST_REQUEST_OPTIONS, }), }, ] .flatMap(testCase => modelTestCases.map((modelTestCase: any) => ({ createModel: modelTestCase.createModel, isPreviewModel: modelTestCase.isPreviewModel, ...testCase, })) ) .filter( (testCase: any) => !testCase.previewOnly || (testCase.previewOnly && testCase.isPreviewModel) ); testCases.forEach((testCase: any) => { it(`${testCase.name} when call countTokens`, async () => { const model = testCase.createModel(testCase.modelParams); const countTokensSpy: jasmine.Spy = spyOn( CountTokensFunctions, 'countTokens' ); await model.countTokens(testCase.countTokensRequest); const expectedParams = testCase.expectedParams; expect(countTokensSpy).toHaveBeenCalledWith(...expectedParams); }); }); }); }); ================================================ FILE: vertexai/src/models/test/models_test.ts ================================================ /** * @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. */ import {constants} from '../../util'; import {GenerativeModel, GenerativeModelPreview} from '../generative_models'; import {ChatSession, ChatSessionPreview} from '../chat_session'; import { CountTokensRequest, FinishReason, FunctionDeclarationSchemaType, GenerateContentRequest, GenerateContentResponse, GenerateContentResult, GoogleSearchRetrievalTool, HarmBlockThreshold, HarmCategory, HarmProbability, Mode, RequestOptions, SafetyRating, SafetySetting, StreamGenerateContentResult, Tool, } from '../../types'; import * as PostFetchFunctions from '../../functions/post_fetch_processing'; import * as GenerateContentFunctions from '../../functions/generate_content'; import * as CountTokensFunctions from '../../functions/count_tokens'; import {createFakeGoogleAuth} from '../../testing/fake_google_auth'; const PROJECT = 'test_project'; const LOCATION = 'test_location'; const TEST_TOKEN = 'testtoken'; const FAKE_GOOGLE_AUTH = 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: constants.USER_ROLE, parts: [{text: TEST_CHAT_MESSSAGE_TEXT}]}, ]; const TEST_SAFETY_RATINGS: SafetyRating[] = [ { category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, probability: HarmProbability.NEGLIGIBLE, }, ]; const TEST_CANDIDATES = [ { index: 1, content: { role: constants.MODEL_ROLE, parts: [{text: 'Im doing great! How are you?'}], }, finishReason: 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: 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: 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: constants.USER_ROLE, parts: [ {text: TEST_CHAT_MESSSAGE_TEXT}, {fileData: {fileUri: 'test_image.jpeg', mimeType: 'image/jpeg'}}, ], }, ]; const TEST_SAFETY_SETTINGS: SafetySetting[] = [ { category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: 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: constants.MODEL_ROLE, parts: [TEST_FUNCTION_CALL_RESPONSE], }, finishReason: 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: Tool[] = [ { functionDeclarations: [ { name: 'get_current_weather', description: 'get weather in a given location', parameters: { type: FunctionDeclarationSchemaType.OBJECT, properties: { location: {type: FunctionDeclarationSchemaType.STRING}, unit: { type: FunctionDeclarationSchemaType.STRING, enum: ['celsius', 'fahrenheit'], }, }, required: ['location'], }, }, ], }, ]; const TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL: GoogleSearchRetrievalTool[] = [ { googleSearchRetrieval: { dynamicRetrievalConfig: { dynamicThreshold: 0.5, mode: Mode.MODE_DYNAMIC, }, }, }, ]; const TEST_GCS_FILENAME = 'gs://test_bucket/test_image.jpeg'; const TEST_MULTIPART_MESSAGE = [ { role: 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: 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: constants.SYSTEM_ROLE, parts: [{text: 'system instruction'}], }; const TEST_SYSTEM_INSTRUCTION_1 = { role: constants.SYSTEM_ROLE, parts: [{text: 'system instruction1'}], }; const TEST_SYSTEM_INSTRUCTION_WRONG_ROLE = { role: 'WRONG_ROLE', parts: [{text: 'system instruction'}], }; async function* testGenerator(): AsyncGenerator { yield { candidates: TEST_CANDIDATES, }; } const DATE_NOW_PRECISION_MILLIS = 2; async function* testGeneratorMultiStream(): AsyncGenerator { yield { candidates: TEST_CANDIDATES, }; await new Promise(resolve => setTimeout(resolve, 200)); yield { candidates: TEST_CANDIDATES2, }; } class ChatSessionForTest extends ChatSession { public declare readonly requestOptions?: RequestOptions; } class ChatSessionPreviewForTest extends ChatSessionPreview { public declare readonly requestOptions?: RequestOptions; } describe('GenerativeModel startChat', () => { it('returns ChatSession when pass no arg', () => { const model = new GenerativeModel({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const chat = model.startChat(); expect(chat).toBeInstanceOf(ChatSession); }); it('returns ChatSession when pass an arg', () => { const model = new GenerativeModel({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const chat = model.startChat({ history: TEST_USER_CHAT_MESSAGE, }); expect(chat).toBeInstanceOf(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 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(ChatSession); }); it('set timeout info in ChatSession', () => { const model = new 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, }) as ChatSessionForTest; 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 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 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 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 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 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 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 GenerativeModelPreview({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const chat = model.startChat(); expect(chat).toBeInstanceOf(ChatSessionPreview); }); it('returns ChatSessionPreview when pass an arg', () => { const model = new GenerativeModelPreview({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const chat = model.startChat({ history: TEST_USER_CHAT_MESSAGE, }); expect(chat).toBeInstanceOf(ChatSessionPreview); }); it('returns ChatSessionPreview when pass an arg with generationConfig including responseMimeType', async () => { const model = new 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(ChatSessionPreview); }); it('set timeout info in ChatSession', () => { const model = new 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, }) as ChatSessionPreviewForTest; 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 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 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 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 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 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 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: GenerativeModel; let fetchSpy: jasmine.Spy; let expectedResult: GenerateContentResponse; beforeEach(() => { model = new 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: GenerateContentRequest = { contents: TEST_USER_CHAT_MESSAGE, }; const expectedResult: GenerateContentResult = { 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 GenerativeModel({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: GenerateContentRequest = { 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 GenerativeModel({ model: 'models/gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: GenerateContentRequest = { 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 GenerativeModel({ model: 'projects/my-project/my-tuned-gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: GenerateContentRequest = { 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 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 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 GenerativeModel({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, requestOptions: TEST_REQUEST_OPTIONS, }); const req: GenerateContentRequest = { 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 GenerativeModel({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, systemInstruction: TEST_SYSTEM_INSTRUCTION, }); const req: GenerateContentRequest = { 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 GenerativeModel({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: GenerateContentRequest = { 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 GenerativeModel({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, systemInstruction: TEST_SYSTEM_INSTRUCTION_WRONG_ROLE, }); const req: GenerateContentRequest = { 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 GenerativeModel({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: GenerateContentRequest = { 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: GenerateContentResult = { 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: GenerateContentRequest = { contents: TEST_USER_CHAT_MESSAGE_WITH_GCS_FILE, }; const expectedResult: GenerateContentResult = { 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: GenerateContentRequest = { contents: TEST_USER_CHAT_MESSAGE, safetySettings: TEST_SAFETY_SETTINGS, generationConfig: TEST_GENERATION_CONFIG, }; const expectedResult: GenerateContentResult = { 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 GenerativeModel({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, apiEndpoint: TEST_ENDPOINT_BASE_PATH, }); const req: GenerateContentRequest = { 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: GenerateContentRequest = { 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: GenerateContentRequest = { 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: GenerateContentRequest = { 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: GenerateContentRequest = { 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 as string; expect(actualRequestArgsBody).toEqual(expectedRequestArgBody); }); it('aggregates citation metadata', async () => { const req: GenerateContentRequest = { contents: TEST_USER_CHAT_MESSAGE, }; const resp = await model.generateContent(req); expect( resp.response.candidates![0].citationMetadata?.citations.length ).toEqual( TEST_MODEL_RESPONSE.candidates[0].citationMetadata.citations.length ); }); it('returns a FunctionCall when passed a FunctionDeclaration', async () => { const req: GenerateContentRequest = { contents: [ {role: 'user', parts: [{text: 'What is the weater like in Boston?'}]}, ], tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION, }; const expectedResult: GenerateContentResult = { 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 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 GenerativeModel({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION, }); const req: GenerateContentRequest = { 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: GenerativeModelPreview; let fetchSpy: jasmine.Spy; let expectedResult: GenerateContentResponse; beforeEach(() => { model = new 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: GenerateContentRequest = { contents: TEST_USER_CHAT_MESSAGE, }; const expectedResult: GenerateContentResult = { 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 GenerativeModelPreview({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: GenerateContentRequest = { 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 GenerativeModelPreview({ model: 'models/gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: GenerateContentRequest = { 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 GenerativeModelPreview({ model: 'projects/my-project/my-tuned-gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: GenerateContentRequest = { 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 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 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 GenerativeModelPreview({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, requestOptions: TEST_REQUEST_OPTIONS, }); const req: GenerateContentRequest = { 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 GenerativeModelPreview({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, systemInstruction: TEST_SYSTEM_INSTRUCTION, }); const req: GenerateContentRequest = { 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 GenerativeModelPreview({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: GenerateContentRequest = { 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 GenerativeModelPreview({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, systemInstruction: TEST_SYSTEM_INSTRUCTION_WRONG_ROLE, }); const req: GenerateContentRequest = { 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 GenerativeModelPreview({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: GenerateContentRequest = { 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: GenerateContentResult = { 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: GenerateContentRequest = { contents: TEST_USER_CHAT_MESSAGE_WITH_GCS_FILE, }; const expectedResult: GenerateContentResult = { 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: GenerateContentRequest = { contents: TEST_USER_CHAT_MESSAGE, safetySettings: TEST_SAFETY_SETTINGS, generationConfig: TEST_GENERATION_CONFIG, }; const expectedResult: GenerateContentResult = { 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 GenerativeModelPreview({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, apiEndpoint: TEST_ENDPOINT_BASE_PATH, }); const req: GenerateContentRequest = { 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: GenerateContentRequest = { 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: GenerateContentRequest = { 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: GenerateContentRequest = { 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: GenerateContentRequest = { 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 as string; expect(actualRequestArgsBody).toEqual(expectedRequestArgsBody); }); it('aggregates citation metadata', async () => { const req: GenerateContentRequest = { contents: TEST_USER_CHAT_MESSAGE, }; const resp = await model.generateContent(req); expect( resp.response.candidates![0].citationMetadata?.citations.length ).toEqual( TEST_MODEL_RESPONSE.candidates[0].citationMetadata.citations.length ); }); it('returns a FunctionCall when passed a FunctionDeclaration', async () => { const req: GenerateContentRequest = { contents: [ {role: 'user', parts: [{text: 'What is the weater like in Boston?'}]}, ], tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION, }; const expectedResult: GenerateContentResult = { 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 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 GenerativeModelPreview({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION, }); const req: GenerateContentRequest = { 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: GenerativeModel; let expectedStreamResult: StreamGenerateContentResult; let fetchSpy: jasmine.Spy; beforeEach(() => { model = new 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: GenerateContentRequest = {contents: TEST_USER_CHAT_MESSAGE}; const expectedResult: StreamGenerateContentResult = { 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 GenerativeModel({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: GenerateContentRequest = { 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 GenerativeModel({ model: 'models/gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: GenerateContentRequest = { 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 GenerativeModel({ model: 'projects/my-project/my-tuned-gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: GenerateContentRequest = { 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 GenerativeModel({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, requestOptions: TEST_REQUEST_OPTIONS, }); const req: GenerateContentRequest = { 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 GenerativeModel({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: GenerateContentRequest = { 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 GenerativeModel({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: GenerateContentRequest = { 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: StreamGenerateContentResult = { 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: GenerateContentRequest = { contents: TEST_MULTIPART_MESSAGE, }; const expectedResult: StreamGenerateContentResult = { 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: GenerateContentRequest = { contents: TEST_MULTIPART_MESSAGE_BASE64, }; const expectedResult: StreamGenerateContentResult = { 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: GenerateContentRequest = { contents: [ {role: 'user', parts: [{text: 'What is the weater like in Boston?'}]}, ], tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION, }; const expectedStreamResult: StreamGenerateContentResult = { 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 GenerativeModel({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION, }); const expectedResult: StreamGenerateContentResult = { 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 GenerativeModel({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION, }); const expectedResult: StreamGenerateContentResult = { response: Promise.resolve(TEST_MODEL_RESPONSE_WITH_FUNCTION_CALL), stream: testGenerator(), }; const req: GenerateContentRequest = { 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: GenerativeModelPreview; let expectedStreamResult: StreamGenerateContentResult; let fetchSpy: jasmine.Spy; beforeEach(() => { model = new 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: GenerateContentRequest = {contents: TEST_USER_CHAT_MESSAGE}; const expectedResult: StreamGenerateContentResult = { 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: GenerateContentRequest = {contents: TEST_USER_CHAT_MESSAGE}; const expectedResult: StreamGenerateContentResult = { 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 GenerativeModelPreview({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: GenerateContentRequest = { 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 GenerativeModelPreview({ model: 'models/gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: GenerateContentRequest = { 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 GenerativeModelPreview({ model: 'projects/my-project/my-tuned-gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: GenerateContentRequest = { 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 GenerativeModelPreview({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, requestOptions: TEST_REQUEST_OPTIONS, }); const req: GenerateContentRequest = { 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 GenerativeModelPreview({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: GenerateContentRequest = { 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 GenerativeModelPreview({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: GenerateContentRequest = { 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: StreamGenerateContentResult = { 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: GenerateContentRequest = { contents: TEST_MULTIPART_MESSAGE, }; const expectedResult: StreamGenerateContentResult = { 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: GenerateContentRequest = { contents: TEST_MULTIPART_MESSAGE_BASE64, }; const expectedResult: StreamGenerateContentResult = { 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: GenerateContentRequest = { contents: [ {role: 'user', parts: [{text: 'What is the weater like in Boston?'}]}, ], tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION, }; const expectedStreamResult: StreamGenerateContentResult = { 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 GenerativeModelPreview({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION, }); const expectedResult: StreamGenerateContentResult = { 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 GenerativeModelPreview({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, tools: TEST_TOOLS_WITH_FUNCTION_DECLARATION, }); const expectedResult: StreamGenerateContentResult = { response: Promise.resolve(TEST_MODEL_RESPONSE_WITH_FUNCTION_CALL), stream: testGenerator(), }; const req: GenerateContentRequest = { 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: ChatSession; let chatSessionWithNoArgs: ChatSession; let chatSessionWithFunctionCall: ChatSession; let model: GenerativeModel; beforeEach(async () => { model = new 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: jasmine.Spy; 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: GenerateContentResult = { 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 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: GenerateContentResult = { 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 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: GenerateContentResult = { 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 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: GenerateContentResult = { 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: GenerateContentResult = { response: TEST_MODEL_RESPONSE, }; const model = new 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 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, }) as ChatSessionForTest; const req = 'How are you doing today?'; const generateContentSpy: jasmine.Spy = 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: GenerateContentResult = { 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: GenerateContentResult = { 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: GenerateContentResult = { response: TEST_MODEL_RESPONSE_WITH_FUNCTION_CALL, }; const expectedResult: GenerateContentResult = { 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: GenerateContentResult = { response: TEST_MODEL_RESPONSE, }; const expectedFollowUpResult: GenerateContentResult = { 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: StreamGenerateContentResult = { response: Promise.resolve(TEST_MODEL_RESPONSE), stream: testGenerator(), }; const chatSession = model.startChat({ history: [ { role: 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(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(constants.USER_ROLE); expect(secondHistory[1].role).toEqual(constants.USER_ROLE); expect(secondHistory[2].role).toEqual(constants.MODEL_ROLE); }); it('returns a StreamGenerateContentResponse in streaming mode', async () => { const req = 'How are you doing today?'; const expectedResult: StreamGenerateContentResult = { response: Promise.resolve(TEST_MODEL_RESPONSE), stream: testGeneratorMultiStream(), }; spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult); const chatSession = model.startChat({ history: [ { role: 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 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: StreamGenerateContentResult = { 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 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: StreamGenerateContentResult = { 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 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: StreamGenerateContentResult = { 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 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, }) as ChatSessionForTest; const req = 'How are you doing today?'; const generateContentSpy: jasmine.Spy = 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: StreamGenerateContentResult = { 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: StreamGenerateContentResult = { 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: ChatSessionPreview; let chatSessionWithNoArgs: ChatSessionPreview; let chatSessionWithFunctionCall: ChatSessionPreview; let model: GenerativeModelPreview; let expectedStreamResult: StreamGenerateContentResult; let fetchSpy: jasmine.Spy; beforeEach(async () => { model = new 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: GenerateContentResult = { 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 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: GenerateContentResult = { 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 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: GenerateContentResult = { 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 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: GenerateContentResult = { 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 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 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, }) as ChatSessionPreviewForTest; const req = TEST_CHAT_MESSSAGE_TEXT; const generateContentSpy: jasmine.Spy = 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: GenerateContentResult = { 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: GenerateContentResult = { 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: GenerateContentResult = { response: TEST_MODEL_RESPONSE_WITH_FUNCTION_CALL, }; const expectedResult: GenerateContentResult = { 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: GenerateContentResult = { response: TEST_MODEL_RESPONSE, }; const expectedFollowUpResult: GenerateContentResult = { 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: StreamGenerateContentResult = { response: Promise.resolve(TEST_MODEL_RESPONSE), stream: testGenerator(), }; const chatSession = model.startChat({ history: [ { role: 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(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(constants.USER_ROLE); expect(secondHistory[1].role).toEqual(constants.USER_ROLE); expect(secondHistory[2].role).toEqual(constants.MODEL_ROLE); }); it('returns a StreamGenerateContentResponse in streaming mode', async () => { const req = TEST_CHAT_MESSSAGE_TEXT; const expectedResult: StreamGenerateContentResult = { response: Promise.resolve(TEST_MODEL_RESPONSE), stream: testGeneratorMultiStream(), }; spyOn(PostFetchFunctions, 'processStream').and.resolveTo(expectedResult); const chatSession = model.startChat({ history: [ { role: 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 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: StreamGenerateContentResult = { 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 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: StreamGenerateContentResult = { 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 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: StreamGenerateContentResult = { 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 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, }) as ChatSessionPreviewForTest; const req = TEST_CHAT_MESSSAGE_TEXT; const generateContentSpy: jasmine.Spy = 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: StreamGenerateContentResult = { 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: StreamGenerateContentResult = { 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 GenerativeModel({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: CountTokensRequest = { 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 GenerativeModel({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, requestOptions: TEST_REQUEST_OPTIONS, }); const req: CountTokensRequest = { 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 GenerativeModelPreview({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: CountTokensRequest = { 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 GenerativeModelPreview({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, requestOptions: TEST_REQUEST_OPTIONS, }); const req: CountTokensRequest = { 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 GenerativeModel({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const chatSession = model.startChat(); const message = 'hi'; const req: GenerateContentRequest = { contents: TEST_USER_CHAT_MESSAGE, }; const countTokenReq: CountTokensRequest = { 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 GenerativeModelPreview({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const chatSession = model.startChat(); const message = 'hi'; const req: GenerateContentRequest = { contents: TEST_USER_CHAT_MESSAGE, }; const countTokenReq: CountTokensRequest = { 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 GenerativeModel({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: GenerateContentRequest = { contents: TEST_USER_CHAT_MESSAGE, }; const message = 'hi'; const chatSession = model.startChat(); const countTokenReq: CountTokensRequest = { 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 GenerativeModelPreview({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const req: GenerateContentRequest = { contents: TEST_USER_CHAT_MESSAGE, }; const message = 'hi'; const chatSession = model.startChat(); const countTokenReq: CountTokensRequest = { 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: GenerateContentRequest = { 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 GenerativeModel({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const message = 'hi'; const chatSession = model.startChat(); const countTokenReq: CountTokensRequest = { 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: GenerateContentRequest = { 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 GenerativeModelPreview({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const message = 'hi'; const chatSession = model.startChat(); const countTokenReq: CountTokensRequest = { 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: GenerateContentRequest = { 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 GenerativeModel({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const message = 'hi'; const chatSession = model.startChat(); const countTokenReq: CountTokensRequest = { 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: GenerateContentRequest = { 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 GenerativeModelPreview({ model: 'gemini-pro', project: PROJECT, location: LOCATION, googleAuth: FAKE_GOOGLE_AUTH, }); const message = 'hi'; const chatSession = model.startChat(); const countTokenReq: CountTokensRequest = { 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); // }); }); }); ================================================ FILE: vertexai/src/models/util.ts ================================================ /** * @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. */ import {Content} from '../types/content'; import {constants} from '../util'; export function formulateSystemInstructionIntoContent( systemInstruction: string | Content ): Content { if (typeof systemInstruction === 'string') { return { role: constants.SYSTEM_ROLE, parts: [{text: systemInstruction}], } as Content; } systemInstruction.role = constants.SYSTEM_ROLE; return systemInstruction; } ================================================ FILE: vertexai/src/resources/cached_contents.ts ================================================ /** * @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. */ import {formulateSystemInstructionIntoContent} from '../functions/util'; import {ClientError} from '../types'; import {CachedContent, ListCachedContentsResponse} from '../types'; import {ApiClient} from './shared/api_client'; function camelToSnake(str: string): string { return str.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`); } class CachedContentsClient { constructor(readonly apiClient: ApiClient) {} create(cachedContent: CachedContent): Promise { return this.apiClient.unaryApiCall( new URL( this.apiClient.getBaseUrl() + '/' + this.apiClient.getBaseResourePath() + '/cachedContents' ), { body: JSON.stringify(cachedContent), }, 'POST' ); } update( cachedContent: CachedContent, updateMask: string[] ): Promise { const url = new URL(this.apiClient.getBaseUrl() + '/' + cachedContent.name); url.searchParams.append( 'updateMask', updateMask.map(e => camelToSnake(e)).join(',') ); return this.apiClient.unaryApiCall( url, { body: JSON.stringify(cachedContent), }, 'PATCH' ); } delete(name: string): Promise { return this.apiClient.unaryApiCall( new URL(this.apiClient.getBaseUrl() + '/' + name), {}, 'DELETE' ); } list( pageSize?: number, pageToken?: string ): Promise { const url = new URL( this.apiClient.getBaseUrl() + '/' + this.apiClient.getBaseResourePath() + '/cachedContents' ); if (pageSize) url.searchParams.append('pageSize', String(pageSize)); if (pageToken) url.searchParams.append('pageToken', pageToken); return this.apiClient.unaryApiCall(url, {}, 'GET'); } get(name: string): Promise { return this.apiClient.unaryApiCall( new URL(this.apiClient.getBaseUrl() + '/' + name), {}, 'GET' ); } } export function inferFullResourceName( project: string, location: string, cachedContentId: string ): string { if (cachedContentId.startsWith('projects/')) { return cachedContentId; } if (cachedContentId.startsWith('locations/')) { return `projects/${project}/${cachedContentId}`; } if (cachedContentId.startsWith('cachedContents/')) { return `projects/${project}/locations/${location}/${cachedContentId}`; } if (!cachedContentId.includes('/')) { return `projects/${project}/locations/${location}/cachedContents/${cachedContentId}`; } throw new ClientError( `Invalid CachedContent.name: ${cachedContentId}. CachedContent.name should start with 'projects/', 'locations/', 'cachedContents/' or is a number type.` ); } /** * Infers the full model name based on the provided project, location, and model. * * @internal */ export function inferModelName( project: string, location: string, model?: string ) { if (!model) { throw new ClientError('Model name is required.'); } if (model.startsWith('publishers/')) { return `projects/${project}/locations/${location}/${model}`; } if (!model.startsWith('projects/')) { return `projects/${project}/locations/${location}/publishers/google/models/${model}`; } return model; } /** * This class is for managing Vertex AI's CachedContent resource. * @public */ export class CachedContents { private readonly client: CachedContentsClient; constructor(client: ApiClient) { this.client = new CachedContentsClient(client); } /** * Creates cached content, this call will initialize the cached content in the data storage, and users need to pay for the cache data storage. * @param cachedContent * @param parent - Required. The parent resource where the cached content will be created. */ create(cachedContent: CachedContent): Promise { const curatedCachedContent = { ...cachedContent, systemInstruction: cachedContent.systemInstruction ? formulateSystemInstructionIntoContent(cachedContent.systemInstruction) : undefined, model: inferModelName( this.client.apiClient.project, this.client.apiClient.location, cachedContent.model ), } as CachedContent; return this.client.create(curatedCachedContent); } /** * Updates cached content configurations * * @param updateMask - Required. The list of fields to update. Format: google-fieldmask. See {@link https://cloud.google.com/docs/discovery/type-format} * @param name - Immutable. Identifier. The server-generated resource name of the cached content Format: projects/{project}/locations/{location}/cachedContents/{cached_content}. */ update( cachedContent: CachedContent, updateMask: string[] ): Promise { if (!cachedContent.name) { throw new ClientError('Cached content name is required for update.'); } if (!updateMask || updateMask.length === 0) { throw new ClientError( 'Update mask is required for update. Fields set in cachedContent but not in updateMask will be ignored. Examples: ["ttl"] or ["expireTime"].' ); } const curatedCachedContent = { ...cachedContent, systemInstruction: cachedContent.systemInstruction ? formulateSystemInstructionIntoContent(cachedContent.systemInstruction) : undefined, name: inferFullResourceName( this.client.apiClient.project, this.client.apiClient.location, cachedContent.name ), }; return this.client.update(curatedCachedContent, updateMask); } /** * Deletes cached content. * * @param name - Required. The resource name referring to the cached content. */ delete(name: string): Promise { return this.client.delete( inferFullResourceName( this.client.apiClient.project, this.client.apiClient.location, name ) ); } /** * Lists cached contents in a project. * * @param pageSize - Optional. The maximum number of cached contents to return. The service may return fewer than this value. If unspecified, some default (under maximum) number of items will be returned. The maximum value is 1000; values above 1000 will be coerced to 1000. * @param pageToken - Optional. A page token, received from a previous `ListCachedContents` call. Provide this to retrieve the subsequent page. When paginating, all other parameters provided to `ListCachedContents` must match the call that provided the page token. */ list( pageSize?: number, pageToken?: string ): Promise { return this.client.list(pageSize, pageToken); } /** * Gets cached content configurations. * * @param name - Required. The resource name referring to the cached content. */ get(name: string): Promise { return this.client.get( inferFullResourceName( this.client.apiClient.project, this.client.apiClient.location, name ) ); } } ================================================ FILE: vertexai/src/resources/index.ts ================================================ /** * @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. */ export {CachedContents} from './cached_contents'; export {ApiClient} from './shared/api_client'; ================================================ FILE: vertexai/src/resources/shared/api_client.ts ================================================ /** * @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. */ import {GoogleAuth} from 'google-auth-library'; import {constants} from '../../util'; import { ClientError, GoogleApiError, GoogleAuthError, GoogleGenerativeAIError, } from '../../types'; const AUTHORIZATION_HEADER = 'Authorization'; const CONTENT_TYPE_HEADER = 'Content-Type'; const USER_AGENT_HEADER = 'User-Agent'; export class ApiClient { constructor( readonly project: string, readonly location: string, readonly apiVersion: 'v1' | 'v1beta1', private readonly googleAuth: GoogleAuth ) {} /** * Gets access token from GoogleAuth. Throws {@link GoogleAuthError} when * fails. * @returns Promise of token string. */ private fetchToken(): Promise { const tokenPromise = this.googleAuth.getAccessToken().catch(e => { throw new GoogleAuthError(constants.CREDENTIAL_ERROR_MESSAGE, e); }); return tokenPromise; } getBaseUrl() { return `https://${this.location}-aiplatform.googleapis.com/${this.apiVersion}`; } getBaseResourePath() { return `projects/${this.project}/locations/${this.location}`; } async unaryApiCall( url: URL, requestInit: RequestInit, httpMethod: 'GET' | 'POST' | 'PATCH' | 'DELETE' ): Promise { const token = await this.getHeaders(); return this.apiCall(url.toString(), { ...requestInit, method: httpMethod, headers: token, }); } private async apiCall( url: string, requestInit: RequestInit ): Promise { const response = await fetch(url, requestInit).catch(e => { throw new GoogleGenerativeAIError( `exception sending request to url: ${url} with requestInit: ${JSON.stringify(requestInit)}}`, e ); }); await throwErrorIfNotOK(response, url, requestInit).catch(e => { throw e; }); try { return await response.json(); } catch (e) { throw new GoogleGenerativeAIError(JSON.stringify(response), e as Error); } } private async getHeaders(): Promise { const token = await this.fetchToken(); return new Headers({ [AUTHORIZATION_HEADER]: `Bearer ${token}`, [CONTENT_TYPE_HEADER]: 'application/json', [USER_AGENT_HEADER]: constants.USER_AGENT, }); } } async function throwErrorIfNotOK( response: Response | undefined, url: string, requestInit: RequestInit ) { if (response === undefined) { throw new GoogleGenerativeAIError('response is undefined'); } if (!response.ok) { const status: number = response.status; const statusText: string = response.statusText; let errorBody; if (response.headers.get('content-type')?.includes('application/json')) { errorBody = await response.json(); } else { errorBody = { error: { message: `exception sending request to url: ${url} with requestInit: ${JSON.stringify(requestInit)}}`, code: response.status, status: response.statusText, }, }; } const errorMessage = `got status: ${status} ${statusText}. ${JSON.stringify( errorBody )}`; if (status >= 400 && status < 500) { const error = new ClientError( errorMessage, new GoogleApiError( errorBody.error.message, errorBody.error.code, errorBody.error.status, errorBody.error.details ) ); throw error; } throw new GoogleGenerativeAIError(errorMessage); } } ================================================ FILE: vertexai/src/testing/fake_google_auth.ts ================================================ /** * @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. */ import {GoogleAuth} from 'google-auth-library'; interface FakeGoogleAuthParams { scopes?: string; /** Returned from getAccessToken(). */ accessToken?: string | null; /** If provided, will be thrown when getAccessToken() is called. */ accessTokenError?: Error; } /** Fake version of GoogleAuth. */ export class FakeGoogleAuth extends GoogleAuth { constructor(private readonly params: FakeGoogleAuthParams) { super(); } override getAccessToken(): Promise { if (this.params.accessTokenError) throw this.params.accessTokenError; return Promise.resolve(this.params.accessToken); } } /** Creates a fake GoogleAuth for testing. */ export function createFakeGoogleAuth( params: FakeGoogleAuthParams = { accessToken: 'DEFAULT_TOKEN', } ): GoogleAuth { return new FakeGoogleAuth(params); } ================================================ FILE: vertexai/src/testing/fake_google_auth_test.ts ================================================ /** * @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. */ import {GoogleAuth} from 'google-auth-library'; import {createFakeGoogleAuth} from './fake_google_auth'; describe('Fake GoogleAuth', () => { it('can create fake GoogleAuth with GoogleAuth instance.', () => { const auth = createFakeGoogleAuth(); expect(auth).toBeInstanceOf(GoogleAuth); }); it('can setup and get fake token.', async () => { const accessToken = 'abc123'; const auth = createFakeGoogleAuth({accessToken}); const token = await auth.getAccessToken(); expect(token).toEqual('abc123'); }); it('can setup and get undefined token.', async () => { const accessToken = undefined; const auth = createFakeGoogleAuth({accessToken}); const token = await auth.getAccessToken(); expect(token).toBeUndefined(); }); it('can setup and get null token.', async () => { const accessToken = null; const auth = createFakeGoogleAuth({accessToken}); const token = await auth.getAccessToken(); expect(token).toBeNull(); }); }); ================================================ FILE: vertexai/src/types/common.ts ================================================ /** * @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. */ /** This file contains interfaces that are usable in the types folder. */ /** * The list of OpenAPI data types * as defined by https://swagger.io/docs/specification/data-models/data-types/ */ export enum SchemaType { /** String type. */ STRING = 'STRING', /** Number type. */ NUMBER = 'NUMBER', /** Integer type. */ INTEGER = 'INTEGER', /** Boolean type. */ BOOLEAN = 'BOOLEAN', /** Array type. */ ARRAY = 'ARRAY', /** Object type. */ OBJECT = 'OBJECT', } /** * Schema is used to define the format of input/output data. * Represents a select subset of an OpenAPI 3.0 schema object. * More fields may be added in the future as needed. */ export interface Schema { /** * Optional. The type of the property. {@link * SchemaType}. */ type?: SchemaType; /** Optional. The format of the property. */ format?: string; /** Optional. The description of the property. */ description?: string; /** Optional. Whether the property is nullable. */ nullable?: boolean; /** Optional. The items of the property. {@link Schema} */ items?: Schema; /** Optional. The enum of the property. */ enum?: string[]; /** Optional. Map of {@link Schema}. */ properties?: {[k: string]: Schema}; /** Optional. Array of required property. */ required?: string[]; /** Optional. The example of the property. */ example?: unknown; } ================================================ FILE: vertexai/src/types/content.ts ================================================ /** * @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. */ // @ts-nocheck import {GoogleAuth, GoogleAuthOptions} from 'google-auth-library'; import {ToolConfig} from './tool'; import {SchemaType, Schema} from './common'; /** * Params used to initialize the Vertex SDK. */ export declare interface VertexInit { /** * Optional. The Google Cloud project ID. It is not the numeric project name. * If not provided, SDK will try to resolve it from runtime environment. * If still not cannot resovle project ID, SDK will throw exception. */ project?: string; /** * Optional. The Google Cloud project location. If not provided, SDK will * first try to resolve it from runtime environment. If no location resolved * from runtime environment, SDK will use default value `us-central1`. */ location?: string; /** * Optional. The base Vertex AI endpoint to use for the request. If not * provided, the default regionalized endpoint (i.e. * us-central1-aiplatform.googleapis.com) will be used. */ apiEndpoint?: string; /** * Optional. The Authentication options provided by google-auth-library. * Complete list of authentication options is documented in the * GoogleAuthOptions interface: * https://github.com/googleapis/google-auth-library-nodejs/blob/main/src/auth/googleauth.ts. */ googleAuthOptions?: GoogleAuthOptions; } /** * Params used to call the generateContent method. */ export declare interface GenerateContentRequest extends BaseModelParams { /** Array of {@link Content}.*/ contents: Content[]; /** * Optional. The user provided system instructions for the model. * Note: only text should be used in parts of {@link Content} */ systemInstruction?: string | Content; /** * Optional. The name of the cached content used as context to serve the prediction. * This is the name of a `CachedContent` and not the cache object itself. */ cachedContent?: string; /** * Optional. Custom metadata labels for organizing API calls and managing costs at scale. See * https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/add-labels-to-api-calls */ labels?: Record; } /** * Params used to call the countTokens method. */ export declare interface CountTokensRequest { /** Array of {@link Content}. */ contents: Content[]; } /** * Response returned from countTokens method. */ export declare interface CountTokensResponse { /** * The total number of tokens counted across all instances from the request. */ totalTokens: number; /** * Optional. The total number of billable characters counted across all * instances from the request. */ totalBillableCharacters?: number; } /** * Params used to call the getGenerativeModel method. */ export declare interface GetGenerativeModelParams extends ModelParams { /** The name of the model to get. */ model: string; /** The Google Cloud project to use for the request. */ project: string; /** The Google Cloud project location to use for the request. */ location: string; /** * GoogleAuth class instance that handles authentication. * Details about GoogleAuth is referred to * https://github.com/googleapis/google-auth-library-nodejs/blob/main/src/auth/googleauth.ts */ googleAuth: GoogleAuth; /** * Optional. The base Vertex AI endpoint to use for the request. If not * provided, the default regionalized endpoint (i.e. * us-central1-aiplatform.googleapis.com) will be used. */ apiEndpoint?: string; /** Optional. The configuration to use for generation. */ generationConfig?: GenerationConfig; /** Optional. The safety settings to use for generation. */ safetySettings?: SafetySetting[]; /** Optional. The tools to use for generation. */ tools?: Tool[]; /** Optional. This config is shared for all tools provided in the request. */ toolConfig?: ToolConfig; /** Optional. The request options to use for generation. */ requestOptions?: RequestOptions; /** * Optional. The user provided system instructions for the model. * Note: only text should be used in parts of {@link Content} */ systemInstruction?: string | Content; } /** * Configuration for initializing a model, for example via getGenerativeModel in * VertexAI class. */ export declare interface ModelParams extends BaseModelParams { /** * The name of the model. * @example "gemini-1.0-pro". */ model: string; /** * Optional. The cached content used as context to serve the prediction. * Note: only used in explicit caching, where users can have control over caching * (e.g. what content to cache) and enjoy guaranteed cost savings. */ cachedContent?: CachedContent; } /** * Base params for initializing a model or calling GenerateContent. */ export declare interface BaseModelParams { /** Optional. Array of {@link SafetySetting}. */ safetySettings?: SafetySetting[]; /** Optional. {@link GenerationConfig}. */ generationConfig?: GenerationConfig; /** Optional. Array of {@link Tool}. */ tools?: Tool[]; /** Optional. This config is shared for all tools provided in the request. */ toolConfig?: ToolConfig; /** * Optional. The user provided system instructions for the model. * Note: only text should be used in parts of {@link Content} */ systemInstruction?: string | Content; } /** * Safety feedback for an entire request. */ export declare interface SafetySetting { /** The harm category. {@link HarmCategory} */ category: HarmCategory; /** The harm threshold. {@link HarmBlockThreshold} */ threshold: HarmBlockThreshold; } /** * Schema passed to `GenerationConfig.responseSchema` * @public */ // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface ResponseSchema extends Schema {} /** * Configuration options for model generation and outputs. */ export declare interface GenerationConfig { /** Optional. If true, the timestamp of the audio will be included in the response. */ audioTimestamp?: boolean; /** Optional. Number of candidates to generate. */ candidateCount?: number; /** Optional. Stop sequences. */ stopSequences?: string[]; /** Optional. The maximum number of output tokens to generate per message. */ maxOutputTokens?: number; /** Optional. Controls the randomness of predictions. */ temperature?: number; /** Optional. If specified, nucleus sampling will be used. */ topP?: number; /** Optional. If specified, topK sampling will be used. */ topK?: number; /** * Optional. Positive values penalize tokens that repeatedly appear in the generated text, decreasing the probability of repeating content. * This maximum value for frequencyPenalty is up to, but not including, 2.0. Its minimum value is -2.0. * Supported by gemini-1.5-pro and gemini-1.5-flash only. */ frequencyPenalty?: number; /** * Optional. Output response mimetype of the generated candidate text. * Supported mimetype: * - `text/plain`: (default) Text output. * - `application/json`: JSON response in the candidates. * The model needs to be prompted to output the appropriate response type, * otherwise the behavior is undefined. */ responseMimeType?: string; /** * Optional. The schema that generated candidate text must follow. For more * information, see * https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/control-generated-output. * If set, a compatible responseMimeType must also be set. */ responseSchema?: ResponseSchema; } /** * Harm categories that will block the content. */ export enum HarmCategory { /** The harm category is unspecified. */ HARM_CATEGORY_UNSPECIFIED = 'HARM_CATEGORY_UNSPECIFIED', /** The harm category is hate speech. */ HARM_CATEGORY_HATE_SPEECH = 'HARM_CATEGORY_HATE_SPEECH', /** The harm category is dangerous content. */ HARM_CATEGORY_DANGEROUS_CONTENT = 'HARM_CATEGORY_DANGEROUS_CONTENT', /** The harm category is harassment. */ HARM_CATEGORY_HARASSMENT = 'HARM_CATEGORY_HARASSMENT', /** The harm category is sexually explicit content. */ HARM_CATEGORY_SEXUALLY_EXPLICIT = 'HARM_CATEGORY_SEXUALLY_EXPLICIT', } /** * Probability based thresholds levels for blocking. */ export enum HarmBlockThreshold { /** Unspecified harm block threshold. */ HARM_BLOCK_THRESHOLD_UNSPECIFIED = 'HARM_BLOCK_THRESHOLD_UNSPECIFIED', /** Block low threshold and above (i.e. block more). */ BLOCK_LOW_AND_ABOVE = 'BLOCK_LOW_AND_ABOVE', /** Block medium threshold and above. */ BLOCK_MEDIUM_AND_ABOVE = 'BLOCK_MEDIUM_AND_ABOVE', /** Block only high threshold (i.e. block less). */ BLOCK_ONLY_HIGH = 'BLOCK_ONLY_HIGH', /** Block none. */ BLOCK_NONE = 'BLOCK_NONE', /** Turn off the safety filter. */ OFF = 'OFF', } /** * Harm probability levels in the content. */ export enum HarmProbability { /** Harm probability unspecified. */ HARM_PROBABILITY_UNSPECIFIED = 'HARM_PROBABILITY_UNSPECIFIED', NEGLIGIBLE = 'NEGLIGIBLE', /** Low level of harm. */ LOW = 'LOW', /** Medium level of harm. */ MEDIUM = 'MEDIUM', /** High level of harm. */ HIGH = 'HIGH', } /** * Harm severity levels */ export enum HarmSeverity { /** Harm severity unspecified. */ HARM_SEVERITY_UNSPECIFIED = 'HARM_SEVERITY_UNSPECIFIED', /** Negligible level of harm severity. */ HARM_SEVERITY_NEGLIGIBLE = 'HARM_SEVERITY_NEGLIGIBLE', /** Low level of harm severity. */ HARM_SEVERITY_LOW = 'HARM_SEVERITY_LOW', /** Medium level of harm severity. */ HARM_SEVERITY_MEDIUM = 'HARM_SEVERITY_MEDIUM', /** High level of harm severity. */ HARM_SEVERITY_HIGH = 'HARM_SEVERITY_HIGH', } /** * Safety rating corresponding to the generated content. */ export declare interface SafetyRating { /** The harm category. {@link HarmCategory} */ category?: HarmCategory; /** The harm probability. {@link HarmProbability} */ probability?: HarmProbability; /** The harm probability score. */ probabilityScore?: number; /** The harm severity.level {@link HarmSeverity} */ severity?: HarmSeverity; /** The harm severity score. */ severityScore?: number; } /** * The base structured datatype containing multi-part content of a message. */ export declare interface Content { /** Array of {@link Part}. */ parts: Part[]; /** The producer of the content. */ role: string; } /** * A part of a turn in a conversation with the model with a fixed MIME type. * It has one of the following mutually exclusive fields: * 1. text * 2. inlineData * 3. fileData * 4. functionResponse * 5. functionCall */ // TODO: Adjust so one must be true. // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface BasePart {} /** * A text part of a conversation with the model. */ export interface TextPart extends BasePart { /** Only this property is expected for TextPart. */ text: string; /** inlineData is not expected for TextPart. */ inlineData?: never; /** fileData is not expected for TextPart. */ fileData?: never; /** functionResponse is not expected for TextPart. */ functionResponse?: never; /** functionCall is not expected for TextPart. */ functionCall?: never; } /** * An inline data part of a conversation with the model. */ export interface InlineDataPart extends BasePart { /** text is not expected for InlineDataPart. */ text?: never; /** Only this property is expected for InlineDataPart. */ inlineData: GenerativeContentBlob; /** fileData is not expected for InlineDataPart. */ fileData?: never; /** functionResponse is not expected for InlineDataPart. */ functionResponse?: never; /** functionCall is not expected for InlineDataPart. */ functionCall?: never; } /** * URI based data. */ export interface FileData { /** The IANA standard MIME type of the source data. */ mimeType: string; /** URI of the file. */ fileUri: string; } /** * A file data part of a conversation with the model. */ export interface FileDataPart extends BasePart { /** text is not expected for FileDataPart. */ text?: never; /** inlineData is not expected for FileDataPart. */ inlineData?: never; /** Only this property is expected for FileDataPart. */ fileData: FileData; /** functionResponse is not expected for FileDataPart. */ functionResponse?: never; /** functionCall is not expected for FileDataPart. */ functionCall?: never; } /** * A function response part of a conversation with the model. */ export interface FunctionResponsePart extends BasePart { /** text is not expected for FunctionResponsePart. */ text?: never; /** inlineData is not expected for FunctionResponsePart. */ inlineData?: never; /** fileData is not expected for FunctionResponsePart. */ fileData?: never; /** Only this property is expected for FunctionResponsePart. */ functionResponse: FunctionResponse; /** functionCall is not expected for FunctionResponsePart. */ functionCall?: never; } /** * A function call part of a conversation with the model. */ export interface FunctionCallPart extends BasePart { /** text is not expected for FunctionCallPart. */ text?: never; /** inlineData is not expected for FunctionCallPart. */ inlineData?: never; /** fileData is not expected for FunctionCallPart. */ fileData?: never; /** functionResponse is not expected for FunctionCallPart. */ functionResponse?: never; /** Only this property is expected for FunctionCallPart. */ functionCall: FunctionCall; } /** * A datatype containing media that is part of a multi-part {@link Content} * message. A `Part` is a union type of {@link TextPart}, {@link InlineDataPart}, * {@link FileDataPart}, and {@link FunctionResponsePart}. A * `Part` has one of the following mutually exclusive fields: * 1. text * 2. inlineData * 3. fileData * 4. functionResponse */ export declare type Part = | TextPart | InlineDataPart | FileDataPart | FunctionResponsePart | FunctionCallPart; /** * Raw media bytes sent directly in the request. Text should not be sent as * raw bytes. */ export declare interface GenerativeContentBlob { /** * The MIME type of the source data. The only accepted values: "image/png" or * "image/jpeg". */ mimeType: string; /** Base64 encoded data. */ data: string; } /** * Usage metadata about response(s). */ export declare interface UsageMetadata { /** Optional. Number of tokens in the request. */ promptTokenCount?: number; /** Optional. Number of tokens in the response(s). */ candidatesTokenCount?: number; /** Optional. Total number of tokens. */ totalTokenCount?: number; /** Optional. Number of tokens in the cached content. */ cachedContentTokenCount?: number; } /** * Content filter results for a prompt sent in the request. */ export declare interface PromptFeedback { /** The reason why the response is blocked. {@link BlockReason}. */ blockReason: BlockedReason; /** Array of {@link SafetyRating} */ safetyRatings: SafetyRating[]; /** A readable block reason message. */ blockReasonMessage?: string; } /** * The reason why the reponse is blocked. */ export enum BlockedReason { /** Unspecified blocked reason. */ BLOCKED_REASON_UNSPECIFIED = 'BLOCK_REASON_UNSPECIFIED', /** Candidates blocked due to safety. */ SAFETY = 'SAFETY', /** Candidates blocked due to other reason. */ OTHER = 'OTHER', /** terminology blocklist. */ BLOCKLIST = 'BLOCKLIST', /** Candidates blocked due to prohibited content. */ PROHIBITED_CONTENT = 'PROHIBITED_CONTENT', } /** * The reason why the model stopped generating tokens. * If empty, the model has not stopped generating the tokens. */ export enum FinishReason { /** The finish reason is unspecified. */ FINISH_REASON_UNSPECIFIED = 'FINISH_REASON_UNSPECIFIED', /** Natural stop point of the model or provided stop sequence. */ STOP = 'STOP', /** The maximum number of tokens as specified in the request was reached. */ MAX_TOKENS = 'MAX_TOKENS', /** * The token generation was stopped as the response was flagged for safety * reasons. */ SAFETY = 'SAFETY', /** * The token generation was stopped as the response was flagged for * unauthorized citations. */ RECITATION = 'RECITATION', /** All other reasons that stopped the token generation. */ OTHER = 'OTHER', /** * The token generation was stopped as the response was flagged for the * terms which are included from the terminology blocklist. */ BLOCKLIST = 'BLOCKLIST', /** * The token generation was stopped as the response was flagged for * the prohibited contents. */ PROHIBITED_CONTENT = 'PROHIBITED_CONTENT', /** * The token generation was stopped as the response was flagged for * Sensitive Personally Identifiable Information (SPII) contents. */ SPII = 'SPII', } /** * Wrapper for respones from a generateContent request. */ export declare interface GenerateContentResult { /** * All GenerateContentResponses received so far. {@link * GenerateContentResponse} */ response: GenerateContentResponse; } /** * Wrapper for respones from a generateContentStream method. */ export declare interface StreamGenerateContentResult { /** Promise of {@link GenerateContentResponse}. */ response: Promise; /** * Async iterable that provides one {@link GenerateContentResponse} at a * time. */ stream: AsyncGenerator; } /** * Response from the model supporting multiple candidates. */ export declare interface GenerateContentResponse { /** Array of {@link GenerateContentCandidate}. */ candidates?: GenerateContentCandidate[]; /** * Optional. This is only populated if there are no candidates due to a * safety block. {@link PromptFeedback}. */ promptFeedback?: PromptFeedback; /** Optional. {@link UsageMetadata}. */ usageMetadata?: UsageMetadata; } /** * A response candidate generated from the model. */ export declare interface GenerateContentCandidate { /** {@link Content}. */ content: Content; /** * Optional. The index of the candidate in the {@link * GenerateContentResponse}. */ index: number; /** * Optional. The reason why the model stopped generating tokens. {@link * FinishReason}. */ finishReason?: FinishReason; /** * Optional. A readable message describing why the model stopped generating * tokens. */ finishMessage?: string; /** Optional. Array of {@link SafetyRating}. */ safetyRatings?: SafetyRating[]; /** Optional. {@link CitationMetadata}. */ citationMetadata?: CitationMetadata; /** Optional. {@link GroundingMetadata}. */ groundingMetadata?: GroundingMetadata; } /** * A collection of source attributions for a piece of content. */ export declare interface CitationMetadata { /** Array of {@link Citation}. */ citations: Citation[]; } /** * Represents a whole or partial calendar date, such as a birthday. The time of * day and time zone are either specified elsewhere or are insignificant. The * date is relative to the Gregorian Calendar. This can represent one of the * following: * * A full date, with non-zero year, month, and day values. * A month and day, with a zero year (for example, an anniversary). * A year on its own, with a zero month and a zero day. * A year and month, with a zero day (for example, a credit card expiration * date). */ export declare interface GoogleDate { /** * Year of the date. Must be from 1 to 9999, or 0 to specify a date without a * year. */ year?: number; /** * Month of the date. Must be from 1 to 12, or 0 to specify a year without a * monthi and day. */ month?: number; /** * Day of the date. Must be from 1 to 31 and valid for the year and month. * or 0 to specify a year by itself or a year and month where the day isn't * significant */ day?: number; } /** * Source attributions for content. */ export declare interface Citation { /** Optional. Start index into the content. */ startIndex?: number; /** Optional. End index into the content. */ endIndex?: number; /** Optional. Url reference of the attribution. */ uri?: string; /** Optional. Title of the attribution. */ title?: string; /** Optional. License of the attribution. */ license?: string; /** Optional. Publication date of the attribution. */ publicationDate?: GoogleDate; } /** * Google search entry point. */ export declare interface SearchEntryPoint { /** * Optional. Web content snippet that can be embedded in a web page or an app * webview. */ renderedContent?: string; /** Optional. Base64 encoded JSON representing array of tuple. */ sdkBlob?: string; } /** * Grounding chunk from the web. */ export declare interface GroundingChunkWeb { /** Optional. URI reference of the grounding chunk. */ uri?: string; /** Optional. Title of the grounding chunk. */ title?: string; } /** * Grounding chunk from context retrieved by the retrieval tools. */ export declare interface GroundingChunkRetrievedContext { /** Optional. URI reference of the attribution. */ uri?: string; /** Optional. Title of the attribution. */ title?: string; } /** * Grounding chunk. */ export declare interface GroundingChunk { /** Optional. Grounding chunk from the web. */ web?: GroundingChunkWeb; /** * Optional. Grounding chunk from context retrieved by the retrieval tools. */ retrievedContext?: GroundingChunkRetrievedContext; } /** * Grounding support segment. */ export declare interface GroundingSupportSegment { /** Optional. The index of a Part object within its parent Content object. */ partIndex?: number; /** * Optional. Start index in the given Part, measured in bytes. * Offset from the start of the Part, inclusive, starting at zero. */ startIndex?: number; /** * Optional. End index in the given Part, measured in bytes. * Offset from the start of the Part, exclusive, starting at zero. */ endIndex?: number; /** Optional. The text corresponding to the segment from the response. */ text?: string; } /** * Grounding support. */ export declare interface GroundingSupport { /** Optional. Segment of the content this support belongs to. */ segment?: GroundingSupportSegment; /** * Optional. A arrau of indices (into {@link GroundingChunk}) specifying the * citations associated with the claim. For instance [1,3,4] means * that grounding_chunk[1], grounding_chunk[3], * grounding_chunk[4] are the retrieved content attributed to the claim. */ groundingChunkIndices?: number[]; /** * Confidence score of the support references. Ranges from 0 to 1. 1 is the * most confident. This list must have the same size as the * groundingChunkIndices. */ confidenceScores?: number[]; } /** * A collection of grounding attributions for a piece of content. */ export declare interface GroundingMetadata { /** Optional. Web search queries for the following-up web search. */ webSearchQueries?: string[]; /** Optional. Queries executed by the retrieval tools. */ retrievalQueries?: string[]; /** Optional. Google search entry for the following-up web searches. {@link SearchEntryPoint} */ searchEntryPoint?: SearchEntryPoint; /** * Optional. Array of supporting references retrieved from specified * grounding source. {@link GroundingChunk}. */ groundingChunks?: GroundingChunk[]; /** Optional. Array of grounding support. {@link GroundingSupport}. */ groundingSupports?: GroundingSupport[]; } /** * @deprecated * Segment of the content this attribution belongs to. */ export declare interface GroundingAttributionSegment { /** Optional. The index of a Part object within its parent Content object. */ partIndex?: number; /** * Optional. Start index in the given Part, measured in bytes. Offset from the * start of the Part, inclusive, starting at zero. */ startIndex?: number; /** * Optional. End index in the given Part, measured in bytes. Offset from the * start of the Part, exclusive, starting at zero. */ endIndex?: number; } /** * @deprecated * Attribution from the web. */ export declare interface GroundingAttributionWeb { /** Optional. URI reference of the attribution. */ uri?: string; /** Optional. Title of the attribution. */ title?: string; } /** * @deprecated * Attribution from context retrieved by the retrieval tools. */ export declare interface GroundingAttributionRetrievedContext { /** Optional. URI reference of the attribution. */ uri?: string; /** Optional. Title of the attribution. */ title?: string; } /** * A predicted FunctionCall returned from the model that contains a string * representating the FunctionDeclaration.name with the parameters and their * values. */ export declare interface FunctionCall { /** The name of the function specified in FunctionDeclaration.name. */ name: string; /** The arguments to pass to the function. */ args: object; } /** * The result output of a FunctionCall that contains a string representing * the FunctionDeclaration.name and a structured JSON object containing any * output from the function call. It is used as context to the model. */ export declare interface FunctionResponse { /** The name of the function specified in FunctionDeclaration.name. */ name: string; /** The expected response from the model. */ response: object; } /** * Structured representation of a function declaration as defined by the * [OpenAPI 3.0 specification](https://spec.openapis.org/oas/v3.0.3). Included * in this declaration are the function name and parameters. This * FunctionDeclaration is a representation of a block of code that can be used * as a Tool by the model and executed by the client. */ export declare interface FunctionDeclaration { /** * The name of the function to call. Must start with a letter or an * underscore. Must be a-z, A-Z, 0-9, or contain underscores and dashes, with * a max length of 64. */ name: string; /** * Optional. Description and purpose of the function. Model uses it to decide * how and whether to call the function. */ description?: string; /** * Optional. Describes the parameters to this function in JSON Schema Object * format. Reflects the Open API 3.03 Parameter Object. string Key: the name * of the parameter. Parameter names are case sensitive. Schema Value: the * Schema defining the type used for the parameter. For function with no * parameters, this can be left unset. * * @example with 1 required and 1 optional parameter: type: OBJECT properties: * ``` * param1: * * type: STRING * param2: * * type: INTEGER * required: * * - param1 * ``` */ parameters?: FunctionDeclarationSchema; } /** * A FunctionDeclarationsTool is a piece of code that enables the system to * interact with external systems to perform an action, or set of actions, * outside of knowledge and scope of the model. */ export declare interface FunctionDeclarationsTool { /** * Optional. One or more function declarations * to be passed to the model along with the current user query. Model may * decide to call a subset of these functions by populating * [FunctionCall][content.part.functionCall] in the response. User should * provide a [FunctionResponse][content.part.functionResponse] for each * function call in the next turn. Based on the function responses, Model will * generate the final response back to the user. Maximum 64 function * declarations can be provided. */ functionDeclarations?: FunctionDeclaration[]; } /** * Defines a retrieval tool that model can call to access external knowledge. */ export declare interface RetrievalTool { /** Optional. {@link Retrieval}. */ retrieval?: Retrieval; } export declare interface VertexRagStore { /** * Optional. List of corpora for retrieval. Currently only support one corpus * or multiple files from one corpus. In the future we may open up multiple * corpora support. */ ragResources?: RagResource[]; /** Optional. Number of top k results to return from the selected corpora. */ similarityTopK?: number; /** * Optional. If set this field, results with vector distance smaller than * this threshold will be returned. */ vectorDistanceThreshold?: number; } /** * Config of Vertex RagStore grounding checking. */ export declare interface RagResource { /** * Optional. Vertex RAG Store corpus resource name. * * @example * `projects/{project}/locations/{location}/ragCorpora/{rag_corpus}` */ ragCorpus?: string; /** * Optional. Set this field to select the files under the ragCorpora for * retrieval. */ ragFileIds?: string[]; } /** * Defines a retrieval tool that model can call to access external knowledge. */ export declare interface GoogleSearchRetrievalTool { /** Optional. {@link GoogleSearchRetrieval}. */ googleSearchRetrieval?: GoogleSearchRetrieval; } /** Defines a tool that model can call to access external knowledge. */ export declare type Tool = | FunctionDeclarationsTool | RetrievalTool | GoogleSearchRetrievalTool; /** * Defines a retrieval tool that model can call to access external knowledge. */ export declare interface Retrieval { /** * Optional. Set to use data source powered by Vertex AI Search. {@link * VertexAISearch}. */ vertexAiSearch?: VertexAISearch; /** Optional. Set to use data source powered by Vertex RAG store. */ vertexRagStore?: VertexRagStore; /** * Optional. Disable using the result from this tool in detecting grounding * attribution. This does not affect how the result is given to the model for * generation. */ disableAttribution?: boolean; } export enum Mode { MODE_UNSPECIFIED = 'MODE_UNSPECIFIED', MODE_DYNAMIC = 'MODE_DYNAMIC', } /** Describes the options to customize dynamic retrieval. */ export declare interface DynamicRetrievalConfig { /** Optional. The threshold to be used in dynamic retrieval. If not set, a system default value is used. */ dynamicThreshold?: number; /** The mode of the predictor to be used in dynamic retrieval. */ mode?: Mode; } /** * Tool to retrieve public web data for grounding, powered by Google. */ export declare interface GoogleSearchRetrieval { /** Specifies the dynamic retrieval configuration for the given source. */ dynamicRetrievalConfig?: DynamicRetrievalConfig; } /** * Retrieve from Vertex AI Search datastore for grounding. */ export declare interface VertexAISearch { /** * Fully-qualified Vertex AI Search's datastore resource ID. See * https://cloud.google.com/vertex-ai-search-and-conversation * * @example * "projects/<>/locations/<>/collections/<>/dataStores/<>" */ datastore: string; } /** * Contains the list of OpenAPI data types * as defined by https://swagger.io/docs/specification/data-models/data-types/ */ export declare type FunctionDeclarationSchemaType = SchemaType; export const FunctionDeclarationSchemaType = {...SchemaType}; /** * Schema for parameters passed to {@link FunctionDeclaration.parameters}. */ export interface FunctionDeclarationSchema { /** The type of the parameter. */ type: SchemaType; /** The format of the parameter. */ properties: {[k: string]: FunctionDeclarationSchemaProperty}; /** Optional. Description of the parameter. */ description?: string; /** Optional. Array of required parameters. */ required?: string[]; } /** * FunctionDeclarationSchemaProperty is used to define the format of * input/output data. Represents a select subset of an OpenAPI 3.0 schema object. * More fields may be added in the future as needed. */ export type FunctionDeclarationSchemaProperty = Schema; /** * Params to initiate a multiturn chat with the model via startChat. */ export declare interface StartChatParams { /** Optional. History of the chat session. {@link Content} */ history?: Content[]; /** Optional. Array of {@link SafetySetting}. */ safetySettings?: SafetySetting[]; /** Optional. {@link GenerationConfig}. */ generationConfig?: GenerationConfig; /** Optional. Array of {@link Tool}. */ tools?: Tool[]; /** Optional. This config is shared for all tools provided in the request. */ toolConfig?: ToolConfig; /** Optional. The base Vertex AI endpoint to use for the request. */ apiEndpoint?: string; /** * Optional. The user provided system instructions for the model. * Note: only text should be used in parts of {@link Content} */ systemInstruction?: string | Content; /** * Optional. The name of the cached content used as context to serve the prediction. * This is the name of a `CachedContent` and not the cache object itself. */ cachedContent?: string; } /** * All params passed to initiate multiturn chat via startChat. */ export declare interface StartChatSessionRequest extends StartChatParams { /** The Google Cloud project to use for the request. */ project: string; /** The Google Cloud project location to use for the request. */ location: string; /** The Google Auth to use for the request. */ googleAuth: GoogleAuth; /** The publisher model endpoint to use for the request. */ publisherModelEndpoint: string; /** The resource path to use for the request. */ resourcePath: string; /** * Optional. The user provided system instructions for the model. * Note: only text should be used in parts of {@link Content} */ systemInstruction?: string | Content; } /** * Request options params passed to getGenerativeModel method in VertexAI class. */ export interface RequestOptions { /** timeout in milli seconds. time out value needs to be non negative. */ timeout?: number; /** * Value for x-goog-api-client header to set on the API request. This is * intended for wrapper SDKs to set additional SDK identifiers for the * backend. */ apiClient?: string; /** * Value for custom HTTP headers to set on the HTTP request. */ customHeaders?: Headers; } /** * A resource used in LLM queries for users to explicitly specify * what to cache and how to cache. */ export interface CachedContent { /** * Immutable. Identifier. The server-generated resource name of the cached content. * Format: projects/{project}/locations/{location}/cachedContents/{cached_content} */ name?: string; /** Optional. Immutable. The user-generated meaningful display name of the cached content. */ displayName?: string; /** * Immutable. The name of the publisher model to use for cached content. * Format: projects/{project}/locations/{location}/publishers/{publisher}/models/{model} */ model?: string; /** Developer set system instruction. Currently, text only. */ systemInstruction?: Content | string; /** Optional. Input only. Immutable. The content to cache. */ contents?: Content[]; /** Optional. Input only. Immutable. A list of `Tools` the model may use to generate the next response. */ tools?: Tool[]; /** Optional. Input only. Immutable. Tool config. This config is shared for all tools. */ toolConfig?: ToolConfig; /** * Output only. Creatation time of the cache entry. * Format: google-datetime. See {@link https://cloud.google.com/docs/discovery/type-format} */ createTime?: string; /** * Output only. When the cache entry was last updated in UTC time. * Format: google-datetime. See {@link https://cloud.google.com/docs/discovery/type-format} */ updateTime?: string; /** Output only. Metadata on the usage of the cached content. */ usageMetadata?: CachedContentUsageMetadata; /** * Timestamp of when this resource is considered expired. * This is *always* provided on output, regardless of what was sent on input. */ expireTime?: string; /** * Input only. The TTL seconds for this resource. The expiration time * is computed: now + TTL. * Format: google-duration. See {@link https://cloud.google.com/docs/discovery/type-format} */ ttl?: string; } /** Metadata on the usage of the cached content. */ export interface CachedContentUsageMetadata { /** Total number of tokens that the cached content consumes. */ totalTokenCount?: number; /** Number of text characters. */ textCount?: number; /** Number of images. */ imageCount?: number; /** Duration of video in seconds. */ videoDurationSeconds?: number; /** Duration of audio in seconds. */ audioDurationSeconds?: number; } /** Response with a list of CachedContents. */ export interface ListCachedContentsResponse { /** List of cached contents. */ cachedContents?: CachedContent[]; /** A token, which can be sent as `page_token` to retrieve the next page. If this field is omitted, there are no subsequent pages. */ nextPageToken?: string; } ================================================ FILE: vertexai/src/types/errors.ts ================================================ /** * @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. */ /** * GoogleAuthError is thrown when there is authentication issue with the request */ class GoogleAuthError extends Error { public readonly stackTrace?: Error; constructor(message: string, stackTrace?: Error) { super(message, {cause: stackTrace}); this.message = constructErrorMessage('GoogleAuthError', message); this.name = 'GoogleAuthError'; this.stackTrace = stackTrace; } } /** * ClientError is thrown when http 4XX status is received. * For details please refer to https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#client_error_responses */ class ClientError extends Error { public readonly stackTrace?: Error; constructor(message: string, stackTrace?: Error) { super(message, {cause: stackTrace}); this.message = constructErrorMessage('ClientError', message); this.name = 'ClientError'; this.stackTrace = stackTrace; } } /** * Google API Error Details object that may be included in an error response. * See https://cloud.google.com/apis/design/errors * @public */ export declare interface ErrorDetails { '@type'?: string; reason?: string; domain?: string; metadata?: Record; [key: string]: unknown; } /** * GoogleApiError is thrown when http 4XX status is received. * See https://cloud.google.com/apis/design/errors */ class GoogleApiError extends Error { constructor( message: string, public code?: number, public status?: string, public errorDetails?: ErrorDetails[] ) { super(message); } } /** * GoogleGenerativeAIError is thrown when http response is not ok and status code is not 4XX * For details please refer to https://developer.mozilla.org/en-US/docs/Web/HTTP/Status */ class GoogleGenerativeAIError extends Error { public readonly stackTrace?: Error; constructor(message: string, stackTrace?: Error) { super(message, {cause: stackTrace}); this.message = constructErrorMessage('GoogleGenerativeAIError', message); this.name = 'GoogleGenerativeAIError'; this.stackTrace = stackTrace; } } /** * IllegalArgumentError is thrown when the request or operation is invalid */ class IllegalArgumentError extends Error { public readonly stackTrace?: Error; constructor(message: string, stackTrace?: Error) { super(message, {cause: stackTrace}); this.message = constructErrorMessage('IllegalArgumentError', message); this.name = 'IllegalArgumentError'; this.stackTrace = stackTrace; } } function constructErrorMessage( exceptionClass: string, message: string ): string { return `[VertexAI.${exceptionClass}]: ${message}`; } export { ClientError, GoogleApiError, GoogleAuthError, GoogleGenerativeAIError, IllegalArgumentError, }; ================================================ FILE: vertexai/src/types/generate_content_response_handler.ts ================================================ /** * @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. */ import {GenerateContentCandidate, FunctionCall, Part} from './content'; /** Helper class to render any extra properties out of * {@link GenerateContentResponse} or properties of {@link GenerateContentResponse} */ export class GenerateContentResponseHandler { /** * Extracts function calls from a {@link GenerateContentCandidate}. * * @param candidate - The candidate to extract function calls from. * @returns the array of function calls in a {@link GenerateContentCandidate}. */ static getFunctionCallsFromCandidate( candidate?: GenerateContentCandidate ): FunctionCall[] { if (!candidate) return [] as FunctionCall[]; return candidate.content.parts .filter((part: Part | undefined) => !!part && !!part.functionCall) .map((part: Part) => part.functionCall!); } } ================================================ FILE: vertexai/src/types/index.ts ================================================ /** * @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. */ export * from './content'; export * from './errors'; export * from './tool'; export * from './common'; export {GenerateContentResponseHandler} from './generate_content_response_handler'; ================================================ FILE: vertexai/src/types/tool.ts ================================================ /** * @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. */ /** This config is shared for all tools provided in the request. */ export interface ToolConfig { /** Function calling config. */ functionCallingConfig?: FunctionCallingConfig; } /** Function calling mode. */ export enum FunctionCallingMode { /** Unspecified function calling mode. This value should not be used. */ MODE_UNSPECIFIED = 'MODE_UNSPECIFIED', /** * Default model behavior, model decides to predict either function calls * or natural language response. */ AUTO = 'AUTO', /** * Model is constrained to always predicting function calls only. * If "allowedFunctionNames" are set, the predicted function calls will be * limited to any one of "allowedFunctionNames", else the predicted * function calls will be any one of the provided "function_declarations". */ ANY = 'ANY', /** * Model will not predict any function calls. Model behavior is same as when * not passing any function declarations. */ NONE = 'NONE', } export interface FunctionCallingConfig { /** Optional. Function calling mode. */ mode?: FunctionCallingMode; /** * Optional. Function names to call. Only set when the Mode is ANY. Function * names should match [FunctionDeclaration.name]. With mode set to ANY, model * will predict a function call from the set of function names provided. */ allowedFunctionNames?: string[]; } ================================================ FILE: vertexai/src/util/constants.ts ================================================ /** * @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. */ export const GENERATE_CONTENT_METHOD = 'generateContent'; export const STREAMING_GENERATE_CONTENT_METHOD = 'streamGenerateContent'; export const COUNT_TOKENS_METHOD = 'countTokens'; export const USER_ROLE = 'user'; export const MODEL_ROLE = 'model'; export const SYSTEM_ROLE = 'system'; const USER_AGENT_PRODUCT = 'model-builder'; const CLIENT_LIBRARY_VERSION = '1.12.0'; const CLIENT_LIBRARY_LANGUAGE = `grpc-node/${CLIENT_LIBRARY_VERSION}`; export const USER_AGENT = `${USER_AGENT_PRODUCT}/${CLIENT_LIBRARY_VERSION} ${CLIENT_LIBRARY_LANGUAGE}`; export const CREDENTIAL_ERROR_MESSAGE = '\nUnable to authenticate your request\ \nDepending on your run time environment, you can get authentication by\ \n- if in local instance or cloud shell: `!gcloud auth login`\ \n- if in Colab:\ \n -`from google.colab import auth`\ \n -`auth.authenticate_user()`\ \n- if in service account or other: please follow guidance in https://cloud.google.com/docs/authentication'; ================================================ FILE: vertexai/src/util/index.ts ================================================ /** * @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. */ export * as constants from './constants'; ================================================ FILE: vertexai/src/vertex_ai.ts ================================================ /** * @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. */ /* tslint:disable */ import {GoogleAuth, GoogleAuthOptions} from 'google-auth-library'; import {GenerativeModelPreview, GenerativeModel} from './models'; import { CachedContent, GetGenerativeModelParams, ModelParams, RequestOptions, VertexInit, } from './types/content'; import { GoogleAuthError, IllegalArgumentError, ClientError, } from './types/errors'; import * as Resources from './resources'; import {inferFullResourceName} from './resources/cached_contents'; /** * The `VertexAI` class is the base class for authenticating to Vertex AI. * To use Vertex AI's generative AI models, use the `getGenerativeModel` method. * To use generative AI features that are in Preview, use the `preview` * namespace. */ export class VertexAI { public readonly preview: VertexAIPreview; private readonly project: string; private readonly location: string; private readonly googleAuth: GoogleAuth; private readonly apiEndpoint?: string; /** * @constructor * @param init - assign authentication related information, * including the project and location strings, to instantiate a Vertex AI * client. * @throws {IllegalArgumentError} */ constructor(init: VertexInit) { const opts = validateGoogleAuthOptions( init.project, init.googleAuthOptions ); console.warn( 'The VertexAI class and all its dependencies are deprecated' + ' as of June 24, 2025 and will be removed on June 24, 2026. Please use' + ' the Google Gen AI SDK (https://www.npmjs.com/package/@google/genai) to' + ' access Gemini features. For details, see' + ' https://cloud.google.com/vertex-ai/generative-ai/docs/deprecations/genai-vertexai-sdk.' ); this.location = resolveLocation(init.location); this.project = resolveProject(init.project); this.googleAuth = new GoogleAuth(opts); this.apiEndpoint = init.apiEndpoint; this.preview = new VertexAIPreview( this.project, this.location, this.googleAuth, this.apiEndpoint ); } /** * Gets the GenerativeModel class instance. * * This method creates a new instance of the `GenerativeModel` class with the * platform initialization parameters provided in {@link VertexInit} and model * initialization parameters provided in {@link ModelParams}. You can * optionally provide {@link RequestOptions} to override the default request * options. * * @example * ``` * const project = 'your-cloud-project'; * const location = 'us-central1'; * const textModel = 'gemini-1.0-pro'; * const visionModel = 'gemini-1.0-pro-vision'; * * const vertexAI = new VertexAI({project: project, location: location}); * * // Instantiate models * const generativeModel = vertexAI.getGenerativeModel({ * model: textModel, * // The following parameters are optional * // They can also be passed to individual content generation requests * safetySettings: [{ * category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, * threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE * }], * generationConfig: {maxOutputTokens: 256}, * }); * * const generativeVisionModel = vertexAI.getGenerativeModel({ * model: visionModel, * }); * * const generativeModelPreview = vertexAI.preview.getGenerativeModel({ * model: textModel, * }); * ``` * * @param modelParams - {@link ModelParams} Parameters to * specify the generative model. * @param requestOptions - {@link RequestOptions} Parameters to specify * request options * @returns Instance of the GenerativeModel class. */ getGenerativeModel( modelParams: ModelParams, requestOptions?: RequestOptions ): GenerativeModel { const getGenerativeModelParams: GetGenerativeModelParams = { model: modelParams.model, project: this.project, location: this.location, googleAuth: this.googleAuth, apiEndpoint: this.apiEndpoint, safetySettings: modelParams.safetySettings, generationConfig: modelParams.generationConfig, tools: modelParams.tools, toolConfig: modelParams.toolConfig, requestOptions: requestOptions, systemInstruction: modelParams.systemInstruction, }; return new GenerativeModel(getGenerativeModelParams); } protected getProject(): string { return this.project; } protected getLocation(): string { return this.location; } } /** * The preview namespace for VertexAI. Users invoke the `getGenerativeModel` * method to start using generative AI features that are in preview. */ class VertexAIPreview { private readonly project: string; private readonly location: string; private readonly googleAuth: GoogleAuth; private readonly apiEndpoint?: string; private readonly apiClient: Resources.ApiClient; readonly cachedContents: Resources.CachedContents; /** * @constructor * @param project - The Google Cloud project to use for the request * @param location - location The Google Cloud project location to use for the * request * @param googleAuth - The GoogleAuthen class instance from * google-auth-library. * Complete list of authentication options is documented in the * GoogleAuthOptions interface: * https://github.com/googleapis/google-auth-library-nodejs/blob/main/src/auth/googleauth.ts * @param apiEndpoint - [apiEndpoint] The base Vertex AI endpoint to use for * the request. If * not provided, the default regionalized endpoint * (i.e. us-central1-aiplatform.googleapis.com) will be used. */ constructor( project: string, location: string, googleAuth: GoogleAuth, apiEndpoint?: string ) { this.project = project; this.location = location; this.googleAuth = googleAuth; this.apiEndpoint = apiEndpoint; this.apiClient = new Resources.ApiClient( this.project, this.location, 'v1beta1', this.googleAuth ); this.cachedContents = new Resources.CachedContents(this.apiClient); } /** * @param modelParams - {@link ModelParams} Parameters to * specify the generative model. * @returns Instance of the GenerativeModelPreview class. */ getGenerativeModel( modelParams: ModelParams, requestOptions?: RequestOptions ): GenerativeModelPreview { const getGenerativeModelParams: GetGenerativeModelParams = { model: modelParams.model, project: this.project, location: this.location, googleAuth: this.googleAuth, apiEndpoint: this.apiEndpoint, safetySettings: modelParams.safetySettings, generationConfig: modelParams.generationConfig, tools: modelParams.tools, toolConfig: modelParams.toolConfig, requestOptions: requestOptions, systemInstruction: modelParams.systemInstruction, }; return new GenerativeModelPreview(getGenerativeModelParams); } getGenerativeModelFromCachedContent( cachedContent: CachedContent, modelParams?: Partial, requestOptions?: RequestOptions ) { if (!cachedContent.name) { throw new ClientError('Cached content must contain a `name` field.'); } if (!cachedContent.model) { throw new ClientError('Cached content must contain a `model` field.'); } validateCachedContentModel(cachedContent.model); /** * Not checking tools and toolConfig for now as it would require a deep * equality comparison and isn't likely to be a common case. */ const disallowedDuplicates: Array = ['model', 'systemInstruction']; for (const key of disallowedDuplicates) { if ( modelParams?.[key] && cachedContent[key] && modelParams?.[key] !== cachedContent[key] ) { if (key === 'model') { const modelParamsComp = parseModelName(modelParams[key]!); const cachedContentComp = parseModelName(cachedContent[key]!); if (modelParamsComp === cachedContentComp) { continue; } } throw new ClientError( `Different value for "${key}" specified in modelParams` + ` (${modelParams[key]}) and cachedContent (${cachedContent[key]})` ); } } cachedContent.name = inferFullResourceName( this.project, this.location, cachedContent.name ); const modelParamsFromCache: GetGenerativeModelParams = { model: cachedContent.model, project: this.project, location: this.location, googleAuth: this.googleAuth, apiEndpoint: this.apiEndpoint, safetySettings: modelParams?.safetySettings, generationConfig: modelParams?.generationConfig, tools: cachedContent.tools, toolConfig: cachedContent.toolConfig, requestOptions: requestOptions, systemInstruction: cachedContent.systemInstruction, cachedContent, }; return new GenerativeModelPreview(modelParamsFromCache); } } function validateCachedContentModel(modelName: string) { if ( modelName.startsWith('models/') || (modelName.startsWith('projects/') && modelName.includes('/publishers/google/models/')) || !modelName.includes('/') ) { return; } throw new ClientError( `Cached content model name must start with "models/" or match "projects/.*/publishers/google/models/.*" or is a model name listed at https://cloud.google.com/vertex-ai/generative-ai/docs/learn/model-versions. Received: ${modelName}` ); } function parseModelName(modelName: string): string { if (!modelName.includes('/')) { return modelName; } return modelName.split('/').pop()!; } function validateGoogleAuthOptions( project?: string, googleAuthOptions?: GoogleAuthOptions ): GoogleAuthOptions { let opts: GoogleAuthOptions; const requiredScope = 'https://www.googleapis.com/auth/cloud-platform'; if (!googleAuthOptions) { opts = { scopes: requiredScope, }; return opts; } if (googleAuthOptions.projectId && googleAuthOptions.projectId !== project) { throw new Error( `inconsistent project ID values. argument project got value ${project} but googleAuthOptions.projectId got value ${googleAuthOptions.projectId}` ); } opts = googleAuthOptions; if (!opts.scopes) { opts.scopes = requiredScope; return opts; } if ( (typeof opts.scopes === 'string' && opts.scopes !== requiredScope) || (Array.isArray(opts.scopes) && opts.scopes.indexOf(requiredScope) < 0) ) { throw new GoogleAuthError( `input GoogleAuthOptions.scopes ${opts.scopes} doesn't contain required scope ${requiredScope}, please include ${requiredScope} into GoogleAuthOptions.scopes or leave GoogleAuthOptions.scopes undefined` ); } return opts; } function resolveProject(projectFromInput?: string): string { const projectNotFoundErrorMessage = 'Unable to infer your project.' + 'Please provide a project Id by one of the following:' + '\n- Passing a constructor argument by using new VertexAI({project: my-project})' + '\n- Setting project using `gcloud config set project my-project`'; if (projectFromInput) { return projectFromInput; } const inferredProjectFromEnv = process.env['GOOGLE_CLOUD_PROJECT']; if (inferredProjectFromEnv) { return inferredProjectFromEnv; } throw new IllegalArgumentError(projectNotFoundErrorMessage); } function resolveLocation(locationFromInput?: string): string { if (locationFromInput) { return locationFromInput; } const inferredLocation = process.env['GOOGLE_CLOUD_REGION'] || process.env['CLOUD_ML_REGION']; if (inferredLocation) { return inferredLocation; } return 'us-central1'; } ================================================ FILE: vertexai/system_test/end_to_end_sample_test.ts ================================================ /** * @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. */ // @ts-ignore import { ClientError, FunctionDeclarationsTool, GoogleSearchRetrievalTool, Part, TextPart, VertexAI, GenerateContentResponseHandler, GoogleApiError, Mode, } from '../src'; import {FunctionDeclarationSchemaType} from '../src/types'; const PROJECT = process.env['GCLOUD_PROJECT']; const LOCATION = 'us-central1'; const TEXT_REQUEST = { contents: [{role: 'user', parts: [{text: 'How are you doing today?'}]}], }; const TEXT_PART = { text: 'What is this a picture of?', }; const GCS_FILE_PART = { fileData: { fileUri: 'gs://generativeai-downloads/images/scones.jpg', mimeType: 'image/jpeg', }, }; const BASE_64_IMAGE = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='; const INLINE_DATA_FILE_PART = { inlineData: { data: BASE_64_IMAGE, mimeType: 'image/jpeg', }, }; const MULTI_PART_GCS_REQUEST = { contents: [{role: 'user', parts: [TEXT_PART, GCS_FILE_PART]}], }; const MULTI_PART_BASE64_REQUEST = { contents: [{role: 'user', parts: [TEXT_PART, INLINE_DATA_FILE_PART]}], }; const FUNCTION_CALL_NAME = 'get_current_weather'; const TOOLS_WITH_FUNCTION_DECLARATION: FunctionDeclarationsTool[] = [ { functionDeclarations: [ { name: FUNCTION_CALL_NAME, description: 'get weather in a given location', parameters: { type: FunctionDeclarationSchemaType.OBJECT, properties: { location: {type: FunctionDeclarationSchemaType.STRING}, unit: { type: FunctionDeclarationSchemaType.STRING, enum: ['celsius', 'fahrenheit'], }, }, required: ['location'], }, }, ], }, ]; const TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL: GoogleSearchRetrievalTool[] = [ { googleSearchRetrieval: { dynamicRetrievalConfig: { dynamicThreshold: 0.2, mode: Mode.MODE_DYNAMIC, }, }, }, ]; const TOOLS_WITH_RAG = [ { retrieval: { vertexRagStore: { ragResources: [ { ragCorpus: 'projects/ucaip-sample-tests/locations/us-central1/ragCorpora/6917529027641081856', }, ], }, }, }, ]; const WEATHER_FORECAST = 'super nice'; const FUNCTION_RESPONSE_PART = [ { functionResponse: { name: FUNCTION_CALL_NAME, response: { name: FUNCTION_CALL_NAME, content: {weather: WEATHER_FORECAST}, }, }, }, ]; const FUNCTION_CALL = [ {functionCall: {name: FUNCTION_CALL_NAME, args: {location: 'boston'}}}, ]; // Initialize Vertex with your Cloud project and location const vertexAI = new VertexAI({ project: PROJECT as string, location: LOCATION, }); const TEXT_MODEL_NAME = 'gemini-2.0-flash'; const generativeTextModel = vertexAI.getGenerativeModel({ model: TEXT_MODEL_NAME, generationConfig: { maxOutputTokens: 256, }, }); const generativeTextModelPreview = vertexAI.preview.getGenerativeModel({ model: TEXT_MODEL_NAME, generationConfig: { maxOutputTokens: 256, }, }); const generativeTextModelWithPrefix = vertexAI.getGenerativeModel({ model: 'models/gemini-2.0-flash', generationConfig: { maxOutputTokens: 256, }, }); const generativeTextModelWithPrefixPreview = vertexAI.preview.getGenerativeModel({ model: 'models/gemini-2.0-flash', generationConfig: { maxOutputTokens: 256, }, }); const generativeVisionModel = vertexAI.getGenerativeModel({ model: 'gemini-2.0-flash', }); const generativeVisionModelPreview = vertexAI.preview.getGenerativeModel({ model: 'gemini-2.0-flash', }); const generativeVisionModelWithPrefix = vertexAI.getGenerativeModel({ model: 'gemini-2.0-flash', }); const generativeVisionModelWithPrefixPreview = vertexAI.preview.getGenerativeModel({ model: 'models/gemini-2.0-flash', }); describe('generateContentStream', () => { beforeEach(() => { jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000; }); it('should should return a stream and aggregated response when passed text', async () => { const streamingResp = await generativeTextModel.generateContentStream(TEXT_REQUEST); for await (const item of streamingResp.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on generateContentStream, for item ${JSON.stringify( item )}` ); } const aggregatedResp = await streamingResp.response; expect(aggregatedResp.candidates![0]).toBeTruthy( `sys test failure on generateContentStream for testing candidates in aggregated response: ${JSON.stringify( aggregatedResp )}` ); expect(aggregatedResp.usageMetadata).toBeTruthy( `sys test failure on generateContentStream for testing usageMetadata in aggregated response: ${JSON.stringify( aggregatedResp )}` ); }); it('in preview should should return a stream and aggregated response when passed text', async () => { const streamingResp = await generativeTextModelPreview.generateContentStream(TEXT_REQUEST); for await (const item of streamingResp.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on generateContentStream in preview, for item ${JSON.stringify( item )}` ); } const aggregatedResp = await streamingResp.response; expect(aggregatedResp.candidates![0]).toBeTruthy( `sys test failure on generateContentStream in preview for testing candidates in aggregated response: ${JSON.stringify( aggregatedResp )}` ); expect(aggregatedResp.usageMetadata).toBeTruthy( `sys test failure on generateContentStream in preview for testing usageMetadata in aggregated response: ${JSON.stringify( aggregatedResp )}` ); }); it('should not return a invalid unicode', async () => { const streamingResp = await generativeTextModel.generateContentStream({ contents: [{role: 'user', parts: [{text: '创作一首古诗'}]}], }); for await (const item of streamingResp.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on generateContentStream, for item ${JSON.stringify( item )}` ); for (const candidate of item.candidates!) { for (const part of candidate.content.parts as TextPart[]) { expect(part.text).not.toContain( '\ufffd', `sys test failure on generateContentStream, for item ${JSON.stringify( item )}` ); } } } const aggregatedResp = await streamingResp.response; expect(aggregatedResp.candidates![0]).toBeTruthy( `sys test failure on generateContentStream for aggregated response: ${JSON.stringify( aggregatedResp )}` ); }); it('in preview should not return a invalid unicode', async () => { const streamingResp = await generativeTextModelPreview.generateContentStream({ contents: [{role: 'user', parts: [{text: '创作一首古诗'}]}], }); for await (const item of streamingResp.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on generateContentStream in preview, for item ${JSON.stringify( item )}` ); for (const candidate of item.candidates!) { for (const part of candidate.content.parts as TextPart[]) { expect(part.text).not.toContain( '\ufffd', `sys test failure on generateContentStream in preview, for item ${JSON.stringify( item )}` ); } } } const aggregatedResp = await streamingResp.response; expect(aggregatedResp.candidates![0]).toBeTruthy( `sys test failure on generateContentStream in preview for aggregated response: ${JSON.stringify( aggregatedResp )}` ); }); it('should return a stream and aggregated response when passed multipart base64 content', async () => { const streamingResp = await generativeVisionModel.generateContentStream( MULTI_PART_BASE64_REQUEST ); for await (const item of streamingResp.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on generateContentStream, for item ${JSON.stringify( item )}` ); } const aggregatedResp = await streamingResp.response; expect(aggregatedResp.candidates![0]).toBeTruthy( `sys test failure on generateContentStream for aggregated response: ${JSON.stringify( aggregatedResp )}` ); }); it('in preview should return a stream and aggregated response when passed multipart base64 content', async () => { const streamingResp = await generativeVisionModelPreview.generateContentStream( MULTI_PART_BASE64_REQUEST ); for await (const item of streamingResp.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on generateContentStream in preview, for item ${JSON.stringify( item )}` ); } const aggregatedResp = await streamingResp.response; expect(aggregatedResp.candidates![0]).toBeTruthy( `sys test failure on generateContentStream in preview for aggregated response: ${JSON.stringify( aggregatedResp )}` ); }); it('should throw ClientError when having invalid input', async () => { const badRequest = { contents: [ { role: 'user', parts: [ {text: 'describe this image:'}, {inlineData: {mimeType: 'image/png', data: 'invalid data'}}, ], }, ], }; await generativeVisionModel.generateContentStream(badRequest).catch(e => { expect(e).toBeInstanceOf(ClientError); expect(e.message).toContain( '[VertexAI.ClientError]: got status: 400 Bad Request', `sys test failure on generateContentStream when having bad request got wrong error message: ${e.message}` ); expect(e.cause).toBeInstanceOf(GoogleApiError); expect(e.cause.code).toBe(400); expect(e.cause.status).toBe('INVALID_ARGUMENT'); expect(e.cause.message).toBeInstanceOf(String); }); }); it('in preview should throw ClientError when having invalid input', async () => { const badRequest = { contents: [ { role: 'user', parts: [ {text: 'describe this image:'}, {inlineData: {mimeType: 'image/png', data: 'invalid data'}}, ], }, ], }; await generativeVisionModelPreview .generateContentStream(badRequest) .catch(e => { expect(e).toBeInstanceOf(ClientError); expect(e.message).toContain( '[VertexAI.ClientError]: got status: 400 Bad Request', `sys test failure on generateContentStream in preview when having bad request got wrong error message: ${e.message}` ); expect(e.cause).toBeInstanceOf(GoogleApiError); expect(e.cause.code).toBe(400); expect(e.cause.status).toBe('INVALID_ARGUMENT'); expect(e.cause.message).toBeInstanceOf(String); }); }); it('should should return a stream and aggregated response when passed multipart GCS content', async () => { const streamingResp = await generativeVisionModel.generateContentStream( MULTI_PART_GCS_REQUEST ); for await (const item of streamingResp.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on generateContentStream, for item ${JSON.stringify( item )}` ); } const aggregatedResp = await streamingResp.response; expect(aggregatedResp.candidates![0]).toBeTruthy( `sys test failure on generateContentStream for aggregated response: ${JSON.stringify( aggregatedResp )}` ); }); it('in preview should should return a stream and aggregated response when passed multipart GCS content', async () => { const streamingResp = await generativeVisionModelPreview.generateContentStream( MULTI_PART_GCS_REQUEST ); for await (const item of streamingResp.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on generateContentStream in preview, for item ${JSON.stringify( item )}` ); } const aggregatedResp = await streamingResp.response; expect(aggregatedResp.candidates![0]).toBeTruthy( `sys test failure on generateContentStream in preview for aggregated response: ${JSON.stringify( aggregatedResp )}` ); }); xit('should return a text when passed a FunctionDeclaration or FunctionResponse', async () => { const request = { contents: [ {role: 'user', parts: [{text: 'What is the weather in Boston?'}]}, {role: 'model', parts: FUNCTION_CALL}, {role: 'user', parts: FUNCTION_RESPONSE_PART}, ], tools: TOOLS_WITH_FUNCTION_DECLARATION, }; const streamingResp = await generativeTextModel.generateContentStream(request); for await (const item of streamingResp.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on generateContentStream, for item ${JSON.stringify( item )}` ); } const aggregaratedResponse = await streamingResp.response; expect( aggregaratedResponse.candidates![0].content.parts[0].text?.toLowerCase() ).toContain( WEATHER_FORECAST, `sys test failure on generateContentStream for candidate part ${JSON.stringify( aggregaratedResponse.candidates![0].content.parts[0] )}` ); }); xit('in preview should return a text when passed a FunctionDeclaration or FunctionResponse', async () => { const request = { contents: [ {role: 'user', parts: [{text: 'What is the weather in Boston?'}]}, {role: 'model', parts: FUNCTION_CALL}, {role: 'user', parts: FUNCTION_RESPONSE_PART}, ], tools: TOOLS_WITH_FUNCTION_DECLARATION, }; const streamingResp = await generativeTextModelPreview.generateContentStream(request); for await (const item of streamingResp.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on generateContentStream in preview, for item ${JSON.stringify( item )}` ); } const aggregaratedResponse = await streamingResp.response; expect( aggregaratedResponse.candidates![0].content.parts[0].text?.toLowerCase() ).toContain( WEATHER_FORECAST, `sys test failure on generateContentStream for candidate part ${JSON.stringify( aggregaratedResponse.candidates![0].content.parts[0] )}` ); }); xit('should return a FunctionCall when passed a FunctionDeclaration', async () => { const request = { contents: [ {role: 'user', parts: [{text: 'What is the weather in Boston?'}]}, ], tools: TOOLS_WITH_FUNCTION_DECLARATION, }; const streamingResp = await generativeTextModel.generateContentStream(request); for await (const item of streamingResp.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on generateContentStream, for item ${JSON.stringify( item )}` ); const functionCalls = item .candidates![0].content.parts.filter(part => !!part.functionCall) .map(part => part.functionCall!); expect(functionCalls).toHaveSize(1); expect( GenerateContentResponseHandler.getFunctionCallsFromCandidate( item.candidates?.[0] ) ).toEqual(functionCalls!); } }); xit('in preview should return a FunctionCall when passed a FunctionDeclaration', async () => { const request = { contents: [ {role: 'user', parts: [{text: 'What is the weather in Boston?'}]}, ], tools: TOOLS_WITH_FUNCTION_DECLARATION, }; const streamingResp = await generativeTextModelPreview.generateContentStream(request); for await (const item of streamingResp.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on generateContentStream in preview, for item ${JSON.stringify( item )}` ); const functionCalls = item .candidates![0].content.parts.filter(part => !!part.functionCall) .map(part => part.functionCall!); expect(functionCalls).toHaveSize(1); expect( GenerateContentResponseHandler.getFunctionCallsFromCandidate( item.candidates?.[0] ) ).toEqual(functionCalls!); } }); xit('should return grounding metadata when passed GoogleSearchRetriever in getGenerativeModel', async () => { const generativeTextModel = vertexAI.getGenerativeModel({ model: TEXT_MODEL_NAME, tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL, }); const result = await generativeTextModel.generateContentStream({ contents: [{role: 'user', parts: [{text: 'Why is the sky blue?'}]}], }); const response = await result.response; const groundingMetadata = response.candidates![0].groundingMetadata; expect(!!groundingMetadata).toBeTruthy( `sys test failure on generateContentStream for grounding metadata: ${groundingMetadata}` ); if (groundingMetadata) { expect(!!groundingMetadata.webSearchQueries).toBeTruthy( `sys test failure on generateContentStream for web search queries: ${groundingMetadata.webSearchQueries}` ); } }); xit('should return grounding metadata when passed GoogleSearchRetriever in generateContent', async () => { const generativeTextModel = vertexAI.getGenerativeModel({ model: TEXT_MODEL_NAME, }); const result = await generativeTextModel.generateContentStream({ contents: [{role: 'user', parts: [{text: 'Why is the sky blue?'}]}], tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL, }); const response = await result.response; const groundingMetadata = response.candidates![0].groundingMetadata; expect(!!groundingMetadata).toBeTruthy( `sys test failure on generateContentStream for grounding metadata: ${groundingMetadata}` ); if (groundingMetadata) { expect(!!groundingMetadata.webSearchQueries).toBeTruthy( `sys test failure on generateContentStream for web search queries: ${groundingMetadata.webSearchQueries}` ); } }); xit('in preview should return grounding metadata when passed GoogleSearchRetriever in getGenerativeModel', async () => { const generativeTextModel = vertexAI.preview.getGenerativeModel({ model: TEXT_MODEL_NAME, tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL, }); const result = await generativeTextModel.generateContentStream({ contents: [{role: 'user', parts: [{text: 'Why is the sky blue?'}]}], }); const response = await result.response; const groundingMetadata = response.candidates![0].groundingMetadata; expect(!!groundingMetadata).toBeTruthy( `sys test failure on generateContentStream in preview for grounding metadata: ${groundingMetadata}` ); if (groundingMetadata) { expect(!!groundingMetadata.webSearchQueries).toBeTruthy( `sys test failure on generateContentStream in preview for web search queries: ${groundingMetadata.webSearchQueries}` ); } }); xit('in preview should return grounding metadata when passed GoogleSearchRetriever in generateContent', async () => { const generativeTextModel = vertexAI.preview.getGenerativeModel({ model: TEXT_MODEL_NAME, }); const result = await generativeTextModel.generateContentStream({ contents: [{role: 'user', parts: [{text: 'Why is the sky blue?'}]}], tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL, }); const response = await result.response; const groundingMetadata = response.candidates![0].groundingMetadata; expect(!!groundingMetadata).toBeTruthy( `sys test failure on generateContentStream in preview for grounding metadata: ${groundingMetadata}` ); if (groundingMetadata) { expect(!!groundingMetadata.webSearchQueries).toBeTruthy( `sys test failure on generateContentStream in preview for web search queries: ${groundingMetadata.webSearchQueries}` ); } }); xit('in preview should return grounding metadata when passed a VertexRagStore', async () => { const request = { contents: [ { role: 'user', parts: [ { text: 'How much gain or loss did Google get in the Motorola Mobile deal in 2014?', }, ], }, ], tools: TOOLS_WITH_RAG, }; const result = await generativeTextModelPreview.generateContentStream(request); const response = await result.response; expect(response.candidates![0]).toBeTruthy( `sys test failure on generateContent with RAG tool, for resp ${JSON.stringify( response )}` ); expect( response.candidates![0]?.groundingMetadata?.retrievalQueries ).toBeTruthy( `sys test failure on generateContent with RAG tool, empty groundingMetadata.retrievalQueries, for resp ${JSON.stringify( response )}` ); }); }); describe('generateContent', () => { beforeEach(() => { jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000; }); it('should return the aggregated response', async () => { const response = await generativeTextModel.generateContent(TEXT_REQUEST); const aggregatedResp = response.response; expect(aggregatedResp.candidates![0]).toBeTruthy( `sys test failure on generateContentStream for aggregated response: ${JSON.stringify( aggregatedResp )}` ); }); it('in preview should return the aggregated response', async () => { const response = await generativeTextModelPreview.generateContent(TEXT_REQUEST); const aggregatedResp = response.response; expect(aggregatedResp.candidates![0]).toBeTruthy( `sys test failure on generateContentStream in preview for aggregated response: ${JSON.stringify( aggregatedResp )}` ); }); xit('should return grounding metadata when passed GoogleSearchRetriever in getGenerativeModel', async () => { const generativeTextModel = vertexAI.getGenerativeModel({ model: TEXT_MODEL_NAME, tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL, }); const result = await generativeTextModel.generateContent({ contents: [{role: 'user', parts: [{text: 'Why is the sky blue?'}]}], }); const response = result.response; const groundingMetadata = response.candidates![0].groundingMetadata; expect(!!groundingMetadata).toBeTruthy( `sys test failure on generateContent for grounding metadata: ${groundingMetadata}` ); if (groundingMetadata) { expect(!!groundingMetadata.webSearchQueries).toBeTruthy( `sys test failure on generateContent for web search queries: ${groundingMetadata.webSearchQueries}` ); } }); xit('should return grounding metadata when passed GoogleSearchRetriever in generateContent', async () => { const generativeTextModel = vertexAI.getGenerativeModel({ model: TEXT_MODEL_NAME, }); const result = await generativeTextModel.generateContent({ contents: [{role: 'user', parts: [{text: 'Why is the sky blue?'}]}], tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL, }); const response = result.response; const groundingMetadata = response.candidates![0].groundingMetadata; expect(!!groundingMetadata).toBeTruthy( `sys test failure on generateContent for grounding metadata: ${groundingMetadata}` ); if (groundingMetadata) { expect(!!groundingMetadata.webSearchQueries).toBeTruthy( `sys test failure on generateContent for web search queries: ${groundingMetadata.webSearchQueries}` ); } }); xit('in preview should return grounding metadata when passed GoogleSearchRetriever in getGenerativeModel', async () => { const generativeTextModel = vertexAI.preview.getGenerativeModel({ model: TEXT_MODEL_NAME, tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL, }); const result = await generativeTextModel.generateContent({ contents: [{role: 'user', parts: [{text: 'Why is the sky blue?'}]}], }); const response = result.response; const groundingMetadata = response.candidates![0].groundingMetadata; expect(!!groundingMetadata).toBeTruthy( `sys test failure on generateContent in preview for grounding metadata: ${groundingMetadata}` ); if (groundingMetadata) { expect(!!groundingMetadata.webSearchQueries).toBeTruthy( `sys test failure on generateContent in preview for web search queries: ${groundingMetadata.webSearchQueries}` ); } }); xit('in preview should return grounding metadata when passed GoogleSearchRetriever in generateContent', async () => { const generativeTextModel = vertexAI.preview.getGenerativeModel({ model: TEXT_MODEL_NAME, }); const result = await generativeTextModel.generateContent({ contents: [{role: 'user', parts: [{text: 'Why is the sky blue?'}]}], tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL, }); const response = result.response; const groundingMetadata = response.candidates![0].groundingMetadata; expect(!!groundingMetadata).toBeTruthy( `sys test failure on generateContent in preview for grounding metadata: ${groundingMetadata}` ); if (groundingMetadata) { expect(!!groundingMetadata.webSearchQueries).toBeTruthy( `sys test failure on generateContent in preview for web search queries: ${groundingMetadata.webSearchQueries}` ); } }); xit('should return a text when passed a FunctionDeclaration or FunctionResponse', async () => { const request = { contents: [ {role: 'user', parts: [{text: 'What is the weather in Boston?'}]}, {role: 'model', parts: FUNCTION_CALL}, {role: 'user', parts: FUNCTION_RESPONSE_PART}, ], tools: TOOLS_WITH_FUNCTION_DECLARATION, }; const resp = await generativeTextModel.generateContent(request); expect(resp.response.candidates![0]).toBeTruthy( `sys test failure on generateContentStream, for resp ${JSON.stringify( resp )}` ); expect( resp.response.candidates![0].content.parts[0].text?.toLowerCase() ).toContain( WEATHER_FORECAST, `sys test failure on generateContentStream for candidate part ${JSON.stringify( resp.response.candidates![0].content.parts[0] )}` ); }); xit('in preview should return a text when passed a FunctionDeclaration or FunctionResponse', async () => { const request = { contents: [ {role: 'user', parts: [{text: 'What is the weather in Boston?'}]}, {role: 'model', parts: FUNCTION_CALL}, {role: 'user', parts: FUNCTION_RESPONSE_PART}, ], tools: TOOLS_WITH_FUNCTION_DECLARATION, }; const resp = await generativeTextModelPreview.generateContent(request); expect(resp.response.candidates![0]).toBeTruthy( `sys test failure on generateContentStream in preview, for resp ${JSON.stringify( resp )}` ); expect( resp.response.candidates![0].content.parts[0].text?.toLowerCase() ).toContain( WEATHER_FORECAST, `sys test failure on generateContentStream in preview for candidate part ${JSON.stringify( resp.response.candidates![0].content.parts[0] )}` ); }); xit('in preview should return grounding metadata when passed a VertexRagStore', async () => { const request = { contents: [ { role: 'user', parts: [ { text: 'How much gain or loss did Google get in the Motorola Mobile deal in 2014?', }, ], }, ], tools: TOOLS_WITH_RAG, }; const resp = await generativeTextModelPreview.generateContent(request); expect(resp.response.candidates![0]).toBeTruthy( `sys test failure on generateContent with RAG tool, for resp ${JSON.stringify( resp )}` ); expect( resp.response.candidates![0]?.groundingMetadata?.retrievalQueries ).toBeTruthy( `sys test failure on generateContent with RAG tool, empty groundingMetadata.retrievalQueries, for resp ${JSON.stringify( resp )}` ); }); xit('should return a FunctionCall when passed a FunctionDeclaration', async () => { const request = { contents: [ {role: 'user', parts: [{text: 'What is the weather in Boston?'}]}, ], tools: TOOLS_WITH_FUNCTION_DECLARATION, }; const resp = await generativeTextModel.generateContent(request); expect(resp.response.candidates![0]).toBeTruthy( `sys test failure on generateContentStream, for resp ${JSON.stringify( resp )}` ); const functionCalls = resp.response .candidates![0].content.parts.filter((part: Part) => !!part.functionCall) .map((part: Part) => part.functionCall!); expect(functionCalls).toHaveSize(1); expect( GenerateContentResponseHandler.getFunctionCallsFromCandidate( resp.response.candidates![0] ) ).toEqual(functionCalls!); }); xit('in preview should return a FunctionCall when passed a FunctionDeclaration', async () => { const request = { contents: [ {role: 'user', parts: [{text: 'What is the weather in Boston?'}]}, ], tools: TOOLS_WITH_FUNCTION_DECLARATION, }; const resp = await generativeTextModelPreview.generateContent(request); expect(resp.response.candidates![0]).toBeTruthy( `sys test failure on generateContentStream in preview, for resp ${JSON.stringify( resp )}` ); const functionCalls = resp.response .candidates![0].content.parts.filter((part: Part) => !!part.functionCall) .map((part: Part) => part.functionCall!); expect(functionCalls).toHaveSize(1); expect( GenerateContentResponseHandler.getFunctionCallsFromCandidate( resp.response.candidates![0] ) ).toEqual(functionCalls!); }); }); describe('sendMessage', () => { beforeEach(() => { jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000; }); it('should populate history and return a chat response', async () => { const chat = generativeTextModel.startChat(); const chatInput1 = 'How can I learn more about Node.js?'; const result1 = await chat.sendMessage(chatInput1); const response1 = result1.response; expect(response1.candidates![0]).toBeTruthy( `sys test failure on sendMessage for aggregated response: ${response1}` ); expect((await chat.getHistory()).length).toBe(2); }); it('in preview should populate history and return a chat response', async () => { const chat = generativeTextModelPreview.startChat(); const chatInput1 = 'How can I learn more about Node.js?'; const result1 = await chat.sendMessage(chatInput1); const response1 = result1.response; expect(response1.candidates![0]).toBeTruthy( `sys test failure on sendMessage in preview for aggregated response: ${response1}` ); expect((await chat.getHistory()).length).toBe(2); }); xit('should return grounding metadata when passed GoogleSearchRetriever in getGenerativeModel', async () => { const generativeTextModel = vertexAI.getGenerativeModel({ model: TEXT_MODEL_NAME, tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL, }); const chat = generativeTextModel.startChat(); const result = await chat.sendMessage('Why is the sky blue?'); const response = result.response; const groundingMetadata = response.candidates![0].groundingMetadata; expect(!!groundingMetadata).toBeTruthy( `sys test failure on sendMessage for grounding metadata: ${groundingMetadata}` ); if (groundingMetadata) { expect(!!groundingMetadata.webSearchQueries).toBeTruthy( `sys test failure on sendMessage for web search queries: ${groundingMetadata.webSearchQueries}` ); } }); xit('should return grounding metadata when passed GoogleSearchRetriever in startChat', async () => { const generativeTextModel = vertexAI.getGenerativeModel({ model: TEXT_MODEL_NAME, }); const chat = generativeTextModel.startChat({ tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL, }); const result = await chat.sendMessage('Why is the sky blue?'); const response = result.response; const groundingMetadata = response.candidates![0].groundingMetadata; expect(!!groundingMetadata).toBeTruthy( `sys test failure on sendMessage for grounding metadata: ${groundingMetadata}` ); if (groundingMetadata) { expect(!!groundingMetadata.webSearchQueries).toBeTruthy( `sys test failure on sendMessage for web search queries: ${groundingMetadata.webSearchQueries}` ); } }); xit('in preview should return grounding metadata when passed GoogleSearchRetriever in getGenerativeModel', async () => { const generativeTextModel = vertexAI.preview.getGenerativeModel({ model: TEXT_MODEL_NAME, tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL, }); const chat = generativeTextModel.startChat(); const result = await chat.sendMessage('Why is the sky blue?'); const response = result.response; const groundingMetadata = response.candidates![0].groundingMetadata; expect(!!groundingMetadata).toBeTruthy( `sys test failure on sendMessage in preview for grounding metadata: ${groundingMetadata}` ); if (groundingMetadata) { expect(!!groundingMetadata.webSearchQueries).toBeTruthy( `sys test failure on sendMessage in preview for web search queries: ${groundingMetadata.webSearchQueries}` ); } }); xit('in preview should return grounding metadata when passed GoogleSearchRetriever in startChat', async () => { const generativeTextModel = vertexAI.preview.getGenerativeModel({ model: TEXT_MODEL_NAME, }); const chat = generativeTextModel.startChat({ tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL, }); const result = await chat.sendMessage('Why is the sky blue?'); const response = result.response; const groundingMetadata = response.candidates![0].groundingMetadata; expect(!!groundingMetadata).toBeTruthy( `sys test failure on sendMessage in preview for grounding metadata: ${groundingMetadata}` ); if (groundingMetadata) { expect(!!groundingMetadata.webSearchQueries).toBeTruthy( `sys test failure on sendMessage in preview for web search queries: ${groundingMetadata.webSearchQueries}` ); } }); }); describe('sendMessageStream', () => { beforeEach(() => { jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000; }); it('should should return a stream and populate history when generationConfig is passed to startChat', async () => { const chat = generativeTextModel.startChat({ generationConfig: { maxOutputTokens: 256, }, }); const chatInput1 = 'How can I learn more about Node.js?'; const result1 = await chat.sendMessageStream(chatInput1); for await (const item of result1.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on sendMessageStream, for item ${JSON.stringify( item )}` ); } const resp = await result1.response; expect(resp.candidates![0]).toBeTruthy( `sys test failure on sendMessageStream for aggregated response: ${JSON.stringify( resp )}` ); expect((await chat.getHistory()).length).toBe(2); }); it('in preview should should return a stream and populate history when generationConfig is passed to startChat', async () => { const chat = generativeTextModelPreview.startChat({ generationConfig: { maxOutputTokens: 256, }, }); const chatInput1 = 'How can I learn more about Node.js?'; const result1 = await chat.sendMessageStream(chatInput1); for await (const item of result1.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on sendMessageStream in preview, for item ${JSON.stringify( item )}` ); } const resp = await result1.response; expect(resp.candidates![0]).toBeTruthy( `sys test failure on sendMessageStream in preview for aggregated response: ${JSON.stringify( resp )}` ); expect((await chat.getHistory()).length).toBe(2); }); it('should should return a stream and populate history when startChat is passed no request obj', async () => { const chat = generativeTextModel.startChat(); const chatInput1 = 'How can I learn more about Node.js?'; const result1 = await chat.sendMessageStream(chatInput1); for await (const item of result1.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on sendMessageStream, for item ${JSON.stringify( item )}` ); } const resp = await result1.response; expect(resp.candidates![0]).toBeTruthy( `sys test failure on sendMessageStream for aggregated response: ${JSON.stringify( resp )}` ); expect((await chat.getHistory()).length).toBe(2); }); it('in preview should should return a stream and populate history when startChat is passed no request obj', async () => { const chat = generativeTextModelPreview.startChat(); const chatInput1 = 'How can I learn more about Node.js?'; const result1 = await chat.sendMessageStream(chatInput1); for await (const item of result1.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on sendMessageStream in preview, for item ${JSON.stringify( item )}` ); } const resp = await result1.response; expect(resp.candidates![0]).toBeTruthy( `sys test failure on sendMessageStream in preview for aggregated response: ${JSON.stringify( resp )}` ); expect((await chat.getHistory()).length).toBe(2); }); xit('should return a FunctionCall or text when passed a FunctionDeclaration or FunctionResponse', async () => { const chat = generativeTextModel.startChat({ tools: TOOLS_WITH_FUNCTION_DECLARATION, }); const chatInput1 = 'What is the weather in Boston?'; const result1 = await chat.sendMessageStream(chatInput1); for await (const item of result1.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on sendMessageStream with function calling, for item ${JSON.stringify( item )}` ); } const response1 = await result1.response; expect( JSON.stringify(response1.candidates![0].content.parts[0].functionCall) ).toContain( FUNCTION_CALL_NAME, `sys test failure on sendMessageStream with function calling, for function call: ${JSON.stringify( response1.candidates![0].content.parts[0] )}` ); expect( JSON.stringify(response1.candidates![0].content.parts[0].functionCall) ).toContain( 'location', `sys test failure on sendMessageStream with function calling, for function call: ${JSON.stringify( response1.candidates![0].content.parts[0] )}` ); // Send a follow up message with a FunctionResponse const result2 = await chat.sendMessageStream(FUNCTION_RESPONSE_PART); for await (const item of result2.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on sendMessageStream with function calling, for item ${JSON.stringify( item )}` ); } const response2 = await result2.response; expect(response2.candidates![0].content.parts[0].text).toContain( WEATHER_FORECAST, `sys test failure on sendMessageStream with function calling, for text: ${JSON.stringify( response2.candidates![0].content.parts[0].text )}` ); }); xit('in preview should return a FunctionCall or text when passed a FunctionDeclaration or FunctionResponse', async () => { const chat = generativeTextModelPreview.startChat({ tools: TOOLS_WITH_FUNCTION_DECLARATION, }); const chatInput1 = 'What is the weather in Boston?'; const result1 = await chat.sendMessageStream(chatInput1); for await (const item of result1.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on sendMessageStream in preview with function calling, for item ${JSON.stringify( item )}` ); } const response1 = await result1.response; expect( JSON.stringify(response1.candidates![0].content.parts[0].functionCall) ).toContain( FUNCTION_CALL_NAME, `sys test failure on sendMessageStream in preview with function calling, for function call: ${JSON.stringify( response1.candidates![0].content.parts[0] )}` ); expect( JSON.stringify(response1.candidates![0].content.parts[0].functionCall) ).toContain( 'location', `sys test failure on sendMessageStream in preview with function calling, for function call: ${JSON.stringify( response1.candidates![0].content.parts[0] )}` ); // Send a follow up message with a FunctionResponse const result2 = await chat.sendMessageStream(FUNCTION_RESPONSE_PART); for await (const item of result2.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on sendMessageStream in preview with function calling, for item ${JSON.stringify( item )}` ); } const response2 = await result2.response; expect(response2.candidates![0].content.parts[0].text).toContain( WEATHER_FORECAST ); }); xit('should return grounding metadata when passed GoogleSearchRetriever in getGenerativeModel', async () => { const generativeTextModel = vertexAI.getGenerativeModel({ model: TEXT_MODEL_NAME, tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL, }); const chat = generativeTextModel.startChat(); const result = await chat.sendMessageStream('Why is the sky blue?'); const response = await result.response; const groundingMetadata = response.candidates![0].groundingMetadata; expect(!!groundingMetadata).toBeTruthy( `sys test failure on groundingMetadata, ${groundingMetadata}` ); if (groundingMetadata) { expect(!!groundingMetadata.webSearchQueries).toBeTruthy( `sys test failure on groundingMetadata.webSearchQueries, ${groundingMetadata.webSearchQueries}` ); } }); xit('should return grounding metadata when passed GoogleSearchRetriever in startChat', async () => { const generativeTextModel = vertexAI.getGenerativeModel({ model: TEXT_MODEL_NAME, }); const chat = generativeTextModel.startChat({ tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL, }); const result = await chat.sendMessageStream('Why is the sky blue?'); const response = await result.response; const groundingMetadata = response.candidates![0].groundingMetadata; expect(!!groundingMetadata).toBeTruthy( `sys test failure on groundingMetadata, ${groundingMetadata}` ); if (groundingMetadata) { expect(!!groundingMetadata.webSearchQueries).toBeTruthy( `sys test failure on groundingMetadata.webSearchQueries, ${groundingMetadata.webSearchQueries}` ); } }); xit('in preview should return grounding metadata when passed GoogleSearchRetriever in getGenerativeModel', async () => { const generativeTextModel = vertexAI.preview.getGenerativeModel({ model: TEXT_MODEL_NAME, tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL, }); const chat = generativeTextModel.startChat(); const result = await chat.sendMessageStream('Why is the sky blue?'); const response = await result.response; const groundingMetadata = response.candidates![0].groundingMetadata; expect(!!groundingMetadata).toBeTruthy( `sys test failure on groundingMetadata in preview, ${groundingMetadata}` ); if (groundingMetadata) { expect(!!groundingMetadata.webSearchQueries).toBeTruthy( `sys test failure on groundingMetadata.webSearchQueries in preview, ${groundingMetadata.webSearchQueries}` ); } }); xit('in preview should return grounding metadata when passed GoogleSearchRetriever in startChat', async () => { const generativeTextModel = vertexAI.preview.getGenerativeModel({ model: TEXT_MODEL_NAME, }); const chat = generativeTextModel.startChat({ tools: TOOLS_WITH_GOOGLE_SEARCH_RETRIEVAL, }); const result = await chat.sendMessageStream('Why is the sky blue?'); const response = await result.response; const groundingMetadata = response.candidates![0].groundingMetadata; expect(!!groundingMetadata).toBeTruthy( `sys test failure on groundingMetadata in preview, ${groundingMetadata}` ); if (groundingMetadata) { expect(!!groundingMetadata.webSearchQueries).toBeTruthy( `sys test failure on groundingMetadata.webSearchQueries in preview, ${groundingMetadata.webSearchQueries}` ); } }); }); describe('countTokens', () => { beforeEach(() => { jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000; }); it('should should return a CountTokensResponse', async () => { const countTokensResp = await generativeTextModel.countTokens(TEXT_REQUEST); expect(countTokensResp.totalTokens).toBeTruthy( `sys test failure on countTokens, ${countTokensResp}` ); }); it('in preview should should return a CountTokensResponse', async () => { const countTokensResp = await generativeTextModelPreview.countTokens(TEXT_REQUEST); expect(countTokensResp.totalTokens).toBeTruthy( `sys test failure on countTokens in preview, ${countTokensResp}` ); }); }); describe('generateContentStream using models/model-id', () => { beforeEach(() => { jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000; }); it('should should return a stream and aggregated response when passed text', async () => { const streamingResp = await generativeTextModelWithPrefix.generateContentStream(TEXT_REQUEST); for await (const item of streamingResp.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on generateContentStream using models/gemini-pro, for item ${JSON.stringify( item )}` ); } const aggregatedResp = await streamingResp.response; expect(aggregatedResp.candidates![0]).toBeTruthy( `sys test failure on generateContentStream using models/gemini-pro for aggregated response: ${JSON.stringify( aggregatedResp )}` ); }); it('in preview should should return a stream and aggregated response when passed text', async () => { const streamingResp = await generativeTextModelWithPrefixPreview.generateContentStream( TEXT_REQUEST ); for await (const item of streamingResp.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on generateContentStream in preview using models/gemini-pro, for item ${JSON.stringify( item )}` ); } const aggregatedResp = await streamingResp.response; expect(aggregatedResp.candidates![0]).toBeTruthy( `sys test failure on generateContentStream in preview using models/gemini-pro for aggregated response: ${JSON.stringify( aggregatedResp )}` ); }); it('should return a stream and aggregated response when passed multipart base64 content when using models/gemini-pro-vision', async () => { const streamingResp = await generativeVisionModelWithPrefix.generateContentStream( MULTI_PART_BASE64_REQUEST ); for await (const item of streamingResp.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on generateContentStream using models/gemini-pro-vision, for item ${JSON.stringify( item )}` ); } const aggregatedResp = await streamingResp.response; expect(aggregatedResp.candidates![0]).toBeTruthy( `sys test failure on generateContentStream using models/gemini-pro-vision for aggregated response: ${JSON.stringify( aggregatedResp )}` ); }); it('in preview should return a stream and aggregated response when passed multipart base64 content when using models/gemini-pro-vision', async () => { const streamingResp = await generativeVisionModelWithPrefixPreview.generateContentStream( MULTI_PART_BASE64_REQUEST ); for await (const item of streamingResp.stream) { expect(item.candidates![0]).toBeTruthy( `sys test failure on generateContentStream in preview using models/gemini-pro-vision, for item ${JSON.stringify( item )}` ); } const aggregatedResp = await streamingResp.response; expect(aggregatedResp.candidates![0]).toBeTruthy( `sys test failure on generateContentStream in preview using models/gemini-pro-vision for aggregated response: ${JSON.stringify( aggregatedResp )}` ); }); }); ================================================ FILE: vertexai/test/index_test.ts ================================================ /** * @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. */ import {VertexAI} from '../src/index'; describe('SDK', () => { it('should import VertexAI', () => { const PROJECT = 'test_project'; const LOCATION = 'test_location'; const vertexai = new VertexAI({ project: PROJECT, location: LOCATION, }); expect(vertexai).toBeInstanceOf(VertexAI); }); }); ================================================ FILE: vertexai/test/vertex_ai_test.ts ================================================ /** * @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. */ import {VertexAI} from '../src/vertex_ai'; import {GenerativeModelPreview, GenerativeModel} from '../src/models'; import {GoogleAuthError, IllegalArgumentError} from '../src/types/errors'; const PROJECT = 'test_project'; const LOCATION = 'test_location'; class VertexAIForTest extends VertexAI { public override getProject(): string { return super.getProject(); } public override getLocation(): string { return super.getLocation(); } } describe('VertexAI', () => { let vertexai: VertexAI; beforeEach(() => { cleanupEnvironmentVariable(); vertexai = new VertexAI({ project: PROJECT, location: LOCATION, }); }); it('no location given, should instantiate VertexAI and VertexAIPreview', () => { const vertexaiNoLocation = new VertexAI({ project: PROJECT, }) as VertexAIForTest; const generativeModel = vertexaiNoLocation.getGenerativeModel({ model: 'gemini-pro', }); const generativeModelPreview = vertexaiNoLocation.preview.getGenerativeModel({ model: 'gemini-pro', }); expect(vertexaiNoLocation.getLocation()).toEqual('us-central1'); expect(vertexaiNoLocation).toBeInstanceOf(VertexAI); expect(generativeModel).toBeInstanceOf(GenerativeModel); expect(generativeModelPreview).toBeInstanceOf(GenerativeModelPreview); }); it('location in run time env GOOGLE_CLOUD_REGION, should instantiate VertexAI and VertexAIPreview', () => { process.env['GOOGLE_CLOUD_REGION'] = 'us-central2'; process.env['CLOUD_ML_REGION'] = 'us-central3'; const vertexaiNoLocation = new VertexAI({ project: PROJECT, }) as VertexAIForTest; const generativeModel = vertexaiNoLocation.getGenerativeModel({ model: 'gemini-pro', }); const generativeModelPreview = vertexaiNoLocation.preview.getGenerativeModel({ model: 'gemini-pro', }); expect(vertexaiNoLocation.getLocation()).toEqual('us-central2'); expect(vertexaiNoLocation).toBeInstanceOf(VertexAI); expect(generativeModel).toBeInstanceOf(GenerativeModel); expect(generativeModelPreview).toBeInstanceOf(GenerativeModelPreview); }); it('location in run time env CLOUD_ML_REGION, should instantiate VertexAI and VertexAIPreview', () => { process.env['CLOUD_ML_REGION'] = 'us-central3'; const vertexaiNoLocation = new VertexAI({ project: PROJECT, }) as VertexAIForTest; const generativeModel = vertexaiNoLocation.getGenerativeModel({ model: 'gemini-pro', }); const generativeModelPreview = vertexaiNoLocation.preview.getGenerativeModel({ model: 'gemini-pro', }); expect(vertexaiNoLocation.getLocation()).toEqual('us-central3'); expect(vertexaiNoLocation).toBeInstanceOf(VertexAI); expect(generativeModel).toBeInstanceOf(GenerativeModel); expect(generativeModelPreview).toBeInstanceOf(GenerativeModelPreview); }); it('location in run time env GOOGLE_CLOUD_REGION, project in GOOGLE_CLOUD_PROJECT, should instantiate VertexAI and VertexAIPreview', () => { process.env['GOOGLE_CLOUD_REGION'] = 'us-central2'; process.env['CLOUD_ML_REGION'] = 'us-central3'; process.env['GOOGLE_CLOUD_PROJECT'] = 'my-project'; const vertexaiNoArgs = new VertexAI({}) as VertexAIForTest; const generativeModel = vertexaiNoArgs.getGenerativeModel({ model: 'gemini-pro', }); const generativeModelPreview = vertexaiNoArgs.preview.getGenerativeModel({ model: 'gemini-pro', }); expect(vertexaiNoArgs.getLocation()).toEqual('us-central2'); expect(vertexaiNoArgs.getProject()).toEqual('my-project'); expect(vertexaiNoArgs).toBeInstanceOf(VertexAI); expect(generativeModel).toBeInstanceOf(GenerativeModel); expect(generativeModelPreview).toBeInstanceOf(GenerativeModelPreview); }); it('cannot resolve project, should throw', () => { const expectedProjectNotFoundErrorMessage = 'Unable to infer your project.' + 'Please provide a project Id by one of the following:' + '\n- Passing a constructor argument by using new VertexAI({project: my-project})' + '\n- Setting project using `gcloud config set project my-project`'; expect(() => { new VertexAI({}); }).toThrow(new IllegalArgumentError(expectedProjectNotFoundErrorMessage)); }); it('given undefined google auth options, should be instantiated', () => { expect(vertexai).toBeInstanceOf(VertexAI); }); it('given specified google auth options, should be instantiated', () => { const googleAuthOptions = { scopes: 'https://www.googleapis.com/auth/cloud-platform', }; const vetexai1 = new VertexAI({ project: PROJECT, location: LOCATION, googleAuthOptions: googleAuthOptions, }); expect(vetexai1).toBeInstanceOf(VertexAI); }); it('given inconsistent project ID, should throw error', () => { const googleAuthOptions = { projectId: 'another_project', }; expect(() => { new VertexAI({ project: PROJECT, location: LOCATION, googleAuthOptions: googleAuthOptions, }); }).toThrow( new Error( 'inconsistent project ID values. argument project got value test_project but googleAuthOptions.projectId got value another_project' ) ); }); it('given scopes missing required scope, should throw GoogleAuthError', () => { const invalidGoogleAuthOptionsStringScopes = {scopes: 'test.scopes'}; expect(() => { new VertexAI({ project: PROJECT, location: LOCATION, googleAuthOptions: invalidGoogleAuthOptionsStringScopes, }); }).toThrow( new GoogleAuthError( "input GoogleAuthOptions.scopes test.scopes doesn't contain required scope " + 'https://www.googleapis.com/auth/cloud-platform, ' + 'please include https://www.googleapis.com/auth/cloud-platform into GoogleAuthOptions.scopes ' + 'or leave GoogleAuthOptions.scopes undefined' ) ); const invalidGoogleAuthOptionsArrayScopes = { scopes: ['test1.scopes', 'test2.scopes'], }; expect(() => { new VertexAI({ project: PROJECT, location: LOCATION, googleAuthOptions: invalidGoogleAuthOptionsArrayScopes, }); }).toThrow( new GoogleAuthError( "input GoogleAuthOptions.scopes test1.scopes,test2.scopes doesn't contain required scope " + 'https://www.googleapis.com/auth/cloud-platform, ' + 'please include https://www.googleapis.com/auth/cloud-platform into GoogleAuthOptions.scopes ' + 'or leave GoogleAuthOptions.scopes undefined' ) ); }); it('VertexAIPreview should generate GenerativatModelPreview', () => { const generativeModelPreview = vertexai.preview.getGenerativeModel({ model: 'gemini-pro', }); expect(generativeModelPreview).toBeInstanceOf(GenerativeModelPreview); }); it('VertexAI should generate GenerativatModel', () => { const generativeModel = vertexai.getGenerativeModel({ model: 'gemini-pro', }); expect(generativeModel).toBeInstanceOf(GenerativeModel); }); }); function cleanupEnvironmentVariable() { delete process.env['GOOGLE_CLOUD_REGION']; delete process.env['CLOUD_ML_REGION']; delete process.env['GOOGLE_CLOUD_PROJECT']; } ================================================ FILE: vertexai/tsconfig.json ================================================ { "extends": "./node_modules/gts/tsconfig-google.json", "compilerOptions": { "module": "commonjs", "moduleResolution": "node", "baseUrl": ".", "paths": { "@google/genai": ["./node_modules/@google/genai/dist/genai.d.ts"], "@google/genai/vertex_internal": ["./node_modules/@google/genai/dist/vertex_internal/index.d.ts"] }, "rootDir": ".", "outDir": "build", "resolveJsonModule": true, "lib": [ "es2022", "dom", "dom.iterable" ], "skipLibCheck": true }, "include": [ "src/**/*.ts", "test/**/*.ts", "system_test/**/*.ts" ], "exclude": [ "build", "node_modules", "dist" ] }