Skip to content

feat(schematics): rewrite Vertex AI imports to AI Logic on ng update - #3725

Open
armando-navarro wants to merge 1 commit into
angular:mainfrom
armando-navarro:a19-vertexai-ai-migration
Open

feat(schematics): rewrite Vertex AI imports to AI Logic on ng update#3725
armando-navarro wants to merge 1 commit into
angular:mainfrom
armando-navarro:a19-vertexai-ai-migration

Conversation

@armando-navarro

Copy link
Copy Markdown
Collaborator

Adds an ng update migration that moves a workspace off the Vertex AI module onto Firebase AI Logic, and a guide for upgrading from AngularFire 20 to 21.

Background

AngularFire 21 renamed the Vertex AI module to Firebase AI Logic. The @angular/fire/vertexai entry point (and the older @angular/fire/vertexai-preview) were removed in favor of @angular/fire/ai, and the exported symbols were renamed. A project upgrading from 20 that used Vertex AI would fail to compile until it updated those imports by hand.

What this does

  • Extends the existing v21 migration (the one that aligns the firebase dependency) to also rewrite Vertex AI imports and their usages to AI Logic. It parses each source file with the TypeScript compiler and edits only real references, leaving strings, comments, and unrelated identifiers that happen to share a name untouched. It handles named imports and aliases, namespace imports in value and type position, bare local re-exports, and shorthand properties.
  • Adds docs/version-21-upgrade.md, a note in docs/ai.md, and a README link.
  • Adds typescript to the schematics esbuild externals, so the compiler is resolved from the workspace at ng update time rather than bundled into the package. This matches how Angular's own migrations ship and keeps the package from growing by several megabytes.

Symbol map

Before (@angular/fire/vertexai) After (@angular/fire/ai)
getVertexAI getAI
provideVertexAI provideAI
VertexAI AI
VertexAIInstances AIInstances
vertexAIInstance$ AIInstance$
VertexAIModule AIModule

getGenerativeModel and getImagenModel keep their names.

Known limitation

The rewrite matches by name, so a local variable that shadows an imported name with the same spelling can be mis-renamed. ng update always shows its changes as a diff to review, so this surfaces on inspection.

Verification

Unit specs cover each kind of code the migration can run into:

  • named imports, and aliased imports where only the imported name changes
  • namespace imports, in both value position (ns.getVertexAI()) and type position (ns.VertexAI)
  • shorthand properties ({ getVertexAI }) and bare local re-exports (export { VertexAI })
  • unchanged symbols, a file with nothing to rewrite, and an idempotent second run

I also ran the migration for real, not just in specs:

  • scaffolded a fresh Angular 20 app that imports from @angular/fire/vertexai
  • ran ng update and confirmed every import and usage rewrote to @angular/fire/ai
  • confirmed firebase aligned to ^12.4.0, and that a second run made no changes

Refs #3686

AngularFire 21 renamed the Vertex AI module to Firebase AI Logic: the
@angular/fire/vertexai and older @angular/fire/vertexai-preview entry points
were removed in favor of @angular/fire/ai, and the exported symbols were renamed
(getVertexAI to getAI, provideVertexAI to provideAI, VertexAI to AI, and so on).
A workspace on 20 that used Vertex AI would fail to compile after the upgrade.

Extend the existing v21 migration (which aligns the firebase dependency) to also
rewrite these imports and their usages. The rewrite parses each source file with
the TypeScript compiler and edits only genuine references, so it leaves strings,
comments, and unrelated identifiers that merely share a name untouched. It
handles named imports and their aliases, namespace imports in both value and
type position, bare local re-exports, and shorthand properties.

The one accepted limitation is name shadowing: because the rewrite matches by
name, a local variable that shadows an imported name with the same spelling can
be mis-renamed. ng update always presents its changes as a diff for review, so
this is caught on inspection.

Also add typescript to the schematics esbuild externals so the compiler is
resolved from the workspace at ng-update time rather than bundled into the
package, matching how Angular's own migrations ship.

Docs: add a 20-to-21 upgrade guide, note the rename in the AI Logic guide, and
link the upgrade guide from the README.

Refs angular#3686

