diff --git a/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/assistant/create.operation.ts b/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/assistant/create.operation.ts
index 341a17712a..b9a0dee535 100644
--- a/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/assistant/create.operation.ts
+++ b/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/assistant/create.operation.ts
@@ -9,7 +9,7 @@ import { apiRequest } from '../../transport';
import { modelRLC } from '../descriptions';
const properties: INodeProperties[] = [
- modelRLC,
+ modelRLC('modelSearch'),
{
displayName: 'Name',
name: 'name',
diff --git a/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/assistant/update.operation.ts b/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/assistant/update.operation.ts
index 061bb0165a..8a997aa99d 100644
--- a/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/assistant/update.operation.ts
+++ b/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/assistant/update.operation.ts
@@ -67,7 +67,7 @@ const properties: INodeProperties[] = [
description:
'Whether to augments the assistant with knowledge from outside its model, such as proprietary product information or documents, find more here',
},
- { ...modelRLC, required: false },
+ { ...modelRLC('modelSearch'), required: false },
{
displayName: 'Name',
name: 'name',
diff --git a/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/descriptions.ts b/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/descriptions.ts
index 8416e794d2..2f27ba6414 100644
--- a/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/descriptions.ts
+++ b/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/descriptions.ts
@@ -1,6 +1,6 @@
import type { INodeProperties } from 'n8n-workflow';
-export const modelRLC: INodeProperties = {
+export const modelRLC = (searchListMethod: string = 'modelSearch'): INodeProperties => ({
displayName: 'Model',
name: 'modelId',
type: 'resourceLocator',
@@ -12,7 +12,7 @@ export const modelRLC: INodeProperties = {
name: 'list',
type: 'list',
typeOptions: {
- searchListMethod: 'modelSearch',
+ searchListMethod,
searchable: true,
},
},
@@ -23,7 +23,7 @@ export const modelRLC: INodeProperties = {
placeholder: 'e.g. gpt-4',
},
],
-};
+});
export const assistantRLC: INodeProperties = {
displayName: 'Assistant',
diff --git a/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/image/analyze.operation.ts b/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/image/analyze.operation.ts
index b29019602a..07a91ab82d 100644
--- a/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/image/analyze.operation.ts
+++ b/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/image/analyze.operation.ts
@@ -6,8 +6,13 @@ import type {
} from 'n8n-workflow';
import { updateDisplayOptions, NodeOperationError } from 'n8n-workflow';
import { apiRequest } from '../../transport';
+import { modelRLC } from '../descriptions';
const properties: INodeProperties[] = [
+ {
+ ...modelRLC('imageModelSearch'),
+ displayOptions: { show: { '@version': [{ _cnd: { gte: 1.4 } }] } },
+ },
{
displayName: 'Text Input',
name: 'text',
@@ -123,7 +128,11 @@ const displayOptions = {
export const description = updateDisplayOptions(displayOptions, properties);
export async function execute(this: IExecuteFunctions, i: number): Promise {
- const model = 'gpt-4-vision-preview';
+ let model = 'gpt-4-vision-preview';
+ if (this.getNode().typeVersion >= 1.4) {
+ model = this.getNodeParameter('modelId', i, 'gpt-4o', { extractValue: true }) as string;
+ }
+
const text = this.getNodeParameter('text', i, '') as string;
const inputType = this.getNodeParameter('inputType', i) as string;
const options = this.getNodeParameter('options', i, {});
diff --git a/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/text/message.operation.ts b/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/text/message.operation.ts
index ddcb250d26..4cf72e9f5f 100644
--- a/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/text/message.operation.ts
+++ b/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/text/message.operation.ts
@@ -14,7 +14,7 @@ import { getConnectedTools } from '../../../../../utils/helpers';
import { MODELS_NOT_SUPPORT_FUNCTION_CALLS } from '../../helpers/constants';
const properties: INodeProperties[] = [
- modelRLC,
+ modelRLC('modelSearch'),
{
displayName: 'Messages',
name: 'messages',
diff --git a/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/versionDescription.ts b/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/versionDescription.ts
index 2ed98f89f9..45954f333b 100644
--- a/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/versionDescription.ts
+++ b/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/actions/versionDescription.ts
@@ -69,7 +69,7 @@ export const versionDescription: INodeTypeDescription = {
name: 'openAi',
icon: { light: 'file:openAi.svg', dark: 'file:openAi.dark.svg' },
group: ['transform'],
- version: [1, 1.1, 1.2, 1.3],
+ version: [1, 1.1, 1.2, 1.3, 1.4],
subtitle: `={{(${prettifyOperation})($parameter.resource, $parameter.operation)}}`,
description: 'Message an assistant or GPT, analyze images, generate audio, etc.',
defaults: {
diff --git a/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/methods/listSearch.ts b/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/methods/listSearch.ts
index 8ec3c53a2b..9aa3633d45 100644
--- a/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/methods/listSearch.ts
+++ b/packages/@n8n/nodes-langchain/nodes/vendors/OpenAi/methods/listSearch.ts
@@ -5,6 +5,8 @@ import type {
INodeListSearchResult,
} from 'n8n-workflow';
+import type { Model } from 'openai/resources/models';
+import type { Assistant } from 'openai/resources/beta/assistants';
import { apiRequest } from '../transport';
export async function fileSearch(
@@ -38,37 +40,52 @@ export async function fileSearch(
}
}
+const getModelSearch =
+ (filterCondition: (model: Model) => boolean) =>
+ async (ctx: ILoadOptionsFunctions, filter?: string): Promise => {
+ let { data } = (await apiRequest.call(ctx, 'GET', '/models')) as { data: Model[] };
+
+ data = data?.filter((model) => filterCondition(model));
+
+ let results: INodeListSearchItems[] = [];
+
+ if (filter) {
+ for (const model of data || []) {
+ if (model.id?.toLowerCase().includes(filter.toLowerCase())) {
+ results.push({
+ name: model.id.toUpperCase(),
+ value: model.id,
+ });
+ }
+ }
+ } else {
+ results = (data || []).map((model) => ({
+ name: model.id.toUpperCase(),
+ value: model.id,
+ }));
+ }
+
+ results = results.sort((a, b) => a.name.localeCompare(b.name));
+
+ return {
+ results,
+ };
+ };
+
export async function modelSearch(
this: ILoadOptionsFunctions,
filter?: string,
): Promise {
- let { data } = await apiRequest.call(this, 'GET', '/models');
+ return await getModelSearch((model) => model.id.startsWith('gpt-'))(this, filter);
+}
- data = data?.filter((model: IDataObject) => (model.id as string).startsWith('gpt-'));
-
- let results: INodeListSearchItems[] = [];
-
- if (filter) {
- for (const model of data || []) {
- if ((model.id as string)?.toLowerCase().includes(filter.toLowerCase())) {
- results.push({
- name: (model.id as string).toUpperCase(),
- value: model.id as string,
- });
- }
- }
- } else {
- results = (data || []).map((model: IDataObject) => ({
- name: (model.id as string).toUpperCase(),
- value: model.id as string,
- }));
- }
-
- results = results.sort((a, b) => a.name.localeCompare(b.name));
-
- return {
- results,
- };
+export async function imageModelSearch(
+ this: ILoadOptionsFunctions,
+ filter?: string,
+): Promise {
+ return await getModelSearch(
+ (model) => model.id.includes('vision') || model.id.includes('gpt-4o'),
+ )(this, filter);
}
export async function assistantSearch(
@@ -76,7 +93,7 @@ export async function assistantSearch(
filter?: string,
paginationToken?: string,
): Promise {
- const { data, has_more, last_id } = await apiRequest.call(this, 'GET', '/assistants', {
+ const { data, has_more, last_id } = (await apiRequest.call(this, 'GET', '/assistants', {
headers: {
'OpenAI-Beta': 'assistants=v2',
},
@@ -84,9 +101,14 @@ export async function assistantSearch(
limit: 100,
after: paginationToken,
},
- });
+ })) as {
+ data: Assistant[];
+ has_more: boolean;
+ last_id: string;
+ first_id: string;
+ };
- if (has_more === true) {
+ if (has_more) {
paginationToken = last_id;
} else {
paginationToken = undefined;
@@ -96,10 +118,10 @@ export async function assistantSearch(
const results: INodeListSearchItems[] = [];
for (const assistant of data || []) {
- if ((assistant.name as string)?.toLowerCase().includes(filter.toLowerCase())) {
+ if (assistant.name?.toLowerCase().includes(filter.toLowerCase())) {
results.push({
- name: assistant.name as string,
- value: assistant.id as string,
+ name: assistant.name,
+ value: assistant.id,
});
}
}
@@ -109,9 +131,9 @@ export async function assistantSearch(
};
} else {
return {
- results: (data || []).map((assistant: IDataObject) => ({
- name: assistant.name as string,
- value: assistant.id as string,
+ results: (data || []).map((assistant) => ({
+ name: assistant.name ?? assistant.id,
+ value: assistant.id,
})),
paginationToken,
};