mirror of
https://github.com/n8n-io/n8n.git
synced 2026-07-28 03:24:59 +02:00
fix(core): Keep $fromAI placeholders intact on fields with expressions disabled (#31681)
Co-authored-by: Alexander Gekov <40495748+alexander-gekov@users.noreply.github.com>
This commit is contained in:
parent
227050b965
commit
43eec00e6b
|
|
@ -9,6 +9,7 @@ import { v4 as uuid } from 'uuid';
|
|||
import { EXECUTE_WORKFLOW_NODE_TYPE, WORKFLOW_TOOL_LANGCHAIN_NODE_TYPE } from './constants';
|
||||
import { UnexpectedError, UserError } from './errors';
|
||||
import { isExpression } from './expressions/expression-helpers';
|
||||
import { isFromAIOnlyExpression } from './from-ai-parse-utils';
|
||||
import { NodeConnectionTypes } from './interfaces';
|
||||
import type {
|
||||
FieldType,
|
||||
|
|
@ -823,7 +824,8 @@ export function getNodeParameters(
|
|||
// Strip expression prefix if noDataExpression is true
|
||||
if (nodeProperties.noDataExpression && nodeParameters[nodeProperties.name] !== undefined) {
|
||||
const value = nodeParameters[nodeProperties.name];
|
||||
if (isExpression(value)) {
|
||||
// A lone $fromAI() placeholder must keep its "=" or the AI tool call never resolves it (#30531)
|
||||
if (isExpression(value) && !isFromAIOnlyExpression(value)) {
|
||||
nodeParameters[nodeProperties.name] = value.slice(1);
|
||||
nodeParametersFull[nodeProperties.name] = nodeParameters[nodeProperties.name];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6729,6 +6729,70 @@ describe('NodeHelpers', () => {
|
|||
// When undefined, the default value (empty string) is used
|
||||
expect(result?.resource).toBe('');
|
||||
});
|
||||
|
||||
describe('$fromAI placeholder carve-out', () => {
|
||||
const resolveQuery = (query: string) => {
|
||||
const properties: INodeProperties[] = [
|
||||
{
|
||||
name: 'query',
|
||||
displayName: 'Query',
|
||||
type: 'string',
|
||||
default: '',
|
||||
noDataExpression: true,
|
||||
},
|
||||
];
|
||||
|
||||
const nodeValues: Record<string, string> = { query };
|
||||
|
||||
const node: INode = {
|
||||
id: 'test-123',
|
||||
name: 'Test',
|
||||
type: 'n8n-nodes-base.test',
|
||||
typeVersion: 1,
|
||||
position: [0, 0],
|
||||
parameters: nodeValues,
|
||||
credentials: {},
|
||||
};
|
||||
|
||||
const description: INodeTypeDescription = {
|
||||
displayName: 'Test',
|
||||
name: 'Test',
|
||||
group: [],
|
||||
version: 1,
|
||||
description: 'Test',
|
||||
defaults: {},
|
||||
inputs: [],
|
||||
outputs: [],
|
||||
properties,
|
||||
};
|
||||
|
||||
return getNodeParameters(properties, nodeValues, true, false, node, description)?.query;
|
||||
};
|
||||
|
||||
it('keeps a lone $fromAI() placeholder intact', () => {
|
||||
const query = "=$fromAI('sqlQuery', 'The SQL query to execute', 'string')";
|
||||
expect(resolveQuery(query)).toBe(query);
|
||||
});
|
||||
|
||||
it('keeps a $fromAI() placeholder wrapped in {{ }} intact', () => {
|
||||
const query = "={{ $fromAI('sqlQuery') }}";
|
||||
expect(resolveQuery(query)).toBe(query);
|
||||
});
|
||||
|
||||
it('still strips a plain expression that is not a $fromAI() call', () => {
|
||||
expect(resolveQuery('=$env.SECRET')).toBe('$env.SECRET');
|
||||
});
|
||||
|
||||
it('still strips $fromAI() concatenated with another expression', () => {
|
||||
expect(resolveQuery("=$fromAI('x') + $env.SECRET")).toBe("$fromAI('x') + $env.SECRET");
|
||||
});
|
||||
|
||||
it('still strips $fromAI() with an interpolated value in its argument', () => {
|
||||
// Split the `${` token so the lint rule doesn't read it as interpolation.
|
||||
const interpolated = '`$' + '{$env.SECRET}`';
|
||||
expect(resolveQuery(`=$fromAI(${interpolated})`)).toBe(`$fromAI(${interpolated})`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getNodeParameters filter defaults', () => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user