Skip to content

Commit f62800c

Browse files
fix: Continue on fail / error output support for chains and agents (#9078)
1 parent 8c26225 commit f62800c

File tree

9 files changed

+459
-378
lines changed

9 files changed

+459
-378
lines changed

packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ConversationalAgent/execute.ts

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -79,36 +79,45 @@ export async function conversationalAgentExecute(
7979

8080
const items = this.getInputData();
8181
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
82-
let input;
83-
84-
if (this.getNode().typeVersion <= 1.2) {
85-
input = this.getNodeParameter('text', itemIndex) as string;
86-
} else {
87-
input = getPromptInputByType({
88-
ctx: this,
89-
i: itemIndex,
90-
inputKey: 'text',
91-
promptTypeKey: 'promptType',
92-
});
93-
}
94-
95-
if (input === undefined) {
96-
throw new NodeOperationError(this.getNode(), 'The ‘text parameter is empty.');
97-
}
98-
99-
if (prompt) {
100-
input = (await prompt.invoke({ input })).value;
101-
}
102-
103-
let response = await agentExecutor
104-
.withConfig(getTracingConfig(this))
105-
.invoke({ input, outputParsers });
106-
107-
if (outputParser) {
108-
response = { output: await outputParser.parse(response.output as string) };
82+
try {
83+
let input;
84+
85+
if (this.getNode().typeVersion <= 1.2) {
86+
input = this.getNodeParameter('text', itemIndex) as string;
87+
} else {
88+
input = getPromptInputByType({
89+
ctx: this,
90+
i: itemIndex,
91+
inputKey: 'text',
92+
promptTypeKey: 'promptType',
93+
});
94+
}
95+
96+
if (input === undefined) {
97+
throw new NodeOperationError(this.getNode(), 'The ‘text parameter is empty.');
98+
}
99+
100+
if (prompt) {
101+
input = (await prompt.invoke({ input })).value;
102+
}
103+
104+
let response = await agentExecutor
105+
.withConfig(getTracingConfig(this))
106+
.invoke({ input, outputParsers });
107+
108+
if (outputParser) {
109+
response = { output: await outputParser.parse(response.output as string) };
110+
}
111+
112+
returnData.push({ json: response });
113+
} catch (error) {
114+
if (this.continueOnFail()) {
115+
returnData.push({ json: { error: error.message }, pairedItem: { item: itemIndex } });
116+
continue;
117+
}
118+
119+
throw error;
109120
}
110-
111-
returnData.push({ json: response });
112121
}
113122

114123
return await this.prepareOutputData(returnData);

packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/OpenAiFunctionsAgent/execute.ts

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -85,35 +85,44 @@ export async function openAiFunctionsAgentExecute(
8585

8686
const items = this.getInputData();
8787
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
88-
let input;
89-
if (this.getNode().typeVersion <= 1.2) {
90-
input = this.getNodeParameter('text', itemIndex) as string;
91-
} else {
92-
input = getPromptInputByType({
93-
ctx: this,
94-
i: itemIndex,
95-
inputKey: 'text',
96-
promptTypeKey: 'promptType',
97-
});
88+
try {
89+
let input;
90+
if (this.getNode().typeVersion <= 1.2) {
91+
input = this.getNodeParameter('text', itemIndex) as string;
92+
} else {
93+
input = getPromptInputByType({
94+
ctx: this,
95+
i: itemIndex,
96+
inputKey: 'text',
97+
promptTypeKey: 'promptType',
98+
});
99+
}
100+
101+
if (input === undefined) {
102+
throw new NodeOperationError(this.getNode(), 'The ‘text‘ parameter is empty.');
103+
}
104+
105+
if (prompt) {
106+
input = (await prompt.invoke({ input })).value;
107+
}
108+
109+
let response = await agentExecutor
110+
.withConfig(getTracingConfig(this))
111+
.invoke({ input, outputParsers });
112+
113+
if (outputParser) {
114+
response = { output: await outputParser.parse(response.output as string) };
115+
}
116+
117+
returnData.push({ json: response });
118+
} catch (error) {
119+
if (this.continueOnFail()) {
120+
returnData.push({ json: { error: error.message }, pairedItem: { item: itemIndex } });
121+
continue;
122+
}
123+
124+
throw error;
98125
}
99-
100-
if (input === undefined) {
101-
throw new NodeOperationError(this.getNode(), 'The ‘text‘ parameter is empty.');
102-
}
103-
104-
if (prompt) {
105-
input = (await prompt.invoke({ input })).value;
106-
}
107-
108-
let response = await agentExecutor
109-
.withConfig(getTracingConfig(this))
110-
.invoke({ input, outputParsers });
111-
112-
if (outputParser) {
113-
response = { output: await outputParser.parse(response.output as string) };
114-
}
115-
116-
returnData.push({ json: response });
117126
}
118127

119128
return await this.prepareOutputData(returnData);

packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/PlanAndExecuteAgent/execute.ts

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -60,35 +60,44 @@ export async function planAndExecuteAgentExecute(
6060

6161
const items = this.getInputData();
6262
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
63-
let input;
64-
if (this.getNode().typeVersion <= 1.2) {
65-
input = this.getNodeParameter('text', itemIndex) as string;
66-
} else {
67-
input = getPromptInputByType({
68-
ctx: this,
69-
i: itemIndex,
70-
inputKey: 'text',
71-
promptTypeKey: 'promptType',
72-
});
63+
try {
64+
let input;
65+
if (this.getNode().typeVersion <= 1.2) {
66+
input = this.getNodeParameter('text', itemIndex) as string;
67+
} else {
68+
input = getPromptInputByType({
69+
ctx: this,
70+
i: itemIndex,
71+
inputKey: 'text',
72+
promptTypeKey: 'promptType',
73+
});
74+
}
75+
76+
if (input === undefined) {
77+
throw new NodeOperationError(this.getNode(), 'The ‘text‘ parameter is empty.');
78+
}
79+
80+
if (prompt) {
81+
input = (await prompt.invoke({ input })).value;
82+
}
83+
84+
let response = await agentExecutor
85+
.withConfig(getTracingConfig(this))
86+
.invoke({ input, outputParsers });
87+
88+
if (outputParser) {
89+
response = { output: await outputParser.parse(response.output as string) };
90+
}
91+
92+
returnData.push({ json: response });
93+
} catch (error) {
94+
if (this.continueOnFail()) {
95+
returnData.push({ json: { error: error.message }, pairedItem: { item: itemIndex } });
96+
continue;
97+
}
98+
99+
throw error;
73100
}
74-
75-
if (input === undefined) {
76-
throw new NodeOperationError(this.getNode(), 'The ‘text‘ parameter is empty.');
77-
}
78-
79-
if (prompt) {
80-
input = (await prompt.invoke({ input })).value;
81-
}
82-
83-
let response = await agentExecutor
84-
.withConfig(getTracingConfig(this))
85-
.invoke({ input, outputParsers });
86-
87-
if (outputParser) {
88-
response = { output: await outputParser.parse(response.output as string) };
89-
}
90-
91-
returnData.push({ json: response });
92101
}
93102

94103
return await this.prepareOutputData(returnData);

packages/@n8n/nodes-langchain/nodes/agents/Agent/agents/ReActAgent/execute.ts

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -80,36 +80,45 @@ export async function reActAgentAgentExecute(
8080

8181
const items = this.getInputData();
8282
for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
83-
let input;
84-
85-
if (this.getNode().typeVersion <= 1.2) {
86-
input = this.getNodeParameter('text', itemIndex) as string;
87-
} else {
88-
input = getPromptInputByType({
89-
ctx: this,
90-
i: itemIndex,
91-
inputKey: 'text',
92-
promptTypeKey: 'promptType',
93-
});
83+
try {
84+
let input;
85+
86+
if (this.getNode().typeVersion <= 1.2) {
87+
input = this.getNodeParameter('text', itemIndex) as string;
88+
} else {
89+
input = getPromptInputByType({
90+
ctx: this,
91+
i: itemIndex,
92+
inputKey: 'text',
93+
promptTypeKey: 'promptType',
94+
});
95+
}
96+
97+
if (input === undefined) {
98+
throw new NodeOperationError(this.getNode(), 'The ‘text‘ parameter is empty.');
99+
}
100+
101+
if (prompt) {
102+
input = (await prompt.invoke({ input })).value;
103+
}
104+
105+
let response = await agentExecutor
106+
.withConfig(getTracingConfig(this))
107+
.invoke({ input, outputParsers });
108+
109+
if (outputParser) {
110+
response = { output: await outputParser.parse(response.output as string) };
111+
}
112+
113+
returnData.push({ json: response });
114+
} catch (error) {
115+
if (this.continueOnFail()) {
116+
returnData.push({ json: { error: error.message }, pairedItem: { item: itemIndex } });
117+
continue;
118+
}
119+
120+
throw error;
94121
}
95-
96-
if (input === undefined) {
97-
throw new NodeOperationError(this.getNode(), 'The ‘text‘ parameter is empty.');
98-
}
99-
100-
if (prompt) {
101-
input = (await prompt.invoke({ input })).value;
102-
}
103-
104-
let response = await agentExecutor
105-
.withConfig(getTracingConfig(this))
106-
.invoke({ input, outputParsers });
107-
108-
if (outputParser) {
109-
response = { output: await outputParser.parse(response.output as string) };
110-
}
111-
112-
returnData.push({ json: response });
113122
}
114123

115124
return await this.prepareOutputData(returnData);

0 commit comments

Comments
 (0)