fix(editor): Differentiate $fromAI overrides within lists (#14696)

This commit is contained in:
Charlie Kolb
2025-04-17 15:44:24 +02:00
committed by GitHub
parent acf2453ea7
commit 5aa6054bc9
2 changed files with 64 additions and 2 deletions

View File

@@ -1,6 +1,7 @@
import type { INodeUi } from '@/Interface';
import type { FromAIOverride, OverrideContext } from './fromAIOverrideUtils';
import {
buildUniqueName,
buildValueFromOverride,
fromAIExtraProps,
isFromAIOverrideValue,
@@ -213,3 +214,40 @@ describe('FromAiOverride', () => {
);
});
});
describe('buildUniqueName', () => {
test.each<[string, string, string]>([
['no list segments', 'parameters.someParameter', DISPLAY_NAME],
[
'list segments in the path',
'parameters.someList[0].someParameter',
'someList0_' + DISPLAY_NAME,
],
[
'multiple list segments in the path',
'parameters.someList[0].nestedList[1].someParameter',
'someList0_nestedList1_' + DISPLAY_NAME,
],
[
'paths without parameters',
'someList[0].nestedList[1]',
'someList0_nestedList1_' + DISPLAY_NAME,
],
['empty paths', '', DISPLAY_NAME],
[
'path with multiple lists and segment exceeding 63 characters',
'parameters.someLoooooongList[0].nestedListWithAVeryLongNameThatExceedsTheLimit[1].someParameter',
`someLoooooongList0_nestedListWithAVeryLongNameThatExceedsTheLimit1_${DISPLAY_NAME}`.slice(
-63,
),
],
[
'path with multiple long segments and truncation',
'parameters.someExtremelyLongListNameThatExceedsTheLimit.anotherLongSegmentName.finalParameter',
DISPLAY_NAME,
],
])('should build a unique name with %s', (_description, path, expected) => {
const context = makeContext('value', path);
expect(buildUniqueName(context)).toEqual(expected);
});
});

View File

@@ -119,14 +119,38 @@ function getBestQuoteChar(description: string) {
return "'";
}
// Note that this is not *technically* unique, as two lists with the
// same list name and the same property display name could theoretically
// exist within one node. However, this is unlikely to happen in practice.
export function buildUniqueName(props: Pick<OverrideContext, 'parameter' | 'path'>) {
const path = props.path.split('.');
// include any list segments in the path (e.g. .myListName[0].) for uniqueness
// but drop brackets to avoid token limits
const filteredPaths = path
.filter((x) => /\[\d+\]/i.test(x))
.map((x) => x.replaceAll(/[\[\]]/gi, ''));
let result = [...filteredPaths, props.parameter.displayName].join('_');
// Langchain requires the name to be <64 characters
if (filteredPaths.length > 1) {
// Prefer clipping the list names over the display name
result = result.slice(-63);
} else {
result = result.slice(0, 63);
}
return result;
}
export function buildValueFromOverride(
override: FromAIOverride,
props: Pick<OverrideContext, 'parameter'>,
props: Pick<OverrideContext, 'parameter' | 'path'>,
includeMarker: boolean,
) {
const { extraPropValues, extraProps } = override;
const marker = includeMarker ? `${FROM_AI_AUTO_GENERATED_MARKER} ` : '';
const key = sanitizeFromAiParameterName(props.parameter.displayName);
const key = sanitizeFromAiParameterName(buildUniqueName(props));
const description =
extraPropValues?.description?.toString() ?? extraProps.description.initialValue;