@tyler-reitz tyler-reitz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work on the AST approach — the two-pass design holds up well under poking. The namespace and identifier passes can't double-edit the same token (isMemberOrDeclaredName catches the child visit in both value and type position), applyEdits sorting back-to-front is right, and the spec coverage is genuinely thorough: shorthand expansion, accessor look-alikes, destructuring keys vs. binding initializers, idempotency. *.jasmine.ts is picked up by tools/jasmine.ts, so these run in CI. The symbol map matches the real src/ai/public_api.ts exports for every entry except one — which is the blocker below.

1. getVertexAIgetAI is not a rename, and the rewrite silently changes which backend the app calls

getVertexAI and getAI both existed in the old module. git show ac3dd7c^:src/vertexai/firebase.ts exports all four of getAI, getVertexAI, getGenerativeModel, getImagenModel. Two coexisting functions aren't a rename pair.

getAI() with no options defaults to the Google AI (Gemini Developer API) backend; the Vertex equivalent is getAI(app, { backend: new VertexAIBackend() }). So a user on Vertex who runs ng update ends up with code that compiles and then talks to a different API, with different enablement and billing. Nothing in the diff would look wrong on review, which defeats the "ng update always shows its changes as a diff" safety net cited under Known limitation.

Two ways out:

  • rewrite getVertexAI(...) to getAI(app, { backend: new VertexAIBackend() }), adding VertexAIBackend to the rewritten import, or
  • leave getVertexAI calls alone and context.logger.warn with a pointer to the upgrade guide.

Worth confirming the SDK's default backend against @firebase/ai before picking. The symbol table in docs/version-21-upgrade.md and the note added to docs/ai.md need the same correction — as written, both teach the rename as safe.

2. export { VertexAI } from '@angular/fire/vertexai' renames the user's public export

src/schematics/update/v21/vertexai-to-ai.ts:181collectSpecifierEdit rewrites importedNameNode, which is element.name when there's no propertyName. For a re-export with a from clause that produces export { AI } from '@angular/fire/ai', so the file's external export name changes from VertexAI to AI and downstream consumers break.

identifierUsageEdit already handles this correctly for the bare local re-export — expanding to export { AI as VertexAI }, with a good comment explaining why. The from-clause path should do the same. (export { VertexAI as Foo } from '...' is already correct, since propertyName is set.)

3. The migration walks node_modules when a project has no sourceRoot

rewriteVertexAIToAI derives roots from sourceRoot || root. A root project with root: "" and no sourceRoot — which older CLI versions generate — gives posix.join('/', '')/, and every path in the tree passes the prefix test. The content.includes(specifier) prefilter keeps most files from being parsed, but any dependency that re-exports @angular/fire/vertexai gets rewritten in place inside node_modules.

A filePath.includes('/node_modules/') guard is the usual fix and costs nothing.

4. Step ordering interacts badly with the typescript external

Making typescript an esbuild external is the right call for package size, but it isn't declared anywhere in src/package.json — unlike firebase-tools, which is an optional peer. Under a strict or isolated node_modules layout the top-level import * as ts fails at module load, which takes down the whole migration.

Because src/schematics/update/v21/index.ts:14 runs the rewrite before alignFirebaseVersion, that failure also costs users the firebase-12 alignment — the part they genuinely can't do without. Two small changes: declare typescript as an optional peer dependency, and run alignFirebaseVersion first so a rewrite failure can only cost you the rewrite.

5. Not covered: direct firebase/vertexai imports

Since this migration also moves users to Firebase JS SDK 12, where that entry point is gone, direct SDK imports break too. The guide flags it as manual, but the same AST pass would handle it with one more entry in OLD_MODULE_SPECIFIERS — worth considering, subject to the same getVertexAI caveat above.

Merge order

This is stacked on unmerged predecessor work, and it edits the same README feature-table region as #3724 (that PR re-flows the row boundaries around the last two cells; this one rewrites the Vertex AI cell's content). Whichever lands second will need a manual rebase.

@tyler-reitz tyler-reitz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Marking this as changes-requested to hold the merge, per my earlier review.

The blocker is item 1: getVertexAI and getAI coexisted in the old module (git show ac3dd7c^:src/vertexai/firebase.ts exports both), so rewriting one to the other isn't a rename — it moves a Vertex user onto the Google AI backend silently, and the resulting diff looks correct on inspection. That needs resolving in the migration and in both docs pages before this lands.

Items 2-4 (the export { X } from public-export rename, the node_modules walk when sourceRoot is absent, and the typescript external / step-ordering interaction) are smaller but concrete. Item 5 is optional.

Happy to re-review once the backend question is settled.

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.

2 participants