feat: add AWS SNS tool for publishing messages to SNS topics (#5049)
This commit is contained in:
parent
db4de4552a
commit
32e5b13c46
|
|
@ -0,0 +1,209 @@
|
|||
import { Tool } from '@langchain/core/tools'
|
||||
import { ICommonObject, INode, INodeData, INodeOptionsValue, INodeParams } from '../../../src/Interface'
|
||||
import { getBaseClasses, getCredentialData, getCredentialParam } from '../../../src/utils'
|
||||
import { SNSClient, ListTopicsCommand, PublishCommand } from '@aws-sdk/client-sns'
|
||||
|
||||
class AWSSNSTool extends Tool {
|
||||
name = 'aws_sns_publish'
|
||||
description = 'Publishes a message to an AWS SNS topic'
|
||||
private snsClient: SNSClient
|
||||
private topicArn: string
|
||||
|
||||
constructor(snsClient: SNSClient, topicArn: string) {
|
||||
super()
|
||||
this.snsClient = snsClient
|
||||
this.topicArn = topicArn
|
||||
}
|
||||
|
||||
async _call(message: string): Promise<string> {
|
||||
try {
|
||||
const command = new PublishCommand({
|
||||
TopicArn: this.topicArn,
|
||||
Message: message
|
||||
})
|
||||
|
||||
const response = await this.snsClient.send(command)
|
||||
return `Successfully published message to SNS topic. MessageId: ${response.MessageId}`
|
||||
} catch (error) {
|
||||
return `Failed to publish message to SNS: ${error}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AWSSNS_Tools implements INode {
|
||||
label: string
|
||||
name: string
|
||||
version: number
|
||||
type: string
|
||||
icon: string
|
||||
category: string
|
||||
description: string
|
||||
baseClasses: string[]
|
||||
credential: INodeParams
|
||||
inputs: INodeParams[]
|
||||
|
||||
constructor() {
|
||||
this.label = 'AWS SNS'
|
||||
this.name = 'awsSNS'
|
||||
this.version = 1.0
|
||||
this.type = 'AWSSNS'
|
||||
this.icon = 'awssns.svg'
|
||||
this.category = 'Tools'
|
||||
this.description = 'Publish messages to AWS SNS topics'
|
||||
this.baseClasses = [this.type, ...getBaseClasses(AWSSNSTool)]
|
||||
this.credential = {
|
||||
label: 'AWS Credentials',
|
||||
name: 'credential',
|
||||
type: 'credential',
|
||||
credentialNames: ['awsApi']
|
||||
}
|
||||
this.inputs = [
|
||||
{
|
||||
label: 'AWS Region',
|
||||
name: 'region',
|
||||
type: 'options',
|
||||
options: [
|
||||
{ label: 'US East (N. Virginia) - us-east-1', name: 'us-east-1' },
|
||||
{ label: 'US East (Ohio) - us-east-2', name: 'us-east-2' },
|
||||
{ label: 'US West (N. California) - us-west-1', name: 'us-west-1' },
|
||||
{ label: 'US West (Oregon) - us-west-2', name: 'us-west-2' },
|
||||
{ label: 'Africa (Cape Town) - af-south-1', name: 'af-south-1' },
|
||||
{ label: 'Asia Pacific (Hong Kong) - ap-east-1', name: 'ap-east-1' },
|
||||
{ label: 'Asia Pacific (Mumbai) - ap-south-1', name: 'ap-south-1' },
|
||||
{ label: 'Asia Pacific (Osaka) - ap-northeast-3', name: 'ap-northeast-3' },
|
||||
{ label: 'Asia Pacific (Seoul) - ap-northeast-2', name: 'ap-northeast-2' },
|
||||
{ label: 'Asia Pacific (Singapore) - ap-southeast-1', name: 'ap-southeast-1' },
|
||||
{ label: 'Asia Pacific (Sydney) - ap-southeast-2', name: 'ap-southeast-2' },
|
||||
{ label: 'Asia Pacific (Tokyo) - ap-northeast-1', name: 'ap-northeast-1' },
|
||||
{ label: 'Canada (Central) - ca-central-1', name: 'ca-central-1' },
|
||||
{ label: 'Europe (Frankfurt) - eu-central-1', name: 'eu-central-1' },
|
||||
{ label: 'Europe (Ireland) - eu-west-1', name: 'eu-west-1' },
|
||||
{ label: 'Europe (London) - eu-west-2', name: 'eu-west-2' },
|
||||
{ label: 'Europe (Milan) - eu-south-1', name: 'eu-south-1' },
|
||||
{ label: 'Europe (Paris) - eu-west-3', name: 'eu-west-3' },
|
||||
{ label: 'Europe (Stockholm) - eu-north-1', name: 'eu-north-1' },
|
||||
{ label: 'Middle East (Bahrain) - me-south-1', name: 'me-south-1' },
|
||||
{ label: 'South America (São Paulo) - sa-east-1', name: 'sa-east-1' }
|
||||
],
|
||||
default: 'us-east-1',
|
||||
description: 'AWS Region where your SNS topics are located'
|
||||
},
|
||||
{
|
||||
label: 'SNS Topic',
|
||||
name: 'topicArn',
|
||||
type: 'asyncOptions',
|
||||
loadMethod: 'listTopics',
|
||||
description: 'Select the SNS topic to publish to',
|
||||
refresh: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
loadMethods = {
|
||||
listTopics: async (nodeData: INodeData, options?: ICommonObject): Promise<INodeOptionsValue[]> => {
|
||||
try {
|
||||
const credentialData = await getCredentialData(nodeData.credential ?? '', options ?? {})
|
||||
|
||||
const accessKeyId = getCredentialParam('awsKey', credentialData, nodeData)
|
||||
const secretAccessKey = getCredentialParam('awsSecret', credentialData, nodeData)
|
||||
const sessionToken = getCredentialParam('awsSession', credentialData, nodeData)
|
||||
|
||||
const region = (nodeData.inputs?.region as string) || 'us-east-1'
|
||||
|
||||
if (!accessKeyId || !secretAccessKey) {
|
||||
return [
|
||||
{
|
||||
label: 'AWS Credentials Required',
|
||||
name: 'placeholder',
|
||||
description: 'Enter AWS Access Key ID and Secret Access Key'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const credentials: any = {
|
||||
accessKeyId: accessKeyId,
|
||||
secretAccessKey: secretAccessKey
|
||||
}
|
||||
|
||||
if (sessionToken) {
|
||||
credentials.sessionToken = sessionToken
|
||||
}
|
||||
|
||||
const snsClient = new SNSClient({
|
||||
region: region,
|
||||
credentials: credentials
|
||||
})
|
||||
|
||||
const command = new ListTopicsCommand({})
|
||||
const response = await snsClient.send(command)
|
||||
|
||||
if (!response.Topics || response.Topics.length === 0) {
|
||||
return [
|
||||
{
|
||||
label: 'No topics found',
|
||||
name: 'placeholder',
|
||||
description: 'No SNS topics found in this region'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
return response.Topics.map((topic) => {
|
||||
const topicArn = topic.TopicArn || ''
|
||||
const topicName = topicArn.split(':').pop() || topicArn
|
||||
return {
|
||||
label: topicName,
|
||||
name: topicArn,
|
||||
description: topicArn
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Error loading SNS topics:', error)
|
||||
return [
|
||||
{
|
||||
label: 'Error Loading Topics',
|
||||
name: 'error',
|
||||
description: `Failed to load topics: ${error}`
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
|
||||
const credentialData = await getCredentialData(nodeData.credential ?? '', options)
|
||||
|
||||
const accessKeyId = getCredentialParam('awsKey', credentialData, nodeData)
|
||||
const secretAccessKey = getCredentialParam('awsSecret', credentialData, nodeData)
|
||||
const sessionToken = getCredentialParam('awsSession', credentialData, nodeData)
|
||||
|
||||
const region = (nodeData.inputs?.region as string) || 'us-east-1'
|
||||
const topicArn = nodeData.inputs?.topicArn as string
|
||||
|
||||
if (!accessKeyId || !secretAccessKey) {
|
||||
throw new Error('AWS Access Key ID and Secret Access Key are required')
|
||||
}
|
||||
|
||||
if (!topicArn) {
|
||||
throw new Error('SNS Topic ARN is required')
|
||||
}
|
||||
|
||||
const credentials: any = {
|
||||
accessKeyId: accessKeyId,
|
||||
secretAccessKey: secretAccessKey
|
||||
}
|
||||
|
||||
if (sessionToken) {
|
||||
credentials.sessionToken = sessionToken
|
||||
}
|
||||
|
||||
const snsClient = new SNSClient({
|
||||
region: region,
|
||||
credentials: credentials
|
||||
})
|
||||
|
||||
return new AWSSNSTool(snsClient, topicArn)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { nodeClass: AWSSNS_Tools }
|
||||
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 85 85" fill="#fff" fill-rule="evenodd" stroke="#000" stroke-linecap="round" stroke-linejoin="round"><use xlink:href="#A" x="2.5" y="2.5"/><symbol id="A" overflow="visible"><g stroke="none"><path d="M30.904 72.366l-8.268-2.304-7.813-8.891 8.711.722 7.37 10.474z" fill="#b8852e"/><path d="M30.904 72.365l5.913-12.36-5.528-.78-7.755 2.665 7.37 10.474z" fill="#d9a741"/><path d="M11.79 66.511l-4.641-1.303-5.119-5.831 5.434.85 4.326 6.284z" fill="#b8852e"/><path d="M11.791 66.512l3.335-6.959-3.114-.442-4.548 1.117 4.327 6.284z" fill="#d9a741"/><path d="M0 59.576l4.746.966L28 40.361 4.746 17.76 0 20.146v39.43z" fill="#876929"/><path d="M23.102 21.74v37.102L4.746 60.542V17.76l18.356 3.98z" fill="#d9a741"/><path d="M10.612 61.798l8.14 1.641 22.484-25.988-22.484-26.756-8.14 4.108v46.995z" fill="#876929"/><path d="M65.236 25.429v32.04l-46.484 5.97V10.695l46.484 14.734z" fill="#d9a741"/><path d="M56.828 80l-11.743-3.282-11.102-12.639 12.385 1.036L56.828 80z" fill="#b8852e"/><path d="M56.828 80l8.408-17.562-7.86-1.117-11.009 3.794L56.828 80z" fill="#d9a741"/><path d="M28 65.173l11.977 2.304 16.245-33.739L39.977 0 28 6.04v59.133z" fill="#876929"/><path d="M39.977 67.478L80 59.482V19.971L39.977 0v67.478z" fill="#d9a741"/></g></symbol></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
|
@ -24,6 +24,7 @@
|
|||
"@aws-sdk/client-dynamodb": "^3.360.0",
|
||||
"@aws-sdk/client-s3": "^3.844.0",
|
||||
"@aws-sdk/client-secrets-manager": "^3.699.0",
|
||||
"@aws-sdk/client-sns": "^3.699.0",
|
||||
"@datastax/astra-db-ts": "1.5.0",
|
||||
"@dqbd/tiktoken": "^1.0.21",
|
||||
"@e2b/code-interpreter": "^1.5.1",
|
||||
|
|
|
|||
77269
pnpm-lock.yaml
77269
pnpm-lock.yaml
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue