2024-07-11 05:41:10 -07:00
/* eslint-disable n8n-nodes-base/node-dirname-against-convention */
import {
NodeConnectionType ,
type INodeType ,
type INodeTypeDescription ,
2024-10-28 03:37:23 -07:00
type ISupplyDataFunctions ,
2024-07-11 05:41:10 -07:00
type SupplyData ,
type ILoadOptionsFunctions ,
type JsonObject ,
NodeOperationError ,
} from 'n8n-workflow' ;
import { ChatVertexAI } from '@langchain/google-vertexai' ;
import type { SafetySetting } from '@google/generative-ai' ;
import { ProjectsClient } from '@google-cloud/resource-manager' ;
2024-09-17 00:18:45 -07:00
import { formatPrivateKey } from 'n8n-nodes-base/dist/utils/utilities' ;
2024-07-11 05:41:10 -07:00
import { getConnectionHintNoticeField } from '../../../utils/sharedFields' ;
import { N8nLlmTracing } from '../N8nLlmTracing' ;
import { additionalOptions } from '../gemini-common/additional-options' ;
2024-07-19 08:57:50 -07:00
import { makeErrorFromStatus } from './error-handling' ;
2024-11-08 01:17:11 -08:00
import { makeN8nLlmFailedAttemptHandler } from '../n8nLlmFailedAttemptHandler' ;
2024-07-11 05:41:10 -07:00
export class LmChatGoogleVertex implements INodeType {
description : INodeTypeDescription = {
displayName : 'Google Vertex Chat Model' ,
// eslint-disable-next-line n8n-nodes-base/node-class-description-name-miscased
name : 'lmChatGoogleVertex' ,
icon : 'file:google.svg' ,
group : [ 'transform' ] ,
version : 1 ,
description : 'Chat Model Google Vertex' ,
defaults : {
name : 'Google Vertex Chat Model' ,
} ,
codex : {
categories : [ 'AI' ] ,
subcategories : {
2024-08-05 04:59:02 -07:00
AI : [ 'Language Models' , 'Root Nodes' ] ,
2024-07-23 07:40:28 -07:00
'Language Models' : [ 'Chat Models (Recommended)' ] ,
2024-07-11 05:41:10 -07:00
} ,
resources : {
primaryDocumentation : [
{
url : 'https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.lmchatgooglevertex/' ,
} ,
] ,
} ,
} ,
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
inputs : [ ] ,
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
outputs : [ NodeConnectionType . AiLanguageModel ] ,
outputNames : [ 'Model' ] ,
credentials : [
{
name : 'googleApi' ,
required : true ,
} ,
] ,
properties : [
getConnectionHintNoticeField ( [ NodeConnectionType . AiChain , NodeConnectionType . AiAgent ] ) ,
{
displayName : 'Project ID' ,
name : 'projectId' ,
type : 'resourceLocator' ,
default : { mode : 'list' , value : '' } ,
required : true ,
description : 'Select or enter your Google Cloud project ID' ,
modes : [
{
displayName : 'From List' ,
name : 'list' ,
type : 'list' ,
typeOptions : {
searchListMethod : 'gcpProjectsList' ,
} ,
} ,
{
displayName : 'ID' ,
name : 'id' ,
type : 'string' ,
} ,
] ,
} ,
{
displayName : 'Model Name' ,
name : 'modelName' ,
type : 'string' ,
description :
'The model which will generate the completion. <a href="https://cloud.google.com/vertex-ai/generative-ai/docs/learn/models">Learn more</a>.' ,
default : 'gemini-1.5-flash' ,
} ,
additionalOptions ,
] ,
} ;
methods = {
listSearch : {
async gcpProjectsList ( this : ILoadOptionsFunctions ) {
const results : Array < { name : string ; value : string } > = [ ] ;
const credentials = await this . getCredentials ( 'googleApi' ) ;
2024-09-17 00:18:45 -07:00
const privateKey = formatPrivateKey ( credentials . privateKey as string ) ;
const email = ( credentials . email as string ) . trim ( ) ;
2024-07-11 05:41:10 -07:00
const client = new ProjectsClient ( {
credentials : {
2024-09-17 00:18:45 -07:00
client_email : email ,
private_key : privateKey ,
2024-07-11 05:41:10 -07:00
} ,
} ) ;
const [ projects ] = await client . searchProjects ( ) ;
for ( const project of projects ) {
if ( project . projectId ) {
results . push ( {
name : project.displayName ? ? project . projectId ,
value : project.projectId ,
} ) ;
}
}
return { results } ;
} ,
} ,
} ;
2024-10-28 03:37:23 -07:00
async supplyData ( this : ISupplyDataFunctions , itemIndex : number ) : Promise < SupplyData > {
2024-07-11 05:41:10 -07:00
const credentials = await this . getCredentials ( 'googleApi' ) ;
2024-09-17 00:18:45 -07:00
const privateKey = formatPrivateKey ( credentials . privateKey as string ) ;
const email = ( credentials . email as string ) . trim ( ) ;
2024-07-11 05:41:10 -07:00
const modelName = this . getNodeParameter ( 'modelName' , itemIndex ) as string ;
const projectId = this . getNodeParameter ( 'projectId' , itemIndex , '' , {
extractValue : true ,
} ) as string ;
const options = this . getNodeParameter ( 'options' , itemIndex , {
maxOutputTokens : 2048 ,
temperature : 0.4 ,
topK : 40 ,
topP : 0.9 ,
} ) as {
maxOutputTokens : number ;
temperature : number ;
topK : number ;
topP : number ;
} ;
const safetySettings = this . getNodeParameter (
'options.safetySettings.values' ,
itemIndex ,
null ,
) as SafetySetting [ ] ;
try {
const model = new ChatVertexAI ( {
authOptions : {
projectId ,
credentials : {
2024-09-17 00:18:45 -07:00
client_email : email ,
private_key : privateKey ,
2024-07-11 05:41:10 -07:00
} ,
} ,
model : modelName ,
topK : options.topK ,
topP : options.topP ,
temperature : options.temperature ,
maxOutputTokens : options.maxOutputTokens ,
safetySettings ,
callbacks : [ new N8nLlmTracing ( this ) ] ,
// Handle ChatVertexAI invocation errors to provide better error messages
2024-11-08 01:17:11 -08:00
onFailedAttempt : makeN8nLlmFailedAttemptHandler ( this , ( error : any ) = > {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
2024-07-11 05:41:10 -07:00
const customError = makeErrorFromStatus ( Number ( error ? . response ? . status ) , {
modelName ,
} ) ;
if ( customError ) {
throw new NodeOperationError ( this . getNode ( ) , error as JsonObject , customError ) ;
}
throw error ;
2024-11-08 01:17:11 -08:00
} ) ,
2024-07-11 05:41:10 -07:00
} ) ;
return {
response : model ,
} ;
} catch ( e ) {
// Catch model name validation error from LangChain (https://github.com/langchain-ai/langchainjs/blob/ef201d0ee85ee4049078270a0cfd7a1767e624f8/libs/langchain-google-common/src/utils/common.ts#L124)
// to show more helpful error message
if ( e ? . message ? . startsWith ( 'Unable to verify model params' ) ) {
throw new NodeOperationError ( this . getNode ( ) , e as JsonObject , {
message : 'Unsupported model' ,
description : "Only models starting with 'gemini' are supported." ,
} ) ;
}
// Assume all other exceptions while creating a new ChatVertexAI instance are parameter validation errors
throw new NodeOperationError ( this . getNode ( ) , e as JsonObject , {
message : 'Invalid options' ,
description : e.message ,
} ) ;
}
}
}