-
Notifications
You must be signed in to change notification settings - Fork 3.5k
feat(codemods): add codemod for providerMetadata key change for google-vertex #11049
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@ai-sdk/codemod': patch | ||
| --- | ||
|
|
||
| feat(codemods): add codemods for providerMetadata key change |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
166 changes: 166 additions & 0 deletions
166
packages/codemod/src/codemods/v6/rename-vertex-provider-metadata-key.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,166 @@ | ||
| import { createTransformer } from '../lib/create-transformer'; | ||
|
|
||
| export default createTransformer((fileInfo, api, options, context) => { | ||
| const { j, root } = context; | ||
|
|
||
| // Only apply to files that import from @ai-sdk/google-vertex | ||
| const hasVertexImport = | ||
| root | ||
| .find(j.ImportDeclaration) | ||
| .filter(path => { | ||
| return ( | ||
| path.node.source.type === 'StringLiteral' && | ||
| (path.node.source.value === '@ai-sdk/google-vertex' || | ||
| path.node.source.value === '@ai-sdk/google-vertex/edge') | ||
| ); | ||
| }) | ||
| .size() > 0; | ||
|
|
||
| if (!hasVertexImport) { | ||
| return; | ||
| } | ||
|
|
||
| // Helper to check if a node represents providerMetadata access | ||
| const isProviderMetadataAccess = (object: any): boolean => { | ||
| if (object.type === 'Identifier') { | ||
| return object.name === 'providerMetadata'; | ||
| } | ||
| // Handle chained access like result.providerMetadata or event?.providerMetadata | ||
| if ( | ||
| object.type === 'MemberExpression' || | ||
| object.type === 'OptionalMemberExpression' | ||
| ) { | ||
| const prop = object.property; | ||
| return prop.type === 'Identifier' && prop.name === 'providerMetadata'; | ||
| } | ||
| return false; | ||
| }; | ||
|
|
||
| // Helper to check if a node is inside a providerOptions object | ||
| const isInsideProviderOptions = (path: any): boolean => { | ||
| let current = path.parent; | ||
| while (current) { | ||
| if (current.node.type === 'ObjectExpression') { | ||
| const grandparent = current.parent; | ||
| if ( | ||
| grandparent && | ||
| (grandparent.node.type === 'Property' || | ||
| grandparent.node.type === 'ObjectProperty') | ||
| ) { | ||
| const key = grandparent.node.key; | ||
| if (key.type === 'Identifier' && key.name === 'providerOptions') { | ||
| return true; | ||
| } | ||
| } | ||
| } | ||
| current = current.parent; | ||
| } | ||
| return false; | ||
| }; | ||
|
|
||
| // Transform providerMetadata?.google and providerMetadata.google | ||
| // Using MemberExpression (covers both optional and non-optional in jscodeshift) | ||
| root.find(j.MemberExpression).forEach(path => { | ||
| const property = path.node.property; | ||
| const object = path.node.object; | ||
|
|
||
| // Property must be 'google' | ||
| if (property.type !== 'Identifier' || property.name !== 'google') { | ||
| return; | ||
| } | ||
|
|
||
| // Check if accessing providerMetadata | ||
| if (isProviderMetadataAccess(object)) { | ||
| property.name = 'vertex'; | ||
| context.hasChanges = true; | ||
| } | ||
| }); | ||
|
|
||
| // Transform destructuring: const { google } = providerMetadata | ||
| // Also handles: const { google: metadata } = providerMetadata | ||
| root.find(j.VariableDeclarator).forEach(path => { | ||
| const id = path.node.id; | ||
| const init = path.node.init; | ||
|
|
||
| if (id.type !== 'ObjectPattern') { | ||
| return; | ||
| } | ||
|
|
||
| // Check if init is providerMetadata or something?.providerMetadata | ||
| let isFromProviderMetadata = false; | ||
| if (init) { | ||
| if (init.type === 'Identifier' && init.name === 'providerMetadata') { | ||
| isFromProviderMetadata = true; | ||
| } else if ( | ||
| (init.type === 'MemberExpression' || | ||
| init.type === 'OptionalMemberExpression') && | ||
| init.property.type === 'Identifier' && | ||
| init.property.name === 'providerMetadata' | ||
| ) { | ||
| isFromProviderMetadata = true; | ||
| } else if ( | ||
| init.type === 'LogicalExpression' && | ||
| init.operator === '??' && | ||
| init.left.type === 'MemberExpression' && | ||
| init.left.property.type === 'Identifier' && | ||
| init.left.property.name === 'providerMetadata' | ||
| ) { | ||
| // Handle: const { google } = result.providerMetadata ?? {} | ||
| isFromProviderMetadata = true; | ||
| } | ||
| } | ||
|
|
||
| if (!isFromProviderMetadata) { | ||
| return; | ||
| } | ||
|
|
||
| // Find and rename 'google' property in destructuring | ||
| id.properties.forEach(prop => { | ||
| if (prop.type === 'ObjectProperty' || prop.type === 'Property') { | ||
| const key = prop.key; | ||
| if (key.type === 'Identifier' && key.name === 'google') { | ||
| key.name = 'vertex'; | ||
| // If shorthand, also rename the value | ||
| if ( | ||
| prop.shorthand && | ||
| prop.value.type === 'Identifier' && | ||
| prop.value.name === 'google' | ||
| ) { | ||
| prop.value.name = 'vertex'; | ||
| } | ||
| context.hasChanges = true; | ||
| } | ||
| } | ||
| }); | ||
| }); | ||
|
|
||
| // Transform providerOptions: { google: {...} } → providerOptions: { vertex: {...} } | ||
| root.find(j.Property).forEach(path => { | ||
| const key = path.node.key; | ||
|
|
||
| // Key must be 'google' | ||
| if (key.type !== 'Identifier' || key.name !== 'google') { | ||
| return; | ||
| } | ||
|
|
||
| // Check if this property is inside a providerOptions object | ||
| if (isInsideProviderOptions(path)) { | ||
| key.name = 'vertex'; | ||
| context.hasChanges = true; | ||
| } | ||
| }); | ||
|
|
||
| // Also handle ObjectProperty (for some AST variations) | ||
| root.find(j.ObjectProperty).forEach(path => { | ||
| const key = path.node.key; | ||
|
|
||
| if (key.type !== 'Identifier' || key.name !== 'google') { | ||
| return; | ||
| } | ||
|
|
||
| if (isInsideProviderOptions(path)) { | ||
| key.name = 'vertex'; | ||
| context.hasChanges = true; | ||
| } | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
...odemod/src/test/__testfixtures__/rename-vertex-provider-metadata-key-google-only.input.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| // @ts-nocheck | ||
| // This file uses @ai-sdk/google (NOT vertex) - should NOT be transformed | ||
| import { google } from '@ai-sdk/google'; | ||
| import { generateText } from 'ai'; | ||
|
|
||
| const result = await generateText({ | ||
| model: google('gemini-2.5-flash'), | ||
| providerOptions: { | ||
| google: { | ||
| safetySettings: [], | ||
| }, | ||
| }, | ||
| prompt: 'Hello', | ||
| }); | ||
|
|
||
| // These should stay as 'google' since we're using @ai-sdk/google | ||
| console.log(result.providerMetadata?.google?.safetyRatings); | ||
| const { google: metadata } = result.providerMetadata ?? {}; | ||
|
|
19 changes: 19 additions & 0 deletions
19
...demod/src/test/__testfixtures__/rename-vertex-provider-metadata-key-google-only.output.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| // @ts-nocheck | ||
| // This file uses @ai-sdk/google (NOT vertex) - should NOT be transformed | ||
| import { google } from '@ai-sdk/google'; | ||
| import { generateText } from 'ai'; | ||
|
|
||
| const result = await generateText({ | ||
| model: google('gemini-2.5-flash'), | ||
| providerOptions: { | ||
| google: { | ||
| safetySettings: [], | ||
| }, | ||
| }, | ||
| prompt: 'Hello', | ||
| }); | ||
|
|
||
| // These should stay as 'google' since we're using @ai-sdk/google | ||
| console.log(result.providerMetadata?.google?.safetyRatings); | ||
| const { google: metadata } = result.providerMetadata ?? {}; | ||
|
|
83 changes: 83 additions & 0 deletions
83
packages/codemod/src/test/__testfixtures__/rename-vertex-provider-metadata-key.input.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| // @ts-nocheck | ||
| import { vertex } from '@ai-sdk/google-vertex'; | ||
| import { generateText, streamText } from 'ai'; | ||
|
|
||
| // Case 1: Direct providerMetadata access with optional chaining | ||
| const result1 = await generateText({ | ||
| model: vertex('gemini-2.5-flash'), | ||
| prompt: 'Hello', | ||
| }); | ||
| console.log(result1.providerMetadata?.google?.safetyRatings); | ||
| console.log(result1.providerMetadata?.google?.groundingMetadata); | ||
| console.log(result1.providerMetadata?.google?.urlContextMetadata); | ||
| console.log(result1.providerMetadata?.google?.promptFeedback); | ||
| console.log(result1.providerMetadata?.google?.usageMetadata); | ||
|
|
||
| // Case 2: Non-optional access | ||
| const metadata = result1.providerMetadata.google; | ||
| const ratings = result1.providerMetadata.google.safetyRatings; | ||
|
|
||
| // Case 3: Destructuring from providerMetadata | ||
| const { google } = result1.providerMetadata ?? {}; | ||
| const { google: vertexMeta } = result1.providerMetadata ?? {}; | ||
|
|
||
| // Case 4: providerOptions input | ||
| const result2 = await generateText({ | ||
| model: vertex('gemini-2.5-flash'), | ||
| providerOptions: { | ||
| google: { | ||
| safetySettings: [ | ||
| { | ||
| category: 'HARM_CATEGORY_DANGEROUS_CONTENT', | ||
| threshold: 'BLOCK_LOW_AND_ABOVE', | ||
| }, | ||
| ], | ||
| }, | ||
| }, | ||
| prompt: 'Hello', | ||
| }); | ||
|
|
||
| // Case 5: Streaming with finish event | ||
| const { stream } = await streamText({ | ||
| model: vertex('gemini-2.5-flash'), | ||
| prompt: 'Hello', | ||
| }); | ||
|
|
||
| for await (const event of stream) { | ||
| if (event.type === 'finish') { | ||
| console.log(event.providerMetadata?.google?.safetyRatings); | ||
| } | ||
| } | ||
|
|
||
| // Case 6: Content parts with thoughtSignature | ||
| const result3 = await generateText({ | ||
| model: vertex('gemini-2.5-flash'), | ||
| prompt: 'Think step by step', | ||
| }); | ||
|
|
||
| for (const part of result3.content) { | ||
| if (part.providerMetadata?.google?.thoughtSignature) { | ||
| console.log(part.providerMetadata.google.thoughtSignature); | ||
| } | ||
| } | ||
|
|
||
| // Case 7: Variable assignment | ||
| const providerMetadata = result1.providerMetadata; | ||
| const googleMeta = providerMetadata?.google; | ||
|
|
||
| // Case 8: Function that accesses providerMetadata | ||
| function logSafetyRatings(result: any) { | ||
| return result.providerMetadata?.google?.safetyRatings; | ||
| } | ||
|
|
||
| // Case 9: Nested providerOptions in larger config | ||
| const config = { | ||
| model: vertex('gemini-2.5-flash'), | ||
| providerOptions: { | ||
| google: { | ||
| thinkingConfig: { | ||
| thinkingBudget: 1024, | ||
| }, | ||
| }, | ||
| }, | ||
| }; |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe add a note to the vertex key rename section that a codemod exists? could be good for other sections with codemods as well, so people immediately know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will create a follow up PR for this