From 63f8eb63a4db541d6e2d582f92c8012b71803c07 Mon Sep 17 00:00:00 2001 From: A Vertex SDK engineer Date: Wed, 5 Aug 2026 20:07:51 -0700 Subject: [PATCH] feat: Add sandbox templates and snapshots submodules to the Vertex AI GenAI SDK for JavaScript. Adds the Agent Engine sandbox `templates` and `snapshots` submodules to the JS/TypeScript SDK, exposed as `sandboxes.templates` and `sandboxes.snapshots`, matching the Python SDK surface. Includes an e2e system-test sample and replay-based unit tests. PiperOrigin-RevId: 960014771 --- .../_sandboxsnapshots_converters.ts | 145 ++++++ .../_sandboxtemplates_converters.ts | 162 +++++++ src/sandboxes.ts | 7 + src/sandboxsnapshots.ts | 240 ++++++++++ src/sandboxtemplates.ts | 240 ++++++++++ src/types/common.ts | 415 ++++++++++++++++++ .../sandbox_templates_snapshots_e2e_test.ts | 233 ++++++++++ .../agentengines_sandbox_snapshots_test.ts | 82 ++++ .../agentengines_sandbox_templates_test.ts | 104 +++++ 9 files changed, 1628 insertions(+) create mode 100644 src/converters/_sandboxsnapshots_converters.ts create mode 100644 src/converters/_sandboxtemplates_converters.ts create mode 100644 src/sandboxsnapshots.ts create mode 100644 src/sandboxtemplates.ts create mode 100644 system_test/sandbox_templates_snapshots_e2e_test.ts create mode 100644 test/replays/agentengines_sandbox_snapshots_test.ts create mode 100644 test/replays/agentengines_sandbox_templates_test.ts diff --git a/src/converters/_sandboxsnapshots_converters.ts b/src/converters/_sandboxsnapshots_converters.ts new file mode 100644 index 00000000..875442e3 --- /dev/null +++ b/src/converters/_sandboxsnapshots_converters.ts @@ -0,0 +1,145 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +// Code generated by the Google Gen AI SDK generator DO NOT EDIT. + +import * as common from '@google/genai/vertex_internal'; +import * as types from '../types.js'; + +export function createAgentEngineSandboxSnapshotConfigToVertex( + fromObject: types.CreateAgentEngineSandboxSnapshotConfig, + parentObject: Record, +): Record { + const toObject: Record = {}; + + const fromDisplayName = common.getValueByPath(fromObject, ['displayName']); + if (parentObject !== undefined && fromDisplayName != null) { + common.setValueByPath(parentObject, ['displayName'], fromDisplayName); + } + + const fromOwner = common.getValueByPath(fromObject, ['owner']); + if (parentObject !== undefined && fromOwner != null) { + common.setValueByPath(parentObject, ['owner'], fromOwner); + } + + const fromTtl = common.getValueByPath(fromObject, ['ttl']); + if (parentObject !== undefined && fromTtl != null) { + common.setValueByPath(parentObject, ['ttl'], fromTtl); + } + + return toObject; +} + +export function createSandboxEnvironmentSnapshotRequestParametersToVertex( + fromObject: types.CreateSandboxEnvironmentSnapshotRequestParameters, +): Record { + const toObject: Record = {}; + + const fromSourceSandboxEnvironmentName = common.getValueByPath(fromObject, [ + 'sourceSandboxEnvironmentName', + ]); + if (fromSourceSandboxEnvironmentName != null) { + common.setValueByPath( + toObject, + ['_url', 'name'], + fromSourceSandboxEnvironmentName, + ); + } + + const fromConfig = common.getValueByPath(fromObject, ['config']); + if (fromConfig != null) { + createAgentEngineSandboxSnapshotConfigToVertex(fromConfig, toObject); + } + + return toObject; +} + +export function deleteSandboxEnvironmentSnapshotRequestParametersToVertex( + fromObject: types.DeleteSandboxEnvironmentSnapshotRequestParameters, +): Record { + const toObject: Record = {}; + + const fromName = common.getValueByPath(fromObject, ['name']); + if (fromName != null) { + common.setValueByPath(toObject, ['_url', 'name'], fromName); + } + + return toObject; +} + +export function getAgentEngineSandboxSnapshotOperationParametersToVertex( + fromObject: types.GetAgentEngineSandboxSnapshotOperationParameters, +): Record { + const toObject: Record = {}; + + const fromOperationName = common.getValueByPath(fromObject, [ + 'operationName', + ]); + if (fromOperationName != null) { + common.setValueByPath( + toObject, + ['_url', 'operationName'], + fromOperationName, + ); + } + + return toObject; +} + +export function getSandboxEnvironmentSnapshotRequestParametersToVertex( + fromObject: types.GetSandboxEnvironmentSnapshotRequestParameters, +): Record { + const toObject: Record = {}; + + const fromName = common.getValueByPath(fromObject, ['name']); + if (fromName != null) { + common.setValueByPath(toObject, ['_url', 'name'], fromName); + } + + return toObject; +} + +export function listSandboxEnvironmentSnapshotsConfigToVertex( + fromObject: types.ListSandboxEnvironmentSnapshotsConfig, + parentObject: Record, +): Record { + const toObject: Record = {}; + + const fromPageSize = common.getValueByPath(fromObject, ['pageSize']); + if (parentObject !== undefined && fromPageSize != null) { + common.setValueByPath(parentObject, ['_query', 'pageSize'], fromPageSize); + } + + const fromPageToken = common.getValueByPath(fromObject, ['pageToken']); + if (parentObject !== undefined && fromPageToken != null) { + common.setValueByPath(parentObject, ['_query', 'pageToken'], fromPageToken); + } + + const fromFilter = common.getValueByPath(fromObject, ['filter']); + if (parentObject !== undefined && fromFilter != null) { + common.setValueByPath(parentObject, ['_query', 'filter'], fromFilter); + } + + return toObject; +} + +export function listSandboxEnvironmentSnapshotsRequestParametersToVertex( + fromObject: types.ListSandboxEnvironmentSnapshotsRequestParameters, +): Record { + const toObject: Record = {}; + + const fromName = common.getValueByPath(fromObject, ['name']); + if (fromName != null) { + common.setValueByPath(toObject, ['_url', 'name'], fromName); + } + + const fromConfig = common.getValueByPath(fromObject, ['config']); + if (fromConfig != null) { + listSandboxEnvironmentSnapshotsConfigToVertex(fromConfig, toObject); + } + + return toObject; +} diff --git a/src/converters/_sandboxtemplates_converters.ts b/src/converters/_sandboxtemplates_converters.ts new file mode 100644 index 00000000..4674cbf1 --- /dev/null +++ b/src/converters/_sandboxtemplates_converters.ts @@ -0,0 +1,162 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +// Code generated by the Google Gen AI SDK generator DO NOT EDIT. + +import * as common from '@google/genai/vertex_internal'; +import * as types from '../types.js'; + +export function createSandboxEnvironmentTemplateConfigToVertex( + fromObject: types.CreateSandboxEnvironmentTemplateConfig, + parentObject: Record, +): Record { + const toObject: Record = {}; + + const fromCustomContainerEnvironment = common.getValueByPath(fromObject, [ + 'customContainerEnvironment', + ]); + if (parentObject !== undefined && fromCustomContainerEnvironment != null) { + common.setValueByPath( + parentObject, + ['customContainerEnvironment'], + fromCustomContainerEnvironment, + ); + } + + const fromDefaultContainerEnvironment = common.getValueByPath(fromObject, [ + 'defaultContainerEnvironment', + ]); + if (parentObject !== undefined && fromDefaultContainerEnvironment != null) { + common.setValueByPath( + parentObject, + ['defaultContainerEnvironment'], + fromDefaultContainerEnvironment, + ); + } + + const fromEgressControlConfig = common.getValueByPath(fromObject, [ + 'egressControlConfig', + ]); + if (parentObject !== undefined && fromEgressControlConfig != null) { + common.setValueByPath( + parentObject, + ['egressControlConfig'], + fromEgressControlConfig, + ); + } + + return toObject; +} + +export function createSandboxEnvironmentTemplateRequestParametersToVertex( + fromObject: types.CreateSandboxEnvironmentTemplateRequestParameters, +): Record { + const toObject: Record = {}; + + const fromName = common.getValueByPath(fromObject, ['name']); + if (fromName != null) { + common.setValueByPath(toObject, ['_url', 'name'], fromName); + } + + const fromDisplayName = common.getValueByPath(fromObject, ['displayName']); + if (fromDisplayName != null) { + common.setValueByPath(toObject, ['displayName'], fromDisplayName); + } + + const fromConfig = common.getValueByPath(fromObject, ['config']); + if (fromConfig != null) { + createSandboxEnvironmentTemplateConfigToVertex(fromConfig, toObject); + } + + return toObject; +} + +export function deleteSandboxEnvironmentTemplateRequestParametersToVertex( + fromObject: types.DeleteSandboxEnvironmentTemplateRequestParameters, +): Record { + const toObject: Record = {}; + + const fromName = common.getValueByPath(fromObject, ['name']); + if (fromName != null) { + common.setValueByPath(toObject, ['_url', 'name'], fromName); + } + + return toObject; +} + +export function getSandboxEnvironmentTemplateOperationParametersToVertex( + fromObject: types.GetSandboxEnvironmentTemplateOperationParameters, +): Record { + const toObject: Record = {}; + + const fromOperationName = common.getValueByPath(fromObject, [ + 'operationName', + ]); + if (fromOperationName != null) { + common.setValueByPath( + toObject, + ['_url', 'operationName'], + fromOperationName, + ); + } + + return toObject; +} + +export function getSandboxEnvironmentTemplateRequestParametersToVertex( + fromObject: types.GetSandboxEnvironmentTemplateRequestParameters, +): Record { + const toObject: Record = {}; + + const fromName = common.getValueByPath(fromObject, ['name']); + if (fromName != null) { + common.setValueByPath(toObject, ['_url', 'name'], fromName); + } + + return toObject; +} + +export function listSandboxEnvironmentTemplatesConfigToVertex( + fromObject: types.ListSandboxEnvironmentTemplatesConfig, + parentObject: Record, +): Record { + const toObject: Record = {}; + + const fromPageSize = common.getValueByPath(fromObject, ['pageSize']); + if (parentObject !== undefined && fromPageSize != null) { + common.setValueByPath(parentObject, ['_query', 'pageSize'], fromPageSize); + } + + const fromPageToken = common.getValueByPath(fromObject, ['pageToken']); + if (parentObject !== undefined && fromPageToken != null) { + common.setValueByPath(parentObject, ['_query', 'pageToken'], fromPageToken); + } + + const fromFilter = common.getValueByPath(fromObject, ['filter']); + if (parentObject !== undefined && fromFilter != null) { + common.setValueByPath(parentObject, ['_query', 'filter'], fromFilter); + } + + return toObject; +} + +export function listSandboxEnvironmentTemplatesRequestParametersToVertex( + fromObject: types.ListSandboxEnvironmentTemplatesRequestParameters, +): Record { + const toObject: Record = {}; + + const fromName = common.getValueByPath(fromObject, ['name']); + if (fromName != null) { + common.setValueByPath(toObject, ['_url', 'name'], fromName); + } + + const fromConfig = common.getValueByPath(fromObject, ['config']); + if (fromConfig != null) { + listSandboxEnvironmentTemplatesConfigToVertex(fromConfig, toObject); + } + + return toObject; +} diff --git a/src/sandboxes.ts b/src/sandboxes.ts index 8ab45aff..9114124e 100644 --- a/src/sandboxes.ts +++ b/src/sandboxes.ts @@ -9,11 +9,18 @@ import * as common from '@google/genai/vertex_internal'; import {ApiClient, BaseModule} from '@google/genai/vertex_internal'; import * as converters from './converters/_sandboxes_converters.js'; +import {SandboxSnapshots} from './sandboxsnapshots.js'; +import {SandboxTemplates} from './sandboxtemplates.js'; import * as types from './types.js'; export class Sandboxes extends BaseModule { + public readonly templates: SandboxTemplates; + public readonly snapshots: SandboxSnapshots; + constructor(private readonly apiClient: ApiClient) { super(); + this.templates = new SandboxTemplates(apiClient); + this.snapshots = new SandboxSnapshots(apiClient); } async createInternal( diff --git a/src/sandboxsnapshots.ts b/src/sandboxsnapshots.ts new file mode 100644 index 00000000..bfc069eb --- /dev/null +++ b/src/sandboxsnapshots.ts @@ -0,0 +1,240 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +// Code generated by the Google Gen AI SDK generator DO NOT EDIT. + +import * as common from '@google/genai/vertex_internal'; +import {ApiClient, BaseModule} from '@google/genai/vertex_internal'; +import * as converters from './converters/_sandboxsnapshots_converters.js'; +import * as types from './types.js'; + +export class SandboxSnapshots extends BaseModule { + constructor(private readonly apiClient: ApiClient) { + super(); + } + + async createInternal( + params: types.CreateSandboxEnvironmentSnapshotRequestParameters, + ): Promise { + let response: Promise; + + let path: string = ''; + let queryParams: Record = {}; + if (this.apiClient.isVertexAI()) { + const body = + converters.createSandboxEnvironmentSnapshotRequestParametersToVertex( + params, + ); + path = common.formatMap( + '{name}:snapshot', + body['_url'] as Record, + ); + queryParams = body['_query'] as Record; + delete body['_url']; + delete body['_query']; + delete body['config']; + + response = this.apiClient + .request({ + path: path, + queryParams: queryParams, + body: JSON.stringify(body), + httpMethod: 'POST', + httpOptions: params.config?.httpOptions, + abortSignal: params.config?.abortSignal, + }) + .then((httpResponse) => { + return httpResponse.json(); + }) as Promise; + + return response.then((resp) => { + return resp as types.AgentEngineSandboxSnapshotOperation; + }); + } else { + throw new Error( + 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', + ); + } + } + + async deleteInternal( + params: types.DeleteSandboxEnvironmentSnapshotRequestParameters, + ): Promise { + let response: Promise; + + let path: string = ''; + let queryParams: Record = {}; + if (this.apiClient.isVertexAI()) { + const body = + converters.deleteSandboxEnvironmentSnapshotRequestParametersToVertex( + params, + ); + path = common.formatMap( + '{name}', + body['_url'] as Record, + ); + queryParams = body['_query'] as Record; + delete body['_url']; + delete body['_query']; + delete body['config']; + + response = this.apiClient + .request({ + path: path, + queryParams: queryParams, + body: JSON.stringify(body), + httpMethod: 'DELETE', + httpOptions: params.config?.httpOptions, + abortSignal: params.config?.abortSignal, + }) + .then((httpResponse) => { + return httpResponse.json(); + }) as Promise; + + return response.then((resp) => { + return resp as types.DeleteSandboxEnvironmentSnapshotOperation; + }); + } else { + throw new Error( + 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', + ); + } + } + + async getInternal( + params: types.GetSandboxEnvironmentSnapshotRequestParameters, + ): Promise { + let response: Promise; + + let path: string = ''; + let queryParams: Record = {}; + if (this.apiClient.isVertexAI()) { + const body = + converters.getSandboxEnvironmentSnapshotRequestParametersToVertex( + params, + ); + path = common.formatMap( + '{name}', + body['_url'] as Record, + ); + queryParams = body['_query'] as Record; + delete body['_url']; + delete body['_query']; + delete body['config']; + + response = this.apiClient + .request({ + path: path, + queryParams: queryParams, + body: JSON.stringify(body), + httpMethod: 'GET', + httpOptions: params.config?.httpOptions, + abortSignal: params.config?.abortSignal, + }) + .then((httpResponse) => { + return httpResponse.json(); + }) as Promise; + + return response.then((resp) => { + return resp as types.SandboxEnvironmentSnapshot; + }); + } else { + throw new Error( + 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', + ); + } + } + + async listInternal( + params: types.ListSandboxEnvironmentSnapshotsRequestParameters, + ): Promise { + let response: Promise; + + let path: string = ''; + let queryParams: Record = {}; + if (this.apiClient.isVertexAI()) { + const body = + converters.listSandboxEnvironmentSnapshotsRequestParametersToVertex( + params, + ); + path = common.formatMap( + '{name}/sandboxEnvironmentSnapshots', + body['_url'] as Record, + ); + queryParams = body['_query'] as Record; + delete body['_url']; + delete body['_query']; + delete body['config']; + + response = this.apiClient + .request({ + path: path, + queryParams: queryParams, + body: JSON.stringify(body), + httpMethod: 'GET', + httpOptions: params.config?.httpOptions, + abortSignal: params.config?.abortSignal, + }) + .then((httpResponse) => { + return httpResponse.json(); + }) as Promise; + + return response.then((resp) => { + const typedResp = new types.ListSandboxEnvironmentSnapshotsResponse(); + Object.assign(typedResp, resp); + return typedResp; + }); + } else { + throw new Error( + 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', + ); + } + } + + async getSandboxSnapshotOperation( + params: types.GetAgentEngineSandboxSnapshotOperationParameters, + ): Promise { + let response: Promise; + + let path: string = ''; + let queryParams: Record = {}; + if (this.apiClient.isVertexAI()) { + const body = + converters.getAgentEngineSandboxSnapshotOperationParametersToVertex( + params, + ); + path = common.formatMap( + '{operationName}', + body['_url'] as Record, + ); + queryParams = body['_query'] as Record; + delete body['_url']; + delete body['_query']; + delete body['config']; + + response = this.apiClient + .request({ + path: path, + queryParams: queryParams, + body: JSON.stringify(body), + httpMethod: 'GET', + httpOptions: params.config?.httpOptions, + abortSignal: params.config?.abortSignal, + }) + .then((httpResponse) => { + return httpResponse.json(); + }) as Promise; + + return response.then((resp) => { + return resp as types.AgentEngineSandboxSnapshotOperation; + }); + } else { + throw new Error( + 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', + ); + } + } +} diff --git a/src/sandboxtemplates.ts b/src/sandboxtemplates.ts new file mode 100644 index 00000000..0a1c275f --- /dev/null +++ b/src/sandboxtemplates.ts @@ -0,0 +1,240 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +// Code generated by the Google Gen AI SDK generator DO NOT EDIT. + +import * as common from '@google/genai/vertex_internal'; +import {ApiClient, BaseModule} from '@google/genai/vertex_internal'; +import * as converters from './converters/_sandboxtemplates_converters.js'; +import * as types from './types.js'; + +export class SandboxTemplates extends BaseModule { + constructor(private readonly apiClient: ApiClient) { + super(); + } + + async createInternal( + params: types.CreateSandboxEnvironmentTemplateRequestParameters, + ): Promise { + let response: Promise; + + let path: string = ''; + let queryParams: Record = {}; + if (this.apiClient.isVertexAI()) { + const body = + converters.createSandboxEnvironmentTemplateRequestParametersToVertex( + params, + ); + path = common.formatMap( + '{name}/sandboxEnvironmentTemplates', + body['_url'] as Record, + ); + queryParams = body['_query'] as Record; + delete body['_url']; + delete body['_query']; + delete body['config']; + + response = this.apiClient + .request({ + path: path, + queryParams: queryParams, + body: JSON.stringify(body), + httpMethod: 'POST', + httpOptions: params.config?.httpOptions, + abortSignal: params.config?.abortSignal, + }) + .then((httpResponse) => { + return httpResponse.json(); + }) as Promise; + + return response.then((resp) => { + return resp as types.SandboxEnvironmentTemplateOperation; + }); + } else { + throw new Error( + 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', + ); + } + } + + async deleteInternal( + params: types.DeleteSandboxEnvironmentTemplateRequestParameters, + ): Promise { + let response: Promise; + + let path: string = ''; + let queryParams: Record = {}; + if (this.apiClient.isVertexAI()) { + const body = + converters.deleteSandboxEnvironmentTemplateRequestParametersToVertex( + params, + ); + path = common.formatMap( + '{name}', + body['_url'] as Record, + ); + queryParams = body['_query'] as Record; + delete body['_url']; + delete body['_query']; + delete body['config']; + + response = this.apiClient + .request({ + path: path, + queryParams: queryParams, + body: JSON.stringify(body), + httpMethod: 'DELETE', + httpOptions: params.config?.httpOptions, + abortSignal: params.config?.abortSignal, + }) + .then((httpResponse) => { + return httpResponse.json(); + }) as Promise; + + return response.then((resp) => { + return resp as types.DeleteSandboxEnvironmentTemplateOperation; + }); + } else { + throw new Error( + 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', + ); + } + } + + async getInternal( + params: types.GetSandboxEnvironmentTemplateRequestParameters, + ): Promise { + let response: Promise; + + let path: string = ''; + let queryParams: Record = {}; + if (this.apiClient.isVertexAI()) { + const body = + converters.getSandboxEnvironmentTemplateRequestParametersToVertex( + params, + ); + path = common.formatMap( + '{name}', + body['_url'] as Record, + ); + queryParams = body['_query'] as Record; + delete body['_url']; + delete body['_query']; + delete body['config']; + + response = this.apiClient + .request({ + path: path, + queryParams: queryParams, + body: JSON.stringify(body), + httpMethod: 'GET', + httpOptions: params.config?.httpOptions, + abortSignal: params.config?.abortSignal, + }) + .then((httpResponse) => { + return httpResponse.json(); + }) as Promise; + + return response.then((resp) => { + return resp as types.SandboxEnvironmentTemplate; + }); + } else { + throw new Error( + 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', + ); + } + } + + async listInternal( + params: types.ListSandboxEnvironmentTemplatesRequestParameters, + ): Promise { + let response: Promise; + + let path: string = ''; + let queryParams: Record = {}; + if (this.apiClient.isVertexAI()) { + const body = + converters.listSandboxEnvironmentTemplatesRequestParametersToVertex( + params, + ); + path = common.formatMap( + '{name}/sandboxEnvironmentTemplates', + body['_url'] as Record, + ); + queryParams = body['_query'] as Record; + delete body['_url']; + delete body['_query']; + delete body['config']; + + response = this.apiClient + .request({ + path: path, + queryParams: queryParams, + body: JSON.stringify(body), + httpMethod: 'GET', + httpOptions: params.config?.httpOptions, + abortSignal: params.config?.abortSignal, + }) + .then((httpResponse) => { + return httpResponse.json(); + }) as Promise; + + return response.then((resp) => { + const typedResp = new types.ListSandboxEnvironmentTemplatesResponse(); + Object.assign(typedResp, resp); + return typedResp; + }); + } else { + throw new Error( + 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', + ); + } + } + + async getSandboxEnvironmentTemplateOperation( + params: types.GetSandboxEnvironmentTemplateOperationParameters, + ): Promise { + let response: Promise; + + let path: string = ''; + let queryParams: Record = {}; + if (this.apiClient.isVertexAI()) { + const body = + converters.getSandboxEnvironmentTemplateOperationParametersToVertex( + params, + ); + path = common.formatMap( + '{operationName}', + body['_url'] as Record, + ); + queryParams = body['_query'] as Record; + delete body['_url']; + delete body['_query']; + delete body['config']; + + response = this.apiClient + .request({ + path: path, + queryParams: queryParams, + body: JSON.stringify(body), + httpMethod: 'GET', + httpOptions: params.config?.httpOptions, + abortSignal: params.config?.abortSignal, + }) + .then((httpResponse) => { + return httpResponse.json(); + }) as Promise; + + return response.then((resp) => { + return resp as types.SandboxEnvironmentTemplateOperation; + }); + } else { + throw new Error( + 'This method is only supported by the Gemini Enterprise Agent Platform (previously known as Vertex AI).', + ); + } + } +} diff --git a/src/types/common.ts b/src/types/common.ts index abba4d46..2e31f69a 100644 --- a/src/types/common.ts +++ b/src/types/common.ts @@ -156,6 +156,50 @@ export enum SandboxState { STATE_DELETED = 'STATE_DELETED', } +/** Protocol for port. Defaults to TCP if not specified. */ +export enum Protocol { + /** + * Unspecified protocol. Defaults to TCP. + */ + PROTOCOL_UNSPECIFIED = 'PROTOCOL_UNSPECIFIED', + /** + * TCP protocol. + */ + TCP = 'TCP', + /** + * UDP protocol. + */ + UDP = 'UDP', +} + +/** The category of the default container image. */ +export enum DefaultContainerCategory { + /** + * The default value. This value is unused. + */ + DEFAULT_CONTAINER_CATEGORY_UNSPECIFIED = 'DEFAULT_CONTAINER_CATEGORY_UNSPECIFIED', + /** + * The default container image for Computer Use. + */ + DEFAULT_CONTAINER_CATEGORY_COMPUTER_USE = 'DEFAULT_CONTAINER_CATEGORY_COMPUTER_USE', +} + +/** Input only. Action to take on the source SandboxEnvironment after the snapshot is taken. This field is only used in CreateSandboxEnvironmentSnapshotRequest and it is not stored in the resource. */ +export enum PostSnapshotAction { + /** + * The default value. This value is unused. + */ + POST_SNAPSHOT_ACTION_UNSPECIFIED = 'POST_SNAPSHOT_ACTION_UNSPECIFIED', + /** + * Sandbox environment will continue to run after snapshot is taken. + */ + RUNNING = 'RUNNING', + /** + * Sandbox environment will be paused after snapshot is taken. + */ + PAUSE = 'PAUSE', +} + /** Output only. The source of the Skill. */ export enum SkillSource { /** @@ -2325,6 +2369,377 @@ export declare interface GetAgentEngineSandboxOperationParameters { config?: GetAgentEngineOperationConfig; } +/** Specification for deploying from a custom container image. */ +export declare interface SandboxEnvironmentTemplateCustomContainerSpec { + /** Required. The Artifact Registry Docker image URI (e.g., us-central1-docker.pkg.dev/my-project/my-repo/my-image:tag) of the container image that is to be run on each worker replica. */ + imageUri?: string; +} + +/** Represents a network port in a container. */ +export declare interface SandboxEnvironmentTemplateNetworkPort { + /** Optional. Port number to expose. This must be a valid port number, between 1 and 65535. */ + port?: number; + /** Optional. Protocol for port. Defaults to TCP if not specified. */ + protocol?: Protocol; +} + +/** Message to define resource requests and limits (mirroring Kubernetes) for each sandbox instance created from this template. */ +export declare interface SandboxEnvironmentTemplateResourceRequirements { + /** Optional. The maximum amounts of compute resources allowed. Keys are resource names (e.g., "cpu", "memory"). Values are quantities (e.g., "500m", "1Gi"). */ + limits?: Record; + /** Optional. The requested amounts of compute resources. Keys are resource names (e.g., "cpu", "memory"). Values are quantities (e.g., "250m", "512Mi"). */ + requests?: Record; +} + +/** The customized sandbox runtime environment for BYOC. */ +export declare interface SandboxEnvironmentTemplateCustomContainerEnvironment { + /** The specification of the custom container environment. */ + customContainerSpec?: SandboxEnvironmentTemplateCustomContainerSpec; + /** Ports to expose from the container. */ + ports?: SandboxEnvironmentTemplateNetworkPort[]; + /** Resource requests and limits for the container. */ + resources?: SandboxEnvironmentTemplateResourceRequirements; +} + +/** The default sandbox runtime environment for default container workloads. */ +export declare interface SandboxEnvironmentTemplateDefaultContainerEnvironment { + /** Required. The category of the default container image. */ + defaultContainerCategory?: DefaultContainerCategory; + /** Optional. Resource requests and limits for the default container. */ + resources?: SandboxEnvironmentTemplateResourceRequirements; +} + +/** Configuration for egress control of sandbox instances. */ +export declare interface SandboxEnvironmentTemplateEgressControlConfig { + /** Optional. Whether to allow internet access. */ + internetAccess?: boolean; +} + +/** Config for creating a Sandbox Template. */ +export declare interface CreateSandboxEnvironmentTemplateConfig { + /** Used to override HTTP request options. */ + httpOptions?: genaiTypes.HttpOptions; + /** Abort signal which can be used to cancel the request. + + NOTE: AbortSignal is a client-only operation. Using it to cancel an + operation will not cancel the request in the service. You will still + be charged usage for any applicable operations. + */ + abortSignal?: AbortSignal; + /** The custom container environment for the sandbox template. */ + customContainerEnvironment?: SandboxEnvironmentTemplateCustomContainerEnvironment; + /** The default container environment for the sandbox template. */ + defaultContainerEnvironment?: SandboxEnvironmentTemplateDefaultContainerEnvironment; + /** The egress control config for the sandbox template. */ + egressControlConfig?: SandboxEnvironmentTemplateEgressControlConfig; + /** Waits for the operation to complete before returning. */ + waitForCompletion?: boolean; +} + +/** Parameters for creating Sandbox Environment Templates. */ +export declare interface CreateSandboxEnvironmentTemplateRequestParameters { + /** Name of the agent engine to create the template under. */ + name: string; + /** The display name of the sandbox template. */ + displayName: string; + config?: CreateSandboxEnvironmentTemplateConfig; +} + +/** A sandbox environment template. */ +export declare interface SandboxEnvironmentTemplate { + /** Output only. The timestamp when this SandboxEnvironmentTemplate was created. */ + createTime?: string; + /** The sandbox environment for custom container workloads. */ + customContainerEnvironment?: SandboxEnvironmentTemplateCustomContainerEnvironment; + /** The sandbox environment for default container workloads. */ + defaultContainerEnvironment?: SandboxEnvironmentTemplateDefaultContainerEnvironment; + /** Required. The display name of the SandboxEnvironmentTemplate. */ + displayName?: string; + /** Optional. The configuration for egress control of this template. */ + egressControlConfig?: SandboxEnvironmentTemplateEgressControlConfig; + /** Identifier. The resource name of the SandboxEnvironmentTemplate. Format: `projects/{project}/locations/{location}/reasoningEngines/{reasoning_engine}/sandboxEnvironmentTemplates/{sandbox_environment_template}` */ + name?: string; + /** Output only. The state of the sandbox environment template. */ + state?: + | 'UNSPECIFIED' + | 'PROVISIONING' + | 'ACTIVE' + | 'DEPROVISIONING' + | 'DELETED' + | 'FAILED'; + /** Output only. The timestamp when this SandboxEnvironmentTemplate was most recently updated. */ + updateTime?: string; +} + +/** Operation that has an agent engine sandbox as a response. */ +export declare interface SandboxEnvironmentTemplateOperation { + /** The server-assigned name, which is only unique within the same service that originally returns it. If you use the default HTTP mapping, the `name` should be a resource name ending with `operations/{unique_id}`. */ + name?: string; + /** Service-specific metadata associated with the operation. It typically contains progress information and common metadata such as create time. Some services might not provide such metadata. Any method that returns a long-running operation should document the metadata type, if any. */ + metadata?: Record; + /** If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed, and either `error` or `response` is available. */ + done?: boolean; + /** The error result of the operation in case of failure or cancellation. */ + error?: Record; + /** The Agent Engine Sandbox Template. */ + response?: SandboxEnvironmentTemplate; +} + +/** Config for deleting a Sandbox Template. */ +export declare interface DeleteSandboxEnvironmentTemplateConfig { + /** Used to override HTTP request options. */ + httpOptions?: genaiTypes.HttpOptions; + /** Abort signal which can be used to cancel the request. + + NOTE: AbortSignal is a client-only operation. Using it to cancel an + operation will not cancel the request in the service. You will still + be charged usage for any applicable operations. + */ + abortSignal?: AbortSignal; +} + +/** Parameters for deleting sandbox templates. */ +export declare interface DeleteSandboxEnvironmentTemplateRequestParameters { + /** Name of the sandbox template to delete. */ + name: string; + config?: DeleteSandboxEnvironmentTemplateConfig; +} + +/** Operation for deleting sandbox templates. */ +export declare interface DeleteSandboxEnvironmentTemplateOperation { + /** The server-assigned name, which is only unique within the same service that originally returns it. If you use the default HTTP mapping, the `name` should be a resource name ending with `operations/{unique_id}`. */ + name?: string; + /** Service-specific metadata associated with the operation. It typically contains progress information and common metadata such as create time. Some services might not provide such metadata. Any method that returns a long-running operation should document the metadata type, if any. */ + metadata?: Record; + /** If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed, and either `error` or `response` is available. */ + done?: boolean; + /** The error result of the operation in case of failure or cancellation. */ + error?: Record; +} + +/** Config for getting a Sandbox Template. */ +export declare interface GetSandboxEnvironmentTemplateConfig { + /** Used to override HTTP request options. */ + httpOptions?: genaiTypes.HttpOptions; + /** Abort signal which can be used to cancel the request. + + NOTE: AbortSignal is a client-only operation. Using it to cancel an + operation will not cancel the request in the service. You will still + be charged usage for any applicable operations. + */ + abortSignal?: AbortSignal; +} + +/** Parameters for getting a sandbox template. */ +export declare interface GetSandboxEnvironmentTemplateRequestParameters { + /** Name of the sandbox template. */ + name: string; + config?: GetSandboxEnvironmentTemplateConfig; +} + +/** Config for listing sandbox templates. */ +export declare interface ListSandboxEnvironmentTemplatesConfig { + /** Used to override HTTP request options. */ + httpOptions?: genaiTypes.HttpOptions; + /** Abort signal which can be used to cancel the request. + + NOTE: AbortSignal is a client-only operation. Using it to cancel an + operation will not cancel the request in the service. You will still + be charged usage for any applicable operations. + */ + abortSignal?: AbortSignal; + pageSize?: number; + pageToken?: string; + /** An expression for filtering the results of the request. */ + filter?: string; +} + +/** Parameters for listing sandbox templates. */ +export declare interface ListSandboxEnvironmentTemplatesRequestParameters { + /** Name of the agent engine. */ + name: string; + config?: ListSandboxEnvironmentTemplatesConfig; +} + +/** Response for listing sandbox templates. */ +export class ListSandboxEnvironmentTemplatesResponse { + /** Used to retain the full HTTP response. */ + sdkHttpResponse?: genaiTypes.HttpResponse; + nextPageToken?: string; + /** List of sandbox templates. */ + sandboxEnvironmentTemplates?: SandboxEnvironmentTemplate[]; +} + +/** Parameters for getting an operation with a sandbox template as a response. */ +export declare interface GetSandboxEnvironmentTemplateOperationParameters { + /** The server-assigned name for the operation. */ + operationName: string; + /** Used to override the default configuration. */ + config?: GetAgentEngineOperationConfig; +} + +/** Config for creating a Sandbox Environment Snapshot. */ +export declare interface CreateAgentEngineSandboxSnapshotConfig { + /** Used to override HTTP request options. */ + httpOptions?: genaiTypes.HttpOptions; + /** Abort signal which can be used to cancel the request. + + NOTE: AbortSignal is a client-only operation. Using it to cancel an + operation will not cancel the request in the service. You will still + be charged usage for any applicable operations. + */ + abortSignal?: AbortSignal; + /** The display name of the sandbox snapshot. */ + displayName?: string; + /** The owner of the sandbox snapshot. */ + owner?: string; + /** The TTL for this resource. The expiration time is computed: now + TTL. */ + ttl?: string; + /** Waits for the operation to complete before returning. */ + waitForCompletion?: boolean; +} + +/** Parameters for creating a sandbox environment snapshot. */ +export declare interface CreateSandboxEnvironmentSnapshotRequestParameters { + /** Name of the sandbox environment to snapshot. */ + sourceSandboxEnvironmentName: string; + config?: CreateAgentEngineSandboxSnapshotConfig; +} + +/** A sandbox environment snapshot. */ +export declare interface SandboxEnvironmentSnapshot { + /** The display name of the sandbox environment snapshot. */ + displayName?: string; + /** Expiration time of the sandbox environment snapshot. + */ + expireTime?: string; + /** Output only. The timestamp when this SandboxEnvironmentSnapshot was created. */ + createTime?: string; + /** Identifier. The resource name of the SandboxEnvironmentSnapshot. Format: `projects/{project}/locations/{location}/reasoningEngines/{reasoning_engine}/sandboxEnvironmentSnapshots/{sandbox_environment_snapshot}` */ + name?: string; + /** Optional. Owner information for this sandbox snapshot. Different owners will have isolations on snapshot storage and identity. If not set, snapshot will be created as the default owner. */ + owner?: string; + /** Output only. The resource name of the parent SandboxEnvironmentSnapshot. Empty if this is a root Snapshot (the first snapshot from a newly created sandbox). Can be used to reconstruct the whole ancestry tree of snapshots. */ + parentSnapshot?: string; + /** Optional. Input only. Action to take on the source SandboxEnvironment after the snapshot is taken. This field is only used in CreateSandboxEnvironmentSnapshotRequest and it is not stored in the resource. */ + postSnapshotAction?: PostSnapshotAction; + /** Optional. Output only. Size of the snapshot data in bytes. */ + sizeBytes?: string; + /** Required. The resource name of the source SandboxEnvironment this snapshot was taken from. */ + sourceSandboxEnvironment?: string; + /** Optional. Input only. The TTL for the sandbox environment snapshot. The expiration time is computed: now + TTL. */ + ttl?: string; + /** Output only. The timestamp when this SandboxEnvironment was most recently updated. */ + updateTime?: string; +} + +/** Operation that has an agent engine sandbox snapshot as a response. */ +export declare interface AgentEngineSandboxSnapshotOperation { + /** The server-assigned name, which is only unique within the same service that originally returns it. If you use the default HTTP mapping, the `name` should be a resource name ending with `operations/{unique_id}`. */ + name?: string; + /** Service-specific metadata associated with the operation. It typically contains progress information and common metadata such as create time. Some services might not provide such metadata. Any method that returns a long-running operation should document the metadata type, if any. */ + metadata?: Record; + /** If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed, and either `error` or `response` is available. */ + done?: boolean; + /** The error result of the operation in case of failure or cancellation. */ + error?: Record; + /** The Agent Engine Sandbox Snapshot. */ + response?: SandboxEnvironmentSnapshot; +} + +/** Config for deleting a Sandbox Environment Snapshot. */ +export declare interface DeleteSandboxEnvironmentSnapshotConfig { + /** Used to override HTTP request options. */ + httpOptions?: genaiTypes.HttpOptions; + /** Abort signal which can be used to cancel the request. + + NOTE: AbortSignal is a client-only operation. Using it to cancel an + operation will not cancel the request in the service. You will still + be charged usage for any applicable operations. + */ + abortSignal?: AbortSignal; +} + +/** Parameters for deleting sandbox environment snapshots. */ +export declare interface DeleteSandboxEnvironmentSnapshotRequestParameters { + /** Name of the sandbox environment snapshot to delete. */ + name: string; + config?: DeleteSandboxEnvironmentSnapshotConfig; +} + +/** Operation for deleting sandbox environment snapshots. */ +export declare interface DeleteSandboxEnvironmentSnapshotOperation { + /** The server-assigned name, which is only unique within the same service that originally returns it. If you use the default HTTP mapping, the `name` should be a resource name ending with `operations/{unique_id}`. */ + name?: string; + /** Service-specific metadata associated with the operation. It typically contains progress information and common metadata such as create time. Some services might not provide such metadata. Any method that returns a long-running operation should document the metadata type, if any. */ + metadata?: Record; + /** If the value is `false`, it means the operation is still in progress. If `true`, the operation is completed, and either `error` or `response` is available. */ + done?: boolean; + /** The error result of the operation in case of failure or cancellation. */ + error?: Record; +} + +/** Config for getting a Sandbox Environment Snapshot. */ +export declare interface GetSandboxEnvironmentSnapshotConfig { + /** Used to override HTTP request options. */ + httpOptions?: genaiTypes.HttpOptions; + /** Abort signal which can be used to cancel the request. + + NOTE: AbortSignal is a client-only operation. Using it to cancel an + operation will not cancel the request in the service. You will still + be charged usage for any applicable operations. + */ + abortSignal?: AbortSignal; +} + +/** Parameters for getting a sandbox environment snapshot. */ +export declare interface GetSandboxEnvironmentSnapshotRequestParameters { + /** Name of the sandbox environment snapshot. */ + name: string; + config?: GetSandboxEnvironmentSnapshotConfig; +} + +/** Config for listing sandbox environment snapshots. */ +export declare interface ListSandboxEnvironmentSnapshotsConfig { + /** Used to override HTTP request options. */ + httpOptions?: genaiTypes.HttpOptions; + /** Abort signal which can be used to cancel the request. + + NOTE: AbortSignal is a client-only operation. Using it to cancel an + operation will not cancel the request in the service. You will still + be charged usage for any applicable operations. + */ + abortSignal?: AbortSignal; + pageSize?: number; + pageToken?: string; + /** An expression for filtering the results of the request. */ + filter?: string; +} + +/** Parameters for listing sandbox environment snapshots. */ +export declare interface ListSandboxEnvironmentSnapshotsRequestParameters { + /** Name of the reasoning engine to list snapshots from. */ + name: string; + config?: ListSandboxEnvironmentSnapshotsConfig; +} + +/** Response for listing sandbox environment snapshots. */ +export class ListSandboxEnvironmentSnapshotsResponse { + /** Used to retain the full HTTP response. */ + sdkHttpResponse?: genaiTypes.HttpResponse; + nextPageToken?: string; + /** List of sandbox environment snapshots. */ + sandboxEnvironmentSnapshots?: SandboxEnvironmentSnapshot[]; +} + +/** Parameters for getting an operation with a sandbox snapshot as a response. */ +export declare interface GetAgentEngineSandboxSnapshotOperationParameters { + /** The server-assigned name for the operation. */ + operationName: string; + /** Used to override the default configuration. */ + config?: GetAgentEngineOperationConfig; +} + /** Config for creating a Session. */ export declare interface CreateAgentEngineSessionConfig { /** Used to override HTTP request options. */ diff --git a/system_test/sandbox_templates_snapshots_e2e_test.ts b/system_test/sandbox_templates_snapshots_e2e_test.ts new file mode 100644 index 00000000..852cb2d9 --- /dev/null +++ b/system_test/sandbox_templates_snapshots_e2e_test.ts @@ -0,0 +1,233 @@ +/** + * @license + * Copyright 2026 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import {Client} from '../src/client.js'; +import * as types from '../src/types.js'; + +const PROJECT = process.env['GCLOUD_PROJECT']; +const LOCATION = 'us-central1'; + +// This end-to-end test provisions a real Agent Engine sandbox (a running +// container VM), which requires a project with sandbox provisioning enabled. +// That infrastructure is not available in the standard client-library CI +// project, so the test only runs when RUN_SANDBOX_E2E is set (e.g. against a +// sandbox-enabled project). CI skips it; the templates/snapshots CRUD paths are +// covered by the replay unit tests. +const sandboxE2eDescribe = + process.env['RUN_SANDBOX_E2E'] === 'true' ? describe : xdescribe; + +/** Polls an Agent Engine operation until it completes. */ +async function pollAgentOperation(client: Client, operationName: string) { + for (let pollCount = 0; pollCount < 120; pollCount++) { + const status = await client.agentEnginesInternal.getAgentOperationInternal({ + operationName, + }); + if (status.done) { + return status; + } + await new Promise((resolve) => setTimeout(resolve, 5000)); + } + throw new Error(`Operation ${operationName} did not complete within the timeout.`); +} + +/** Polls a sandbox operation until it completes. */ +async function pollSandboxOperation(client: Client, operationName: string) { + for (let pollCount = 0; pollCount < 120; pollCount++) { + const status = + await client.agentEnginesInternal.sandboxes.getSandboxOperationInternal({ + operationName, + }); + if (status.done) { + return status; + } + await new Promise((resolve) => setTimeout(resolve, 5000)); + } + throw new Error(`Operation ${operationName} did not complete within the timeout.`); +} + +/** Polls a sandbox template operation until it completes. */ +async function pollTemplateOperation(client: Client, operationName: string) { + for (let pollCount = 0; pollCount < 120; pollCount++) { + const status = + await client.agentEnginesInternal.sandboxes.templates + .getSandboxEnvironmentTemplateOperation({operationName}); + if (status.done) { + return status; + } + await new Promise((resolve) => setTimeout(resolve, 5000)); + } + throw new Error(`Operation ${operationName} did not complete within the timeout.`); +} + +/** Polls a sandbox snapshot operation until it completes. */ +async function pollSnapshotOperation(client: Client, operationName: string) { + for (let pollCount = 0; pollCount < 120; pollCount++) { + const status = + await client.agentEnginesInternal.sandboxes.snapshots + .getSandboxSnapshotOperation({operationName}); + if (status.done) { + return status; + } + await new Promise((resolve) => setTimeout(resolve, 5000)); + } + throw new Error(`Operation ${operationName} did not complete within the timeout.`); +} + +sandboxE2eDescribe('agentEngineSandboxTemplatesAndSnapshots', () => { + let client: Client; + let agentEngineName: string|undefined; + + beforeAll(async () => { + jasmine.DEFAULT_TIMEOUT_INTERVAL = 600000; + client = new Client({ + project: PROJECT as string, + location: LOCATION, + }); + + // Create a temporary Agent Engine to own the sandboxes. + const createOp = await client.agentEnginesInternal.createInternal({ + config: { + displayName: 'sandbox-templates-snapshots-sample', + labels: {'test-label': 'test-value'}, + }, + }); + const status = await pollAgentOperation(client, createOp.name!); + agentEngineName = status.response?.name; + }, 600000); + + afterAll(async () => { + if (agentEngineName) { + try { + await client.agentEnginesInternal.deleteInternal({name: agentEngineName}); + } catch (e) { + console.error('Failed to delete Agent Engine during cleanup:', e); + } + } + }); + + it('should create, get, list, and delete a sandbox template', async () => { + // 1. Create a sandbox environment template. + const createOp = + await client.agentEnginesInternal.sandboxes.templates.createInternal({ + name: agentEngineName!, + displayName: 'Example Sandbox Template', + config: { + defaultContainerEnvironment: { + defaultContainerCategory: types.DefaultContainerCategory + .DEFAULT_CONTAINER_CATEGORY_COMPUTER_USE, + }, + egressControlConfig: {internetAccess: true}, + }, + }); + const status = await pollTemplateOperation(client, createOp.name!); + const templateName = status.response?.name; + expect(templateName).toBeDefined(); + + // 2. Get the template. + const template = + await client.agentEnginesInternal.sandboxes.templates.getInternal({ + name: templateName!, + }); + expect(template.name).toEqual(templateName); + + // 3. List templates. + const listResponse = + await client.agentEnginesInternal.sandboxes.templates.listInternal({ + name: agentEngineName!, + }); + expect(listResponse.sandboxEnvironmentTemplates).toBeDefined(); + + // 4. Delete the template. + const deleteOp = + await client.agentEnginesInternal.sandboxes.templates.deleteInternal({ + name: templateName!, + }); + expect(deleteOp.name).toBeDefined(); + }); + + it('should create, get, list, and delete a sandbox snapshot', async () => { + // Snapshots capture the state of a running sandbox, and only + // template-based (e.g. computer-use) sandboxes are snapshottable. Create a + // computer-use template, then a sandbox from it, before snapshotting. + const templateCreateOp = + await client.agentEnginesInternal.sandboxes.templates.createInternal({ + name: agentEngineName!, + displayName: 'Snapshot Source Template', + config: { + defaultContainerEnvironment: { + defaultContainerCategory: types.DefaultContainerCategory + .DEFAULT_CONTAINER_CATEGORY_COMPUTER_USE, + }, + egressControlConfig: {internetAccess: true}, + }, + }); + const templateStatus = + await pollTemplateOperation(client, templateCreateOp.name!); + const templateName = templateStatus.response?.name; + expect(templateName).toBeDefined(); + + try { + // Create a sandbox from the template so it has a snapshottable state. + const sandboxCreateOp = + await client.agentEnginesInternal.sandboxes.createInternal({ + name: agentEngineName!, + config: {sandboxEnvironmentTemplate: templateName!}, + }); + const sandboxStatus = + await pollSandboxOperation(client, sandboxCreateOp.name!); + const sandboxName = sandboxStatus.response?.name; + expect(sandboxName).toBeDefined(); + + try { + // 1. Create a snapshot of the sandbox. + const createOp = + await client.agentEnginesInternal.sandboxes.snapshots.createInternal( + { + sourceSandboxEnvironmentName: sandboxName!, + config: { + displayName: 'Example Sandbox Snapshot', + ttl: '3600s', + }, + }); + const status = await pollSnapshotOperation(client, createOp.name!); + const snapshotName = status.response?.name; + expect(snapshotName).toBeDefined(); + + // 2. Get the snapshot. + const snapshot = + await client.agentEnginesInternal.sandboxes.snapshots.getInternal({ + name: snapshotName!, + }); + expect(snapshot.name).toEqual(snapshotName); + + // 3. List snapshots. + const listResponse = + await client.agentEnginesInternal.sandboxes.snapshots.listInternal({ + name: agentEngineName!, + }); + expect(listResponse.sandboxEnvironmentSnapshots).toBeDefined(); + + // 4. Delete the snapshot. + const deleteOp = + await client.agentEnginesInternal.sandboxes.snapshots.deleteInternal( + { + name: snapshotName!, + }); + expect(deleteOp.name).toBeDefined(); + } finally { + // Clean up the source sandbox. + await client.agentEnginesInternal.sandboxes.deleteInternal({ + name: sandboxName!, + }); + } + } finally { + // Clean up the source template. + await client.agentEnginesInternal.sandboxes.templates.deleteInternal({ + name: templateName!, + }); + } + }); +}); diff --git a/test/replays/agentengines_sandbox_snapshots_test.ts b/test/replays/agentengines_sandbox_snapshots_test.ts new file mode 100644 index 00000000..4314936d --- /dev/null +++ b/test/replays/agentengines_sandbox_snapshots_test.ts @@ -0,0 +1,82 @@ +/** + * @license + * Copyright 2026 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import 'jasmine'; + +import {ReplayClient} from './_replay_client.js'; + +describe('AgentEnginesSandboxSnapshots', () => { + let client: ReplayClient; + + beforeEach(() => { + client = new ReplayClient({ + project: 'test-project', + location: 'us-central1', + }); + }); + + it('creates a sandbox environment snapshot', async () => { + const fetchSpy = client.setupReplay( + 'ae_sandbox_snapshots_create/test_create_sandbox_snapshot.vertex.json'); + + const createOp = + await client.agentEnginesInternal.sandboxes.snapshots.createInternal({ + sourceSandboxEnvironmentName: + `projects/802583348448/locations/us-central1/reasoningEngines/6130241318758121472/sandboxEnvironments/525190525100228608`, + config: { + displayName: 'test_snapshot', + ttl: '3600s', + owner: 'test_owner', + }, + }); + client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); + expect(createOp.name).toBeDefined(); + client.verifyAllInteractions(); + }); + + it('gets a sandbox environment snapshot', async () => { + const fetchSpy = client.setupReplay( + 'ae_sandbox_snapshots_get/test_get_sandbox_snapshot.vertex.json'); + + const snapshotName = + `projects/802583348448/locations/us-central1/reasoningEngines/6130241318758121472/sandboxEnvironmentSnapshots/2433069698686910464`; + const snapshot = + await client.agentEnginesInternal.sandboxes.snapshots.getInternal({ + name: snapshotName, + }); + client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); + expect(snapshot.name).toEqual(snapshotName); + client.verifyAllInteractions(); + }); + + it('lists sandbox environment snapshots', async () => { + const fetchSpy = client.setupReplay( + 'ae_sandbox_snapshots_list/test_list_sandbox_snapshots.vertex.json'); + + const listResponse = + await client.agentEnginesInternal.sandboxes.snapshots.listInternal({ + name: + `projects/802583348448/locations/us-central1/reasoningEngines/6130241318758121472`, + }); + client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); + expect(listResponse.sandboxEnvironmentSnapshots).toBeDefined(); + client.verifyAllInteractions(); + }); + + it('deletes a sandbox environment snapshot', async () => { + const fetchSpy = client.setupReplay( + 'ae_sandbox_snapshots_delete/test_delete_sandbox_snapshot.vertex.json'); + + const deleteOp = + await client.agentEnginesInternal.sandboxes.snapshots.deleteInternal({ + name: + `projects/802583348448/locations/us-central1/reasoningEngines/6130241318758121472/sandboxEnvironmentSnapshots/421086565159141376`, + }); + client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); + expect(deleteOp.name).toBeDefined(); + client.verifyAllInteractions(); + }); +}); diff --git a/test/replays/agentengines_sandbox_templates_test.ts b/test/replays/agentengines_sandbox_templates_test.ts new file mode 100644 index 00000000..a8742946 --- /dev/null +++ b/test/replays/agentengines_sandbox_templates_test.ts @@ -0,0 +1,104 @@ +/** + * @license + * Copyright 2026 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import 'jasmine'; + +import * as types from '../../src/types.js'; + +import {ReplayClient} from './_replay_client.js'; + +describe('AgentEnginesSandboxTemplates', () => { + let client: ReplayClient; + + beforeEach(() => { + client = new ReplayClient({ + project: 'test-project', + location: 'us-central1', + }); + }); + + it('creates a sandbox environment template', async () => { + const fetchSpy = client.setupReplay( + 'ae_sandbox_templates_default_create/test_sandbox_templates_default_create.vertex.json'); + + const createOp = + await client.agentEnginesInternal.sandboxes.templates.createInternal({ + name: + `projects/802583348448/locations/us-central1/reasoningEngines/6130241318758121472`, + displayName: 'Test Sandbox Template 1', + config: { + defaultContainerEnvironment: { + defaultContainerCategory: types.DefaultContainerCategory + .DEFAULT_CONTAINER_CATEGORY_COMPUTER_USE, + }, + egressControlConfig: { + internetAccess: true, + }, + }, + }); + client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); + expect(createOp.name).toBeDefined(); + client.verifyAllInteractions(); + }); + + it('gets a sandbox environment template', async () => { + const fetchSpy = client.setupReplay( + 'ae_sandbox_templates_get/test_sandbox_templates_get.vertex.json'); + + const templateName = + `projects/254005681254/locations/us-central1/reasoningEngines/208148546254274560/sandboxEnvironmentTemplates/4632233691727265792`; + const template = + await client.agentEnginesInternal.sandboxes.templates.getInternal({ + name: templateName, + }); + client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); + expect(template.name).toEqual(templateName); + client.verifyAllInteractions(); + }); + + it('lists sandbox environment templates', async () => { + const fetchSpy = client.setupReplay( + 'ae_sandbox_templates_list/test_sandbox_templates_list.vertex.json'); + + const listResponse = + await client.agentEnginesInternal.sandboxes.templates.listInternal({ + name: + `projects/254005681254/locations/us-central1/reasoningEngines/208148546254274560`, + }); + client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); + expect(listResponse.sandboxEnvironmentTemplates).toBeDefined(); + client.verifyAllInteractions(); + }); + + it('deletes a sandbox environment template', async () => { + const fetchSpy = client.setupReplay( + 'ae_sandbox_templates_delete/test_sandbox_templates_delete.vertex.json'); + + const deleteOp = + await client.agentEnginesInternal.sandboxes.templates.deleteInternal({ + name: + `projects/254005681254/locations/us-central1/reasoningEngines/208148546254274560/sandboxEnvironmentTemplates/4632233691727265792`, + }); + client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); + expect(deleteOp.name).toBeDefined(); + client.verifyAllInteractions(); + }); + + it('gets a sandbox environment template operation', async () => { + const fetchSpy = client.setupReplay( + 'ae_sandbox_templates_get_sandbox_template_operation/test_get_sandbox_template_operation.vertex.json'); + + const operationName = + `projects/254005681254/locations/us-central1/operations/7252775414349692928`; + const op = await client.agentEnginesInternal.sandboxes.templates + .getSandboxEnvironmentTemplateOperation({ + operationName: operationName, + }); + client.verifyInteraction(0, fetchSpy.calls.argsFor(0)); + expect(op.name).toEqual(operationName); + client.verifyAllInteractions(); + }); +});