Skip to content

Fix: import Client from the @google-cloud/vertexai package root in two integration tests - #622

Open
AmaadMartin wants to merge 1 commit into
mainfrom
fix/vertexai-client-root-import-integration-tests
Open

Fix: import Client from the @google-cloud/vertexai package root in two integration tests#622
AmaadMartin wants to merge 1 commit into
mainfrom
fix/vertexai-client-root-import-integration-tests

Conversation

@AmaadMartin

@AmaadMartin AmaadMartin commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Please ensure you have read the contribution guide before creating a pull request.

Link to Issue or Description of Change

  1. Link to an existing issue (if applicable):
    N/A — no public issue is open for this.
  2. Or, if no issue exists, describe the change:
    Problem: Two integration tests import the Client class by reaching into the @google-cloud/vertexai package's compiled output directory:
import {Client} from '@google-cloud/vertexai/build/src/genai/client.js';

build/src/... is emitted output, not documented surface. Nothing guarantees that path across releases — if the package adds an exports map, changes its outDir, or moves genai/client.ts, both files break with a module-resolution error even though the symbol they want never moved. Seven other call sites in this repo already import Client from the package root (core/src/memory/vertex_ai_memory_bank_service.ts, core/src/code_executors/agent_engine_sandbox_code_executor.ts, core/src/skills/gcp_skill_registry.ts, core/test/memory/vertex_ai_memory_bank_service_test.ts, core/test/code_executors/agent_engine_sandbox_code_executor_test.ts, core/test/tools/skills/skill_registry_test.ts, tests/integration/agents/agent_with_sandbox_executor_test.ts), so these two lines are also an internal inconsistency.

Solution: Point both at the package root, import {Client} from '@google-cloud/vertexai';. This is a test-only, behaviour-preserving change — no production code, no public API, no dependency versions.

Why it is safe. The installed version is @google-cloud/vertexai@1.12.0 (core/package.json declares ^1.12.0; the lockfile pins 1.12.0). Its root barrel re-exports the class directly — node_modules/@google-cloud/vertexai/build/src/index.d.ts:17, verbatim:

export {Client} from './genai/client';

and build/src/index.js re-exports it as a live getter onto the same binding, so the root and deep specifiers name the identical class object. Verified at runtime:

$ node --input-type=module -e "
import {Client as RootClient} from '@google-cloud/vertexai';
import {Client as DeepClient} from '@google-cloud/vertexai/build/src/genai/client.js';
console.log('RootClient === DeepClient:', RootClient === DeepClient);
"
RootClient === DeepClient: true

Both tests use Client purely as a type (an as unknown as Client cast over a hand-rolled object injected through the service constructor); neither file instantiates it, and neither contains a vi.mock, so module resolution at test time is not involved at all.

Why the sibling deep imports were deliberately left alone. The root barrel's export * from './types' refers to build/src/types/ — the legacy Vertex AI types module — which is a different module from build/src/genai/types. Sessions (./genai/sessions) is likewise absent from the root barrel. Hoisting them is therefore a compile error, not a style choice. Demonstrated by mutating line 8 of the agent-tool test to the root specifier:

tests/integration/tools/agent_tool_vertexai_test.ts:8:9 - error TS2305: Module '"@google-cloud/vertexai"' has no exported member 'Sessions'.

So Client is the only symbol in these files that is hoistable. Left untouched: tests/integration/tools/agent_tool_vertexai_test.ts:8 and tests/integration/sessions/vertex_ai_session_service_test.ts:7 (both Sessions), and every deep import under core/src, dev/src and dev/test. In particular dev/test/cli/cli_deploy_agent_engine_test.ts does vi.mock('@google-cloud/vertexai/build/src/genai/client.js', ...) paired with a new Client({...}) in dev/src/cli/deploy/cli_deploy_agent_engine.ts — those use Client as a value and the mock is bound to the deep specifier, which is a materially riskier change that must not ride along here.

Overlap check with open PRs (disclosure). Before implementing I checked the 521 open PRs on the fork for a collision. Two open PRs already contain these same two import edits as part of larger changes: #475 (Chore(lint): forbid deep imports into the @google-cloud/vertexai build output — same rename plus an ESLint guard and core/dev source changes) and #303 (Fix: contain @google-cloud/vertexai build-output deep imports behind one adapter module — same rename plus a new core/src/utils/vertex_ai_internal.ts adapter). Those two conflict with each other on these lines and each couples the rename to a broader design decision. This PR is the standalone two-line subset, which can land regardless of which of the larger designs is chosen; if either #475 or #303 merges first, this PR becomes a no-op and should simply be closed.

Testing Plan

Please describe the tests that you ran to verify your changes. This is required for all PRs that are not small documentation or typo fixes.
Unit Tests:
[x] I have added or updated unit tests for my change.

No new tests, deliberately. This change adds zero lines of production code and alters no behaviour, so there is nothing new to cover and no assertion that could distinguish before from after — a new test here would be a green light with no signal. The repo's "Add a New Test; Do Not Rewrite an Existing One" rule also means no existing test was touched: no describe, it, expect, mock object or fixture changed, only the import specifier. The diff is 2 files / 2 insertions / 2 deletions.

The analogue of "prove the test can fail" for a no-op rename is a before/after baseline plus a negative control, both run:

Baseline, on the unmodified tree:

