diff --git a/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs.tsx b/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs.tsx index 70e78cc0..a5ce285e 100644 --- a/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs.tsx +++ b/public/pages/workflow_detail/workflow_inputs/processor_inputs/ml_processor_inputs.tsx @@ -487,17 +487,7 @@ export function MLProcessorInputs(props: MLProcessorInputsProps) { optionalField.id !== 'query_template' - ) || []), - ] - : props.config.optionalFields || [] - } + configFields={props.config.optionalFields || []} baseConfigPath={props.baseConfigPath} /> diff --git a/public/pages/workflow_detail/workflow_inputs/processor_inputs/modals/output_transform_modal.tsx b/public/pages/workflow_detail/workflow_inputs/processor_inputs/modals/output_transform_modal.tsx index 558e3162..15ef0364 100644 --- a/public/pages/workflow_detail/workflow_inputs/processor_inputs/modals/output_transform_modal.tsx +++ b/public/pages/workflow_detail/workflow_inputs/processor_inputs/modals/output_transform_modal.tsx @@ -35,6 +35,7 @@ import { IngestPipelineConfig, JSONPATH_ROOT_SELECTOR, MapArrayFormValue, + MapFormValue, ModelInterface, OutputTransformFormValues, OutputTransformSchema, @@ -157,7 +158,7 @@ export function OutputTransformModal(props: OutputTransformModalProps) { sampleSourceOutput = JSON.parse(sourceOutput); const output = generateTransform( sampleSourceOutput, - tempOutputMap[selectedTransformOption] + reverseKeysAndValues(tempOutputMap[selectedTransformOption]) ); setTransformedOutput(customStringify(output)); } catch {} @@ -641,3 +642,14 @@ root object selector "${JSONPATH_ROOT_SELECTOR}"`} ); } + +// since we persist the form keys/values reversed, we have a util fn to reverse back, so we can use +// single util fns for manipulation of the form values (generating transforms, etc.) +function reverseKeysAndValues(values: MapFormValue): MapFormValue { + return values.map((mapEntry) => { + return { + key: mapEntry.value, + value: mapEntry.key, + }; + }); +} diff --git a/public/pages/workflow_detail/workflow_inputs/processor_inputs/modals/override_query_modal.tsx b/public/pages/workflow_detail/workflow_inputs/processor_inputs/modals/override_query_modal.tsx index b7d11e57..561ff8ee 100644 --- a/public/pages/workflow_detail/workflow_inputs/processor_inputs/modals/override_query_modal.tsx +++ b/public/pages/workflow_detail/workflow_inputs/processor_inputs/modals/override_query_modal.tsx @@ -68,13 +68,13 @@ export function OverrideQueryModal(props: OverrideQueryModalProps) { ); // TODO: should handle edge case of multiple output maps configured. Currently // defaulting to prediction 0 / assuming not multiple predictions to track. - const outputMapKeys = getIn(outputMap, '0', []).map( - (mapEntry: MapEntry) => mapEntry.key + const outputMapValues = getIn(outputMap, '0', []).map( + (mapEntry: MapEntry) => mapEntry.value ) as string[]; const finalModelOutputs = - outputMapKeys.length > 0 - ? outputMapKeys.map((outputMapKey) => { - return { label: outputMapKey }; + outputMapValues.length > 0 + ? outputMapValues.map((outputMapValue) => { + return { label: outputMapValue }; }) : modelOutputs.map((modelOutput) => { return { label: modelOutput.label }; diff --git a/public/pages/workflows/new_workflow/quick_configure_modal.tsx b/public/pages/workflows/new_workflow/quick_configure_modal.tsx index d2bac5fc..7ec123ca 100644 --- a/public/pages/workflows/new_workflow/quick_configure_modal.tsx +++ b/public/pages/workflows/new_workflow/quick_configure_modal.tsx @@ -293,10 +293,10 @@ function updateIngestProcessors( if (outputMap.length > 0) { outputMap[0] = { ...outputMap[0], - key: defaultField, + value: defaultField, }; } else { - outputMap.push({ key: defaultField, value: '' }); + outputMap.push({ key: '', value: defaultField }); } } field.value = [outputMap] as MapArrayFormValue; @@ -344,16 +344,18 @@ function updateSearchRequestProcessors( } if (field.id === 'output_map') { const outputMap = generateMapFromModelOutputs(modelInterface); - const defaultKey = isVectorSearchUseCase ? VECTOR : defaultQueryValue; + const defaultValue = isVectorSearchUseCase + ? VECTOR + : defaultQueryValue; if (outputMap.length > 0) { outputMap[0] = { ...outputMap[0], - key: defaultKey, + value: defaultValue, }; } else { outputMap.push({ - key: defaultKey, - value: '', + key: '', + value: defaultValue, }); } field.value = [outputMap] as MapArrayFormValue; @@ -412,10 +414,10 @@ function updateSearchResponseProcessors( if (outputMap.length > 0) { outputMap[0] = { ...outputMap[0], - key: fields.llmResponseField, + value: fields.llmResponseField, }; } else { - outputMap.push({ key: fields.llmResponseField, value: '' }); + outputMap.push({ key: '', value: fields.llmResponseField }); } } field.value = [outputMap] as MapArrayFormValue; @@ -540,7 +542,7 @@ function generateMapFromModelInputs( return inputMap; } -// generate a set of mappings s.t. each value is +// generate a set of mappings s.t. each key is // a unique model output function generateMapFromModelOutputs( modelInterface?: ModelInterface @@ -550,8 +552,8 @@ function generateMapFromModelOutputs( const modelOutputs = parseModelOutputs(modelInterface); modelOutputs.forEach((modelOutput) => { outputMap.push({ - key: '', - value: modelOutput.label, + key: modelOutput.label, + value: '', }); }); } diff --git a/public/utils/utils.ts b/public/utils/utils.ts index 34970ce6..dd29f916 100644 --- a/public/utils/utils.ts +++ b/public/utils/utils.ts @@ -229,13 +229,18 @@ function getTransformedResult( // the entire value. This may happen if full_response_path=false // and the input is the entire result with nothing else to parse out. // get() does not cover this case, so we override manually. - return path === '.' - ? input - : mapEntry.value.startsWith(JSONPATH_ROOT_SELECTOR) - ? // JSONPath transform - jsonpath.value(input, path) - : // Standard dot notation - get(input, path); + const result = + path === '.' + ? input + : mapEntry.value.startsWith(JSONPATH_ROOT_SELECTOR) + ? // JSONPath transform + jsonpath.query(input, path) + : // Standard dot notation + get(input, path); + + // ML processors dynamically handle arrays vs. single values differently when indexing. + // We replicate that logic here to get consistent results + return Array.isArray(result) && result.length === 1 ? result[0] : result; } // Derive the collection of model inputs from the model interface JSONSchema into a form-ready list