From e29d194731782549610733bbc82b4db2ab39d8d6 Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Thu, 9 Jul 2026 10:09:26 -0600 Subject: [PATCH 01/34] ci: fix undefined CAIP_PROJECT_ID by exporting secrets to GITHUB_ENV (#4374) --- .github/workflows/ai-platform-snippets.yaml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ai-platform-snippets.yaml b/.github/workflows/ai-platform-snippets.yaml index a264a69b10..ce2e83f854 100644 --- a/.github/workflows/ai-platform-snippets.yaml +++ b/.github/workflows/ai-platform-snippets.yaml @@ -55,6 +55,10 @@ jobs: secrets: |- caip_id:nodejs-docs-samples-tests/nodejs-docs-samples-ai-platform-caip-project-id location:nodejs-docs-samples-tests/nodejs-docs-samples-ai-platform-location + - name: Set environment variables + run: | + echo "CAIP_PROJECT_ID=${{ steps.secrets.outputs.caip_id }}" >> $GITHUB_ENV + echo "LOCATION=${{ steps.secrets.outputs.location }}" >> $GITHUB_ENV - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 with: node-version: 16 @@ -77,6 +81,4 @@ jobs: - name: Run Tests run: make test dir=ai-platform/snippets env: - GOOGLE_SAMPLES_PROJECT: "long-door-651" - LOCATION: ${{ steps.secrets.outputs.location }} - CAIP_PROJECT_ID: ${{ steps.secrets.outputs.caip_id }} + GOOGLE_SAMPLES_PROJECT: "long-door-651" \ No newline at end of file From 1d8c421d3db012f43a2288da5c2bf94532b08cb7 Mon Sep 17 00:00:00 2001 From: fosky94 Date: Mon, 13 Jul 2026 13:39:37 -0500 Subject: [PATCH 02/34] feat(redis): create client side metrics for redis (#4319) * Create Client side metrics for redis * Update license * feat(redis): create client side metrics for redis * fix:fixing missing dependencies and add tests * style:fix gts style and formating errors --------- Co-authored-by: Angel Caamal --- .../redis/client_side_metrics/package.json | 36 ++++ .../redis/client_side_metrics/server.js | 156 ++++++++++++++++++ .../client_side_metrics/test/server.test.js | 140 ++++++++++++++++ 3 files changed, 332 insertions(+) create mode 100644 memorystore/redis/client_side_metrics/package.json create mode 100644 memorystore/redis/client_side_metrics/server.js create mode 100644 memorystore/redis/client_side_metrics/test/server.test.js diff --git a/memorystore/redis/client_side_metrics/package.json b/memorystore/redis/client_side_metrics/package.json new file mode 100644 index 0000000000..4ccec3a57a --- /dev/null +++ b/memorystore/redis/client_side_metrics/package.json @@ -0,0 +1,36 @@ +{ + "name": "memorystore-redis-client-side-metrics", + "description": "An example of using Memorystore (Redis) with OpenTelemetry for client-side metrics and tracing in Node.js", + "version": "0.0.1", + "private": true, + "license": "Apache-2.0", + "author": "Google Inc.", + "engines": { + "node": ">=18.0.0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git" + }, + "scripts": { + "test": "mocha test/**/*.js" + }, + "dependencies": { + "@google-cloud/opentelemetry-cloud-monitoring-exporter": "^0.21.0", + "@google-cloud/opentelemetry-cloud-trace-exporter": "^3.0.0", + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/instrumentation": "^0.205.0", + "@opentelemetry/instrumentation-redis": "^0.67.0", + "@opentelemetry/resources": "^2.1.0", + "@opentelemetry/sdk-metrics": "^2.1.0", + "@opentelemetry/sdk-trace-base": "^2.1.0", + "@opentelemetry/sdk-trace-node": "^2.1.0", + "redis": "^4.6.0" + }, + "devDependencies": { + "mocha": "^10.0.0", + "chai": "^4.3.0", + "proxyquire": "^2.1.0", + "sinon": "^15.0.0" + } +} \ No newline at end of file diff --git a/memorystore/redis/client_side_metrics/server.js b/memorystore/redis/client_side_metrics/server.js new file mode 100644 index 0000000000..171481be4e --- /dev/null +++ b/memorystore/redis/client_side_metrics/server.js @@ -0,0 +1,156 @@ +/** + * Copyright 2026 Google, Inc. + * 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. + */ + +// [START memorystore_redis_client_side_metrics] + +'use strict'; + +const {trace, metrics} = require('@opentelemetry/api'); +const {NodeTracerProvider} = require('@opentelemetry/sdk-trace-node'); +const {BatchSpanProcessor} = require('@opentelemetry/sdk-trace-base'); +const { + TraceExporter, +} = require('@google-cloud/opentelemetry-cloud-trace-exporter'); +const { + MeterProvider, + PeriodicExportingMetricReader, +} = require('@opentelemetry/sdk-metrics'); +const { + MetricExporter, +} = require('@google-cloud/opentelemetry-cloud-monitoring-exporter'); +const {RedisInstrumentation} = require('@opentelemetry/instrumentation-redis'); +const {registerInstrumentations} = require('@opentelemetry/instrumentation'); +const {performance} = require('perf_hooks'); + +// FIX: Pass spanProcessors in the constructor options for NodeTracerProvider in SDK 2.x +const provider = new NodeTracerProvider({ + spanProcessors: [new BatchSpanProcessor(new TraceExporter())], +}); +provider.register(); + +registerInstrumentations({ + instrumentations: [new RedisInstrumentation()], +}); + +const redis = require('redis'); + +const metricExporter = new MetricExporter(); +const metricReader = new PeriodicExportingMetricReader({ + exporter: metricExporter, + exportIntervalMillis: 10000, +}); +const meterProvider = new MeterProvider({readers: [metricReader]}); +metrics.setGlobalMeterProvider(meterProvider); + +const tracer = trace.getTracer('redis.client.node'); +const meter = metrics.getMeter('redis.metrics.node'); + +const rttHist = meter.createHistogram('redis_client_rtt', {unit: 'ms'}); +const appBlockHist = meter.createHistogram( + 'redis_application_blocking_latency', + {unit: 'ms'} +); +const retryCounter = meter.createCounter('redis_retry_count'); +const connErrorCounter = meter.createCounter('redis_connectivity_error_count'); + +retryCounter.add(0, {operation: 'startup'}); +connErrorCounter.add(0, {operation: 'startup'}); + +const REDISHOST = process.env.REDISHOST || 'localhost'; +const REDISPORT = process.env.REDISPORT || 6379; + +const client = redis.createClient({ + socket: { + host: REDISHOST, + port: REDISPORT, + reconnectStrategy: retries => { + connErrorCounter.add(1, {error: 'socket_reconnect'}); + if (retries > 5) return new Error('Max retries reached'); + return Math.min(retries * 100, 3000); + }, + }, +}); +client.on('error', err => console.log('Redis Client Error', err)); + +async function smartRedisCall(operationName, func, ...args) { + let attempt = 0; + while (attempt < 3) { + try { + const reqStart = performance.now(); + const response = await func(...args); + rttHist.record(performance.now() - reqStart, {operation: operationName}); + + const appParseStart = performance.now(); + // eslint-disable-next-line no-unused-vars + const _ = String(response); + appBlockHist.record(performance.now() - appParseStart, { + operation: operationName, + }); + + return response; + } catch (e) { + attempt++; + retryCounter.add(1, {operation: operationName}); + if (attempt >= 3) throw e; + await new Promise(resolve => + setTimeout(resolve, Math.pow(2, attempt) * 100) + ); + } + } +} + +async function main() { + await client.connect(); + + await tracer.startActiveSpan('process_user_span', async span => { + try { + // Simple write and read operations + await smartRedisCall( + 'set_user', + client.set.bind(client), + 'user:123', + 'active' + ); + + const result = await smartRedisCall( + 'get_user', + client.get.bind(client), + 'user:123' + ); + console.log('Retrieved:', result); + } catch (e) { + span.recordException(e); + } finally { + span.end(); + } + }); + + await client.quit(); + await provider.forceFlush(); + await meterProvider.forceFlush(); +} + +// Only run the script automatically if it is executed directly (e.g. `node server.js`) +if (require.main === module) { + main().catch(console.error); +} + +// Export for testability +module.exports = { + main, + smartRedisCall, +}; + +// [END memorystore_redis_client_side_metrics] diff --git a/memorystore/redis/client_side_metrics/test/server.test.js b/memorystore/redis/client_side_metrics/test/server.test.js new file mode 100644 index 0000000000..6a4739177c --- /dev/null +++ b/memorystore/redis/client_side_metrics/test/server.test.js @@ -0,0 +1,140 @@ +// Copyright 2026 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. + +'use strict'; + +const proxyquire = require('proxyquire'); +const sinon = require('sinon'); +const {assert} = require('chai'); + +describe('Memorystore Redis Client-Side Metrics Sample', () => { + it('should run successfully with mocked Redis and GCP exporters', async () => { + // Stubs for Redis Client + const clientStub = { + connect: sinon.stub().resolves(), + set: sinon.stub().resolves('OK'), + get: sinon.stub().resolves('active'), + on: sinon.stub(), + quit: sinon.stub().resolves(), + }; + + const redisMock = { + createClient: sinon.stub().returns(clientStub), + }; + + // Mocks for GCP Exporters to avoid needing live GCP credentials in tests + class MockTraceExporter { + export(spans, resultCallback) { + if (resultCallback) resultCallback({code: 0}); + } + shutdown() { + return Promise.resolve(); + } + forceFlush() { + return Promise.resolve(); + } + } + + class MockMetricExporter { + export(metrics, resultCallback) { + if (resultCallback) resultCallback({code: 0}); + } + shutdown() { + return Promise.resolve(); + } + forceFlush() { + return Promise.resolve(); + } + } + + const traceExporterMock = { + TraceExporter: sinon.stub().returns(new MockTraceExporter()), + }; + + const metricExporterMock = { + MetricExporter: sinon.stub().returns(new MockMetricExporter()), + }; + + // Mock for Redis Instrumentation to prevent it trying to patch the mocked Redis module + class MockRedisInstrumentation { + enable() {} + disable() {} + setTracerProvider() {} + setMeterProvider() {} + getConfig() { + return {}; + } + setConfig() {} + getInstrumentationName() { + return 'mock-redis'; + } + getInstrumentationVersion() { + return '0.0.0'; + } + init() {} + } + + const redisInstrumentationMock = { + RedisInstrumentation: MockRedisInstrumentation, + }; + + // Load the sample with proxyquire, substituting our mocks for its top-level requires + const {main} = proxyquire('../server.js', { + redis: redisMock, + '@google-cloud/opentelemetry-cloud-trace-exporter': traceExporterMock, + '@google-cloud/opentelemetry-cloud-monitoring-exporter': + metricExporterMock, + '@opentelemetry/instrumentation-redis': redisInstrumentationMock, + }); + + // Verify top-level code executed as expected during the initial load phase + assert.isTrue( + redisMock.createClient.calledOnce, + 'redis.createClient should be called during load' + ); + assert.isTrue( + clientStub.on.calledWith('error', sinon.match.func), + 'client.on("error", ...) should be called during load' + ); + assert.isTrue( + traceExporterMock.TraceExporter.calledOnce, + 'TraceExporter should be instantiated during load' + ); + assert.isTrue( + metricExporterMock.MetricExporter.calledOnce, + 'MetricExporter should be instantiated during load' + ); + + // Run the main function and await its completion + await main(); + + // Verify main() interactions + assert.isTrue( + clientStub.connect.calledOnce, + 'client.connect should be called in main()' + ); + assert.isTrue( + clientStub.set.calledOnce, + 'client.set should be called in main() (via smartRedisCall)' + ); + assert.isTrue( + clientStub.get.calledOnce, + 'client.get should be called in main() (via smartRedisCall)' + ); + assert.isTrue( + clientStub.quit.calledOnce, + 'client.quit should be called in main()' + ); + }); +}); From 38fad06097b5fb5b3352816331f7026132c2566a Mon Sep 17 00:00:00 2001 From: Kevin Gordillo Date: Tue, 14 Jul 2026 12:21:18 -0600 Subject: [PATCH 03/34] refactor: rename securitycenter list findings tag (#4380) Co-authored-by: Angel Caamal --- security-center/snippets/v1/listFindingsAtTime.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/security-center/snippets/v1/listFindingsAtTime.js b/security-center/snippets/v1/listFindingsAtTime.js index ad6aa69229..b2cc05864d 100644 --- a/security-center/snippets/v1/listFindingsAtTime.js +++ b/security-center/snippets/v1/listFindingsAtTime.js @@ -15,7 +15,7 @@ /** Demonstrates listing findings at a point in time. */ function main(sourceName = 'FULL RESOURCE PATH TO PARENT SOURCE') { - // [START securitycenter_list_findings_at_time] + // [START securitycenter_list_findings_within_time_range] // Imports the Google Cloud client library. const {SecurityCenterClient} = require('@google-cloud/security-center'); @@ -48,7 +48,7 @@ function main(sourceName = 'FULL RESOURCE PATH TO PARENT SOURCE') { ); } listFindingsAtTime(); - // [END securitycenter_list_findings_at_time] + // [END securitycenter_list_findings_within_time_range] } main(...process.argv.slice(2)); From 906e305f412ea109e8e3a8c6e2034c85987e0064 Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Wed, 15 Jul 2026 10:53:29 -0600 Subject: [PATCH 04/34] chore(ai-platform): remove decommissioned video batch prediction samples (#4378) --- ...tch-prediction-job-video-classification.js | 108 ------------------ ...ch-prediction-job-video-object-tracking.js | 104 ----------------- ...rediction-job-video-classification.test.js | 83 -------------- ...ediction-job-video-object-tracking.test.js | 83 -------------- 4 files changed, 378 deletions(-) delete mode 100644 ai-platform/snippets/create-batch-prediction-job-video-classification.js delete mode 100644 ai-platform/snippets/create-batch-prediction-job-video-object-tracking.js delete mode 100644 ai-platform/snippets/test/create-batch-prediction-job-video-classification.test.js delete mode 100644 ai-platform/snippets/test/create-batch-prediction-job-video-object-tracking.test.js diff --git a/ai-platform/snippets/create-batch-prediction-job-video-classification.js b/ai-platform/snippets/create-batch-prediction-job-video-classification.js deleted file mode 100644 index 6208ffb89a..0000000000 --- a/ai-platform/snippets/create-batch-prediction-job-video-classification.js +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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 - * - * 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'; - -async function main( - batchPredictionDisplayName, - modelId, - gcsSourceUri, - gcsDestinationOutputUriPrefix, - project, - location = 'us-central1' -) { - // [START aiplatform_create_batch_prediction_job_video_classification_sample] - /** - * TODO(developer): Uncomment these variables before running the sample.\ - * (Not necessary if passing values as arguments) - */ - - // const batchPredictionDisplayName = 'YOUR_BATCH_PREDICTION_DISPLAY_NAME'; - // const modelId = 'YOUR_MODEL_ID'; - // const gcsSourceUri = 'YOUR_GCS_SOURCE_URI'; - // const gcsDestinationOutputUriPrefix = 'YOUR_GCS_DEST_OUTPUT_URI_PREFIX'; - // eg. "gs:///destination_path" - // const project = 'YOUR_PROJECT_ID'; - // const location = 'YOUR_PROJECT_LOCATION'; - const aiplatform = require('@google-cloud/aiplatform'); - const {params} = aiplatform.protos.google.cloud.aiplatform.v1.schema.predict; - - // Imports the Google Cloud Job Service Client library - const {JobServiceClient} = require('@google-cloud/aiplatform').v1; - - // Specifies the location of the api endpoint - const clientOptions = { - apiEndpoint: 'us-central1-aiplatform.googleapis.com', - }; - - // Instantiates a client - const jobServiceClient = new JobServiceClient(clientOptions); - - async function createBatchPredictionJobVideoClassification() { - // Configure the parent resource - const parent = `projects/${project}/locations/${location}`; - const modelName = `projects/${project}/locations/${location}/models/${modelId}`; - - // For more information on how to configure the model parameters object, see - // https://cloud.google.com/ai-platform-unified/docs/predictions/batch-predictions - const modelParamsObj = new params.VideoClassificationPredictionParams({ - confidenceThreshold: 0.5, - maxPredictions: 1000, - segmentClassification: true, - shotClassification: true, - oneSecIntervalClassification: true, - }); - - const modelParameters = modelParamsObj.toValue(); - - const inputConfig = { - instancesFormat: 'jsonl', - gcsSource: {uris: [gcsSourceUri]}, - }; - const outputConfig = { - predictionsFormat: 'jsonl', - gcsDestination: {outputUriPrefix: gcsDestinationOutputUriPrefix}, - }; - const batchPredictionJob = { - displayName: batchPredictionDisplayName, - model: modelName, - modelParameters, - inputConfig, - outputConfig, - }; - const request = { - parent, - batchPredictionJob, - }; - - // Create batch prediction job request - const [response] = await jobServiceClient.createBatchPredictionJob(request); - - console.log('Create batch prediction job video classification response'); - console.log(`Name : ${response.name}`); - console.log('Raw response:'); - console.log(JSON.stringify(response, null, 2)); - } - createBatchPredictionJobVideoClassification(); - // [END aiplatform_create_batch_prediction_job_video_classification_sample] -} - -process.on('unhandledRejection', err => { - console.error(err.message); - process.exitCode = 1; -}); - -main(...process.argv.slice(2)); diff --git a/ai-platform/snippets/create-batch-prediction-job-video-object-tracking.js b/ai-platform/snippets/create-batch-prediction-job-video-object-tracking.js deleted file mode 100644 index 0e5b898efd..0000000000 --- a/ai-platform/snippets/create-batch-prediction-job-video-object-tracking.js +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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 - * - * 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'; - -async function main( - batchPredictionDisplayName, - modelId, - gcsSourceUri, - gcsDestinationOutputUriPrefix, - project, - location = 'us-central1' -) { - // [START aiplatform_create_batch_prediction_job_video_object_tracking_sample] - /** - * TODO(developer): Uncomment these variables before running the sample.\ - * (Not necessary if passing values as arguments) - */ - - // const batchPredictionDisplayName = 'YOUR_BATCH_PREDICTION_DISPLAY_NAME'; - // const modelId = 'YOUR_MODEL_ID'; - // const gcsSourceUri = 'YOUR_GCS_SOURCE_URI'; - // const gcsDestinationOutputUriPrefix = 'YOUR_GCS_DEST_OUTPUT_URI_PREFIX'; - // eg. "gs:///destination_path" - // const project = 'YOUR_PROJECT_ID'; - // const location = 'YOUR_PROJECT_LOCATION'; - const aiplatform = require('@google-cloud/aiplatform'); - const {params} = aiplatform.protos.google.cloud.aiplatform.v1.schema.predict; - - // Imports the Google Cloud Job Service Client library - const {JobServiceClient} = require('@google-cloud/aiplatform').v1; - - // Specifies the location of the api endpoint - const clientOptions = { - apiEndpoint: 'us-central1-aiplatform.googleapis.com', - }; - - // Instantiates a client - const jobServiceClient = new JobServiceClient(clientOptions); - - async function createBatchPredictionJobVideoObjectTracking() { - // Configure the parent resource - const parent = `projects/${project}/locations/${location}`; - const modelName = `projects/${project}/locations/${location}/models/${modelId}`; - - // For more information on how to configure the model parameters object, see - // https://cloud.google.com/ai-platform-unified/docs/predictions/batch-predictions - const modelParamsObj = new params.VideoObjectTrackingPredictionParams({ - confidenceThreshold: 0.5, - }); - - const modelParameters = modelParamsObj.toValue(); - - const inputConfig = { - instancesFormat: 'jsonl', - gcsSource: {uris: [gcsSourceUri]}, - }; - const outputConfig = { - predictionsFormat: 'jsonl', - gcsDestination: {outputUriPrefix: gcsDestinationOutputUriPrefix}, - }; - const batchPredictionJob = { - displayName: batchPredictionDisplayName, - model: modelName, - modelParameters, - inputConfig, - outputConfig, - }; - const request = { - parent, - batchPredictionJob, - }; - - // Create batch prediction job request - const [response] = await jobServiceClient.createBatchPredictionJob(request); - - console.log('Create batch prediction job video object tracking response'); - console.log(`Name : ${response.name}`); - console.log('Raw response:'); - console.log(JSON.stringify(response, null, 2)); - } - createBatchPredictionJobVideoObjectTracking(); - // [END aiplatform_create_batch_prediction_job_video_object_tracking_sample] -} - -process.on('unhandledRejection', err => { - console.error(err.message); - process.exitCode = 1; -}); - -main(...process.argv.slice(2)); diff --git a/ai-platform/snippets/test/create-batch-prediction-job-video-classification.test.js b/ai-platform/snippets/test/create-batch-prediction-job-video-classification.test.js deleted file mode 100644 index 16f8ceaf24..0000000000 --- a/ai-platform/snippets/test/create-batch-prediction-job-video-classification.test.js +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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 - * - * 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'; - -const path = require('path'); -const {assert} = require('chai'); -const {after, describe, it} = require('mocha'); -const uuid = require('uuid').v4; -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); -const cwd = path.join(__dirname, '..'); - -const aiplatform = require('@google-cloud/aiplatform'); -const clientOptions = { - apiEndpoint: 'us-central1-aiplatform.googleapis.com', -}; - -const jobServiceClient = new aiplatform.v1.JobServiceClient(clientOptions); - -const batchPredictionDisplayName = `temp_create_batch_prediction_video_classification_test${uuid()}`; -const modelId = '8596984660557299712'; -const gcsSourceUri = - 'gs://ucaip-samples-test-output/inputs/vcn_40_batch_prediction_input.jsonl'; -const gcsDestinationOutputUriPrefix = 'gs://ucaip-samples-test-output/'; -const location = 'us-central1'; -const project = process.env.CAIP_PROJECT_ID; - -let batchPredictionJobId; - -describe('AI platform create batch prediction job video classification', () => { - it('should create a video classification batch prediction job', async () => { - const stdout = execSync( - `node ./create-batch-prediction-job-video-classification.js \ - ${batchPredictionDisplayName} \ - ${modelId} ${gcsSourceUri} \ - ${gcsDestinationOutputUriPrefix} \ - ${project} ${location}`, - { - cwd, - } - ); - assert.match( - stdout, - /Create batch prediction job video classification response/ - ); - batchPredictionJobId = stdout - .split('/locations/us-central1/batchPredictionJobs/')[1] - .split('\n')[0]; - }); - after('should cancel delete the batch prediction job', async () => { - const name = jobServiceClient.batchPredictionJobPath( - project, - location, - batchPredictionJobId - ); - - const cancelRequest = { - name, - }; - - jobServiceClient.cancelBatchPredictionJob(cancelRequest).then(() => { - const deleteRequest = { - name, - }; - - return jobServiceClient.deleteBatchPredictionJob(deleteRequest); - }); - }); -}); diff --git a/ai-platform/snippets/test/create-batch-prediction-job-video-object-tracking.test.js b/ai-platform/snippets/test/create-batch-prediction-job-video-object-tracking.test.js deleted file mode 100644 index 5c3a18887e..0000000000 --- a/ai-platform/snippets/test/create-batch-prediction-job-video-object-tracking.test.js +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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 - * - * 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'; - -const path = require('path'); -const {assert} = require('chai'); -const {after, describe, it} = require('mocha'); -const uuid = require('uuid').v4; -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); -const cwd = path.join(__dirname, '..'); - -const aiplatform = require('@google-cloud/aiplatform'); -const clientOptions = { - apiEndpoint: 'us-central1-aiplatform.googleapis.com', -}; - -const jobServiceClient = new aiplatform.v1.JobServiceClient(clientOptions); - -const batchPredictionDisplayName = `temp_create_batch_prediction_video_object_tracking_test${uuid()}`; -const modelId = '8609932509485989888'; -const gcsSourceUri = - 'gs://ucaip-samples-test-output/inputs/vot_batch_prediction_input.jsonl'; -const gcsDestinationOutputUriPrefix = 'gs://ucaip-samples-test-output/'; -const location = 'us-central1'; -const project = process.env.CAIP_PROJECT_ID; - -let batchPredictionJobId; - -describe('AI platform create batch prediction job video object tracking', () => { - it('should create a video object tracking batch prediction job', async () => { - const stdout = execSync( - `node ./create-batch-prediction-job-video-object-tracking.js \ - ${batchPredictionDisplayName} \ - ${modelId} ${gcsSourceUri} \ - ${gcsDestinationOutputUriPrefix} \ - ${project} ${location}`, - { - cwd, - } - ); - assert.match( - stdout, - /Create batch prediction job video object tracking response/ - ); - batchPredictionJobId = stdout - .split('/locations/us-central1/batchPredictionJobs/')[1] - .split('\n')[0]; - }); - after('should cancel delete the batch prediction job', async () => { - const name = jobServiceClient.batchPredictionJobPath( - project, - location, - batchPredictionJobId - ); - - const cancelRequest = { - name, - }; - - jobServiceClient.cancelBatchPredictionJob(cancelRequest).then(() => { - const deleteRequest = { - name, - }; - - return jobServiceClient.deleteBatchPredictionJob(deleteRequest); - }); - }); -}); From cf2604712e3231718035eee0dd25fb9f00dfdd3e Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Wed, 15 Jul 2026 10:58:01 -0600 Subject: [PATCH 05/34] fix(dlp): resolve CommonJS compatibility issues and stabilize test (#4350) * fix(dlp): downgrade mime to v3 to restore CommonJS compatibility * fix(dlp): downgrade mime and pixelmatch to restore CommonJS compatibility * test(dlp): use realistic mock SSN to fix DLP API likelihood filtering --- dlp/inspectWithCustomHotwords.js | 2 +- dlp/package.json | 4 ++-- dlp/system-test/inspect.test.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dlp/inspectWithCustomHotwords.js b/dlp/inspectWithCustomHotwords.js index ea4c0fe6b4..4204278237 100644 --- a/dlp/inspectWithCustomHotwords.js +++ b/dlp/inspectWithCustomHotwords.js @@ -37,7 +37,7 @@ function main(projectId) { ], rows: [ { - values: [{stringValue: '111-11-1111'}, {stringValue: '222-22-2222'}], + values: [{stringValue: '111-11-1111'}, {stringValue: '458-90-3124'}], }, ], }; diff --git a/dlp/package.json b/dlp/package.json index d2e45292e7..6ae2b1aaf5 100644 --- a/dlp/package.json +++ b/dlp/package.json @@ -22,9 +22,9 @@ "devDependencies": { "c8": "^10.0.0", "chai": "^4.5.0", - "mime": "^4.0.0", + "mime": "^3.0.0", "mocha": "^10.0.0", - "pixelmatch": "^6.0.0", + "pixelmatch": "^5.3.0", "pngjs": "^7.0.0", "proxyquire": "^2.1.3", "sinon": "^18.0.0", diff --git a/dlp/system-test/inspect.test.js b/dlp/system-test/inspect.test.js index 3d51f65817..742dfb5e40 100644 --- a/dlp/system-test/inspect.test.js +++ b/dlp/system-test/inspect.test.js @@ -1144,7 +1144,7 @@ describe('inspect', () => { it('should inspect a table excluding findings in a particular row', () => { const output = execSync(`node inspectWithCustomHotwords.js ${projectId}`); assert.match(output, /Findings: 1/); - assert.match(output, /Quote: 222-22-2222/); + assert.match(output, /Quote: 458-90-3124/); assert.notMatch(output, /Quote: 111-11-1111/); }); From a3dd13bbbbf7ef11982c59facad8a46d63907154 Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Wed, 15 Jul 2026 11:00:49 -0600 Subject: [PATCH 06/34] fix(dataproc): add error handling for quota exhaustion (#4351) * fix(dataproc): add robust error handling for quota exhaustion * Added error handling to test cleanup. * Added error handling to quickstart.test.js --- dataproc/system-test/createCluster.test.js | 39 ++++++++++++++----- .../instantiateInlineWorkflowTemplate.test.js | 27 ++++++++++--- dataproc/system-test/quickstart.test.js | 31 +++++++++++---- dataproc/system-test/submitJob.test.js | 35 +++++++++++++---- 4 files changed, 100 insertions(+), 32 deletions(-) diff --git a/dataproc/system-test/createCluster.test.js b/dataproc/system-test/createCluster.test.js index 6d6aad852a..ae311e46db 100644 --- a/dataproc/system-test/createCluster.test.js +++ b/dataproc/system-test/createCluster.test.js @@ -35,18 +35,37 @@ const execSync = cmd => }); describe('create a dataproc cluster', () => { - it('should create a dataproc cluster', async () => { - const stdout = execSync( - `node createCluster.js "${projectId}" "${region}" "${clusterName}"` - ); - assert.match(stdout, new RegExp(`${clusterName}`)); + it('should create a dataproc cluster', async function () { + try { + const stdout = execSync( + `node createCluster.js "${projectId}" "${region}" "${clusterName}"` + ); + assert.match(stdout, new RegExp(`${clusterName}`)); + } catch (err) { + if ( + err?.message?.includes('QUOTA') || + err?.message?.includes('RESOURCE_EXHAUSTED') || + err?.message?.includes('DISKS_TOTAL_GB') + ) { + console.warn( + `Quota limit reached in project ${projectId}. Skipping test.` + ); + this.skip(); + } else { + throw err; + } + } }); after(async () => { - await clusterClient.deleteCluster({ - projectId: projectId, - region: region, - clusterName: clusterName, - }); + try { + await clusterClient.deleteCluster({ + projectId: projectId, + region: region, + clusterName: clusterName, + }); + } catch (err) { + // Ignore errors during cleanup + } }); }); diff --git a/dataproc/system-test/instantiateInlineWorkflowTemplate.test.js b/dataproc/system-test/instantiateInlineWorkflowTemplate.test.js index f1669b2d50..f5541a78e4 100644 --- a/dataproc/system-test/instantiateInlineWorkflowTemplate.test.js +++ b/dataproc/system-test/instantiateInlineWorkflowTemplate.test.js @@ -30,11 +30,26 @@ const {delay} = require('./util'); describe('instantiate an inline workflow template', () => { it('should instantiate an inline workflow template', async function () { - this.retries(4); - await delay(this.test); - const stdout = execSync( - `node instantiateInlineWorkflowTemplate.js "${projectId}" "${region}"` - ); - assert.match(stdout, /successfully/); + try { + this.retries(4); + await delay(this.test); + const stdout = execSync( + `node instantiateInlineWorkflowTemplate.js "${projectId}" "${region}"` + ); + assert.match(stdout, /successfully/); + } catch (err) { + if ( + err?.message?.includes('QUOTA') || + err?.message?.includes('RESOURCE_EXHAUSTED') || + err?.message?.includes('DISKS_TOTAL_GB') + ) { + console.warn( + `Quota limit reached in project ${projectId}. Skipping test.` + ); + this.skip(); + } else { + throw err; + } + } }); }); diff --git a/dataproc/system-test/quickstart.test.js b/dataproc/system-test/quickstart.test.js index 56c1b29963..954cd07656 100644 --- a/dataproc/system-test/quickstart.test.js +++ b/dataproc/system-test/quickstart.test.js @@ -55,14 +55,29 @@ describe('execute the quickstart', () => { }); it('should execute the quickstart', async function () { - this.retries(4); - await delay(this.test); - const stdout = execSync( - `node quickstart.js "${projectId}" "${region}" "${clusterName}" "${jobFilePath}"` - ); - assert.match(stdout, /Cluster created successfully/); - assert.match(stdout, /Job finished successfully/); - assert.match(stdout, /successfully deleted/); + try { + this.retries(4); + await delay(this.test); + const stdout = execSync( + `node quickstart.js "${projectId}" "${region}" "${clusterName}" "${jobFilePath}"` + ); + assert.match(stdout, /Cluster created successfully/); + assert.match(stdout, /Job finished successfully/); + assert.match(stdout, /successfully deleted/); + } catch (err) { + if ( + err?.message?.includes('QUOTA') || + err?.message?.includes('RESOURCE_EXHAUSTED') || + err?.message?.includes('DISKS_TOTAL_GB') + ) { + console.warn( + `Quota limit reached in project ${projectId}. Skipping test.` + ); + this.skip(); + } else { + throw err; + } + } }); afterEach(async () => { diff --git a/dataproc/system-test/submitJob.test.js b/dataproc/system-test/submitJob.test.js index e62c29e1b5..39a27f506a 100644 --- a/dataproc/system-test/submitJob.test.js +++ b/dataproc/system-test/submitJob.test.js @@ -51,9 +51,24 @@ const execSync = cmd => }); describe('submit a Spark job to a Dataproc cluster', () => { - before(async () => { - const [operation] = await clusterClient.createCluster(cluster); - await operation.promise(); + before(async function () { + try { + const [operation] = await clusterClient.createCluster(cluster); + await operation.promise(); + } catch (err) { + if ( + err?.message?.includes('QUOTA') || + err?.message?.includes('RESOURCE_EXHAUSTED') || + err?.message?.includes('DISKS_TOTAL_GB') + ) { + console.warn( + `Quota limit reached in project ${projectId}. Skipping test.` + ); + this.skip(); + } else { + throw err; + } + } }); it('should submit a job to a dataproc cluster', async () => { @@ -64,10 +79,14 @@ describe('submit a Spark job to a Dataproc cluster', () => { }); after(async () => { - await clusterClient.deleteCluster({ - projectId: projectId, - region: region, - clusterName: clusterName, - }); + try { + await clusterClient.deleteCluster({ + projectId: projectId, + region: region, + clusterName: clusterName, + }); + } catch (err) { + // Ignore errors during cleanup + } }); }); From a5db09212b233d1358b3cfdfbaad4e9c1863b084 Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Wed, 15 Jul 2026 11:15:04 -0600 Subject: [PATCH 07/34] chore(vertexai): Decommission function_calling region tags (#4364) --- .../snippets/function-calling/functionCallingAdvanced.js | 2 -- .../snippets/function-calling/functionCallingStreamChat.js | 2 -- .../snippets/function-calling/functionCallingStreamContent.js | 2 -- 3 files changed, 6 deletions(-) diff --git a/generative-ai/snippets/function-calling/functionCallingAdvanced.js b/generative-ai/snippets/function-calling/functionCallingAdvanced.js index 72fcfa43fc..e1a7cb2935 100644 --- a/generative-ai/snippets/function-calling/functionCallingAdvanced.js +++ b/generative-ai/snippets/function-calling/functionCallingAdvanced.js @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// [START generativeaionvertexai_function_calling_advanced] const {GoogleGenAI} = require('@google/genai'); const tools = [ @@ -77,7 +76,6 @@ async function functionCallingAdvanced( }); console.log(JSON.stringify(result.functionCalls)); } -// [END generativeaionvertexai_function_calling_advanced] functionCallingAdvanced(...process.argv.slice(2)).catch(err => { console.error(err.message); diff --git a/generative-ai/snippets/function-calling/functionCallingStreamChat.js b/generative-ai/snippets/function-calling/functionCallingStreamChat.js index 5cbea5a558..8ff521d0ce 100644 --- a/generative-ai/snippets/function-calling/functionCallingStreamChat.js +++ b/generative-ai/snippets/function-calling/functionCallingStreamChat.js @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// [START generativeaionvertexai_gemini_function_calling_chat] const {GoogleGenAI} = require('@google/genai'); const tools = [ @@ -80,7 +79,6 @@ async function functionCallingStreamChat( // provided above console.log(result2.text); } -// [END generativeaionvertexai_gemini_function_calling_chat] functionCallingStreamChat(...process.argv.slice(2)).catch(err => { console.error(err.message); diff --git a/generative-ai/snippets/function-calling/functionCallingStreamContent.js b/generative-ai/snippets/function-calling/functionCallingStreamContent.js index 4af3d86a71..c25bb995d2 100644 --- a/generative-ai/snippets/function-calling/functionCallingStreamContent.js +++ b/generative-ai/snippets/function-calling/functionCallingStreamContent.js @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// [START aiplatform_gemini_function_calling_content] // [START generativeaionvertexai_gemini_function_calling_content] const {GoogleGenAI} = require('@google/genai'); @@ -89,7 +88,6 @@ async function functionCallingStreamContent( } console.log(completeResponseText); } -// [END aiplatform_gemini_function_calling_content] // [END generativeaionvertexai_gemini_function_calling_content] functionCallingStreamContent(...process.argv.slice(2)).catch(err => { From 7bf87a3614d3f8670eff0cc632999e295be0baf8 Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Wed, 15 Jul 2026 11:28:52 -0600 Subject: [PATCH 08/34] chore(vertexai): Decommission inference region tags (#4365) --- generative-ai/snippets/inference/nonStreamMultiModalityBasic.js | 2 -- generative-ai/snippets/inference/nonStreamTextBasic.js | 2 -- generative-ai/snippets/inference/streamMultiModalityBasic.js | 2 -- generative-ai/snippets/inference/streamTextBasic.js | 2 -- 4 files changed, 8 deletions(-) diff --git a/generative-ai/snippets/inference/nonStreamMultiModalityBasic.js b/generative-ai/snippets/inference/nonStreamMultiModalityBasic.js index 16e3621284..32888d06a1 100644 --- a/generative-ai/snippets/inference/nonStreamMultiModalityBasic.js +++ b/generative-ai/snippets/inference/nonStreamMultiModalityBasic.js @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// [START generativeaionvertexai_non_stream_multimodality_basic] const {GoogleGenAI} = require('@google/genai'); /** * TODO(developer): Update these variables before running the sample. @@ -56,7 +55,6 @@ async function generateContent( console.log(result.text); } -// [END generativeaionvertexai_non_stream_multimodality_basic] generateContent(...process.argv.slice(2)).catch(err => { console.error(err.message); diff --git a/generative-ai/snippets/inference/nonStreamTextBasic.js b/generative-ai/snippets/inference/nonStreamTextBasic.js index 80c9c689f3..ba2461e19d 100644 --- a/generative-ai/snippets/inference/nonStreamTextBasic.js +++ b/generative-ai/snippets/inference/nonStreamTextBasic.js @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// [START generativeaionvertexai_non_stream_text_basic] const {GoogleGenAI} = require('@google/genai'); /** * TODO(developer): Update these variables before running the sample. @@ -50,7 +49,6 @@ async function generateContent( console.log(response.text); } -// [END generativeaionvertexai_non_stream_text_basic] generateContent(...process.argv.slice(2)).catch(err => { console.error(err.message); diff --git a/generative-ai/snippets/inference/streamMultiModalityBasic.js b/generative-ai/snippets/inference/streamMultiModalityBasic.js index d541a48d96..9071b6a14a 100644 --- a/generative-ai/snippets/inference/streamMultiModalityBasic.js +++ b/generative-ai/snippets/inference/streamMultiModalityBasic.js @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// [START generativeaionvertexai_stream_multimodality_basic] const {GoogleGenAI} = require('@google/genai'); /** @@ -62,7 +61,6 @@ async function generateContent( console.log(chunk.text); } } -// [END generativeaionvertexai_stream_multimodality_basic] generateContent(...process.argv.slice(2)).catch(err => { console.error(err.message); diff --git a/generative-ai/snippets/inference/streamTextBasic.js b/generative-ai/snippets/inference/streamTextBasic.js index a4dc0ae898..ef4f960704 100644 --- a/generative-ai/snippets/inference/streamTextBasic.js +++ b/generative-ai/snippets/inference/streamTextBasic.js @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// [START generativeaionvertexai_stream_text_basic] const {GoogleGenAI} = require('@google/genai'); /** @@ -52,7 +51,6 @@ async function generateContent( console.log(chunk.text); } } -// [END generativeaionvertexai_stream_text_basic] generateContent(...process.argv.slice(2)).catch(err => { console.error(err.message); From 5e2db285f296abaea8277c211c562a606bc6b589 Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Wed, 15 Jul 2026 11:31:16 -0600 Subject: [PATCH 09/34] feat(genai): add migrated functionCallingBasic sample from generative-ai (#4366) * feat(genai): introduce new sample and region tag for function calling basic * test(genai): strengthen function calling test assertions * fix(genai): update environment variables in function calling test * fix(genai): correct sample path in function calling test * fix: update region tag for function calling --- .../test/tools-func-calling-basic.test.js | 44 ++++++++++++ genai/tools/tools-func-calling-basic.js | 69 +++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 genai/tools/test/tools-func-calling-basic.test.js create mode 100644 genai/tools/tools-func-calling-basic.js diff --git a/genai/tools/test/tools-func-calling-basic.test.js b/genai/tools/test/tools-func-calling-basic.test.js new file mode 100644 index 0000000000..b421623eb5 --- /dev/null +++ b/genai/tools/test/tools-func-calling-basic.test.js @@ -0,0 +1,44 @@ +// 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. + +'use strict'; + +const {assert} = require('chai'); +const {describe, it} = require('mocha'); +const cp = require('child_process'); +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const projectId = process.env.GOOGLE_CLOUD_PROJECT; +const location = process.env.GOOGLE_CLOUD_LOCATION || 'global'; +const model = 'gemini-2.5-flash'; + +describe('tools-func-calling-basic', () => { + /** + * TODO(developer): Uncomment these variables before running the sample.\ + * (Not necessary if passing values as arguments) + */ + // const projectId = 'YOUR_PROJECT_ID'; + // const location = 'YOUR_LOCATION'; + // const model = 'gemini-2.5-flash'; + + it('should define a function and have the model invoke it', async () => { + const output = execSync( + `node ./tools-func-calling-basic.js ${projectId} ${location} ${model}` + ); + + // Assert that the response is what we expect + assert(output.length > 0); + assert.include(output, 'get_current_weather'); + }); +}); diff --git a/genai/tools/tools-func-calling-basic.js b/genai/tools/tools-func-calling-basic.js new file mode 100644 index 0000000000..f1991f6d9b --- /dev/null +++ b/genai/tools/tools-func-calling-basic.js @@ -0,0 +1,69 @@ +// 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. + +// [START aiplatform_genai_function_calling_basic] +const {GoogleGenAI} = require('@google/genai'); + +const 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'], + }, + }, + ], + }, +]; + +/** + * TODO(developer): Update these variables before running the sample. + */ +async function functionCallingBasic( + projectId = 'PROJECT_ID', + location = 'us-central1', + model = 'gemini-2.5-flash' +) { + // Initialize client with your Cloud project and location + const client = new GoogleGenAI({ + vertexai: true, + project: projectId, + location: location, + }); + + const result = await client.models.generateContent({ + model: model, + contents: 'What is the weather in Boston?', + config: { + tools: tools, + }, + }); + console.log(JSON.stringify(result.functionCalls)); +} +// [END aiplatform_genai_function_calling_basic] + +functionCallingBasic(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; +}); From b8418de7183bf072d243f68ff0d8386d5ee6152c Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Wed, 15 Jul 2026 11:34:38 -0600 Subject: [PATCH 10/34] chore(ai-platform): remove video action training pipeline samples (#4375) --- ...ining-pipeline-video-action-recognition.js | 96 ------------------- ...-training-pipeline-video-classification.js | 94 ------------------ ...training-pipeline-video-object-tracking.js | 96 ------------------- ...-pipeline-video-action-recognition.test.js | 77 --------------- ...ning-pipeline-video-classification.test.js | 85 ---------------- ...ing-pipeline-video-object-tracking.test.js | 85 ---------------- 6 files changed, 533 deletions(-) delete mode 100644 ai-platform/snippets/create-training-pipeline-video-action-recognition.js delete mode 100644 ai-platform/snippets/create-training-pipeline-video-classification.js delete mode 100644 ai-platform/snippets/create-training-pipeline-video-object-tracking.js delete mode 100644 ai-platform/snippets/test/create-training-pipeline-video-action-recognition.test.js delete mode 100644 ai-platform/snippets/test/create-training-pipeline-video-classification.test.js delete mode 100644 ai-platform/snippets/test/create-training-pipeline-video-object-tracking.test.js diff --git a/ai-platform/snippets/create-training-pipeline-video-action-recognition.js b/ai-platform/snippets/create-training-pipeline-video-action-recognition.js deleted file mode 100644 index accb3de20b..0000000000 --- a/ai-platform/snippets/create-training-pipeline-video-action-recognition.js +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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 - * - * 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'; - -async function main( - datasetId, - modelDisplayName, - trainingPipelineDisplayName, - project, - location = 'us-central1' -) { - // [START aiplatform_create_training_pipeline_video_action_recognition_sample] - /** - * TODO(developer): Uncomment these variables before running the sample.\ - * (Not necessary if passing values as arguments) - */ - - // const datasetId = 'YOUR_DATASET_ID'; - // const modelDisplayName = 'YOUR_MODEL_DISPLAY_NAME'; - // const trainingPipelineDisplayName = 'YOUR_TRAINING_PIPELINE_DISPLAY_NAME'; - // const project = 'YOUR_PROJECT_ID'; - // const location = 'YOUR_PROJECT_LOCATION'; - const aiplatform = require('@google-cloud/aiplatform'); - const {definition} = - aiplatform.protos.google.cloud.aiplatform.v1.schema.trainingjob; - - // Imports the Google Cloud Pipeline Service Client library - const {PipelineServiceClient} = aiplatform.v1; - - // Specifies the location of the api endpoint - const clientOptions = { - apiEndpoint: 'us-central1-aiplatform.googleapis.com', - }; - - // Instantiates a client - const pipelineServiceClient = new PipelineServiceClient(clientOptions); - - async function createTrainingPipelineVideoActionRecognition() { - // Configure the parent resource - const parent = `projects/${project}/locations/${location}`; - // Values should match the input expected by your model. - const trainingTaskInputObj = - new definition.AutoMlVideoActionRecognitionInputs({ - // modelType can be either 'CLOUD' or 'MOBILE_VERSATILE_1' - modelType: 'CLOUD', - }); - const trainingTaskInputs = trainingTaskInputObj.toValue(); - - const modelToUpload = {displayName: modelDisplayName}; - const inputDataConfig = {datasetId: datasetId}; - const trainingPipeline = { - displayName: trainingPipelineDisplayName, - trainingTaskDefinition: - 'gs://google-cloud-aiplatform/schema/trainingjob/definition/automl_video_action_recognition_1.0.0.yaml', - trainingTaskInputs, - inputDataConfig, - modelToUpload, - }; - const request = { - parent, - trainingPipeline, - }; - - // Create training pipeline request - const [response] = - await pipelineServiceClient.createTrainingPipeline(request); - - console.log('Create training pipeline video action recognition response'); - console.log(`Name : ${response.name}`); - console.log('Raw response:'); - console.log(JSON.stringify(response, null, 2)); - } - createTrainingPipelineVideoActionRecognition(); - // [END aiplatform_create_training_pipeline_video_action_recognition_sample] -} - -process.on('unhandledRejection', err => { - console.error(err.message); - process.exitCode = 1; -}); - -main(...process.argv.slice(2)); diff --git a/ai-platform/snippets/create-training-pipeline-video-classification.js b/ai-platform/snippets/create-training-pipeline-video-classification.js deleted file mode 100644 index 3989c4c2a6..0000000000 --- a/ai-platform/snippets/create-training-pipeline-video-classification.js +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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 - * - * 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'; - -async function main( - datasetId, - modelDisplayName, - trainingPipelineDisplayName, - project, - location = 'us-central1' -) { - // [START aiplatform_create_training_pipeline_video_classification_sample] - /** - * TODO(developer): Uncomment these variables before running the sample.\ - * (Not necessary if passing values as arguments) - */ - - // const datasetId = 'YOUR_DATASET_ID'; - // const modelDisplayName = 'YOUR_MODEL_DISPLAY_NAME'; - // const trainingPipelineDisplayName = 'YOUR_TRAINING_PIPELINE_DISPLAY_NAME'; - // const project = 'YOUR_PROJECT_ID'; - // const location = 'YOUR_PROJECT_LOCATION'; - const aiplatform = require('@google-cloud/aiplatform'); - const {definition} = - aiplatform.protos.google.cloud.aiplatform.v1.schema.trainingjob; - - // Imports the Google Cloud Pipeline Service Client library - const {PipelineServiceClient} = aiplatform.v1; - - // Specifies the location of the api endpoint - const clientOptions = { - apiEndpoint: 'us-central1-aiplatform.googleapis.com', - }; - - // Instantiates a client - const pipelineServiceClient = new PipelineServiceClient(clientOptions); - - async function createTrainingPipelineVideoClassification() { - // Configure the parent resource - const parent = `projects/${project}/locations/${location}`; - // Values should match the input expected by your model. - const trainingTaskInputObj = new definition.AutoMlVideoClassificationInputs( - {} - ); - const trainingTaskInputs = trainingTaskInputObj.toValue(); - - const modelToUpload = {displayName: modelDisplayName}; - const inputDataConfig = {datasetId: datasetId}; - const trainingPipeline = { - displayName: trainingPipelineDisplayName, - trainingTaskDefinition: - 'gs://google-cloud-aiplatform/schema/trainingjob/definition/automl_video_classification_1.0.0.yaml', - trainingTaskInputs, - inputDataConfig, - modelToUpload, - }; - const request = { - parent, - trainingPipeline, - }; - - // Create training pipeline request - const [response] = - await pipelineServiceClient.createTrainingPipeline(request); - - console.log('Create training pipeline video classification response'); - console.log(`Name : ${response.name}`); - console.log('Raw response:'); - console.log(JSON.stringify(response, null, 2)); - } - createTrainingPipelineVideoClassification(); - // [END aiplatform_create_training_pipeline_video_classification_sample] -} - -process.on('unhandledRejection', err => { - console.error(err.message); - process.exitCode = 1; -}); - -main(...process.argv.slice(2)); diff --git a/ai-platform/snippets/create-training-pipeline-video-object-tracking.js b/ai-platform/snippets/create-training-pipeline-video-object-tracking.js deleted file mode 100644 index 42fc795e38..0000000000 --- a/ai-platform/snippets/create-training-pipeline-video-object-tracking.js +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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 - * - * 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'; - -async function main( - datasetId, - modelDisplayName, - trainingPipelineDisplayName, - project, - location = 'us-central1' -) { - // [START aiplatform_create_training_pipeline_video_object_tracking_sample] - /** - * TODO(developer): Uncomment these variables before running the sample.\ - * (Not necessary if passing values as arguments) - */ - - // const datasetId = 'YOUR_DATASET_ID'; - // const modelDisplayName = 'YOUR_MODEL_DISPLAY_NAME'; - // const trainingPipelineDisplayName = 'YOUR_TRAINING_PIPELINE_DISPLAY_NAME'; - // const project = 'YOUR_PROJECT_ID'; - // const location = 'YOUR_PROJECT_LOCATION'; - const aiplatform = require('@google-cloud/aiplatform'); - const {definition} = - aiplatform.protos.google.cloud.aiplatform.v1.schema.trainingjob; - const ModelType = definition.AutoMlVideoObjectTrackingInputs.ModelType; - - // Imports the Google Cloud Pipeline Service Client library - const {PipelineServiceClient} = aiplatform.v1; - - // Specifies the location of the api endpoint - const clientOptions = { - apiEndpoint: 'us-central1-aiplatform.googleapis.com', - }; - - // Instantiates a client - const pipelineServiceClient = new PipelineServiceClient(clientOptions); - - async function createTrainingPipelineVideoObjectTracking() { - // Configure the parent resource - const parent = `projects/${project}/locations/${location}`; - - const trainingTaskInputsObj = - new definition.AutoMlVideoObjectTrackingInputs({ - modelType: ModelType.CLOUD, - }); - const trainingTaskInputs = trainingTaskInputsObj.toValue(); - - const modelToUpload = {displayName: modelDisplayName}; - const inputDataConfig = {datasetId: datasetId}; - const trainingPipeline = { - displayName: trainingPipelineDisplayName, - trainingTaskDefinition: - 'gs://google-cloud-aiplatform/schema/trainingjob/definition/automl_video_object_tracking_1.0.0.yaml', - trainingTaskInputs, - inputDataConfig, - modelToUpload, - }; - const request = { - parent, - trainingPipeline, - }; - - // Create training pipeline request - const [response] = - await pipelineServiceClient.createTrainingPipeline(request); - - console.log('Create training pipeline video object tracking response'); - console.log(`Name : ${response.name}`); - console.log('Raw response:'); - console.log(JSON.stringify(response, null, 2)); - } - createTrainingPipelineVideoObjectTracking(); - // [END aiplatform_create_training_pipeline_video_object_tracking_sample] -} - -process.on('unhandledRejection', err => { - console.error(err.message); - process.exitCode = 1; -}); - -main(...process.argv.slice(2)); diff --git a/ai-platform/snippets/test/create-training-pipeline-video-action-recognition.test.js b/ai-platform/snippets/test/create-training-pipeline-video-action-recognition.test.js deleted file mode 100644 index 33d5f472ac..0000000000 --- a/ai-platform/snippets/test/create-training-pipeline-video-action-recognition.test.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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 - * - * 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'; - -const {assert} = require('chai'); -const {after, describe, it} = require('mocha'); - -const uuid = require('uuid').v4; -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const aiplatform = require('@google-cloud/aiplatform'); -const clientOptions = { - apiEndpoint: 'us-central1-aiplatform.googleapis.com', -}; - -const pipelineServiceClient = new aiplatform.v1.PipelineServiceClient( - clientOptions -); - -const datasetId = '6881957627459272704'; -const modelDisplayName = `temp_create_training_pipeline_node_var_model_test_${uuid()}`; -const trainingPipelineDisplayName = `temp_create_training_pipeline_node_var_test_${uuid()}`; -const location = 'us-central1'; -const project = process.env.CAIP_PROJECT_ID; - -let trainingPipelineId; - -describe('AI platform create training pipeline video action recognition', async function () { - this.retries(2); - it('should create a new video action-recognition training pipeline', async () => { - const stdout = execSync( - `node ./create-training-pipeline-video-action-recognition.js ${datasetId} ${modelDisplayName} ${trainingPipelineDisplayName} ${project} ${location}` - ); - assert.match( - stdout, - /Create training pipeline video action recognition response/ - ); - trainingPipelineId = stdout - .split('/locations/us-central1/trainingPipelines/')[1] - .split('\n')[0]; - }); - - after('should cancel the training pipeline and delete it', async () => { - const name = pipelineServiceClient.trainingPipelinePath( - project, - location, - trainingPipelineId - ); - - const cancelRequest = { - name, - }; - - pipelineServiceClient.cancelTrainingPipeline(cancelRequest).then(() => { - const deleteRequest = { - name, - }; - - return pipelineServiceClient.deleteTrainingPipeline(deleteRequest); - }); - }); -}); diff --git a/ai-platform/snippets/test/create-training-pipeline-video-classification.test.js b/ai-platform/snippets/test/create-training-pipeline-video-classification.test.js deleted file mode 100644 index 5a818b6f17..0000000000 --- a/ai-platform/snippets/test/create-training-pipeline-video-classification.test.js +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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 - * - * 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'; - -const path = require('path'); -const {assert} = require('chai'); -const {after, describe, it} = require('mocha'); - -const uuid = require('uuid').v4; -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); -const cwd = path.join(__dirname, '..'); - -const aiplatform = require('@google-cloud/aiplatform'); -const clientOptions = { - apiEndpoint: 'us-central1-aiplatform.googleapis.com', -}; - -const pipelineServiceClient = new aiplatform.v1.PipelineServiceClient( - clientOptions -); - -const datasetId = '3757409464110546944'; -const modelDisplayName = `temp_create_training_pipeline_video_classification_model_test${uuid()}`; -const trainingPipelineDisplayName = `temp_create_training_pipeline_video_classification_test_${uuid()}`; -const location = 'us-central1'; -const project = process.env.CAIP_PROJECT_ID; - -let trainingPipelineId; - -describe('AI platform create training pipeline video classification', async function () { - this.retries(2); - it('should create a new video classification training pipeline', async () => { - const stdout = execSync( - `node ./create-training-pipeline-video-classification.js ${datasetId} \ - ${modelDisplayName} \ - ${trainingPipelineDisplayName} \ - ${project} ${location}`, - { - cwd, - } - ); - assert.match( - stdout, - /Create training pipeline video classification response/ - ); - trainingPipelineId = stdout - .split('/locations/us-central1/trainingPipelines/')[1] - .split('\n')[0]; - }); - - after('should cancel the training pipeline and delete it', async () => { - const name = pipelineServiceClient.trainingPipelinePath( - project, - location, - trainingPipelineId - ); - - const cancelRequest = { - name, - }; - - pipelineServiceClient.cancelTrainingPipeline(cancelRequest).then(() => { - const deleteRequest = { - name, - }; - - return pipelineServiceClient.deleteTrainingPipeline(deleteRequest); - }); - }); -}); diff --git a/ai-platform/snippets/test/create-training-pipeline-video-object-tracking.test.js b/ai-platform/snippets/test/create-training-pipeline-video-object-tracking.test.js deleted file mode 100644 index b6a893360f..0000000000 --- a/ai-platform/snippets/test/create-training-pipeline-video-object-tracking.test.js +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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 - * - * 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'; - -const path = require('path'); -const {assert} = require('chai'); -const {after, describe, it} = require('mocha'); - -const uuid = require('uuid').v4; -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); -const cwd = path.join(__dirname, '..'); - -const aiplatform = require('@google-cloud/aiplatform'); -const clientOptions = { - apiEndpoint: 'us-central1-aiplatform.googleapis.com', -}; - -const pipelineServiceClient = new aiplatform.v1.PipelineServiceClient( - clientOptions -); - -const datasetId = '1138566280794603520'; -const modelDisplayName = `temp_create_training_pipeline_video_object_tracking_model_test${uuid()}`; -const trainingPipelineDisplayName = `temp_create_training_pipeline_video_object_tracking_test_${uuid()}`; -const location = 'us-central1'; -const project = process.env.CAIP_PROJECT_ID; - -let trainingPipelineId; - -describe('AI platform create training pipeline object tracking', async function () { - this.retries(2); - it('should create a new object tracking training pipeline', async () => { - const stdout = execSync( - `node ./create-training-pipeline-video-object-tracking.js \ - ${datasetId} ${modelDisplayName} \ - ${trainingPipelineDisplayName} \ - ${project} ${location}`, - { - cwd, - } - ); - assert.match( - stdout, - /Create training pipeline video object tracking response/ - ); - trainingPipelineId = stdout - .split('/locations/us-central1/trainingPipelines/')[1] - .split('\n')[0]; - }); - - after('should cancel the training pipeline and delete it', async () => { - const name = pipelineServiceClient.trainingPipelinePath( - project, - location, - trainingPipelineId - ); - - const cancelRequest = { - name, - }; - - pipelineServiceClient.cancelTrainingPipeline(cancelRequest).then(() => { - const deleteRequest = { - name, - }; - - return pipelineServiceClient.deleteTrainingPipeline(deleteRequest); - }); - }); -}); From 30dc2e6bfb88e4f08cced34aab59da08308cafc1 Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Wed, 15 Jul 2026 11:37:02 -0600 Subject: [PATCH 11/34] chore(grounding): remove decommissioned grounding samples (#4376) * chore(grounding): remove decommissioned grounding samples * chore(grounding): remove associated tests for decommissioned samples --- .../grounding/groundingPrivateDataBasic.js | 70 ------------------- .../grounding/groundingPublicDataBasic.js | 56 --------------- .../groundingPrivateDataBasic.test.js | 42 ----------- .../groundingPublicDataBasic.test.js | 41 ----------- 4 files changed, 209 deletions(-) delete mode 100644 generative-ai/snippets/grounding/groundingPrivateDataBasic.js delete mode 100644 generative-ai/snippets/grounding/groundingPublicDataBasic.js delete mode 100644 generative-ai/snippets/test/grounding/groundingPrivateDataBasic.test.js delete mode 100644 generative-ai/snippets/test/grounding/groundingPublicDataBasic.test.js diff --git a/generative-ai/snippets/grounding/groundingPrivateDataBasic.js b/generative-ai/snippets/grounding/groundingPrivateDataBasic.js deleted file mode 100644 index ef0b17c396..0000000000 --- a/generative-ai/snippets/grounding/groundingPrivateDataBasic.js +++ /dev/null @@ -1,70 +0,0 @@ -// 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 {GoogleGenAI} = require('@google/genai'); - -/** - * TODO(developer): Update these variables before running the sample. - */ -async function generateContentWithVertexAISearchGrounding( - projectId = 'PROJECT_ID', - location = 'us-central1', - model = 'gemini-2.5-flash', - dataStoreId = 'DATASTORE_ID' -) { - // Initialize client with your Cloud project and location - const client = new GoogleGenAI({ - vertexai: true, - project: projectId, - location: location, - }); - - const tools = [ - { - retrieval: { - vertexAiSearch: { - datastore: `projects/${projectId}/locations/global/collections/default_collection/dataStores/${dataStoreId}`, - }, - }, - }, - ]; - - const result = await client.models.generateContent({ - model: model, - contents: [{role: 'user', parts: [{text: 'Why is the sky blue?'}]}], - config: { - tools: tools, - maxOutputTokens: 256, - safetySettings: [ - { - category: 'HARM_CATEGORY_DANGEROUS_CONTENT', - threshold: 'BLOCK_MEDIUM_AND_ABOVE', - }, - ], - }, - }); - - console.log('Response: ', result.text); - console.log( - 'GroundingMetadata: ', - JSON.stringify(result.candidates[0].groundingMetadata) - ); -} - -generateContentWithVertexAISearchGrounding(...process.argv.slice(2)).catch( - err => { - console.error(err.message); - process.exitCode = 1; - } -); diff --git a/generative-ai/snippets/grounding/groundingPublicDataBasic.js b/generative-ai/snippets/grounding/groundingPublicDataBasic.js deleted file mode 100644 index 167b50ca1a..0000000000 --- a/generative-ai/snippets/grounding/groundingPublicDataBasic.js +++ /dev/null @@ -1,56 +0,0 @@ -// 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 {GoogleGenAI} = require('@google/genai'); - -/** - * TODO(developer): Update these variables before running the sample. - */ -async function generateContentWithGoogleSearchGrounding( - projectId = 'PROJECT_ID', - location = 'us-central1', - model = 'gemini-2.5-flash' -) { - // Initialize client with your Cloud project and location - const client = new GoogleGenAI({ - vertexai: true, - project: projectId, - location: location, - }); - - const googleSearchTool = { - googleSearch: {}, - }; - - const result = await client.models.generateContent({ - model: model, - contents: [{role: 'user', parts: [{text: 'Why is the sky blue?'}]}], - config: { - tools: [googleSearchTool], - maxOutputTokens: 256, - }, - }); - console.log('Response: ', result.text); - console.log( - 'GroundingMetadata is: ', - JSON.stringify(result.candidates[0].groundingMetadata) - ); -} - -generateContentWithGoogleSearchGrounding(...process.argv.slice(2)).catch( - err => { - console.error(err.message); - process.exitCode = 1; - } -); diff --git a/generative-ai/snippets/test/grounding/groundingPrivateDataBasic.test.js b/generative-ai/snippets/test/grounding/groundingPrivateDataBasic.test.js deleted file mode 100644 index 8a84af3a98..0000000000 --- a/generative-ai/snippets/test/grounding/groundingPrivateDataBasic.test.js +++ /dev/null @@ -1,42 +0,0 @@ -// 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. - -'use strict'; - -const {assert} = require('chai'); -const {describe, it} = require('mocha'); -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const projectId = process.env.GOOGLE_SAMPLES_PROJECT; -const location = process.env.LOCATION; -const datastore_id = process.env.DATASTORE_ID; -const model = 'gemini-2.5-flash'; - -describe('Private data grounding', async () => { - /** - * TODO(developer): Uncomment these variables before running the sample.\ - * (Not necessary if passing values as arguments) - */ - // const projectId = 'YOUR_PROJECT_ID'; - // const location = 'YOUR_LOCATION'; - // const model = 'gemini-2.5-flash'; - - it('should ground results in private VertexAI search data', async () => { - const output = execSync( - `node ./grounding/groundingPrivateDataBasic.js ${projectId} ${location} ${model} ${datastore_id}` - ); - assert(output.match(/GroundingMetadata/)); - }); -}); diff --git a/generative-ai/snippets/test/grounding/groundingPublicDataBasic.test.js b/generative-ai/snippets/test/grounding/groundingPublicDataBasic.test.js deleted file mode 100644 index 91f6422dec..0000000000 --- a/generative-ai/snippets/test/grounding/groundingPublicDataBasic.test.js +++ /dev/null @@ -1,41 +0,0 @@ -// 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. - -'use strict'; - -const {assert} = require('chai'); -const {describe, it} = require('mocha'); -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const projectId = process.env.CAIP_PROJECT_ID; -const location = process.env.LOCATION; -const model = 'gemini-2.5-flash'; - -describe('Google search grounding', async () => { - /** - * TODO(developer): Uncomment these variables before running the sample.\ - * (Not necessary if passing values as arguments) - */ - // const projectId = 'YOUR_PROJECT_ID'; - // const location = 'YOUR_LOCATION'; - // const model = 'gemini-2.5-flash'; - - it('should ground results in public search data', async () => { - const output = execSync( - `node ./grounding/groundingPublicDataBasic.js ${projectId} ${location} ${model}` - ); - assert(output.match(/blue/)); - }); -}); From f684603035d9eb4192bdac3de0bd9f62af7cafac Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Wed, 15 Jul 2026 11:40:21 -0600 Subject: [PATCH 12/34] chore(ai-platform): remove decommissioned text and video dataset samples and tests (#4377) --- ai-platform/snippets/create-dataset-text.js | 79 ------------------ ai-platform/snippets/create-dataset-video.js | 79 ------------------ .../import-data-video-classification.js | 82 ------------------- .../snippets/test/create-dataset-text.test.js | 53 ------------ .../test/create-dataset-video.test.js | 54 ------------ .../import-data-video-classification.test.js | 46 ----------- 6 files changed, 393 deletions(-) delete mode 100644 ai-platform/snippets/create-dataset-text.js delete mode 100644 ai-platform/snippets/create-dataset-video.js delete mode 100644 ai-platform/snippets/import-data-video-classification.js delete mode 100644 ai-platform/snippets/test/create-dataset-text.test.js delete mode 100644 ai-platform/snippets/test/create-dataset-video.test.js delete mode 100644 ai-platform/snippets/test/import-data-video-classification.test.js diff --git a/ai-platform/snippets/create-dataset-text.js b/ai-platform/snippets/create-dataset-text.js deleted file mode 100644 index 93b99be7e5..0000000000 --- a/ai-platform/snippets/create-dataset-text.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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 - * - * 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'; - -async function main(datasetDisplayName, project, location = 'us-central1') { - // [START aiplatform_create_dataset_text_sample] - /** - * TODO(developer): Uncomment these variables before running the sample.\ - * (Not necessary if passing values as arguments) - */ - - // const datasetDisplayName = "YOUR_DATASTE_DISPLAY_NAME"; - // const project = 'YOUR_PROJECT_ID'; - // const location = 'YOUR_PROJECT_LOCATION'; - - // Imports the Google Cloud Dataset Service Client library - const {DatasetServiceClient} = require('@google-cloud/aiplatform'); - - // Specifies the location of the api endpoint - const clientOptions = { - apiEndpoint: 'us-central1-aiplatform.googleapis.com', - }; - - // Instantiates a client - const datasetServiceClient = new DatasetServiceClient(clientOptions); - - async function createDatasetText() { - // Configure the parent resource - const parent = `projects/${project}/locations/${location}`; - // Configure the dataset resource - const dataset = { - displayName: datasetDisplayName, - metadataSchemaUri: - 'gs://google-cloud-aiplatform/schema/dataset/metadata/text_1.0.0.yaml', - }; - const request = { - parent, - dataset, - }; - - // Create Dataset Request - const [response] = await datasetServiceClient.createDataset(request); - console.log(`Long running operation: ${response.name}`); - - // Wait for operation to complete - await response.promise(); - const result = response.result; - - console.log('Create dataset text response'); - console.log(`Name : ${result.name}`); - console.log(`Display name : ${result.displayName}`); - console.log(`Metadata schema uri : ${result.metadataSchemaUri}`); - console.log(`Metadata : ${JSON.stringify(result.metadata)}`); - console.log(`Labels : ${JSON.stringify(result.labels)}`); - } - createDatasetText(); - // [END aiplatform_create_dataset_text_sample] -} - -process.on('unhandledRejection', err => { - console.error(err.message); - process.exitCode = 1; -}); - -main(...process.argv.slice(2)); diff --git a/ai-platform/snippets/create-dataset-video.js b/ai-platform/snippets/create-dataset-video.js deleted file mode 100644 index 04c6c2e74a..0000000000 --- a/ai-platform/snippets/create-dataset-video.js +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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 - * - * 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'; - -async function main(datasetDisplayName, project, location = 'us-central1') { - // [START aiplatform_create_dataset_video_sample] - /** - * TODO(developer): Uncomment these variables before running the sample.\ - * (Not necessary if passing values as arguments) - */ - - // const datasetDisplayName = "YOUR_DATASTE_DISPLAY_NAME"; - // const project = 'YOUR_PROJECT_ID'; - // const location = 'YOUR_PROJECT_LOCATION'; - - // Imports the Google Cloud Dataset Service Client library - const {DatasetServiceClient} = require('@google-cloud/aiplatform'); - - // Specifies the location of the api endpoint - const clientOptions = { - apiEndpoint: 'us-central1-aiplatform.googleapis.com', - }; - - // Instantiates a client - const datasetServiceClient = new DatasetServiceClient(clientOptions); - - async function createDatasetVideo() { - // Configure the parent resource - const parent = `projects/${project}/locations/${location}`; - // Configure the dataset resource - const dataset = { - displayName: datasetDisplayName, - metadataSchemaUri: - 'gs://google-cloud-aiplatform/schema/dataset/metadata/video_1.0.0.yaml', - }; - const request = { - parent, - dataset, - }; - - // Create Dataset Request - const [response] = await datasetServiceClient.createDataset(request); - console.log(`Long running operation: ${response.name}`); - - // Wait for operation to complete - await response.promise(); - const result = response.result; - - console.log('Create dataset video response'); - console.log(`Name : ${result.name}`); - console.log(`Display name : ${result.displayName}`); - console.log(`Metadata schema uri : ${result.metadataSchemaUri}`); - console.log(`Metadata : ${JSON.stringify(result.metadata)}`); - console.log(`Labels : ${JSON.stringify(result.labels)}`); - } - createDatasetVideo(); - // [END aiplatform_create_dataset_video_sample] -} - -process.on('unhandledRejection', err => { - console.error(err.message); - process.exitCode = 1; -}); - -main(...process.argv.slice(2)); diff --git a/ai-platform/snippets/import-data-video-classification.js b/ai-platform/snippets/import-data-video-classification.js deleted file mode 100644 index 7439bb8cce..0000000000 --- a/ai-platform/snippets/import-data-video-classification.js +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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 - * - * 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'; - -async function main( - datasetId, - gcsSourceUri, - project, - location = 'us-central1' -) { - // [START aiplatform_import_data_video_classification_sample] - /** - * TODO(developer): Uncomment these variables before running the sample.\ - * (Not necessary if passing values as arguments) - */ - - // const datasetId = 'YOUR_DATASET_ID'; - // const gcsSourceUri = 'YOUR_GCS_SOURCE_URI'; - // eg. 'gs:////[file.csv/file.jsonl]' - // const project = 'YOUR_PROJECT_ID'; - // const location = 'YOUR_PROJECT_LOCATION'; - - // Imports the Google Cloud Dataset Service Client library - const {DatasetServiceClient} = require('@google-cloud/aiplatform'); - - // Specifies the location of the api endpoint - const clientOptions = { - apiEndpoint: 'us-central1-aiplatform.googleapis.com', - }; - const datasetServiceClient = new DatasetServiceClient(clientOptions); - - async function importDataVideoClassification() { - const name = datasetServiceClient.datasetPath(project, location, datasetId); - // Here we use only one import config with one source - const importConfigs = [ - { - gcsSource: {uris: [gcsSourceUri]}, - importSchemaUri: - 'gs://google-cloud-aiplatform/schema/dataset/ioformat/video_classification_io_format_1.0.0.yaml', - }, - ]; - const request = { - name, - importConfigs, - }; - - // Create Import Data Request - const [response] = await datasetServiceClient.importData(request); - console.log(`Long running operation : ${response.name}`); - - // Wait for operation to complete - await response.promise(); - - console.log( - `Import data video classification response : \ - ${JSON.stringify(response.result)}` - ); - } - importDataVideoClassification(); - // [END aiplatform_import_data_video_classification_sample] -} - -process.on('unhandledRejection', err => { - console.error(err.message); - process.exitCode = 1; -}); - -main(...process.argv.slice(2)); diff --git a/ai-platform/snippets/test/create-dataset-text.test.js b/ai-platform/snippets/test/create-dataset-text.test.js deleted file mode 100644 index daf53f52d2..0000000000 --- a/ai-platform/snippets/test/create-dataset-text.test.js +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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 - * - * 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'; - -const path = require('path'); -const {assert} = require('chai'); -const {after, describe, it} = require('mocha'); - -const uuid = require('uuid').v4; -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); -const cwd = path.join(__dirname, '..'); - -const displayName = `temp_create_dataset_text_test_${uuid()}`; -const project = process.env.CAIP_PROJECT_ID; -const location = 'us-central1'; - -let datasetId; - -describe('AI platform create dataset text', () => { - it('should create a new dataset in the parent resource', async () => { - const stdout = execSync( - `node ./create-dataset-text.js ${displayName} ${project} ${location}`, - { - cwd, - } - ); - assert.match(stdout, /Create dataset text response/); - datasetId = stdout - .split('/locations/us-central1/datasets/')[1] - .split('\n')[0] - .split('/')[0]; - }); - after('should delete the created dataset', async () => { - execSync(`node ./delete-dataset.js ${datasetId} ${project} ${location}`, { - cwd, - }); - }); -}); diff --git a/ai-platform/snippets/test/create-dataset-video.test.js b/ai-platform/snippets/test/create-dataset-video.test.js deleted file mode 100644 index 81222ea68e..0000000000 --- a/ai-platform/snippets/test/create-dataset-video.test.js +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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 - * - * 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'; - -const path = require('path'); -const {assert} = require('chai'); -const {after, describe, it} = require('mocha'); - -const uuid = require('uuid').v4; -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); -const cwd = path.join(__dirname, '..'); - -const datasetDisplayName = `temp_create_dataset_video_test_${uuid()}`; -const project = process.env.CAIP_PROJECT_ID; -const location = 'us-central1'; - -let datasetId; - -describe('AI platform create dataset video', () => { - it('should create a new video dataset in the parent resource', async () => { - const stdout = execSync( - `node ./create-dataset-video.js ${datasetDisplayName} ${project} \ - ${location}`, - { - cwd, - } - ); - assert.match(stdout, /Create dataset video response/); - datasetId = stdout - .split('/locations/us-central1/datasets/')[1] - .split('\n')[0] - .split('/')[0]; - }); - after('should delete the created dataset', async () => { - execSync(`node ./delete-dataset.js ${datasetId} ${project} ${location}`, { - cwd, - }); - }); -}); diff --git a/ai-platform/snippets/test/import-data-video-classification.test.js b/ai-platform/snippets/test/import-data-video-classification.test.js deleted file mode 100644 index 5b7aa825d1..0000000000 --- a/ai-platform/snippets/test/import-data-video-classification.test.js +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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 - * - * 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'; - -const path = require('path'); -const {assert} = require('chai'); -const {describe, it} = require('mocha'); - -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); -const cwd = path.join(__dirname, '..'); - -const datasetId = '3757409464110546944'; -const gcsSourceUri = - 'gs://ucaip-sample-resources/hmdb_split1_5classes_train.jsonl'; -const project = process.env.CAIP_PROJECT_ID; -const location = 'us-central1'; - -describe('AI platform import data video classification', () => { - it('should import video classification data to dataset', async () => { - const stdout = execSync( - `node ./import-data-video-classification.js ${datasetId} \ - ${gcsSourceUri} \ - ${project} \ - ${location}`, - { - cwd, - } - ); - assert.match(stdout, /Import data video classification response/); - }); -}); From 8af28f7977c0e8b37845734d834283777b76185f Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Thu, 16 Jul 2026 11:18:49 -0600 Subject: [PATCH 13/34] fix: update batch prediction model to gemini-2.5-flash (#4373) --- ai-platform/snippets/batch-prediction/batch-predict-bq.js | 2 +- ai-platform/snippets/batch-prediction/batch-predict-gcs.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ai-platform/snippets/batch-prediction/batch-predict-bq.js b/ai-platform/snippets/batch-prediction/batch-predict-bq.js index 63ab8d3300..5892a34398 100644 --- a/ai-platform/snippets/batch-prediction/batch-predict-bq.js +++ b/ai-platform/snippets/batch-prediction/batch-predict-bq.js @@ -36,7 +36,7 @@ async function main(projectId, outputUri) { 'bq://storage-samples.generative_ai.batch_requests_for_multimodal_input'; const location = 'us-central1'; const parent = `projects/${projectId}/locations/${location}`; - const modelName = `${parent}/publishers/google/models/gemini-2.0-flash-001`; + const modelName = `${parent}/publishers/google/models/gemini-2.5-flash`; // Specify the location of the api endpoint. const clientOptions = { diff --git a/ai-platform/snippets/batch-prediction/batch-predict-gcs.js b/ai-platform/snippets/batch-prediction/batch-predict-gcs.js index b923350327..b9403f99fd 100644 --- a/ai-platform/snippets/batch-prediction/batch-predict-gcs.js +++ b/ai-platform/snippets/batch-prediction/batch-predict-gcs.js @@ -39,7 +39,7 @@ async function main(projectId, outputUri) { 'gs://cloud-samples-data/generative-ai/batch/batch_requests_for_multimodal_input.jsonl'; const location = 'us-central1'; const parent = `projects/${projectId}/locations/${location}`; - const modelName = `${parent}/publishers/google/models/gemini-2.0-flash-001`; + const modelName = `${parent}/publishers/google/models/gemini-2.5-flash`; // Specify the location of the api endpoint. const clientOptions = { From d4c13c231e2afd6ee8fc822ee015c5458e223d43 Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Fri, 17 Jul 2026 11:46:46 -0600 Subject: [PATCH 14/34] chore: remove obsolete gemini-translate, nonStreamingContent, and streamContent samples (#4383) --- generative-ai/snippets/gemini-translate.js | 88 ------------------- generative-ai/snippets/nonStreamingContent.js | 60 ------------- generative-ai/snippets/streamContent.js | 57 ------------ .../snippets/test/gemini-translate.test.js | 34 ------- .../snippets/test/nonStreamingContent.test.js | 43 --------- .../snippets/test/streamContent.test.js | 44 ---------- 6 files changed, 326 deletions(-) delete mode 100644 generative-ai/snippets/gemini-translate.js delete mode 100644 generative-ai/snippets/nonStreamingContent.js delete mode 100644 generative-ai/snippets/streamContent.js delete mode 100644 generative-ai/snippets/test/gemini-translate.test.js delete mode 100644 generative-ai/snippets/test/nonStreamingContent.test.js delete mode 100644 generative-ai/snippets/test/streamContent.test.js diff --git a/generative-ai/snippets/gemini-translate.js b/generative-ai/snippets/gemini-translate.js deleted file mode 100644 index 6a87019565..0000000000 --- a/generative-ai/snippets/gemini-translate.js +++ /dev/null @@ -1,88 +0,0 @@ -// 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. - -'use strict'; -// [START generativeaionvertexai_gemini_translate] -const {GoogleGenAI} = require('@google/genai'); - -/** - * TODO(developer): Update these variables before running the sample. - */ -async function geminiTranslation( - projectId = 'PROJECT_ID', - location = 'us-central1', - model = 'gemini-2.5-flash' -) { - const client = new GoogleGenAI({ - vertexai: true, - project: projectId, - location, - }); - - // The text to be translated. - const text = 'Hello! How are you doing today?'; - // The language code of the target language. Defaults to "fr" (*French). - // Available language codes: - // https://cloud.google.com/translate/docs/languages#neural_machine_translation_model - const targetLanguageCode = 'fr'; - - const textPart = { - text: ` - User input:${text} - Answer:`, - }; - - const content = `Your mission is to translate text in English to ${targetLanguageCode}`; - - const response = await client.models.generateContent({ - model: model, - contents: [textPart], - config: { - maxOutputTokens: 2048, - temperature: 0.4, - topP: 1, - topK: 32, - systemInstruction: { - parts: [{text: content}], - }, - safetySettings: [ - { - category: 'HARM_CATEGORY_HATE_SPEECH', - threshold: 'BLOCK_MEDIUM_AND_ABOVE', - }, - { - category: 'HARM_CATEGORY_DANGEROUS_CONTENT', - threshold: 'BLOCK_MEDIUM_AND_ABOVE', - }, - { - category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT', - threshold: 'BLOCK_MEDIUM_AND_ABOVE', - }, - { - category: 'HARM_CATEGORY_HARASSMENT', - threshold: 'BLOCK_MEDIUM_AND_ABOVE', - }, - ], - }, - }); - - console.log(response.text); - return response; - // [END generativeaionvertexai_gemini_translate] -} - -geminiTranslation(...process.argv.slice(2)).catch(err => { - console.error(err.message); - process.exitCode = 1; -}); diff --git a/generative-ai/snippets/nonStreamingContent.js b/generative-ai/snippets/nonStreamingContent.js deleted file mode 100644 index 71c6a67872..0000000000 --- a/generative-ai/snippets/nonStreamingContent.js +++ /dev/null @@ -1,60 +0,0 @@ -// 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. - -// [START generativeaionvertexai_gemini_content_nonstreaming] -// [START aiplatform_gemini_content_nonstreaming] -const {VertexAI} = require('@google-cloud/vertexai'); - -/** - * TODO(developer): Update these variables before running the sample. - */ -async function createNonStreamingContent( - projectId = 'PROJECT_ID', - location = 'us-central1', - model = 'gemini-2.0-flash-001' -) { - // Initialize Vertex with your Cloud project and location - const vertexAI = new VertexAI({project: projectId, location: location}); - - // Instantiate the model - const generativeModel = vertexAI.getGenerativeModel({ - model: model, - }); - - const request = { - contents: [ - { - role: 'user', - parts: [ - { - text: 'Write a story about a magic backpack.', - }, - ], - }, - ], - }; - - console.log(JSON.stringify(request)); - - const result = await generativeModel.generateContent(request); - - console.log(result.response.text); -} -// [END aiplatform_gemini_content_nonstreaming] -// [END generativeaionvertexai_gemini_content_nonstreaming] - -createNonStreamingContent(...process.argv.slice(2)).catch(err => { - console.error(err.message); - process.exitCode = 1; -}); diff --git a/generative-ai/snippets/streamContent.js b/generative-ai/snippets/streamContent.js deleted file mode 100644 index 54e34a9c12..0000000000 --- a/generative-ai/snippets/streamContent.js +++ /dev/null @@ -1,57 +0,0 @@ -// 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. - -// [START generativeaionvertexai_gemini_content] -// [START aiplatform_gemini_content] -const {VertexAI} = require('@google-cloud/vertexai'); - -/** - * TODO(developer): Update these variables before running the sample. - */ -async function createStreamContent( - projectId = 'PROJECT_ID', - location = 'us-central1', - model = 'gemini-2.0-flash-001' -) { - // Initialize Vertex with your Cloud project and location - const vertexAI = new VertexAI({project: projectId, location: location}); - - // Instantiate the model - const generativeModel = vertexAI.getGenerativeModel({ - model: model, - }); - - const request = { - contents: [{role: 'user', parts: [{text: 'What is Node.js?'}]}], - }; - - console.log('Prompt:'); - console.log(request.contents[0].parts[0].text); - console.log('Streaming Response Text:'); - - // Create the response stream - const responseStream = await generativeModel.generateContentStream(request); - - // Log the text response as it streams - for await (const item of responseStream.stream) { - process.stdout.write(item.candidates[0].content.parts[0].text); - } -} -// [END aiplatform_gemini_content] -// [END generativeaionvertexai_gemini_content] - -createStreamContent(...process.argv.slice(2)).catch(err => { - console.error(err.message); - process.exitCode = 1; -}); diff --git a/generative-ai/snippets/test/gemini-translate.test.js b/generative-ai/snippets/test/gemini-translate.test.js deleted file mode 100644 index b319a1e7ef..0000000000 --- a/generative-ai/snippets/test/gemini-translate.test.js +++ /dev/null @@ -1,34 +0,0 @@ -// 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. - -'use strict'; - -const assert = require('node:assert/strict'); -const {describe, it} = require('mocha'); -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const projectId = process.env.CAIP_PROJECT_ID; -const location = process.env.LOCATION || 'us-central1'; -const model = 'gemini-2.5-flash'; - -describe('Gemini translate', () => { - it('should translate text', async () => { - const response = execSync( - `node ./gemini-translate.js ${projectId} ${location} ${model}` - ); - - assert(JSON.stringify(response).match(/Bonjour/)); - }); -}); diff --git a/generative-ai/snippets/test/nonStreamingContent.test.js b/generative-ai/snippets/test/nonStreamingContent.test.js deleted file mode 100644 index bb7c7f7517..0000000000 --- a/generative-ai/snippets/test/nonStreamingContent.test.js +++ /dev/null @@ -1,43 +0,0 @@ -// 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'; - -const {assert} = require('chai'); -const {describe, it} = require('mocha'); -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const projectId = process.env.CAIP_PROJECT_ID; -const location = process.env.LOCATION; -const model = 'gemini-2.0-flash-001'; - -describe.skip('Generative AI NonStreaming Content', () => { - /** - * TODO(developer): Uncomment these variables before running the sample.\ - * (Not necessary if passing values as arguments) - */ - // const projectId = 'YOUR_PROJECT_ID'; - // const location = 'YOUR_LOCATION'; - // const model = 'gemini-2.0-flash-001'; - - it('should create nonstreaming content', async () => { - const output = execSync( - `node ./nonStreamingContent.js ${projectId} ${location} ${model}` - ); - - // Assert that the correct prompt was issued - assert(output.match(/Write a story about a magic backpack/)); - }); -}); diff --git a/generative-ai/snippets/test/streamContent.test.js b/generative-ai/snippets/test/streamContent.test.js deleted file mode 100644 index 99fcbf60ae..0000000000 --- a/generative-ai/snippets/test/streamContent.test.js +++ /dev/null @@ -1,44 +0,0 @@ -// 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'; - -const {assert} = require('chai'); -const {describe, it} = require('mocha'); -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const projectId = process.env.CAIP_PROJECT_ID; -const location = process.env.LOCATION; -const model = 'gemini-2.0-flash-001'; - -describe.skip('Generative AI Stream Content', () => { - /** - * TODO(developer): Uncomment these variables before running the sample.\ - * (Not necessary if passing values as arguments) - */ - // const projectId = 'YOUR_PROJECT_ID'; - // const location = 'YOUR_LOCATION'; - // const model = 'gemini-2.0-flash-001'; - - it('should create stream content', async () => { - const output = execSync( - `node ./streamContent.js ${projectId} ${location} ${model}` - ); - // Ensure that the beginning of the conversation is consistent - assert(output.match(/Prompt:/)); - assert(output.match(/What is Node.js/)); - assert(output.match(/Streaming Response Text:/)); - }); -}); From ff51616432b3615aadbe4246b28a5d24d8e7ba6b Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Fri, 17 Jul 2026 12:05:40 -0600 Subject: [PATCH 15/34] feat(genai): add migrated functionCallingStreamContent sample from generative-ai (#4367) * feat(genai): rename and migrate functionCallingStreamContent sample * fix(genai): update function response * fix: update region tag --- .../tools-func-calling-stream-content.test.js | 43 +++++++++ .../tools-func-calling-stream-content.js | 96 +++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 genai/tools/test/tools-func-calling-stream-content.test.js create mode 100644 genai/tools/tools-func-calling-stream-content.js diff --git a/genai/tools/test/tools-func-calling-stream-content.test.js b/genai/tools/test/tools-func-calling-stream-content.test.js new file mode 100644 index 0000000000..ab323c00a8 --- /dev/null +++ b/genai/tools/test/tools-func-calling-stream-content.test.js @@ -0,0 +1,43 @@ +// 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'; + +const {assert} = require('chai'); +const {describe, it} = require('mocha'); +const cp = require('child_process'); +const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); + +const projectId = process.env.GOOGLE_CLOUD_PROJECT; +const location = process.env.GOOGLE_CLOUD_LOCATION || 'global'; +const model = 'gemini-2.5-flash'; + +describe('tools-func-calling-stream-content', () => { + /** + * TODO(developer): Uncomment these variables before running the sample.\ + * (Not necessary if passing values as arguments) + */ + // const projectId = 'YOUR_PROJECT_ID'; + // const location = 'YOUR_LOCATION'; + // const model = 'gemini-2.5-flash'; + + it('should create stream chat and begin the conversation the same in each instance', async () => { + const output = execSync( + `node ./tools-func-calling-stream-content.js ${projectId} ${location} ${model}` + ); + + // Assert that the response is what we expect + assert(output.match(/super nice/), output); + }); +}); diff --git a/genai/tools/tools-func-calling-stream-content.js b/genai/tools/tools-func-calling-stream-content.js new file mode 100644 index 0000000000..3fd8a22607 --- /dev/null +++ b/genai/tools/tools-func-calling-stream-content.js @@ -0,0 +1,96 @@ +// 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. + +// [START aiplatform_genai_function_calling_stream_content] +const {GoogleGenAI} = require('@google/genai'); + +const 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'], + }, + }, + ], + }, +]; + +const functionResponseParts = [ + { + functionResponse: { + name: 'get_current_weather', + response: {weather: 'super nice'}, + }, + }, +]; + +/** + * TODO(developer): Update these variables before running the sample. + */ +async function functionCallingStreamContent( + projectId = 'PROJECT_ID', + location = 'us-central1', + model = 'gemini-2.5-flash' +) { + // Initialize client with your Cloud project and location + const client = new GoogleGenAI({ + vertexai: true, + project: projectId, + location: location, + }); + + const request = [ + {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}, + ]; + + const streamingResp = await client.models.generateContentStream({ + model: model, + contents: request, + config: {tools: tools}, + }); + + let completeResponseText = ''; + for await (const chunk of streamingResp) { + if (chunk.text) { + completeResponseText += chunk.text; + } + } + console.log(completeResponseText); +} +// [END aiplatform_genai_function_calling_stream_content] + +functionCallingStreamContent(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; +}); From 034d08a023b6461259dc43ef5ea19b2cabd2e436 Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Tue, 21 Jul 2026 14:29:09 -0600 Subject: [PATCH 16/34] chore: decommission obsolete count tokens advanced sample (#4384) --- .../count-tokens/countTokensAdvanced.js | 69 ------------------- .../count-tokens/countTokensAdvanced.test.js | 43 ------------ 2 files changed, 112 deletions(-) delete mode 100644 generative-ai/snippets/count-tokens/countTokensAdvanced.js delete mode 100644 generative-ai/snippets/test/count-tokens/countTokensAdvanced.test.js diff --git a/generative-ai/snippets/count-tokens/countTokensAdvanced.js b/generative-ai/snippets/count-tokens/countTokensAdvanced.js deleted file mode 100644 index df90a199cf..0000000000 --- a/generative-ai/snippets/count-tokens/countTokensAdvanced.js +++ /dev/null @@ -1,69 +0,0 @@ -// 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 {GoogleGenAI} = require('@google/genai'); -/** - * TODO(developer): Update these variables before running the sample. - */ -async function countTokens( - projectId = 'PROJECT_ID', - location = 'us-central1', - model = 'gemini-2.5-flash' -) { - // Initialize client with your Cloud project and location - const client = new GoogleGenAI({ - vertexai: true, - project: projectId, - location: location, - }); - - const contents = [ - { - role: 'user', - parts: [ - { - fileData: { - fileUri: 'gs://cloud-samples-data/generative-ai/video/pixel8.mp4', - mimeType: 'video/mp4', - }, - }, - {text: 'Provide a description of the video.'}, - ], - }, - ]; - - const countTokensResp = await client.models.countTokens({ - model: model, - contents: contents, - }); - - console.log('Prompt Token Count:', countTokensResp.totalTokens); - - // Send text to Gemini - const result = await client.models.generateContent({ - model: model, - contents: contents, - }); - - const usageMetadata = result.usageMetadata; - - console.log('Prompt Token Count:', usageMetadata.promptTokenCount); - console.log('Candidates Token Count:', usageMetadata.candidatesTokenCount); - console.log('Total Token Count:', usageMetadata.totalTokenCount); -} - -countTokens(...process.argv.slice(2)).catch(err => { - console.error(err.message); - process.exitCode = 1; -}); diff --git a/generative-ai/snippets/test/count-tokens/countTokensAdvanced.test.js b/generative-ai/snippets/test/count-tokens/countTokensAdvanced.test.js deleted file mode 100644 index e3b8d54da6..0000000000 --- a/generative-ai/snippets/test/count-tokens/countTokensAdvanced.test.js +++ /dev/null @@ -1,43 +0,0 @@ -// 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. - -'use strict'; - -const {assert} = require('chai'); -const {describe, it} = require('mocha'); -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const projectId = process.env.CAIP_PROJECT_ID; -const location = process.env.LOCATION; -const model = 'gemini-2.5-flash'; - -describe('Count tokens advanced', async () => { - /** - * TODO(developer): Uncomment these variables before running the sample.\ - * (Not necessary if passing values as arguments) - */ - // const projectId = 'YOUR_PROJECT_ID'; - // const location = 'YOUR_LOCATION'; - // const model = 'gemini-2.5-flash'; - - it('should count tokens in a multimodal prompt', async () => { - const output = execSync( - `node ./count-tokens/countTokensAdvanced.js ${projectId} ${location} ${model}` - ); - - assert(output.match(/Prompt Token Count: \d+/)); - assert(output.match(/Total Token Count: \d+/)); - }); -}); From 2b5428917dbadce677b2eabf1f175fa7b779827e Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Fri, 24 Jul 2026 10:54:37 -0600 Subject: [PATCH 17/34] cleanup: remove obsolete function calling samples (#4387) --- .../function-calling/functionCallingBasic.js | 69 ------------- .../functionCallingStreamContent.js | 96 ------------------- .../functionCallingBasic.test.js | 43 --------- .../functionCallingStreamContent.test.js | 43 --------- 4 files changed, 251 deletions(-) delete mode 100644 generative-ai/snippets/function-calling/functionCallingBasic.js delete mode 100644 generative-ai/snippets/function-calling/functionCallingStreamContent.js delete mode 100644 generative-ai/snippets/test/function-calling/functionCallingBasic.test.js delete mode 100644 generative-ai/snippets/test/function-calling/functionCallingStreamContent.test.js diff --git a/generative-ai/snippets/function-calling/functionCallingBasic.js b/generative-ai/snippets/function-calling/functionCallingBasic.js deleted file mode 100644 index c3429cbbfd..0000000000 --- a/generative-ai/snippets/function-calling/functionCallingBasic.js +++ /dev/null @@ -1,69 +0,0 @@ -// 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. - -// [START generativeaionvertexai_function_calling_basic] -const {GoogleGenAI} = require('@google/genai'); - -const 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'], - }, - }, - ], - }, -]; - -/** - * TODO(developer): Update these variables before running the sample. - */ -async function functionCallingBasic( - projectId = 'PROJECT_ID', - location = 'us-central1', - model = 'gemini-2.5-flash' -) { - // Initialize client with your Cloud project and location - const client = new GoogleGenAI({ - vertexai: true, - project: projectId, - location: location, - }); - - const result = await client.models.generateContent({ - model: model, - contents: 'What is the weather in Boston?', - config: { - tools: tools, - }, - }); - console.log(JSON.stringify(result.functionCalls)); -} -// [END generativeaionvertexai_function_calling_basic] - -functionCallingBasic(...process.argv.slice(2)).catch(err => { - console.error(err.message); - process.exitCode = 1; -}); diff --git a/generative-ai/snippets/function-calling/functionCallingStreamContent.js b/generative-ai/snippets/function-calling/functionCallingStreamContent.js deleted file mode 100644 index c25bb995d2..0000000000 --- a/generative-ai/snippets/function-calling/functionCallingStreamContent.js +++ /dev/null @@ -1,96 +0,0 @@ -// 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. - -// [START generativeaionvertexai_gemini_function_calling_content] -const {GoogleGenAI} = require('@google/genai'); - -const 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'], - }, - }, - ], - }, -]; - -const functionResponseParts = [ - { - functionResponse: { - name: 'get_current_weather', - response: {name: 'get_current_weather', content: {weather: 'super nice'}}, - }, - }, -]; - -/** - * TODO(developer): Update these variables before running the sample. - */ -async function functionCallingStreamContent( - projectId = 'PROJECT_ID', - location = 'us-central1', - model = 'gemini-2.5-flash' -) { - // Initialize client with your Cloud project and location - const client = new GoogleGenAI({ - vertexai: true, - project: projectId, - location: location, - }); - - const request = [ - {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}, - ]; - - const streamingResp = await client.models.generateContentStream({ - model: model, - contents: request, - config: {tools: tools}, - }); - - let completeResponseText = ''; - for await (const chunk of streamingResp) { - if (chunk.text) { - completeResponseText += chunk.text; - } - } - console.log(completeResponseText); -} -// [END generativeaionvertexai_gemini_function_calling_content] - -functionCallingStreamContent(...process.argv.slice(2)).catch(err => { - console.error(err.message); - process.exitCode = 1; -}); diff --git a/generative-ai/snippets/test/function-calling/functionCallingBasic.test.js b/generative-ai/snippets/test/function-calling/functionCallingBasic.test.js deleted file mode 100644 index 013baaf496..0000000000 --- a/generative-ai/snippets/test/function-calling/functionCallingBasic.test.js +++ /dev/null @@ -1,43 +0,0 @@ -// 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. - -'use strict'; - -const {assert} = require('chai'); -const {describe, it} = require('mocha'); -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const projectId = process.env.CAIP_PROJECT_ID; -const location = process.env.LOCATION; -const model = 'gemini-2.5-flash'; - -describe('Generative AI Function Calling', () => { - /** - * TODO(developer): Uncomment these variables before running the sample.\ - * (Not necessary if passing values as arguments) - */ - // const projectId = 'YOUR_PROJECT_ID'; - // const location = 'YOUR_LOCATION'; - // const model = 'gemini-2.5-flash'; - - it('should define a function and have the model invoke it', async () => { - const output = execSync( - `node ./function-calling/functionCallingBasic.js ${projectId} ${location} ${model}` - ); - - // Assert that the response is what we expect - assert(output.length > 0); - }); -}); diff --git a/generative-ai/snippets/test/function-calling/functionCallingStreamContent.test.js b/generative-ai/snippets/test/function-calling/functionCallingStreamContent.test.js deleted file mode 100644 index f825df3a88..0000000000 --- a/generative-ai/snippets/test/function-calling/functionCallingStreamContent.test.js +++ /dev/null @@ -1,43 +0,0 @@ -// 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'; - -const {assert} = require('chai'); -const {describe, it} = require('mocha'); -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const projectId = process.env.CAIP_PROJECT_ID; -const location = process.env.LOCATION; -const model = 'gemini-2.5-flash'; - -describe('Generative AI Function Calling Stream Content', () => { - /** - * TODO(developer): Uncomment these variables before running the sample.\ - * (Not necessary if passing values as arguments) - */ - // const projectId = 'YOUR_PROJECT_ID'; - // const location = 'YOUR_LOCATION'; - // const model = 'gemini-2.5-flash'; - - it('should create stream chat and begin the conversation the same in each instance', async () => { - const output = execSync( - `node ./function-calling/functionCallingStreamContent.js ${projectId} ${location} ${model}` - ); - - // Assert that the response is what we expect - assert(output.match(/super nice/), output); - }); -}); From d8c246e0eff24c2ff955f3596ca270935a053a2d Mon Sep 17 00:00:00 2001 From: Ben Hu Date: Fri, 24 Jul 2026 10:04:07 -0700 Subject: [PATCH 18/34] feat: BigQuery Storage v1beta1 API migration guide (#4352) * feat: BigQuery Storage API v1beta1 migration guide * Add bigquery-readapi-team to subfolder code owner --------- Co-authored-by: Angel Caamal Co-authored-by: Anayeli --- CODEOWNERS | 1 + .../storage-v1beta1-migration-guide-js.md | 154 +++++++++++++++++ .../storage-v1beta1-migration-guide-ts.md | 163 ++++++++++++++++++ 3 files changed, 318 insertions(+) create mode 100644 bigquery/cloud-client/storage-v1beta1-migration-guide-js.md create mode 100644 bigquery/cloud-client/storage-v1beta1-migration-guide-ts.md diff --git a/CODEOWNERS b/CODEOWNERS index 483e4b4b0b..ebd9560942 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -43,6 +43,7 @@ document-warehouse @GoogleCloudPlatform/nodejs-samples-reviewers @GoogleCloudPla # Self-service ai-platform @GoogleCloudPlatform/nodejs-samples-reviewers @GoogleCloudPlatform/text-embedding @GoogleCloudPlatform/cloud-samples-reviewers asset @GoogleCloudPlatform/cloud-asset-analysis-team @GoogleCloudPlatform/nodejs-samples-reviewers @GoogleCloudPlatform/cloud-samples-reviewers +bigquery @GoogleCloudPlatform/bigquery-readapi-team @GoogleCloudPlatform/nodejs-samples-reviewers @GoogleCloudPlatform/cloud-samples-reviewers dlp @GoogleCloudPlatform/googleapis-dlp @GoogleCloudPlatform/nodejs-samples-reviewers @GoogleCloudPlatform/cloud-samples-reviewers model-armor @GoogleCloudPlatform/nodejs-samples-reviewers @GoogleCloudPlatform/cloud-samples-reviewers @GoogleCloudPlatform/cloud-modelarmor-team security-center @GoogleCloudPlatform/gcp-security-command-center @GoogleCloudPlatform/nodejs-samples-reviewers @GoogleCloudPlatform/cloud-samples-reviewers diff --git a/bigquery/cloud-client/storage-v1beta1-migration-guide-js.md b/bigquery/cloud-client/storage-v1beta1-migration-guide-js.md new file mode 100644 index 0000000000..56fa3ffb1d --- /dev/null +++ b/bigquery/cloud-client/storage-v1beta1-migration-guide-js.md @@ -0,0 +1,154 @@ +# Migrating BigQuery Storage API from v1beta1 to v1: JavaScript + +This guide shows how to migrate JavaScript code using the BigQuery Storage API +from version `v1beta1` to `v1`. + +## Key Changes + +* **Service Client**: `BigQueryStorageClient` (in `v1beta1` namespace) is + replaced by `BigQueryReadClient` (in `v1` namespace). +* **Table Reference**: `tableReference` object is replaced by a simple string + representation of the table path in `readSession.table`. +* **Session Configuration**: Configuration fields (table, format, read + options) have moved into `readSession` object, which is passed in + `createReadSession` request. +* **Parallelism**: `requestedStreams` is replaced by `maxStreamCount`. +* **Sharding Strategy**: `shardingStrategy` is removed. The server now + automatically balances the streams. +* **Read Rows Request**: `readPosition` is flattened. You now pass the stream + name directly as `readStream` and the `offset` as a top-level field in the + `readRows` request. + +## Code Comparison + +### 1. Client Initialization + +**v1beta1:** + +```javascript +const {v1beta1} = require('@google-cloud/bigquery-storage'); +const client = new v1beta1.BigQueryStorageClient(); +``` + +**v1:** + +```javascript +const {v1} = require('@google-cloud/bigquery-storage'); +const client = new v1.BigQueryReadClient(); +``` + +### 2. Creating a Read Session + +**v1beta1:** + +```javascript +const {v1beta1} = require('@google-cloud/bigquery-storage'); + +const tableReference = { + projectId: 'bigquery-public-data', + datasetId: 'usa_names', + tableId: 'usa_1910_current', +}; + +const readOptions = { + selectedFields: ['name'], + rowRestriction: 'state = "WA"', +}; + +const request = { + parent: 'projects/read-session-project', + tableReference: tableReference, + readOptions: readOptions, + requestedStreams: 1, + format: v1beta1.protos.google.cloud.bigquery.storage.v1beta1.DataFormat.AVRO, + shardingStrategy: v1beta1.protos.google.cloud.bigquery.storage.v1beta1.ShardingStrategy.LIQUID, +}; + +const [session] = await client.createReadSession(request); +``` + +**v1:** + +```javascript +const {v1} = require('@google-cloud/bigquery-storage'); + +// Table path is now a string: projects/{project}/datasets/{dataset}/tables/{table} +const tablePath = 'projects/bigquery-public-data/datasets/usa_names/tables/usa_1910_current'; + +const readOptions = { + selectedFields: ['name'], + rowRestriction: 'state = "WA"', +}; + +// ReadSession holds the session configuration +const readSession = { + table: tablePath, + dataFormat: v1.protos.google.cloud.bigquery.storage.v1.DataFormat.AVRO, // format renamed to dataFormat + readOptions: readOptions, +}; + +const request = { + parent: 'projects/read-session-project', + readSession: readSession, + maxStreamCount: 1, // requestedStreams renamed to maxStreamCount +}; + +const [session] = await client.createReadSession(request); +``` + +### 3. Reading Rows + +**v1beta1:** + +```javascript +const stream = session.streams[0]; + +const request = { + readPosition: { + stream: stream, // Stream object + offset: 0, + }, +}; + +const rowStream = client.readRows(request); + +rowStream + .on('data', (response) => { + // Process response.avroRows + }) + .on('error', (err) => { + // Handle error + }) + .on('end', () => { + // Done + }); +``` + +**v1:** + +```javascript +const stream = session.streams?.[0]; +if (!stream) { + throw new Error('No streams available'); +} + +// Request is flattened. Pass readStream (string) and offset directly. +const request = { + readStream: stream.name, // Stream name string + offset: 0, +}; + +const rowStream = client.readRows(request); + +rowStream + .on('data', (response) => { + // Process response.avroRows + // Note: Prefer using response.rowCount over response.avroRows?.rowCount (deprecated) + }) + .on('error', (err) => { + // Handle error + }) + .on('end', () => { + // Done + }); +``` diff --git a/bigquery/cloud-client/storage-v1beta1-migration-guide-ts.md b/bigquery/cloud-client/storage-v1beta1-migration-guide-ts.md new file mode 100644 index 0000000000..8c636d6ac6 --- /dev/null +++ b/bigquery/cloud-client/storage-v1beta1-migration-guide-ts.md @@ -0,0 +1,163 @@ +# Migrating BigQuery Storage API from v1beta1 to v1: TypeScript + +This guide shows how to migrate TypeScript code using the BigQuery Storage API +from version `v1beta1` to `v1`. + +## Key Changes + +* **Service Client**: `BigQueryStorageClient` (in `v1beta1` namespace) is + replaced by `BigQueryReadClient` (in `v1` namespace). +* **Table Reference**: `tableReference` object is replaced by a simple string + representation of the table path in `readSession.table`. +* **Session Configuration**: Configuration fields (table, format, read + options) have moved into `readSession` object, which is passed in + `createReadSession` request. +* **Parallelism**: `requestedStreams` is replaced by `maxStreamCount`. +* **Sharding Strategy**: `shardingStrategy` is removed. The server now + automatically balances the streams. +* **Read Rows Request**: `readPosition` is flattened. You now pass the stream + name directly as `readStream` and the `offset` as a top-level field in the + `readRows` request. + +## Code Comparison + +### 1. Client Initialization + +**v1beta1:** + +```typescript +import {v1beta1} from '@google-cloud/bigquery-storage'; +const client = new v1beta1.BigQueryStorageClient(); +``` + +**v1:** + +```typescript +import {v1} from '@google-cloud/bigquery-storage'; +const client = new v1.BigQueryReadClient(); +``` + +### 2. Creating a Read Session + +**v1beta1:** + +```typescript +import {v1beta1} from '@google-cloud/bigquery-storage'; + +const tableReference = { + projectId: 'bigquery-public-data', + datasetId: 'usa_names', + tableId: 'usa_1910_current', +}; + +const readOptions = { + selectedFields: ['name'], + rowRestriction: 'state = "WA"', +}; + +const request: v1beta1.protos.google.cloud.bigquery.storage.v1beta1.ICreateReadSessionRequest = { + parent: 'projects/read-session-project', + tableReference: tableReference, + readOptions: readOptions, + requestedStreams: 1, + format: v1beta1.protos.google.cloud.bigquery.storage.v1beta1.DataFormat.AVRO, + shardingStrategy: v1beta1.protos.google.cloud.bigquery.storage.v1beta1.ShardingStrategy.LIQUID, +}; + +const [session] = await client.createReadSession(request); +``` + +**v1:** + +```typescript +import {v1} from '@google-cloud/bigquery-storage'; + +// Table path is now a string: projects/{project}/datasets/{dataset}/tables/{table} +const tablePath = 'projects/bigquery-public-data/datasets/usa_names/tables/usa_1910_current'; + +const readOptions = { + selectedFields: ['name'], + rowRestriction: 'state = "WA"', +}; + +// ReadSession holds the session configuration +const readSession = { + table: tablePath, + dataFormat: v1.protos.google.cloud.bigquery.storage.v1.DataFormat.AVRO, // format renamed to dataFormat + readOptions: readOptions, +}; + +const request: v1.protos.google.cloud.bigquery.storage.v1.ICreateReadSessionRequest = { + parent: `projects/read-session-project`, + readSession: readSession, + maxStreamCount: 1, // requestedStreams renamed to maxStreamCount +}; + +const [session] = await client.createReadSession(request); +``` + +### 3. Reading Rows + +In Node.js client, `readRows` returns a stream that emits data events. + +**v1beta1:** + +```typescript +import {v1beta1} from '@google-cloud/bigquery-storage'; + +const stream = session.streams?.[0]; +if (!stream) { + throw new Error('No streams available'); +} + +const request: v1beta1.protos.google.cloud.bigquery.storage.v1beta1.IReadRowsRequest = { + readPosition: { + stream: stream, // Stream object + offset: 0, + }, +}; + +const rowStream = client.readRows(request); + +rowStream + .on('data', (response: v1beta1.protos.google.cloud.bigquery.storage.v1beta1.IReadRowsResponse) => { + // Process response.avroRows + }) + .on('error', (err) => { + // Handle error + }) + .on('end', () => { + // Done + }); +``` + +**v1:** + +```typescript +import {v1} from '@google-cloud/bigquery-storage'; + +const stream = session.streams?.[0]; +if (!stream || !stream.name) { + throw new Error('No streams available'); +} + +// Request is flattened. Pass readStream (string) and offset directly. +const request: v1.protos.google.cloud.bigquery.storage.v1.IReadRowsRequest = { + readStream: stream.name, // Stream name string + offset: 0, +}; + +const rowStream = client.readRows(request); + +rowStream + .on('data', (response: v1.protos.google.cloud.bigquery.storage.v1.IReadRowsResponse) => { + // Process response.avroRows + // Note: Prefer using response.rowCount over response.avroRows?.rowCount (deprecated) + }) + .on('error', (err) => { + // Handle error + }) + .on('end', () => { + // Done + }); +``` From f4d20451bca7ccb31f4a6b751320faa679df2b63 Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Fri, 24 Jul 2026 11:09:53 -0600 Subject: [PATCH 19/34] task: decommission legacy Vertex AI region tags under generative-ai (part 1) (#4369) --- generative-ai/snippets/gemini-all-modalities.js | 2 -- generative-ai/snippets/gemini-audio-summarization.js | 2 -- generative-ai/snippets/gemini-audio-transcription.js | 2 -- generative-ai/snippets/gemini-pdf.js | 2 -- generative-ai/snippets/gemini-system-instruction.js | 2 -- generative-ai/snippets/gemini-text-input.js | 2 -- 6 files changed, 12 deletions(-) diff --git a/generative-ai/snippets/gemini-all-modalities.js b/generative-ai/snippets/gemini-all-modalities.js index 40a913ca72..7ec40e6b4b 100644 --- a/generative-ai/snippets/gemini-all-modalities.js +++ b/generative-ai/snippets/gemini-all-modalities.js @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// [START generativeaionvertexai_gemini_all_modalities] const {GoogleGenAI} = require('@google/genai'); /** @@ -62,7 +61,6 @@ async function analyze_all_modalities( console.log(response.text); } -// [END generativeaionvertexai_gemini_all_modalities] analyze_all_modalities(...process.argv.slice(2)).catch(err => { console.error(err.message); diff --git a/generative-ai/snippets/gemini-audio-summarization.js b/generative-ai/snippets/gemini-audio-summarization.js index 067a335954..e809350f56 100644 --- a/generative-ai/snippets/gemini-audio-summarization.js +++ b/generative-ai/snippets/gemini-audio-summarization.js @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// [START generativeaionvertexai_gemini_audio_summarization] const {GoogleGenAI} = require('@google/genai'); /** * TODO(developer): Update these variables before running the sample. @@ -47,7 +46,6 @@ async function summarize_audio( console.log(response.text); } -// [END generativeaionvertexai_gemini_audio_summarization] summarize_audio(...process.argv.slice(2)).catch(err => { console.error(err.message); diff --git a/generative-ai/snippets/gemini-audio-transcription.js b/generative-ai/snippets/gemini-audio-transcription.js index 568791ea1e..447eaf81ae 100644 --- a/generative-ai/snippets/gemini-audio-transcription.js +++ b/generative-ai/snippets/gemini-audio-transcription.js @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// [START generativeaionvertexai_gemini_audio_transcription] const {GoogleGenAI} = require('@google/genai'); /** @@ -47,7 +46,6 @@ async function transcript_audio( console.log(response.text); } -// [END generativeaionvertexai_gemini_audio_transcription] transcript_audio(...process.argv.slice(2)).catch(err => { console.error(err.message); diff --git a/generative-ai/snippets/gemini-pdf.js b/generative-ai/snippets/gemini-pdf.js index bc9c6ecae5..f4e19c4ebe 100644 --- a/generative-ai/snippets/gemini-pdf.js +++ b/generative-ai/snippets/gemini-pdf.js @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// [START generativeaionvertexai_gemini_pdf] const {GoogleGenAI} = require('@google/genai'); /** @@ -48,7 +47,6 @@ async function analyze_pdf( console.log(response.text); } -// [END generativeaionvertexai_gemini_pdf] analyze_pdf(...process.argv.slice(2)).catch(err => { console.error(err.message); diff --git a/generative-ai/snippets/gemini-system-instruction.js b/generative-ai/snippets/gemini-system-instruction.js index 5d9f845b91..438df205b7 100644 --- a/generative-ai/snippets/gemini-system-instruction.js +++ b/generative-ai/snippets/gemini-system-instruction.js @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// [START generativeaionvertexai_gemini_system_instruction] const {GoogleGenAI} = require('@google/genai'); /** @@ -49,7 +48,6 @@ async function set_system_instruction( console.log(response.text); } -// [END generativeaionvertexai_gemini_system_instruction] set_system_instruction(...process.argv.slice(2)).catch(err => { console.error(err.message); diff --git a/generative-ai/snippets/gemini-text-input.js b/generative-ai/snippets/gemini-text-input.js index 44b4905894..17eadb9ecd 100644 --- a/generative-ai/snippets/gemini-text-input.js +++ b/generative-ai/snippets/gemini-text-input.js @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// [START generativeaionvertexai_gemini_generate_from_text_input] const {GoogleGenAI} = require('@google/genai'); /** * TODO(developer): Update these variables before running the sample. @@ -37,7 +36,6 @@ async function generate_from_text_input( console.log(response.text); } -// [END generativeaionvertexai_gemini_generate_from_text_input] generate_from_text_input(...process.argv.slice(2)).catch(err => { console.error(err.message); From bfa3dcc16b3edb7332ab5893bc41a45aeec2024d Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Fri, 24 Jul 2026 11:27:44 -0600 Subject: [PATCH 20/34] chore(generative-ai): decommission legacy Vertex AI region tags (part 2) (#4370) --- generative-ai/snippets/gemini-video-audio.js | 2 -- generative-ai/snippets/nonStreamingChat.js | 4 ---- generative-ai/snippets/nonStreamingMultipartContent.js | 2 -- generative-ai/snippets/safetySettings.js | 2 -- 4 files changed, 10 deletions(-) diff --git a/generative-ai/snippets/gemini-video-audio.js b/generative-ai/snippets/gemini-video-audio.js index 9df596cb6e..8d7b135655 100644 --- a/generative-ai/snippets/gemini-video-audio.js +++ b/generative-ai/snippets/gemini-video-audio.js @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// [START generativeaionvertexai_gemini_video_with_audio] const {GoogleGenAI} = require('@google/genai'); /** * TODO(developer): Update these variables before running the sample. @@ -47,7 +46,6 @@ async function analyze_video_with_audio( console.log(response.text); } -// [END generativeaionvertexai_gemini_video_with_audio] analyze_video_with_audio(...process.argv.slice(2)).catch(err => { console.error(err.message); diff --git a/generative-ai/snippets/nonStreamingChat.js b/generative-ai/snippets/nonStreamingChat.js index e216bbc572..dae9fa8d00 100644 --- a/generative-ai/snippets/nonStreamingChat.js +++ b/generative-ai/snippets/nonStreamingChat.js @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// [START generativeaionvertexai_gemini_multiturn_chat_nonstreaming] -// [START aiplatform_gemini_multiturn_chat_nonstreaming] const {GoogleGenAI} = require('@google/genai'); /** * TODO(developer): Update these variables before running the sample. @@ -47,8 +45,6 @@ async function createNonStreamingChat( }); console.log('Chat response 3: ', response3.text); } -// [END aiplatform_gemini_multiturn_chat_nonstreaming] -// [END generativeaionvertexai_gemini_multiturn_chat_nonstreaming] createNonStreamingChat(...process.argv.slice(2)).catch(err => { console.error(err.message); diff --git a/generative-ai/snippets/nonStreamingMultipartContent.js b/generative-ai/snippets/nonStreamingMultipartContent.js index a391b96a13..74a4aea996 100644 --- a/generative-ai/snippets/nonStreamingMultipartContent.js +++ b/generative-ai/snippets/nonStreamingMultipartContent.js @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// [START generativeaionvertexai_gemini_get_started] const {VertexAI} = require('@google-cloud/vertexai'); /** @@ -63,7 +62,6 @@ async function createNonStreamingMultipartContent( console.log(fullTextResponse); } -// [END generativeaionvertexai_gemini_get_started] createNonStreamingMultipartContent(...process.argv.slice(2)).catch(err => { console.error(err.message); diff --git a/generative-ai/snippets/safetySettings.js b/generative-ai/snippets/safetySettings.js index 52b229fa65..bc96c12fd3 100644 --- a/generative-ai/snippets/safetySettings.js +++ b/generative-ai/snippets/safetySettings.js @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// [START generativeaionvertexai_gemini_safety_settings] const { VertexAI, HarmCategory, @@ -69,7 +68,6 @@ async function setSafetySettings() { } console.log('This response stream terminated due to safety concerns.'); } -// [END generativeaionvertexai_gemini_safety_settings] setSafetySettings().catch(err => { console.error(err.message); From c9c84242eb49b5de8a1fc3dd35a6c116ac344935 Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Fri, 24 Jul 2026 11:36:50 -0600 Subject: [PATCH 21/34] chore(generative-ai): decommission legacy Vertex AI region tags (part 3) (#4372) --- generative-ai/snippets/sendMultiModalPromptWithImage.js | 2 -- generative-ai/snippets/sendMultiModalPromptWithVideo.js | 2 -- generative-ai/snippets/streamChat.js | 3 --- generative-ai/snippets/streamMultipartContent.js | 2 -- 4 files changed, 9 deletions(-) diff --git a/generative-ai/snippets/sendMultiModalPromptWithImage.js b/generative-ai/snippets/sendMultiModalPromptWithImage.js index bdeb9484ca..6dff45c2ff 100644 --- a/generative-ai/snippets/sendMultiModalPromptWithImage.js +++ b/generative-ai/snippets/sendMultiModalPromptWithImage.js @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// [START generativeaionvertexai_gemini_single_turn_multi_image] const {VertexAI} = require('@google-cloud/vertexai'); const axios = require('axios'); @@ -93,7 +92,6 @@ async function sendMultiModalPromptWithImage( console.log(fullTextResponse); } -// [END generativeaionvertexai_gemini_single_turn_multi_image] sendMultiModalPromptWithImage(...process.argv.slice(2)).catch(err => { console.error(err.message); diff --git a/generative-ai/snippets/sendMultiModalPromptWithVideo.js b/generative-ai/snippets/sendMultiModalPromptWithVideo.js index 3126264f29..2ac06578c0 100644 --- a/generative-ai/snippets/sendMultiModalPromptWithVideo.js +++ b/generative-ai/snippets/sendMultiModalPromptWithVideo.js @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// [START generativeaionvertexai_gemini_single_turn_video] const {VertexAI} = require('@google-cloud/vertexai'); /** @@ -60,7 +59,6 @@ async function sendMultiModalPromptWithVideo( console.log(fullTextResponse); } -// [END generativeaionvertexai_gemini_single_turn_video] sendMultiModalPromptWithVideo(...process.argv.slice(2)).catch(err => { console.error(err.message); diff --git a/generative-ai/snippets/streamChat.js b/generative-ai/snippets/streamChat.js index 212313f95a..d917938a48 100644 --- a/generative-ai/snippets/streamChat.js +++ b/generative-ai/snippets/streamChat.js @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// [START generativeaionvertexai_gemini_multiturn_chat_stream] const {VertexAI} = require('@google-cloud/vertexai'); /** @@ -42,8 +41,6 @@ async function createStreamChat( } } -// [END generativeaionvertexai_gemini_multiturn_chat_stream] - createStreamChat(...process.argv.slice(2)).catch(err => { console.error(err.message); process.exitCode = 1; diff --git a/generative-ai/snippets/streamMultipartContent.js b/generative-ai/snippets/streamMultipartContent.js index 434f7fa5e3..e4d7f58d6d 100644 --- a/generative-ai/snippets/streamMultipartContent.js +++ b/generative-ai/snippets/streamMultipartContent.js @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// [START aiplatform_gemini_get_started] const {VertexAI} = require('@google-cloud/vertexai'); /** @@ -62,7 +61,6 @@ async function createStreamMultipartContent( process.stdout.write(item.candidates[0].content.parts[0].text); } } -// [END aiplatform_gemini_get_started] createStreamMultipartContent(...process.argv.slice(2)).catch(err => { console.error(err.message); From 74ad310e45ce17f91c7b0106ee7bba7a6ff770a9 Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Tue, 28 Jul 2026 12:34:22 -0600 Subject: [PATCH 22/34] fix(compute): update nodemailer and remove decommissioned smtp-transport dependency (#4386) * fix: update nodemailer and remove decommissioned smtp-transport dependency * fix: add missing closing bracket in mailjet placeholder typo --- compute/mailjet.js | 20 ++++++++------------ compute/package.json | 3 +-- compute/test/mailjet.test.js | 22 +++++++++------------- 3 files changed, 18 insertions(+), 27 deletions(-) diff --git a/compute/mailjet.js b/compute/mailjet.js index 5ad072be17..cbbb735cf2 100644 --- a/compute/mailjet.js +++ b/compute/mailjet.js @@ -20,19 +20,15 @@ // [START compute_send] const mailer = require('nodemailer'); -const smtp = require('nodemailer-smtp-transport'); - async function mailjet() { - const transport = mailer.createTransport( - smtp({ - host: 'in.mailjet.com', - port: 2525, - auth: { - user: process.env.MAILJET_API_KEY || '', - }, - }) - ); + const transport = mailer.createTransport({ + host: 'in.mailjet.com', + port: 2525, + auth: { + user: process.env.MAILJET_API_KEY || '', + pass: process.env.MAILJET_API_SECRET || '', + }, + }); const json = await transport.sendMail({ from: 'ANOTHER_EMAIL@ANOTHER_EXAMPLE.COM', // From address diff --git a/compute/package.json b/compute/package.json index e8a4b1cabb..aa7ef5ae9f 100644 --- a/compute/package.json +++ b/compute/package.json @@ -16,8 +16,7 @@ "dependencies": { "@google-cloud/compute": "^4.0.0", "@sendgrid/mail": "^8.0.0", - "nodemailer": "^6.0.0", - "nodemailer-smtp-transport": "^2.7.4", + "nodemailer": "^9.0.0", "sinon": "^19.0.2" }, "devDependencies": { diff --git a/compute/test/mailjet.test.js b/compute/test/mailjet.test.js index b2de020f90..e718256543 100644 --- a/compute/test/mailjet.test.js +++ b/compute/test/mailjet.test.js @@ -24,8 +24,15 @@ describe('mailjet', () => { it('should send an email', () => { proxyquire('../mailjet', { nodemailer: { - createTransport: arg => { - assert.strictEqual(arg, 'test'); + createTransport: options => { + assert.deepStrictEqual(options, { + host: 'in.mailjet.com', + port: 2525, + auth: { + user: 'foo', + pass: 'bar', + }, + }); return { sendMail: payload => { assert.deepStrictEqual(payload, { @@ -39,17 +46,6 @@ describe('mailjet', () => { }; }, }, - 'nodemailer-smtp-transport': options => { - assert.deepStrictEqual(options, { - host: 'in.mailjet.com', - port: 2525, - auth: { - user: 'foo', - pass: 'bar', - }, - }); - return 'test'; - }, }); }); }); From a76527d1bcb8e04a6997309ea0c6926a20576668 Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Wed, 29 Jul 2026 12:12:16 -0600 Subject: [PATCH 23/34] chore: remove decommissioned Vertex AI samples (#4391) --- generative-ai/snippets/gemini-text-input.js | 43 ------------ generative-ai/snippets/gemini-video-audio.js | 53 -------------- .../snippets/nonStreamingMultipartContent.js | 69 ------------------- .../snippets/test/gemini-text-input.test.js | 33 --------- .../snippets/test/gemini-video-audio.test.js | 33 --------- .../test/nonStreamingMultipartContent.test.js | 47 ------------- 6 files changed, 278 deletions(-) delete mode 100644 generative-ai/snippets/gemini-text-input.js delete mode 100644 generative-ai/snippets/gemini-video-audio.js delete mode 100644 generative-ai/snippets/nonStreamingMultipartContent.js delete mode 100644 generative-ai/snippets/test/gemini-text-input.test.js delete mode 100644 generative-ai/snippets/test/gemini-video-audio.test.js delete mode 100644 generative-ai/snippets/test/nonStreamingMultipartContent.test.js diff --git a/generative-ai/snippets/gemini-text-input.js b/generative-ai/snippets/gemini-text-input.js deleted file mode 100644 index 17eadb9ecd..0000000000 --- a/generative-ai/snippets/gemini-text-input.js +++ /dev/null @@ -1,43 +0,0 @@ -// 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 {GoogleGenAI} = require('@google/genai'); -/** - * TODO(developer): Update these variables before running the sample. - */ -async function generate_from_text_input( - projectId = 'PROJECT_ID', - model = 'gemini-2.5-flash' -) { - const client = new GoogleGenAI({ - vertexai: true, - project: projectId, - location: 'us-central1', - }); - - const prompt = - "What's a good name for a flower shop that specializes in selling bouquets of dried flowers?"; - - const response = await client.models.generateContent({ - model: model, - contents: prompt, - }); - - console.log(response.text); -} - -generate_from_text_input(...process.argv.slice(2)).catch(err => { - console.error(err.message); - process.exitCode = 1; -}); diff --git a/generative-ai/snippets/gemini-video-audio.js b/generative-ai/snippets/gemini-video-audio.js deleted file mode 100644 index 8d7b135655..0000000000 --- a/generative-ai/snippets/gemini-video-audio.js +++ /dev/null @@ -1,53 +0,0 @@ -// 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 {GoogleGenAI} = require('@google/genai'); -/** - * TODO(developer): Update these variables before running the sample. - */ -async function analyze_video_with_audio( - projectId = 'PROJECT_ID', - model = 'gemini-2.5-flash' -) { - const client = new GoogleGenAI({ - vertexai: true, - project: projectId, - location: 'us-central1', - }); - - const filePart = { - fileData: { - fileUri: 'gs://cloud-samples-data/generative-ai/video/pixel8.mp4', - mimeType: 'video/mp4', - }, - }; - - const textPart = { - text: ` - Provide a description of the video. - The description should also contain anything important which people say in the video.`, - }; - - const response = await client.models.generateContent({ - model: model, - contents: [filePart, textPart], - }); - - console.log(response.text); -} - -analyze_video_with_audio(...process.argv.slice(2)).catch(err => { - console.error(err.message); - process.exitCode = 1; -}); diff --git a/generative-ai/snippets/nonStreamingMultipartContent.js b/generative-ai/snippets/nonStreamingMultipartContent.js deleted file mode 100644 index 74a4aea996..0000000000 --- a/generative-ai/snippets/nonStreamingMultipartContent.js +++ /dev/null @@ -1,69 +0,0 @@ -// 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. - -const {VertexAI} = require('@google-cloud/vertexai'); - -/** - * TODO(developer): Update these variables before running the sample. - */ -async function createNonStreamingMultipartContent( - projectId = 'PROJECT_ID', - location = 'us-central1', - model = 'gemini-2.0-flash-001', - image = 'gs://generativeai-downloads/images/scones.jpg', - mimeType = 'image/jpeg' -) { - // Initialize Vertex with your Cloud project and location - const vertexAI = new VertexAI({project: projectId, location: location}); - - // Instantiate the model - const generativeVisionModel = vertexAI.getGenerativeModel({ - model: model, - }); - - // For images, the SDK supports both Google Cloud Storage URI and base64 strings - const filePart = { - fileData: { - fileUri: image, - mimeType: mimeType, - }, - }; - - const textPart = { - text: 'what is shown in this image?', - }; - - const request = { - contents: [{role: 'user', parts: [filePart, textPart]}], - }; - - console.log('Prompt Text:'); - console.log(request.contents[0].parts[1].text); - - console.log('Non-Streaming Response Text:'); - - // Generate a response - const response = await generativeVisionModel.generateContent(request); - - // Select the text from the response - const fullTextResponse = - response.response.candidates[0].content.parts[0].text; - - console.log(fullTextResponse); -} - -createNonStreamingMultipartContent(...process.argv.slice(2)).catch(err => { - console.error(err.message); - process.exitCode = 1; -}); diff --git a/generative-ai/snippets/test/gemini-text-input.test.js b/generative-ai/snippets/test/gemini-text-input.test.js deleted file mode 100644 index 80caa063dc..0000000000 --- a/generative-ai/snippets/test/gemini-text-input.test.js +++ /dev/null @@ -1,33 +0,0 @@ -// 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. - -'use strict'; - -const {assert} = require('chai'); -const {describe, it} = require('mocha'); -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const projectId = process.env.CAIP_PROJECT_ID; -const model = 'gemini-2.5-flash'; - -describe('Get store name ideas from text input prompt', async () => { - it('should get store name ideas from text input prompt', async () => { - const output = execSync( - `node ./gemini-text-input.js ${projectId} ${model}` - ); - - assert(output.length > 0); - }); -}); diff --git a/generative-ai/snippets/test/gemini-video-audio.test.js b/generative-ai/snippets/test/gemini-video-audio.test.js deleted file mode 100644 index dfa6123a30..0000000000 --- a/generative-ai/snippets/test/gemini-video-audio.test.js +++ /dev/null @@ -1,33 +0,0 @@ -// 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. - -'use strict'; - -const {assert} = require('chai'); -const {describe, it} = require('mocha'); -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const projectId = process.env.CAIP_PROJECT_ID; -const model = 'gemini-2.5-flash'; - -describe('Analyze video with audio', async () => { - it('should analyze video with audio', async () => { - const output = execSync( - `node ./gemini-video-audio.js ${projectId} ${model}` - ); - - assert(output.length > 0); - }); -}); diff --git a/generative-ai/snippets/test/nonStreamingMultipartContent.test.js b/generative-ai/snippets/test/nonStreamingMultipartContent.test.js deleted file mode 100644 index 1ec9d2487a..0000000000 --- a/generative-ai/snippets/test/nonStreamingMultipartContent.test.js +++ /dev/null @@ -1,47 +0,0 @@ -// 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'; - -const {assert} = require('chai'); -const {describe, it} = require('mocha'); -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const projectId = process.env.CAIP_PROJECT_ID; -const location = process.env.LOCATION; -const model = 'gemini-2.0-flash-001'; - -describe.skip('Generative AI NonStreaming Multipart Content', () => { - /** - * TODO(developer): Uncomment these variables before running the sample.\ - * (Not necessary if passing values as arguments) - */ - // const projectId = 'YOUR_PROJECT_ID'; - // const location = 'YOUR_LOCATION'; - // const model = 'gemini-2.0-flash-001'; - - const image = 'gs://generativeai-downloads/images/scones.jpg'; - - it('should create nonstreaming multipart content and begin the conversation the same in each instance', async () => { - const output = execSync( - `node ./nonStreamingMultipartContent.js ${projectId} ${location} ${model} ${image}` - ); - - // Ensure that the conversation is what we expect for this scone image - assert(output.match(/Prompt Text:/)); - assert(output.match(/what is shown in this image/)); - assert(output.match(/Non-Streaming Response Text:/)); - }); -}); From 634707bc0dacf546cbc4c9e01965bce680a14a41 Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Wed, 29 Jul 2026 15:50:38 -0600 Subject: [PATCH 24/34] chore(generative-ai): remove decommissioned count tokens samples (#4390) --- .../snippets/count-tokens/countTokens.js | 57 ------------------- .../test/count-tokens/countTokens.test.js | 43 -------------- 2 files changed, 100 deletions(-) delete mode 100644 generative-ai/snippets/count-tokens/countTokens.js delete mode 100644 generative-ai/snippets/test/count-tokens/countTokens.test.js diff --git a/generative-ai/snippets/count-tokens/countTokens.js b/generative-ai/snippets/count-tokens/countTokens.js deleted file mode 100644 index 81497b4dd7..0000000000 --- a/generative-ai/snippets/count-tokens/countTokens.js +++ /dev/null @@ -1,57 +0,0 @@ -// 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 {GoogleGenAI} = require('@google/genai'); - -/** - * TODO(developer): Update these variables before running the sample. - */ -async function countTokens( - projectId = 'PROJECT_ID', - location = 'us-central1', - model = 'gemini-2.5-flash' -) { - // Initialize the client with your Cloud project and location - const client = new GoogleGenAI({ - vertexai: true, - project: projectId, - location: location, - }); - - const contents = [ - {role: 'user', parts: [{text: 'How are you doing today?'}]}, - ]; - - // Prompt tokens count - const countTokensResp = await client.models.countTokens({ - model: model, - contents: contents, - }); - console.log('Prompt tokens count: ', countTokensResp); - - // Send text to gemini - const result = await client.models.generateContent({ - model: model, - contents: contents, - }); - - // Response tokens count - const usageMetadata = result.usageMetadata; - console.log('Response tokens count: ', usageMetadata); -} - -countTokens(...process.argv.slice(2)).catch(err => { - console.error(err.message); - process.exitCode = 1; -}); diff --git a/generative-ai/snippets/test/count-tokens/countTokens.test.js b/generative-ai/snippets/test/count-tokens/countTokens.test.js deleted file mode 100644 index 76c09ad3e6..0000000000 --- a/generative-ai/snippets/test/count-tokens/countTokens.test.js +++ /dev/null @@ -1,43 +0,0 @@ -// 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. - -'use strict'; - -const {assert} = require('chai'); -const {describe, it} = require('mocha'); -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const projectId = process.env.CAIP_PROJECT_ID; -const location = process.env.LOCATION; -const model = 'gemini-2.5-flash'; - -describe('Count tokens', async () => { - /** - * TODO(developer): Uncomment these variables before running the sample.\ - * (Not necessary if passing values as arguments) - */ - // const projectId = 'YOUR_PROJECT_ID'; - // const location = 'YOUR_LOCATION'; - // const model = 'gemini-2.5-flash'; - - it('should count tokens', async () => { - const output = execSync( - `node ./count-tokens/countTokens.js ${projectId} ${location} ${model}` - ); - - // Expect 6 tokens - assert(output.match('totalTokens: 6')); - }); -}); From 646f268a10c772dc9bd4bf0e9f457b29da4c2e07 Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Wed, 29 Jul 2026 16:01:53 -0600 Subject: [PATCH 25/34] chore(generative-ai): remove decommissioned function calling samples (#4389) --- .../functionCallingAdvanced.js | 83 ------------------ .../functionCallingStreamChat.js | 86 ------------------- .../functionCallingAdvanced.test.js | 43 ---------- .../functionCallingStreamChat.test.js | 43 ---------- 4 files changed, 255 deletions(-) delete mode 100644 generative-ai/snippets/function-calling/functionCallingAdvanced.js delete mode 100644 generative-ai/snippets/function-calling/functionCallingStreamChat.js delete mode 100644 generative-ai/snippets/test/function-calling/functionCallingAdvanced.test.js delete mode 100644 generative-ai/snippets/test/function-calling/functionCallingStreamChat.test.js diff --git a/generative-ai/snippets/function-calling/functionCallingAdvanced.js b/generative-ai/snippets/function-calling/functionCallingAdvanced.js deleted file mode 100644 index e1a7cb2935..0000000000 --- a/generative-ai/snippets/function-calling/functionCallingAdvanced.js +++ /dev/null @@ -1,83 +0,0 @@ -// 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 {GoogleGenAI} = require('@google/genai'); - -const tools = [ - { - functionDeclarations: [ - { - name: 'get_product_sku', - description: 'Get the available inventory for Google products', - parameters: { - type: 'OBJECT', - properties: { - productName: {type: 'STRING'}, - }, - }, - }, - { - name: 'get_store_location', - description: 'Get the location of the closest store', - parameters: { - type: 'OBJECT', - properties: { - location: {type: 'STRING'}, - }, - }, - }, - ], - }, -]; - -const toolConfig = { - functionCallingConfig: { - mode: 'ANY', - allowedFunctionNames: ['get_product_sku'], - }, -}; - -/** - * TODO(developer): Update these variables before running the sample. - */ -async function functionCallingAdvanced( - projectId = 'PROJECT_ID', - location = 'us-central1', - model = 'gemini-2.5-flash' -) { - // Initialize client with your Cloud project and location - const client = new GoogleGenAI({ - vertexai: true, - project: projectId, - location: location, - }); - - const result = await client.models.generateContent({ - model: model, - contents: 'Do you have the White Pixel 8 Pro 128GB in stock in the US?', - config: { - tools: tools, - toolConfig: toolConfig, - temperature: 0.95, - topP: 1.0, - maxOutputTokens: 8192, - }, - }); - console.log(JSON.stringify(result.functionCalls)); -} - -functionCallingAdvanced(...process.argv.slice(2)).catch(err => { - console.error(err.message); - process.exitCode = 1; -}); diff --git a/generative-ai/snippets/function-calling/functionCallingStreamChat.js b/generative-ai/snippets/function-calling/functionCallingStreamChat.js deleted file mode 100644 index 8ff521d0ce..0000000000 --- a/generative-ai/snippets/function-calling/functionCallingStreamChat.js +++ /dev/null @@ -1,86 +0,0 @@ -// 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. - -const {GoogleGenAI} = require('@google/genai'); - -const 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'], - }, - }, - ], - }, -]; - -/** - * TODO(developer): Update these variables before running the sample. - */ -async function functionCallingStreamChat( - projectId = 'PROJECT_ID', - location = 'us-central1', - model = 'gemini-2.5-flash' -) { - // Initialize client with your Cloud project and location - const client = new GoogleGenAI({ - vertexai: true, - project: projectId, - location: location, - }); - - // Create a chat session and pass your function declarations - const chat = client.chats.create({ - model: model, - config: {tools: tools}, - }); - - // This should include a functionCall response from the model - const result1 = await chat.sendMessage({ - message: 'What is the weather in Boston?', - }); - console.log( - 'Function call requested:', - JSON.stringify(result1.functionCalls, null, 2) - ); - - // Send a follow up message with a FunctionResponse - const result2 = await chat.sendMessage({ - message: [ - { - functionResponse: { - name: 'get_current_weather', - response: {result: {weather: 'super nice'}}, - }, - }, - ], - }); - - // This should include a text response from the model using the response content - // provided above - console.log(result2.text); -} - -functionCallingStreamChat(...process.argv.slice(2)).catch(err => { - console.error(err.message); - process.exitCode = 1; -}); diff --git a/generative-ai/snippets/test/function-calling/functionCallingAdvanced.test.js b/generative-ai/snippets/test/function-calling/functionCallingAdvanced.test.js deleted file mode 100644 index 26ff2a79d9..0000000000 --- a/generative-ai/snippets/test/function-calling/functionCallingAdvanced.test.js +++ /dev/null @@ -1,43 +0,0 @@ -// 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. - -'use strict'; - -const {assert} = require('chai'); -const {describe, it} = require('mocha'); -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const projectId = process.env.CAIP_PROJECT_ID; -const location = process.env.LOCATION; -const model = 'gemini-2.5-flash'; - -describe('Generative AI Function Calling Advanced', () => { - /** - * TODO(developer): Uncomment these variables before running the sample.\ - * (Not necessary if passing values as arguments) - */ - // const projectId = 'YOUR_PROJECT_ID'; - // const location = 'YOUR_LOCATION'; - // const model = 'gemini-2.5-flash'; - - it('should define multiple functions and have the model invoke the specified one', async () => { - const output = execSync( - `node ./function-calling/functionCallingAdvanced.js ${projectId} ${location} ${model}` - ); - - // Assert that the response is what we expect - assert(output.match(/get_product_sku/)); - }); -}); diff --git a/generative-ai/snippets/test/function-calling/functionCallingStreamChat.test.js b/generative-ai/snippets/test/function-calling/functionCallingStreamChat.test.js deleted file mode 100644 index 950ea05a69..0000000000 --- a/generative-ai/snippets/test/function-calling/functionCallingStreamChat.test.js +++ /dev/null @@ -1,43 +0,0 @@ -// 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'; - -const {assert} = require('chai'); -const {describe, it} = require('mocha'); -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const projectId = process.env.CAIP_PROJECT_ID; -const location = process.env.LOCATION; -const model = 'gemini-2.5-flash'; - -describe('Generative AI Function Calling Stream Chat', () => { - /** - * TODO(developer): Uncomment these variables before running the sample.\ - * (Not necessary if passing values as arguments) - */ - // const projectId = 'YOUR_PROJECT_ID'; - // const location = 'YOUR_LOCATION'; - // const model = 'gemini-2.5-flash'; - - it('should create stream chat and begin the conversation the same in each instance', async () => { - const output = execSync( - `node ./function-calling/functionCallingStreamChat.js ${projectId} ${location} ${model}` - ); - - // Assert that the response is what we expect - assert(output.match(/The weather in Boston is super nice./)); - }); -}); From 2187603b816ced6669374956941d1a05489128d3 Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Wed, 29 Jul 2026 16:06:56 -0600 Subject: [PATCH 26/34] chore(generative-ai): remove obsolete inference samples (#4388) Co-authored-by: Anayeli --- .../inference/nonStreamMultiModalityBasic.js | 62 ----------------- .../snippets/inference/nonStreamTextBasic.js | 56 --------------- .../inference/streamMultiModalityBasic.js | 68 ------------------- .../snippets/inference/streamTextBasic.js | 58 ---------------- .../snippets/streamMultipartContent.js | 68 ------------------- .../nonStreamMultiModalityBasic.test.js | 33 --------- .../test/inference/nonStreamTextBasic.test.js | 35 ---------- .../streamMultiModalityBasic.test.js | 33 --------- .../test/inference/streamTextBasic.test.js | 33 --------- .../test/streamMultipartContent.test.js | 49 ------------- 10 files changed, 495 deletions(-) delete mode 100644 generative-ai/snippets/inference/nonStreamMultiModalityBasic.js delete mode 100644 generative-ai/snippets/inference/nonStreamTextBasic.js delete mode 100644 generative-ai/snippets/inference/streamMultiModalityBasic.js delete mode 100644 generative-ai/snippets/inference/streamTextBasic.js delete mode 100644 generative-ai/snippets/streamMultipartContent.js delete mode 100644 generative-ai/snippets/test/inference/nonStreamMultiModalityBasic.test.js delete mode 100644 generative-ai/snippets/test/inference/nonStreamTextBasic.test.js delete mode 100644 generative-ai/snippets/test/inference/streamMultiModalityBasic.test.js delete mode 100644 generative-ai/snippets/test/inference/streamTextBasic.test.js delete mode 100644 generative-ai/snippets/test/streamMultipartContent.test.js diff --git a/generative-ai/snippets/inference/nonStreamMultiModalityBasic.js b/generative-ai/snippets/inference/nonStreamMultiModalityBasic.js deleted file mode 100644 index 32888d06a1..0000000000 --- a/generative-ai/snippets/inference/nonStreamMultiModalityBasic.js +++ /dev/null @@ -1,62 +0,0 @@ -// 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 {GoogleGenAI} = require('@google/genai'); -/** - * TODO(developer): Update these variables before running the sample. - */ -async function generateContent( - projectId = 'PROJECT_ID', - location = 'us-central1', - model = 'gemini-2.5-flash' -) { - // Initialize client - const client = new GoogleGenAI({ - vertexai: true, - project: projectId, - location: location, - }); - - const result = await client.models.generateContent({ - model: model, - contents: [ - { - role: 'user', - parts: [ - { - fileData: { - fileUri: 'gs://cloud-samples-data/video/animals.mp4', - mimeType: 'video/mp4', - }, - }, - { - fileData: { - fileUri: - 'gs://cloud-samples-data/generative-ai/image/character.jpg', - mimeType: 'image/jpeg', - }, - }, - {text: 'Are this video and image correlated?'}, - ], - }, - ], - }); - - console.log(result.text); -} - -generateContent(...process.argv.slice(2)).catch(err => { - console.error(err.message); - process.exitCode = 1; -}); diff --git a/generative-ai/snippets/inference/nonStreamTextBasic.js b/generative-ai/snippets/inference/nonStreamTextBasic.js deleted file mode 100644 index ba2461e19d..0000000000 --- a/generative-ai/snippets/inference/nonStreamTextBasic.js +++ /dev/null @@ -1,56 +0,0 @@ -// 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 {GoogleGenAI} = require('@google/genai'); -/** - * TODO(developer): Update these variables before running the sample. - */ - -async function generateContent( - projectId = 'PROJECT_ID', - location = 'us-central1', - model = 'gemini-2.5-flash' -) { - // Initialize client with your Cloud project and location - const client = new GoogleGenAI({ - vertexai: true, - project: projectId, - location: location, - }); - - const request = { - model: model, - contents: [ - { - role: 'user', - parts: [ - { - text: 'Write a story about a magic backpack.', - }, - ], - }, - ], - }; - - console.log(JSON.stringify(request)); - - const response = await client.models.generateContent(request); - - console.log(response.text); -} - -generateContent(...process.argv.slice(2)).catch(err => { - console.error(err.message); - process.exitCode = 1; -}); diff --git a/generative-ai/snippets/inference/streamMultiModalityBasic.js b/generative-ai/snippets/inference/streamMultiModalityBasic.js deleted file mode 100644 index 9071b6a14a..0000000000 --- a/generative-ai/snippets/inference/streamMultiModalityBasic.js +++ /dev/null @@ -1,68 +0,0 @@ -// 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 {GoogleGenAI} = require('@google/genai'); - -/** - * TODO(developer): Update these variables before running the sample. - */ - -async function generateContent( - projectId = 'PROJECT_ID', - location = 'us-central1', - model = 'gemini-2.5-flash' -) { - // Initialize client - const client = new GoogleGenAI({ - vertexai: true, - project: projectId, - location: location, - }); - - const request = { - model: model, - contents: [ - { - role: 'user', - parts: [ - { - fileData: { - fileUri: 'gs://cloud-samples-data/video/animals.mp4', - mimeType: 'video/mp4', - }, - }, - { - fileData: { - fileUri: - 'gs://cloud-samples-data/generative-ai/image/character.jpg', - mimeType: 'image/jpeg', - }, - }, - {text: 'Are this video and image correlated?'}, - ], - }, - ], - }; - - const responseStream = await client.models.generateContentStream(request); - - for await (const chunk of responseStream) { - console.log(chunk.text); - } -} - -generateContent(...process.argv.slice(2)).catch(err => { - console.error(err.message); - process.exitCode = 1; -}); diff --git a/generative-ai/snippets/inference/streamTextBasic.js b/generative-ai/snippets/inference/streamTextBasic.js deleted file mode 100644 index ef4f960704..0000000000 --- a/generative-ai/snippets/inference/streamTextBasic.js +++ /dev/null @@ -1,58 +0,0 @@ -// 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 {GoogleGenAI} = require('@google/genai'); - -/** - * TODO(developer): Update these variables before running the sample. - */ - -async function generateContent( - projectId = 'PROJECT_ID', - location = 'us-central1', - model = 'gemini-2.5-flash' -) { - // Initialize client with your Cloud project and location - const client = new GoogleGenAI({ - vertexai: true, - project: projectId, - location: location, - }); - - const request = { - model: model, - contents: [ - { - role: 'user', - parts: [ - { - text: 'Write a story about a magic backpack.', - }, - ], - }, - ], - }; - console.log(JSON.stringify(request)); - - const responseStream = await client.models.generateContentStream(request); - - for await (const chunk of responseStream) { - console.log(chunk.text); - } -} - -generateContent(...process.argv.slice(2)).catch(err => { - console.error(err.message); - process.exitCode = 1; -}); diff --git a/generative-ai/snippets/streamMultipartContent.js b/generative-ai/snippets/streamMultipartContent.js deleted file mode 100644 index e4d7f58d6d..0000000000 --- a/generative-ai/snippets/streamMultipartContent.js +++ /dev/null @@ -1,68 +0,0 @@ -// 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. - -const {VertexAI} = require('@google-cloud/vertexai'); - -/** - * TODO(developer): Update these variables before running the sample. - */ -async function createStreamMultipartContent( - projectId = 'PROJECT_ID', - location = 'us-central1', - model = 'gemini-2.0-flash-001', - image = 'gs://generativeai-downloads/images/scones.jpg', - mimeType = 'image/jpeg' -) { - // Initialize Vertex with your Cloud project and location - const vertexAI = new VertexAI({project: projectId, location: location}); - - // Instantiate the model - const generativeVisionModel = vertexAI.getGenerativeModel({ - model: model, - }); - - // For images, the SDK supports both Google Cloud Storage URI and base64 strings - const filePart = { - fileData: { - fileUri: image, - mimeType: mimeType, - }, - }; - - const textPart = { - text: 'what is shown in this image?', - }; - - const request = { - contents: [{role: 'user', parts: [filePart, textPart]}], - }; - - console.log('Prompt Text:'); - console.log(request.contents[0].parts[1].text); - console.log('Streaming Response Text:'); - - // Create the response stream - const responseStream = - await generativeVisionModel.generateContentStream(request); - - // Log the text response as it streams - for await (const item of responseStream.stream) { - process.stdout.write(item.candidates[0].content.parts[0].text); - } -} - -createStreamMultipartContent(...process.argv.slice(2)).catch(err => { - console.error(err.message); - process.exitCode = 1; -}); diff --git a/generative-ai/snippets/test/inference/nonStreamMultiModalityBasic.test.js b/generative-ai/snippets/test/inference/nonStreamMultiModalityBasic.test.js deleted file mode 100644 index b86671c7d0..0000000000 --- a/generative-ai/snippets/test/inference/nonStreamMultiModalityBasic.test.js +++ /dev/null @@ -1,33 +0,0 @@ -// 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. - -'use strict'; - -const {assert} = require('chai'); -const {describe, it} = require('mocha'); -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const projectId = process.env.GOOGLE_SAMPLES_PROJECT; -const location = process.env.LOCATION; -const model = 'gemini-2.5-flash'; - -describe('Generative AI Multimodal Text Inference', () => { - it('should generate text based on a prompt containing text, a video, and an image', async () => { - const output = execSync( - `node ./inference/nonStreamMultiModalityBasic.js ${projectId} ${location} ${model}` - ); - assert(output.length > 0); - }); -}); diff --git a/generative-ai/snippets/test/inference/nonStreamTextBasic.test.js b/generative-ai/snippets/test/inference/nonStreamTextBasic.test.js deleted file mode 100644 index e106744c27..0000000000 --- a/generative-ai/snippets/test/inference/nonStreamTextBasic.test.js +++ /dev/null @@ -1,35 +0,0 @@ -// 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. - -'use strict'; - -const {assert} = require('chai'); -const {describe, it} = require('mocha'); -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const projectId = process.env.GOOGLE_SAMPLES_PROJECT; -const location = process.env.LOCATION; -const model = 'gemini-2.5-flash'; - -describe('Generative AI Basic Text Inference', () => { - it('should create a generative text model and infer text from a prompt', async () => { - const output = execSync( - `node ./inference/nonStreamTextBasic.js ${projectId} ${location} ${model}` - ); - - // Assert that the correct prompt was issued - assert(output.match(/Write a story about a magic backpack/)); - }); -}); diff --git a/generative-ai/snippets/test/inference/streamMultiModalityBasic.test.js b/generative-ai/snippets/test/inference/streamMultiModalityBasic.test.js deleted file mode 100644 index 3f95952cca..0000000000 --- a/generative-ai/snippets/test/inference/streamMultiModalityBasic.test.js +++ /dev/null @@ -1,33 +0,0 @@ -// 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. - -'use strict'; - -const {assert} = require('chai'); -const {describe, it} = require('mocha'); -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const projectId = process.env.GOOGLE_SAMPLES_PROJECT; -const location = process.env.LOCATION; -const model = 'gemini-2.5-flash'; - -describe('Generative AI Basic Multimodal Text Inference Streaming', () => { - it('should create a generative text model and infer text from a prompt, streaming the results', async () => { - const output = execSync( - `node ./inference/streamMultiModalityBasic.js ${projectId} ${location} ${model}` - ); - assert(output.length > 0); - }); -}); diff --git a/generative-ai/snippets/test/inference/streamTextBasic.test.js b/generative-ai/snippets/test/inference/streamTextBasic.test.js deleted file mode 100644 index b3f2b1eea7..0000000000 --- a/generative-ai/snippets/test/inference/streamTextBasic.test.js +++ /dev/null @@ -1,33 +0,0 @@ -// 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. - -'use strict'; - -const {assert} = require('chai'); -const {describe, it} = require('mocha'); -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const projectId = process.env.GOOGLE_SAMPLES_PROJECT; -const location = process.env.LOCATION; -const model = 'gemini-2.5-flash'; - -describe('Generative AI Basic Text Inference Streaming', () => { - it('should create a generative text model and infer text from a prompt, streaming the results', async () => { - const output = execSync( - `node ./inference/streamTextBasic.js ${projectId} ${location} ${model}` - ); - assert(output.length > 0); - }); -}); diff --git a/generative-ai/snippets/test/streamMultipartContent.test.js b/generative-ai/snippets/test/streamMultipartContent.test.js deleted file mode 100644 index ad5e7b6dcc..0000000000 --- a/generative-ai/snippets/test/streamMultipartContent.test.js +++ /dev/null @@ -1,49 +0,0 @@ -// 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'; - -const {assert} = require('chai'); -const {describe, it} = require('mocha'); -const cp = require('child_process'); -const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'}); - -const projectId = process.env.CAIP_PROJECT_ID; -const location = process.env.LOCATION; -const model = 'gemini-2.0-flash-001'; - -describe.skip('Generative AI Stream Multipart Content', () => { - /** - * TODO(developer): Uncomment these variables before running the sample.\ - * (Not necessary if passing values as arguments) - */ - // const projectId = 'YOUR_PROJECT_ID'; - // const location = 'YOUR_LOCATION'; - // const model = 'gemini-2.0-flash-001'; - - const image = 'gs://generativeai-downloads/images/scones.jpg'; - - it('should create stream multipart content', async () => { - const output = execSync( - `node ./streamMultipartContent.js ${projectId} ${location} ${model} ${image}` - ); - // Split up conversation output - const conversation = output.split('\n'); - - // Ensure that the conversation is what we expect for this scone image - assert(conversation[0].match(/Prompt Text:/)); - assert(conversation[1].match(/what is shown in this image/)); - assert(conversation[2].match(/Streaming Response Text:/)); - }); -}); From 779d4c77a5d4799db13e308004fc41caaa1c9014 Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Thu, 30 Jul 2026 11:04:00 -0600 Subject: [PATCH 27/34] fix(imagemagick): bump sharp to ^0.35.3 to resolve libvips CVEs (#4392) --- functions/imagemagick/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions/imagemagick/package.json b/functions/imagemagick/package.json index 5b7a94b5d6..10a5af2232 100644 --- a/functions/imagemagick/package.json +++ b/functions/imagemagick/package.json @@ -17,7 +17,7 @@ "dependencies": { "@google-cloud/storage": "^7.0.0", "@google-cloud/vision": "^4.0.0", - "sharp": "^0.34.5" + "sharp": "^0.35.3" }, "devDependencies": { "@google-cloud/functions-framework": "^3.0.0", From 4c654a7ebde3d59347f73be94ca00132b5eb87b2 Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Thu, 30 Jul 2026 11:09:55 -0600 Subject: [PATCH 28/34] fix(ci): fix formatting and non-breaking spaces in iam-deny workflow (#4393) * fix(ci): fix formatting and non-breaking spaces in iam-deny workflow * fix(ci): update actions/cache comment to match v4.2.4 hash --- .github/workflows/iam-deny.yaml | 90 ++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 40 deletions(-) diff --git a/.github/workflows/iam-deny.yaml b/.github/workflows/iam-deny.yaml index ee8f474fba..cf9830de47 100644 --- a/.github/workflows/iam-deny.yaml +++ b/.github/workflows/iam-deny.yaml @@ -12,26 +12,26 @@ # See the License for the specific language governing permissions and # limitations under the License. - name: iam-deny on: push: branches: - - main + - main paths: - - 'iam/deny/**' - - '.github/workflows/iam-deny.yaml' + - 'iam/deny/**' + - '.github/workflows/iam-deny.yaml' pull_request: types: - - opened - - reopened - - synchronize - - labeled + - opened + - reopened + - synchronize + - labeled paths: - - 'iam/deny/**' - - '.github/workflows/iam-deny.yaml' + - 'iam/deny/**' + - '.github/workflows/iam-deny.yaml' schedule: - - cron: '0 0 * * 0' + - cron: '0 0 * * 0' + jobs: test: permissions: @@ -44,38 +44,48 @@ jobs: run: working-directory: 'iam/deny' steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - ref: ${{github.event.pull_request.head.sha}} - - uses: 'google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093' # v3.0.0 - with: - workload_identity_provider: 'projects/949737848314/locations/global/workloadIdentityPools/iam-deny-test-pool/providers/iam-deny-test-provider' - service_account: 'kokoro-ca@isakovf-iam-deny-samples.iam.gserviceaccount.com' - create_credentials_file: 'true' - access_token_lifetime: 600s - - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 - with: + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + ref: ${{ github.event.pull_request.head.sha }} + + - uses: 'google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093' # v3.0.0 + with: + workload_identity_provider: 'projects/949737848314/locations/global/workloadIdentityPools/iam-deny-test-pool/providers/iam-deny-test-provider' + service_account: 'kokoro-ca@isakovf-iam-deny-samples.iam.gserviceaccount.com' + create_credentials_file: 'true' + access_token_lifetime: 600s + + - uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 + with: node-version: 16 - - name: Get npm cache directory - id: npm-cache-dir - shell: bash - run: echo "dir=$(npm config get cache)" >> ${GITHUB_OUTPUT} - - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4 - id: npm-cache - with: + + - name: Get npm cache directory + id: npm-cache-dir + shell: bash + run: echo "dir=$(npm config get cache)" >> ${GITHUB_OUTPUT} + + - uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4 + id: npm-cache + with: path: ${{ steps.npm-cache-dir.outputs.dir }} key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} - restore-keys: "${{ runner.os }}-node- \n" - - name: install repo dependencies - run: npm install - working-directory: . - - name: install directory dependencies - run: npm install - - run: npm run build --if-present - - name: set env vars for scheduled run - if: github.event.action == 'schedule' - run: | + restore-keys: | + ${{ runner.os }}-node- + + - name: install repo dependencies + run: npm install + working-directory: . + + - name: install directory dependencies + run: npm install + + - run: npm run build --if-present + + - name: set env vars for scheduled run + if: github.event.action == 'schedule' + run: | echo "MOCHA_REPORTER_SUITENAME=iam-deny" >> $GITHUB_ENV echo "MOCHA_REPORTER_OUTPUT=${{github.run_id}}_sponge_log.xml" >> $GITHUB_ENV echo "MOCHA_REPORTER=xunit" >> $GITHUB_ENV - - run: npm test + + - run: npm test \ No newline at end of file From 793a61660a5d7c34d336bdf2b65a922f500989a0 Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Fri, 31 Jul 2026 12:39:15 -0600 Subject: [PATCH 29/34] fix(functions-v2-imagemagick): upgrade sharp to fix inherited libvips vulnerabilities (#4395) --- functions/v2/imagemagick/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions/v2/imagemagick/package.json b/functions/v2/imagemagick/package.json index 3b9b2ede57..1d23bc56f8 100644 --- a/functions/v2/imagemagick/package.json +++ b/functions/v2/imagemagick/package.json @@ -18,7 +18,7 @@ "@google-cloud/functions-framework": "^3.1.0", "@google-cloud/storage": "^7.0.0", "@google-cloud/vision": "^4.0.0", - "sharp": "^0.34.5" + "sharp": "^0.35.3" }, "devDependencies": { "c8": "^10.0.0", From 0d1cfb7da94a6b20e199ec229339d0e2e59f65a4 Mon Sep 17 00:00:00 2001 From: Angel Caamal Date: Fri, 31 Jul 2026 14:45:16 -0600 Subject: [PATCH 30/34] fix(run-image-processing): upgrade sharp to fix inherited libvips vulnerabilities (#4396) --- run/image-processing/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run/image-processing/package.json b/run/image-processing/package.json index 8b062ebf5b..456795d83a 100644 --- a/run/image-processing/package.json +++ b/run/image-processing/package.json @@ -22,7 +22,7 @@ "@google-cloud/storage": "^7.0.0", "@google-cloud/vision": "^4.0.0", "express": "^4.16.4", - "sharp": "^0.34.5" + "sharp": "^0.35.3" }, "devDependencies": { "c8": "^10.0.0", From 7de14fa470fec4e9931d548b61a8ffc02a70a022 Mon Sep 17 00:00:00 2001 From: Thiyagu K Date: Fri, 12 Jun 2026 11:54:39 +0000 Subject: [PATCH 31/34] feat(storage): add samples and system tests for GCS bucket IP filtering operations --- storage/deleteBucketIpFilterRules.js | 63 +++++++++++++++++++++++ storage/disableBucketIpFilter.js | 48 ++++++++++++++++++ storage/enableBucketIpFilter.js | 68 +++++++++++++++++++++++++ storage/getBucketIpFilter.js | 47 ++++++++++++++++++ storage/listBucketIpFilters.js | 74 ++++++++++++++++++++++++++++ storage/system-test/buckets.test.js | 36 ++++++++++++++ 6 files changed, 336 insertions(+) create mode 100644 storage/deleteBucketIpFilterRules.js create mode 100644 storage/disableBucketIpFilter.js create mode 100644 storage/enableBucketIpFilter.js create mode 100644 storage/getBucketIpFilter.js create mode 100644 storage/listBucketIpFilters.js diff --git a/storage/deleteBucketIpFilterRules.js b/storage/deleteBucketIpFilterRules.js new file mode 100644 index 0000000000..cc419069da --- /dev/null +++ b/storage/deleteBucketIpFilterRules.js @@ -0,0 +1,63 @@ +// Copyright 2026 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. + +'use strict'; + +function main(bucketName = 'my-bucket') { + // [START storage_delete_ip_filtering_rules] + /** + * TODO(developer): Uncomment the following lines before running the sample. + */ + // The ID of your GCS bucket + // const bucketName = 'your-unique-bucket-name'; + + // Imports the Google Cloud client library + const {Storage} = require('@google-cloud/storage'); + + // Creates a client + const storage = new Storage(); + + async function deleteBucketIpFilterRules() { + // Note: To delete specific rules, you fetch the existing config, filter out the rules, and update. + const [metadata] = await storage.bucket(bucketName).getMetadata(); + + if (!metadata.ipFilter) { + console.log(`No IP Filter configuration found for bucket ${bucketName}.`); + return; + } + + const updatedIpRanges = ( + metadata.ipFilter.publicNetworkSource?.allowedIpCidrRanges || [] + ).filter(range => range !== '8.8.8.8/32'); + + const updatedIpFilter = { + ...metadata.ipFilter, + publicNetworkSource: { + allowedIpCidrRanges: updatedIpRanges, + }, + }; + + const [updatedMetadata] = await storage.bucket(bucketName).setMetadata({ + ipFilter: updatedIpFilter, + }); + + console.log(`Specific IP Filter rules deleted for bucket ${bucketName}.`); + console.log(JSON.stringify(updatedMetadata.ipFilter, null, 2)); + } + + deleteBucketIpFilterRules().catch(console.error); + // [END storage_delete_ip_filtering_rules] +} + +main(...process.argv.slice(2)); diff --git a/storage/disableBucketIpFilter.js b/storage/disableBucketIpFilter.js new file mode 100644 index 0000000000..63bbff6e84 --- /dev/null +++ b/storage/disableBucketIpFilter.js @@ -0,0 +1,48 @@ +// Copyright 2026 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. + +'use strict'; + +function main(bucketName = 'my-bucket') { + // [START storage_disable_ip_filtering] + /** + * TODO(developer): Uncomment the following lines before running the sample. + */ + // The ID of your GCS bucket + // const bucketName = 'your-unique-bucket-name'; + + // Imports the Google Cloud client library + const {Storage} = require('@google-cloud/storage'); + + // Creates a client + const storage = new Storage(); + + async function disableBucketIpFilter() { + const ipFilter = { + mode: 'Disabled', + }; + + const [updatedMetadata] = await storage.bucket(bucketName).setMetadata({ + ipFilter, + }); + + console.log(`IP Filter disabled for bucket ${bucketName}.`); + console.log(JSON.stringify(updatedMetadata.ipFilter, null, 2)); + } + + disableBucketIpFilter().catch(console.error); + // [END storage_disable_ip_filtering] +} + +main(...process.argv.slice(2)); diff --git a/storage/enableBucketIpFilter.js b/storage/enableBucketIpFilter.js new file mode 100644 index 0000000000..060fca0f99 --- /dev/null +++ b/storage/enableBucketIpFilter.js @@ -0,0 +1,68 @@ +// Copyright 2026 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. + +'use strict'; + +function main(bucketName = 'my-bucket', filterMode = 'Enabled') { + // [START storage_enable_ip_filtering] + /** + * TODO(developer): Uncomment the following lines before running the sample. + */ + // The ID of your GCS bucket + // const bucketName = 'your-unique-bucket-name'; + + // Imports the Google Cloud client library + const {Storage} = require('@google-cloud/storage'); + + // Creates a client + const storage = new Storage(); + + async function enableBucketIpFilter() { + // Note: IP Filter configurations cannot be partially updated. + // We must fetch the existing configuration and modify it, or set a completely new one. + const [metadata] = await storage.bucket(bucketName).getMetadata(); + const existingIpFilter = metadata.ipFilter || { + mode: filterMode, + publicNetworkSource: {allowedIpCidrRanges: ['0.0.0.0/0']}, + allowCrossOrgVpcs: false, + allowAllServiceAgentAccess: false, + }; + + // Add a new IP range to publicNetworkSource + const updatedIpRanges = + existingIpFilter.publicNetworkSource?.allowedIpCidrRanges || []; + if (!updatedIpRanges.includes('8.8.8.8/32')) { + updatedIpRanges.push('8.8.8.8/32'); + } + + const updatedIpFilter = { + ...existingIpFilter, + publicNetworkSource: { + allowedIpCidrRanges: updatedIpRanges, + }, + }; + + const [updatedMetadata] = await storage.bucket(bucketName).setMetadata({ + ipFilter: updatedIpFilter, + }); + + console.log(`IP Filter enabled for bucket ${bucketName}.`); + console.log(JSON.stringify(updatedMetadata.ipFilter, null, 2)); + } + + enableBucketIpFilter().catch(console.error); + // [END storage_enable_ip_filtering] +} + +main(...process.argv.slice(2)); diff --git a/storage/getBucketIpFilter.js b/storage/getBucketIpFilter.js new file mode 100644 index 0000000000..f8a67a9fe7 --- /dev/null +++ b/storage/getBucketIpFilter.js @@ -0,0 +1,47 @@ +// Copyright 2026 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. + +'use strict'; + +function main(bucketName = 'my-bucket') { + // [START storage_get_ip_filtering] + /** + * TODO(developer): Uncomment the following lines before running the sample. + */ + // The ID of your GCS bucket + // const bucketName = 'your-unique-bucket-name'; + + // Imports the Google Cloud client library + const {Storage} = require('@google-cloud/storage'); + + // Creates a client + const storage = new Storage(); + + async function getBucketIpFilter() { + const [metadata] = await storage.bucket(bucketName).getMetadata(); + + if (metadata.ipFilter) { + console.log(`IP Filter Mode: ${metadata.ipFilter.mode}`); + console.log('IP Filter Configuration:'); + console.log(JSON.stringify(metadata.ipFilter, null, 2)); + } else { + console.log(`No IP Filter configuration found for bucket ${bucketName}.`); + } + } + + getBucketIpFilter().catch(console.error); + // [END storage_get_ip_filtering] +} + +main(...process.argv.slice(2)); diff --git a/storage/listBucketIpFilters.js b/storage/listBucketIpFilters.js new file mode 100644 index 0000000000..ce8b4083a4 --- /dev/null +++ b/storage/listBucketIpFilters.js @@ -0,0 +1,74 @@ +// Copyright 2026 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. + +'use strict'; + +function main(projectId = 'my-project-id') { + // [START storage_list_buckets_ip_filtering] + /** + * TODO(developer): Uncomment the following lines before running the sample. + */ + // The ID of the project to which the service account belongs + // const projectId = 'my-project-id'; + + // Imports the Google Cloud client library + const {Storage} = require('@google-cloud/storage'); + + // Creates a client + const storage = new Storage({projectId}); + + async function listBucketsIpFiltering() { + const [buckets] = await storage.getBuckets(); + + for (const bucket of buckets) { + if (bucket.metadata.ipFilter) { + try { + const [metadata] = await storage.bucket(bucket.name).getMetadata(); + const ipFilter = metadata.ipFilter; + console.log(`${bucket.name}: IP Filter Mode - ${ipFilter.mode}`); + + const publicNetworkSource = ipFilter.publicNetworkSource; + if (publicNetworkSource && publicNetworkSource.allowedIpCidrRanges) { + console.log(' Public Network Allowed IP Ranges:'); + publicNetworkSource.allowedIpCidrRanges.forEach(range => { + console.log(` - ${range}`); + }); + } + + const vpcNetworkSources = ipFilter.vpcNetworkSources; + if (vpcNetworkSources && vpcNetworkSources.length > 0) { + console.log(' VPC Network Sources:'); + vpcNetworkSources.forEach(source => { + console.log(` - Network: ${source.network}`); + if (source.allowedIpCidrRanges) { + source.allowedIpCidrRanges.forEach(range => { + console.log(` - ${range}`); + }); + } + }); + } + } catch (err) { + console.log( + `${bucket.name}: Error fetching IP filter - ${err.message}` + ); + } + } + } + } + + listBucketsIpFiltering().catch(console.error); + // [END storage_list_buckets_ip_filtering] +} + +main(...process.argv.slice(2)); diff --git a/storage/system-test/buckets.test.js b/storage/system-test/buckets.test.js index d5055007d8..575ae3d837 100644 --- a/storage/system-test/buckets.test.js +++ b/storage/system-test/buckets.test.js @@ -141,3 +141,39 @@ it('should update and then remove bucket encryption enforcement configuration', const [metadata] = await bucket.getMetadata(); assert.ok(!metadata.encryption); }); + +it('should enable the bucket IP filter', () => { + const output = execSync( + `node enableBucketIpFilter.js ${bucketName} Disabled` + ); + assert.include(output, `IP Filter enabled for bucket ${bucketName}.`); + assert.include(output, '8.8.8.8/32'); +}); + +it('should get the bucket IP filter', () => { + const output = execSync(`node getBucketIpFilter.js ${bucketName}`); + assert.include(output, 'IP Filter Mode: Disabled'); + assert.include(output, '8.8.8.8/32'); +}); + +it('should list the bucket IP filters', () => { + const projectId = process.env.GCLOUD_PROJECT; + const output = execSync(`node listBucketIpFilters.js ${projectId}`); + assert.include(output, `${bucketName}: IP Filter Mode - Disabled`); + assert.include(output, 'Public Network Allowed IP Ranges:'); + assert.include(output, '- 8.8.8.8/32'); +}); + +it('should delete specific bucket IP filter rules', () => { + const output = execSync(`node deleteBucketIpFilterRules.js ${bucketName}`); + assert.include( + output, + `Specific IP Filter rules deleted for bucket ${bucketName}.` + ); +}); + +it('should disable the bucket IP filter', () => { + const output = execSync(`node disableBucketIpFilter.js ${bucketName}`); + assert.include(output, `IP Filter disabled for bucket ${bucketName}.`); + assert.include(output, '"mode": "Disabled"'); +}); From 82c81ff086bfae2ab02f2ddd42f6826a5d502ac1 Mon Sep 17 00:00:00 2001 From: Thiyagu K Date: Fri, 12 Jun 2026 12:09:36 +0000 Subject: [PATCH 32/34] feat: update storage bucket IP filter samples to preserve existing metadata and optimize list retrieval --- storage/deleteBucketIpFilterRules.js | 1 + storage/enableBucketIpFilter.js | 2 ++ storage/listBucketIpFilters.js | 49 ++++++++++++---------------- 3 files changed, 24 insertions(+), 28 deletions(-) diff --git a/storage/deleteBucketIpFilterRules.js b/storage/deleteBucketIpFilterRules.js index cc419069da..26ce449739 100644 --- a/storage/deleteBucketIpFilterRules.js +++ b/storage/deleteBucketIpFilterRules.js @@ -44,6 +44,7 @@ function main(bucketName = 'my-bucket') { const updatedIpFilter = { ...metadata.ipFilter, publicNetworkSource: { + ...metadata.ipFilter.publicNetworkSource, allowedIpCidrRanges: updatedIpRanges, }, }; diff --git a/storage/enableBucketIpFilter.js b/storage/enableBucketIpFilter.js index 060fca0f99..7c78e83b3e 100644 --- a/storage/enableBucketIpFilter.js +++ b/storage/enableBucketIpFilter.js @@ -48,7 +48,9 @@ function main(bucketName = 'my-bucket', filterMode = 'Enabled') { const updatedIpFilter = { ...existingIpFilter, + mode: filterMode, publicNetworkSource: { + ...existingIpFilter.publicNetworkSource, allowedIpCidrRanges: updatedIpRanges, }, }; diff --git a/storage/listBucketIpFilters.js b/storage/listBucketIpFilters.js index ce8b4083a4..c51bcdd065 100644 --- a/storage/listBucketIpFilters.js +++ b/storage/listBucketIpFilters.js @@ -32,36 +32,29 @@ function main(projectId = 'my-project-id') { const [buckets] = await storage.getBuckets(); for (const bucket of buckets) { - if (bucket.metadata.ipFilter) { - try { - const [metadata] = await storage.bucket(bucket.name).getMetadata(); - const ipFilter = metadata.ipFilter; - console.log(`${bucket.name}: IP Filter Mode - ${ipFilter.mode}`); + const ipFilter = bucket.metadata?.ipFilter; + if (ipFilter) { + console.log(`${bucket.name}: IP Filter Mode - ${ipFilter.mode}`); - const publicNetworkSource = ipFilter.publicNetworkSource; - if (publicNetworkSource && publicNetworkSource.allowedIpCidrRanges) { - console.log(' Public Network Allowed IP Ranges:'); - publicNetworkSource.allowedIpCidrRanges.forEach(range => { - console.log(` - ${range}`); - }); - } + const publicNetworkSource = ipFilter.publicNetworkSource; + if (publicNetworkSource && publicNetworkSource.allowedIpCidrRanges) { + console.log(' Public Network Allowed IP Ranges:'); + publicNetworkSource.allowedIpCidrRanges.forEach(range => { + console.log(` - ${range}`); + }); + } - const vpcNetworkSources = ipFilter.vpcNetworkSources; - if (vpcNetworkSources && vpcNetworkSources.length > 0) { - console.log(' VPC Network Sources:'); - vpcNetworkSources.forEach(source => { - console.log(` - Network: ${source.network}`); - if (source.allowedIpCidrRanges) { - source.allowedIpCidrRanges.forEach(range => { - console.log(` - ${range}`); - }); - } - }); - } - } catch (err) { - console.log( - `${bucket.name}: Error fetching IP filter - ${err.message}` - ); + const vpcNetworkSources = ipFilter.vpcNetworkSources; + if (vpcNetworkSources && vpcNetworkSources.length > 0) { + console.log(' VPC Network Sources:'); + vpcNetworkSources.forEach(source => { + console.log(` - Network: ${source.network}`); + if (source.allowedIpCidrRanges) { + source.allowedIpCidrRanges.forEach(range => { + console.log(` - ${range}`); + }); + } + }); } } } From ea52eef8ebb8ab1a7f9f7775a609e6489a286152 Mon Sep 17 00:00:00 2001 From: Thiyagu K Date: Fri, 12 Jun 2026 12:13:45 +0000 Subject: [PATCH 33/34] feat: fetch fresh bucket metadata to display detailed IP filter information with error handling --- storage/listBucketIpFilters.js | 49 +++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/storage/listBucketIpFilters.js b/storage/listBucketIpFilters.js index c51bcdd065..3f10b0ff6c 100644 --- a/storage/listBucketIpFilters.js +++ b/storage/listBucketIpFilters.js @@ -32,29 +32,36 @@ function main(projectId = 'my-project-id') { const [buckets] = await storage.getBuckets(); for (const bucket of buckets) { - const ipFilter = bucket.metadata?.ipFilter; - if (ipFilter) { - console.log(`${bucket.name}: IP Filter Mode - ${ipFilter.mode}`); + if (bucket.metadata?.ipFilter) { + try { + const [metadata] = await storage.bucket(bucket.name).getMetadata(); + const ipFilter = metadata.ipFilter; + console.log(`${bucket.name}: IP Filter Mode - ${ipFilter.mode}`); - const publicNetworkSource = ipFilter.publicNetworkSource; - if (publicNetworkSource && publicNetworkSource.allowedIpCidrRanges) { - console.log(' Public Network Allowed IP Ranges:'); - publicNetworkSource.allowedIpCidrRanges.forEach(range => { - console.log(` - ${range}`); - }); - } + const publicNetworkSource = ipFilter.publicNetworkSource; + if (publicNetworkSource && publicNetworkSource.allowedIpCidrRanges) { + console.log(' Public Network Allowed IP Ranges:'); + publicNetworkSource.allowedIpCidrRanges.forEach(range => { + console.log(` - ${range}`); + }); + } - const vpcNetworkSources = ipFilter.vpcNetworkSources; - if (vpcNetworkSources && vpcNetworkSources.length > 0) { - console.log(' VPC Network Sources:'); - vpcNetworkSources.forEach(source => { - console.log(` - Network: ${source.network}`); - if (source.allowedIpCidrRanges) { - source.allowedIpCidrRanges.forEach(range => { - console.log(` - ${range}`); - }); - } - }); + const vpcNetworkSources = ipFilter.vpcNetworkSources; + if (vpcNetworkSources && vpcNetworkSources.length > 0) { + console.log(' VPC Network Sources:'); + vpcNetworkSources.forEach(source => { + console.log(` - Network: ${source.network}`); + if (source.allowedIpCidrRanges) { + source.allowedIpCidrRanges.forEach(range => { + console.log(` - ${range}`); + }); + } + }); + } + } catch (err) { + console.log( + `${bucket.name}: Error fetching IP filter - ${err.message}` + ); } } } From faf2cf5cefae291a7a37b94c78043faf0383c6b2 Mon Sep 17 00:00:00 2001 From: Thiyagu K Date: Fri, 12 Jun 2026 15:08:37 +0000 Subject: [PATCH 34/34] feat: update bucket IP filter logging to display current mode and safely clone IP ranges --- storage/enableBucketIpFilter.js | 7 ++++--- storage/system-test/buckets.test.js | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/storage/enableBucketIpFilter.js b/storage/enableBucketIpFilter.js index 7c78e83b3e..45ee063e23 100644 --- a/storage/enableBucketIpFilter.js +++ b/storage/enableBucketIpFilter.js @@ -40,8 +40,9 @@ function main(bucketName = 'my-bucket', filterMode = 'Enabled') { }; // Add a new IP range to publicNetworkSource - const updatedIpRanges = - existingIpFilter.publicNetworkSource?.allowedIpCidrRanges || []; + const updatedIpRanges = [ + ...(existingIpFilter.publicNetworkSource?.allowedIpCidrRanges || []), + ]; if (!updatedIpRanges.includes('8.8.8.8/32')) { updatedIpRanges.push('8.8.8.8/32'); } @@ -59,7 +60,7 @@ function main(bucketName = 'my-bucket', filterMode = 'Enabled') { ipFilter: updatedIpFilter, }); - console.log(`IP Filter enabled for bucket ${bucketName}.`); + console.log(`IP Filter mode set to ${updatedMetadata.ipFilter.mode} for bucket ${bucketName}.`); console.log(JSON.stringify(updatedMetadata.ipFilter, null, 2)); } diff --git a/storage/system-test/buckets.test.js b/storage/system-test/buckets.test.js index 575ae3d837..2020c06519 100644 --- a/storage/system-test/buckets.test.js +++ b/storage/system-test/buckets.test.js @@ -146,7 +146,7 @@ it('should enable the bucket IP filter', () => { const output = execSync( `node enableBucketIpFilter.js ${bucketName} Disabled` ); - assert.include(output, `IP Filter enabled for bucket ${bucketName}.`); + assert.include(output, `IP Filter mode set to Disabled for bucket ${bucketName}.`); assert.include(output, '8.8.8.8/32'); });