Skip to content

Commit

Permalink
Merge branch 'master' into ADO-2190-ai-assistant-ui
Browse files Browse the repository at this point in the history
* master:
  feat(Telegram Node): Disable page preview by default (#9267)
  fix(Jira Trigger Node): Update credentials UI (#9198)
  fix(LangChain Code Node): Fix execution of custom n8n tools called via LC code node (#9265)
  fix(editor): Prevent excess runs in manual execution with run data (#9259)
  fix(Baserow Node): Update logo (no-changelog) (#9261)
  fix(Customer.io Node): Update logo (no-changelog) (#9262)
  fix(LangChain Code Node): Fix resolution of scoped langchain modules (#9258)
  fix(core): Prevent node param resolution from failing telemetry graph generation (#9257)
  feat(Groq Chat Model Node): Add support for Groq chat models  (#9250)
  ci: Update release-push-to-channel.yml (no-changelog) (#9254)
  refactor: Update Langchain dependencies (no-changelog) (#9252)
  refactor(editor): Rewrite TabBar to composition API (no-changelog) (#9231)
  refactor(core)!: Switch default Postgres user from `root` to `postgres` (#9248)
  fix(OpenAI Node): Allow to pass files ids as comma separated string in expressions (no-changelog) (#9240)
  refactor(Structured Output Parser Node): Sandbox JSON schema parsing (no-changelog) (#9239)
  feat(Ollama Chat Model Node): Add aditional Ollama config parameters & fix vision (#9215)
  • Loading branch information
MiloradFilipovic committed May 2, 2024
2 parents 402feb9 + 41ce178 commit dbbf6b5
Show file tree
Hide file tree
Showing 42 changed files with 1,147 additions and 449 deletions.
2 changes: 1 addition & 1 deletion .github/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ services:
restart: always
environment:
- POSTGRES_DB=n8n
- POSTGRES_USER=root
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
ports:
- 5432:5432
8 changes: 8 additions & 0 deletions .github/workflows/release-push-to-channel.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,11 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}

- run: docker buildx imagetools create -t ghcr.io/${{ github.repository_owner }}/n8n:${{ github.event.inputs.release-channel }} ghcr.io/${{ github.repository_owner }}/n8n:${{ github.event.inputs.version }}

update-docs:
name: Update latest and next in the docs
runs-on: ubuntu-latest
needs: [release-to-npm, release-to-docker-hub]
steps:
- continue-on-error: true
run: curl -u docsWorkflows:${{ secrets.N8N_WEBHOOK_DOCS_PASSWORD }} --request GET 'https://internal.users.n8n.cloud/webhook/update-latest-next'
28 changes: 28 additions & 0 deletions cypress/e2e/40-manual-partial-execution.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { NDV, WorkflowPage } from '../pages';

const canvas = new WorkflowPage();
const ndv = new NDV();

describe('Manual partial execution', () => {
it('should execute parent nodes with no run data only once', () => {
canvas.actions.visit();

cy.fixture('manual-partial-execution.json').then((data) => {
cy.get('body').paste(JSON.stringify(data));
});

canvas.actions.zoomToFit();

canvas.actions.openNode('Edit Fields');

cy.get('button').contains('Test step').click(); // create run data
cy.get('button').contains('Test step').click(); // use run data

ndv.actions.close();

canvas.actions.openNode('Webhook1');

ndv.getters.nodeRunSuccessIndicator().should('exist');
ndv.getters.outputRunSelector().should('not.exist'); // single run
});
});
107 changes: 107 additions & 0 deletions cypress/fixtures/manual-partial-execution.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
{
"meta": {
"templateCredsSetupCompleted": true
},
"nodes": [
{
"parameters": {
"options": {}
},
"id": "f4467143-fdb9-46fa-8020-6417cc5eea7d",
"name": "Edit Fields",
"type": "n8n-nodes-base.set",
"typeVersion": 3.3,
"position": [
1140,
260
]
},
{
"parameters": {
"path": "30ff316d-405f-4288-a0ac-e713546c9d4e",
"options": {}
},
"id": "4760aafb-5d56-4633-99d3-7a97c576a216",
"name": "Webhook1",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
680,
340
],
"webhookId": "30ff316d-405f-4288-a0ac-e713546c9d4e"
},
{
"parameters": {
"articleId": "123",
"additionalFields": {}
},
"id": "8c811eca-8978-44d9-b8f7-ef2c7725784c",
"name": "Hacker News",
"type": "n8n-nodes-base.hackerNews",
"typeVersion": 1,
"position": [
920,
260
]
},
{
"parameters": {
"path": "4a3398e4-1388-4e10-9d21-add90b804955",
"options": {}
},
"id": "1c2c2d06-45c9-4712-9fa0-c655bef8d0e5",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
680,
180
],
"webhookId": "4a3398e4-1388-4e10-9d21-add90b804955"
}
],
"connections": {
"Webhook1": {
"main": [
[
{
"node": "Hacker News",
"type": "main",
"index": 0
}
]
]
},
"Hacker News": {
"main": [
[
{
"node": "Edit Fields",
"type": "main",
"index": 0
}
]
]
},
"Webhook": {
"main": [
[
{
"node": "Hacker News",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {
"Webhook": [
{
"name": "First item",
"code": 1
}
]
}
}
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@
"sqlite3"
],
"overrides": {
"@langchain/core": "0.1.41",
"@types/node": "^18.16.16",
"axios": "1.6.7",
"chokidar": "3.5.2",
Expand Down
41 changes: 41 additions & 0 deletions packages/@n8n/nodes-langchain/credentials/GroqApi.credentials.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import type {
IAuthenticateGeneric,
ICredentialTestRequest,
ICredentialType,
INodeProperties,
} from 'n8n-workflow';

export class GroqApi implements ICredentialType {
name = 'groqApi';

displayName = 'Groq';

documentationUrl = 'groq';

properties: INodeProperties[] = [
{
displayName: 'API Key',
name: 'apiKey',
type: 'string',
typeOptions: { password: true },
required: true,
default: '',
},
];

authenticate: IAuthenticateGeneric = {
type: 'generic',
properties: {
headers: {
Authorization: '=Bearer {{$credentials.apiKey}}',
},
},
};

test: ICredentialTestRequest = {
request: {
baseURL: 'https://api.groq.com/openai/v1',
url: '/models',
},
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ function getInputs(
filter: {
nodes: [
'@n8n/n8n-nodes-langchain.lmChatAnthropic',
'@n8n/n8n-nodes-langchain.lmChatGroq',
'@n8n/n8n-nodes-langchain.lmChatOllama',
'@n8n/n8n-nodes-langchain.lmChatOpenAi',
'@n8n/n8n-nodes-langchain.lmChatGooglePalm',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { zodToJsonSchema } from 'zod-to-json-schema';
import type { OpenAI as OpenAIClient } from 'openai';
import type { OpenAIClient } from '@langchain/openai';
import type { StructuredTool } from '@langchain/core/tools';

// Copied from langchain(`langchain/src/tools/convert_to_openai.ts`)
Expand Down Expand Up @@ -33,9 +33,7 @@ export function formatToOpenAITool(tool: StructuredTool): OpenAIClient.Chat.Chat
};
}

export function formatToOpenAIAssistantTool(
tool: StructuredTool,
): OpenAIClient.Beta.AssistantCreateParams.AssistantToolsFunction {
export function formatToOpenAIAssistantTool(tool: StructuredTool): OpenAIClient.Beta.AssistantTool {
return {
type: 'function',
function: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { LLMChain } from 'langchain/chains';
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { HumanMessage } from '@langchain/core/messages';
import { ChatGoogleGenerativeAI } from '@langchain/google-genai';
import { ChatOllama } from '@langchain/community/chat_models/ollama';
import { getTemplateNoticeField } from '../../../utils/sharedFields';
import {
getOptionalOutputParsers,
Expand Down Expand Up @@ -81,7 +82,10 @@ async function getImageMessage(
)) as BaseLanguageModel;
const dataURI = `data:image/jpeg;base64,${bufferData.toString('base64')}`;

const imageUrl = model instanceof ChatGoogleGenerativeAI ? dataURI : { url: dataURI, detail };
const directUriModels = [ChatGoogleGenerativeAI, ChatOllama];
const imageUrl = directUriModels.some((i) => model instanceof i)
? dataURI
: { url: dataURI, detail };

return new HumanMessage({
content: [
Expand Down
7 changes: 5 additions & 2 deletions packages/@n8n/nodes-langchain/nodes/code/Code.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,14 @@ return [ {json: { output } } ];`;
const defaultCodeSupplyData = `const { WikipediaQueryRun } = require('langchain/tools');
return new WikipediaQueryRun();`;

const langchainModules = ['langchain', '@langchain/*'];
export const vmResolver = makeResolverFromLegacyOptions({
external: {
modules: external ? ['langchain', ...external.split(',')] : ['langchain'],
modules: external ? [...langchainModules, ...external.split(',')] : [...langchainModules],
transitive: false,
},
resolve(moduleName, parentDirname) {
if (moduleName.match(/^langchain\//)) {
if (moduleName.match(/^langchain\//) ?? moduleName.match(/^@langchain\//)) {
return require.resolve(`@n8n/n8n-nodes-langchain/node_modules/${moduleName}.cjs`, {
paths: [parentDirname],
});
Expand Down Expand Up @@ -89,6 +90,8 @@ function getSandbox(
// eslint-disable-next-line @typescript-eslint/unbound-method
context.getNodeOutputs = this.getNodeOutputs;
// eslint-disable-next-line @typescript-eslint/unbound-method
context.executeWorkflow = this.executeWorkflow;
// eslint-disable-next-line @typescript-eslint/unbound-method
context.logger = this.logger;

if (options?.addItems) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
type SupplyData,
} from 'n8n-workflow';

import type { ChatOllamaInput } from '@langchain/community/chat_models/ollama';
import { ChatOllama } from '@langchain/community/chat_models/ollama';
import { logWrapper } from '../../../utils/logWrapper';
import { getConnectionHintNoticeField } from '../../../utils/sharedFields';
Expand Down Expand Up @@ -54,12 +55,13 @@ export class LmChatOllama implements INodeType {
const credentials = await this.getCredentials('ollamaApi');

const modelName = this.getNodeParameter('model', itemIndex) as string;
const options = this.getNodeParameter('options', itemIndex, {}) as object;
const options = this.getNodeParameter('options', itemIndex, {}) as ChatOllamaInput;

const model = new ChatOllama({
...options,
baseUrl: credentials.baseUrl as string,
model: modelName,
...options,
format: options.format === 'default' ? undefined : options.format,
});

return {
Expand Down
Loading

0 comments on commit dbbf6b5

Please sign in to comment.