UNPKG

@n8n/n8n-nodes-langchain

Version:

![Banner image](https://user-images.githubusercontent.com/10284570/173569848-c624317f-42b1-45a6-ab09-f0ea3c247648.png)

386 lines 16.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.OpenAiAssistant = void 0; const agents_1 = require("@langchain/classic/agents"); const openai_assistant_1 = require("@langchain/classic/experimental/openai_assistant"); const n8n_workflow_1 = require("n8n-workflow"); const openai_1 = require("openai"); const helpers_1 = require("../../../utils/helpers"); const tracing_1 = require("../../../utils/tracing"); const utils_1 = require("./utils"); const di_1 = require("@n8n/di"); const config_1 = require("@n8n/config"); const checkDomainRestrictions_1 = require("../../../utils/checkDomainRestrictions"); class OpenAiAssistant { constructor() { this.description = { displayName: 'OpenAI Assistant', name: 'openAiAssistant', hidden: true, icon: 'fa:robot', group: ['transform'], version: [1, 1.1], description: 'Utilizes Assistant API from Open AI.', subtitle: 'Open AI Assistant', defaults: { name: 'OpenAI Assistant', color: '#404040', }, codex: { alias: ['LangChain'], categories: ['AI'], subcategories: { AI: ['Agents', 'Root Nodes'], }, resources: { primaryDocumentation: [ { url: 'https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.openaiassistant/', }, ], }, }, inputs: [ { type: n8n_workflow_1.NodeConnectionTypes.Main }, { type: n8n_workflow_1.NodeConnectionTypes.AiTool, displayName: 'Tools' }, ], outputs: [n8n_workflow_1.NodeConnectionTypes.Main], builderHint: { inputs: { ai_tool: { required: false }, }, }, credentials: [ { name: 'openAiApi', required: true, }, ], requestDefaults: { ignoreHttpStatusErrors: true, baseURL: '={{ $parameter.options?.baseURL?.split("/").slice(0,-1).join("/") || "https://api.openai.com" }}', }, properties: [ { displayName: 'Operation', name: 'mode', type: 'options', noDataExpression: true, default: 'existing', options: [ { name: 'Use New Assistant', value: 'new', }, { name: 'Use Existing Assistant', value: 'existing', }, ], }, { displayName: 'Name', name: 'name', type: 'string', default: '', required: true, displayOptions: { show: { '/mode': ['new'], }, }, }, { displayName: 'Instructions', name: 'instructions', type: 'string', description: 'How the Assistant and model should behave or respond', default: '', typeOptions: { rows: 5, }, displayOptions: { show: { '/mode': ['new'], }, }, }, { displayName: 'Model', name: 'model', type: 'options', description: 'The model which will be used to power the assistant. <a href="https://beta.openai.com/docs/models/overview">Learn more</a>. The Retrieval tool requires gpt-3.5-turbo-1106 and gpt-4-1106-preview models.', required: true, displayOptions: { show: { '/mode': ['new'], }, }, typeOptions: { loadOptions: { routing: { request: { method: 'GET', url: '={{ $parameter.options?.baseURL?.split("/").slice(-1).pop() || "v1" }}/models', }, output: { postReceive: [ { type: 'rootProperty', properties: { property: 'data', }, }, { type: 'filter', properties: { pass: "={{ $responseItem.id.startsWith('gpt-') && !$responseItem.id.includes('instruct') }}", }, }, { type: 'setKeyValue', properties: { name: '={{$responseItem.id}}', value: '={{$responseItem.id}}', }, }, { type: 'sort', properties: { key: 'name', }, }, ], }, }, }, }, routing: { send: { type: 'body', property: 'model', }, }, default: 'gpt-3.5-turbo-1106', }, { displayName: 'Assistant', name: 'assistantId', type: 'options', noDataExpression: true, displayOptions: { show: { '/mode': ['existing'], }, }, description: 'The assistant to use. <a href="https://beta.openai.com/docs/assistants/overview">Learn more</a>.', typeOptions: { loadOptions: { routing: { request: { method: 'GET', headers: { 'OpenAI-Beta': 'assistants=v1', }, url: '={{ $parameter.options?.baseURL?.split("/").slice(-1).pop() || "v1" }}/assistants', }, output: { postReceive: [ { type: 'rootProperty', properties: { property: 'data', }, }, { type: 'setKeyValue', properties: { name: '={{$responseItem.name}}', value: '={{$responseItem.id}}', description: '={{$responseItem.model}}', }, }, { type: 'sort', properties: { key: 'name', }, }, ], }, }, }, }, routing: { send: { type: 'body', property: 'assistant', }, }, required: true, default: '', }, { displayName: 'Text', name: 'text', type: 'string', required: true, default: '={{ $json.chat_input }}', displayOptions: { show: { '@version': [1], }, }, }, { displayName: 'Text', name: 'text', type: 'string', required: true, default: '={{ $json.chatInput }}', displayOptions: { show: { '@version': [1.1], }, }, }, { displayName: 'OpenAI Tools', name: 'nativeTools', type: 'multiOptions', default: [], options: [ { name: 'Code Interpreter', value: 'code_interpreter', }, { name: 'Knowledge Retrieval', value: 'retrieval', }, ], }, { displayName: 'Connect your own custom tools to this node on the canvas', name: 'noticeTools', type: 'notice', default: '', }, { displayName: 'Upload files for retrieval using the <a href="https://platform.openai.com/playground" target="_blank">OpenAI website<a/>', name: 'noticeTools', type: 'notice', typeOptions: { noticeTheme: 'info', }, displayOptions: { show: { '/nativeTools': ['retrieval'] } }, default: '', }, { displayName: 'Options', name: 'options', placeholder: 'Add Option', description: 'Additional options to add', type: 'collection', default: {}, options: [ { displayName: 'Base URL', name: 'baseURL', default: 'https://api.openai.com/v1', description: 'Override the default base URL for the API', type: 'string', }, { displayName: 'Max Retries', name: 'maxRetries', default: 2, description: 'Maximum number of retries to attempt', type: 'number', }, { displayName: 'Timeout', name: 'timeout', default: 10000, description: 'Maximum amount of time a request is allowed to take in milliseconds', type: 'number', }, ], }, ], }; } async execute() { const nodeVersion = this.getNode().typeVersion; const tools = await (0, helpers_1.getConnectedTools)(this, nodeVersion > 1, false); const credentials = await this.getCredentials('openAiApi'); const items = this.getInputData(); const returnData = []; for (let itemIndex = 0; itemIndex < items.length; itemIndex++) { try { const input = this.getNodeParameter('text', itemIndex); const assistantId = this.getNodeParameter('assistantId', itemIndex, ''); const nativeTools = this.getNodeParameter('nativeTools', itemIndex, []); const options = this.getNodeParameter('options', itemIndex, {}); if (input === undefined) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'The ‘text‘ parameter is empty.'); } const { openAiDefaultHeaders } = di_1.Container.get(config_1.AiConfig); const defaultHeaders = (0, helpers_1.mergeCustomHeaders)(credentials, openAiDefaultHeaders ?? {}); if (options.baseURL) { (0, checkDomainRestrictions_1.checkDomainRestrictions)(this, credentials, options.baseURL); } const client = new openai_1.OpenAI({ apiKey: credentials.apiKey, maxRetries: options.maxRetries ?? 2, timeout: options.timeout ?? 10000, baseURL: options.baseURL, defaultHeaders, }); let agent; const nativeToolsParsed = nativeTools.map((tool) => ({ type: tool })); const transformedConnectedTools = tools?.map(utils_1.formatToOpenAIAssistantTool) ?? []; const newTools = [...transformedConnectedTools, ...nativeToolsParsed]; if (assistantId) { agent = new openai_assistant_1.OpenAIAssistantRunnable({ assistantId, client, asAgent: true }); await client.beta.assistants.update(assistantId, { tools: newTools, }); } else { const name = this.getNodeParameter('name', itemIndex, ''); const instructions = this.getNodeParameter('instructions', itemIndex, ''); const model = this.getNodeParameter('model', itemIndex, 'gpt-3.5-turbo-1106'); agent = await openai_assistant_1.OpenAIAssistantRunnable.createAssistant({ model, client, instructions, name, tools: newTools, asAgent: true, }); } const agentExecutor = agents_1.AgentExecutor.fromAgentAndTools({ agent, tools, }); const response = await agentExecutor.withConfig((0, tracing_1.getTracingConfig)(this)).invoke({ content: input, signal: this.getExecutionCancelSignal(), timeout: options.timeout ?? 10000, }); returnData.push({ json: response }); } catch (error) { if (this.continueOnFail()) { returnData.push({ json: { error: error.message }, pairedItem: { item: itemIndex } }); continue; } throw error; } } return [returnData]; } } exports.OpenAiAssistant = OpenAiAssistant; //# sourceMappingURL=OpenAiAssistant.node.js.map