$ npx vitest run --project integration \
    tests/integration/memory/vertex_ai_memory_bank_service_test.ts \
    tests/integration/tools/agent_tool_vertexai_test.ts

 ✓ |integration| tests/integration/memory/vertex_ai_memory_bank_service_test.ts (1 test) 39ms
 ✓ |integration| tests/integration/tools/agent_tool_vertexai_test.ts (1 test) 1039ms

 Test Files  2 passed (2)
      Tests  2 passed (2)
   Duration  7.78s

After the edit — identical pass/fail/skip counts:

 ✓ |integration| tests/integration/memory/vertex_ai_memory_bank_service_test.ts (1 test) 39ms
 ✓ |integration| tests/integration/tools/agent_tool_vertexai_test.ts (1 test) 1039ms

 Test Files  2 passed (2)
      Tests  2 passed (2)
   Duration  7.86s

Both tests genuinely execute — 0 skipped, no skipIf, no process.env read, no network I/O. The model is GeminiWithMockResponses and the Vertex AI clients are plain injected object literals.

Negative control — proof that the checks would catch a bad hoist rather than passing vacuously. Mutating line 8 of tests/integration/tools/agent_tool_vertexai_test.ts to import {Sessions} from '@google-cloud/vertexai'; makes the type check fail:

tests/integration/tools/agent_tool_vertexai_test.ts:8:9 - error TS2305: Module '"@google-cloud/vertexai"' has no exported member 'Sessions'.

This confirms tsc --noEmit really does type-check tests/integration/** (the root tsconfig.json declares no include/files, so the default applies), so the green run below is real signal about the Client specifier. The mutation was reverted.

Type check. npm run ts:check output is byte-identical before and after the change (diff of the two captured runs is empty): Found 281 errors in 41 files both times — a pre-existing backlog on main, none of it in either file touched here. Zero new diagnostics.

Lint and formatting:

$ npm run lint          # eslint "**/*.ts" — exit 0, no output
$ npx prettier --check tests/integration/memory/vertex_ai_memory_bank_service_test.ts \
                       tests/integration/tools/agent_tool_vertexai_test.ts
Checking formatting...
All matched files use Prettier code style!

prettier-plugin-organize-imports leaves both import blocks in place: '@google-cloud/vertexai' is a proper prefix of '@google-cloud/vertexai/build/src/genai/sessions.js' so it still sorts before line 8, and it sorts before '@google/adk' because - (0x2D) precedes / (0x2F).

Scope guard:

$ git diff --stat
 tests/integration/memory/vertex_ai_memory_bank_service_test.ts | 2 +-
 tests/integration/tools/agent_tool_vertexai_test.ts            | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

[x] All unit tests pass locally.
Manual End-to-End (E2E) Tests:
Please provide instructions on how to manually test your changes, including any necessary setup or configuration.

From the repository root:

npm ci
npm run build   # the integration project's global setup imports @google/adk, which resolves through core/dist

# 1. The two affected tests — expect "Test Files 2 passed (2) / Tests 2 passed (2)".
npx vitest run --project integration \
  tests/integration/memory/vertex_ai_memory_bank_service_test.ts \
  tests/integration/tools/agent_tool_vertexai_test.ts

# 2. Root and deep specifiers name the same class object — expect "true".
node --input-type=module -e "
import {Client as RootClient} from '@google-cloud/vertexai';
import {Client as DeepClient} from '@google-cloud/vertexai/build/src/genai/client.js';
console.log(RootClient === DeepClient);
"

# 3. The root barrel still exports Client — expect the re-export line.
grep -n "Client" node_modules/@google-cloud/vertexai/build/src/index.d.ts

# 4. No deep client.js import remains under tests/ — expect no output.
grep -rn "build/src/genai/client.js" tests/

Checks 2, 3 and 4 were run and pass; 3 prints 17:export { Client } from './genai/client'; and 4 prints nothing.

Checklist

[x] I have read the CONTRIBUTING.md document.
[x] I have performed a self-review of my own code.
[x] I have commented my code, particularly in hard-to-understand areas.
[x] I have added tests that prove my fix is effective or that my feature works.
[x] New and existing unit tests pass locally with my changes.

CI

All jobs green on run-tests: ubuntu-latest, macos-latest, windows-latest, plus the standalone run-tests job.

The first windows-latest attempt failed with Error: CLI exited prematurely with code 1 at tests/integration/test_case_utils.ts:341 in tests/integration/a2a/stream/stream_test.ts. That is the spawned-test-server harness failing to start, not an assertion: the same run reported 2678 tests passed, 44 skipped, 0 tests failed (1 failed suite). It is a known pre-existing Windows flake unrelated to an import specifier, and the job passed on re-run with no code change.

…o integration tests

Both tests reached into the dependency's compiled output
(@google-cloud/vertexai/build/src/genai/client.js) for a class the package
already re-exports from its root entry point. build/src/... is emitted output,
not documented surface: an added exports map, an outDir change or a move of
genai/client.ts would break both files even though the symbol never moved.

The root barrel re-exports the identical class object, so this is a no-op at
both the type and runtime level. Seven other call sites in the repo already
use the root specifier, so this also removes an internal inconsistency.

Sessions and the genai/types symbols are deliberately left on their deep
specifiers: the root barrel does not re-export them, so hoisting them is a
TS2305 compile error.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant