Lifei/UI parameter input (#5222)
This commit is contained in:
@@ -158,7 +158,7 @@ function BaseChatContent({
|
||||
const {
|
||||
recipe,
|
||||
recipeId,
|
||||
recipeParameters,
|
||||
recipeParameterValues,
|
||||
filteredParameters,
|
||||
initialPrompt,
|
||||
isParameterModalOpen,
|
||||
@@ -338,7 +338,7 @@ function BaseChatContent({
|
||||
append={(text: string) => appendWithTracking(text)}
|
||||
activities={Array.isArray(recipe.activities) ? recipe.activities : null}
|
||||
title={recipe.title}
|
||||
parameterValues={recipeParameters || {}}
|
||||
parameterValues={recipeParameterValues || {}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -98,7 +98,7 @@ function BaseChatContent({
|
||||
messageHistoryIndex: 0,
|
||||
messages: [],
|
||||
recipe: null,
|
||||
recipeParameters: null,
|
||||
recipeParameterValues: null,
|
||||
};
|
||||
setChat(emptyChat);
|
||||
|
||||
@@ -111,7 +111,7 @@ function BaseChatContent({
|
||||
messageHistoryIndex: 0,
|
||||
messages: conversation,
|
||||
recipe: null,
|
||||
recipeParameters: null,
|
||||
recipeParameterValues: null,
|
||||
};
|
||||
|
||||
setChat(loadedChat);
|
||||
|
||||
@@ -7,7 +7,6 @@ import JsonSchemaEditor from './JsonSchemaEditor';
|
||||
import InstructionsEditor from './InstructionsEditor';
|
||||
import { Button } from '../../ui/button';
|
||||
import { RecipeFormApi } from './recipeFormSchema';
|
||||
import { extractTemplateVariables } from '../../../utils/providerUtils';
|
||||
|
||||
// Type for field API to avoid linting issues - use any to bypass complex type constraints
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@@ -25,6 +24,27 @@ interface RecipeFormFieldsProps {
|
||||
onJsonSchemaChange?: (value: string) => void;
|
||||
}
|
||||
|
||||
export const extractTemplateVariables = (content: string): string[] => {
|
||||
const templateVarRegex = /\{\{(.*?)\}\}/g;
|
||||
const variables: string[] = [];
|
||||
let match;
|
||||
|
||||
while ((match = templateVarRegex.exec(content)) !== null) {
|
||||
const variable = match[1].trim();
|
||||
|
||||
if (variable && !variables.includes(variable)) {
|
||||
// Filter out complex variables that aren't valid parameter names
|
||||
// This matches the backend logic in filter_complex_variables()
|
||||
const validVarRegex = /^\s*[a-zA-Z_][a-zA-Z0-9_]*\s*$/;
|
||||
if (validVarRegex.test(variable)) {
|
||||
variables.push(variable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return variables;
|
||||
};
|
||||
|
||||
export function RecipeFormFields({
|
||||
form,
|
||||
onTitleChange,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { useForm } from '@tanstack/react-form';
|
||||
|
||||
import { RecipeFormFields } from '../RecipeFormFields';
|
||||
import { RecipeFormFields, extractTemplateVariables } from '../RecipeFormFields';
|
||||
import { type RecipeFormData } from '../recipeFormSchema';
|
||||
|
||||
describe('RecipeFormFields', () => {
|
||||
@@ -683,4 +683,132 @@ describe('RecipeFormFields', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('extractTemplateVariables', () => {
|
||||
it('should extract simple template variables', () => {
|
||||
const content = 'Hello {{name}}, welcome to {{app}}!';
|
||||
const result = extractTemplateVariables(content);
|
||||
expect(result).toEqual(['name', 'app']);
|
||||
});
|
||||
|
||||
it('should extract variables with underscores', () => {
|
||||
const content = 'User: {{user_name}}, ID: {{user_id}}';
|
||||
const result = extractTemplateVariables(content);
|
||||
expect(result).toEqual(['user_name', 'user_id']);
|
||||
});
|
||||
|
||||
it('should extract variables that start with underscore', () => {
|
||||
const content = 'Private: {{_private}}, Internal: {{__internal}}';
|
||||
const result = extractTemplateVariables(content);
|
||||
expect(result).toEqual(['_private', '__internal']);
|
||||
});
|
||||
|
||||
it('should handle variables with numbers', () => {
|
||||
const content = 'Item {{item1}}, Version {{version2_0}}';
|
||||
const result = extractTemplateVariables(content);
|
||||
expect(result).toEqual(['item1', 'version2_0']);
|
||||
});
|
||||
|
||||
it('should trim whitespace from variables', () => {
|
||||
const content = 'Hello {{ name }}, welcome to {{ app }}!';
|
||||
const result = extractTemplateVariables(content);
|
||||
expect(result).toEqual(['name', 'app']);
|
||||
});
|
||||
|
||||
it('should ignore invalid variable names with spaces', () => {
|
||||
const content = 'Invalid: {{user name}}, Valid: {{username}}';
|
||||
const result = extractTemplateVariables(content);
|
||||
expect(result).toEqual(['username']);
|
||||
});
|
||||
|
||||
it('should ignore invalid variable names with dots', () => {
|
||||
const content = 'Invalid: {{user.name}}, Valid: {{user_name}}';
|
||||
const result = extractTemplateVariables(content);
|
||||
expect(result).toEqual(['user_name']);
|
||||
});
|
||||
|
||||
it('should ignore invalid variable names with pipes', () => {
|
||||
const content = 'Invalid: {{name|upper}}, Valid: {{name}}';
|
||||
const result = extractTemplateVariables(content);
|
||||
expect(result).toEqual(['name']);
|
||||
});
|
||||
|
||||
it('should ignore invalid variable names with special characters', () => {
|
||||
const content = 'Invalid: {{user@name}}, {{user-name}}, {{user$name}}, Valid: {{username}}';
|
||||
const result = extractTemplateVariables(content);
|
||||
expect(result).toEqual(['username']);
|
||||
});
|
||||
|
||||
it('should ignore variables starting with numbers', () => {
|
||||
const content = 'Invalid: {{1name}}, {{2user}}, Valid: {{name1}}';
|
||||
const result = extractTemplateVariables(content);
|
||||
expect(result).toEqual(['name1']);
|
||||
});
|
||||
|
||||
it('should remove duplicates', () => {
|
||||
const content = 'Hello {{name}}, goodbye {{name}}, welcome {{app}}, use {{app}}';
|
||||
const result = extractTemplateVariables(content);
|
||||
expect(result).toEqual(['name', 'app']);
|
||||
});
|
||||
|
||||
it('should handle empty content', () => {
|
||||
const content = '';
|
||||
const result = extractTemplateVariables(content);
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('should handle content with no variables', () => {
|
||||
const content = 'This is just plain text with no variables.';
|
||||
const result = extractTemplateVariables(content);
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('should handle single braces (not template variables)', () => {
|
||||
const content = 'This {is} not a {template} variable but {{this}} is.';
|
||||
const result = extractTemplateVariables(content);
|
||||
expect(result).toEqual(['this']);
|
||||
});
|
||||
|
||||
it('should handle malformed template syntax', () => {
|
||||
const content = 'Malformed: {{{name}}}, {{name}}, {name}}';
|
||||
const result = extractTemplateVariables(content);
|
||||
expect(result).toEqual(['name']);
|
||||
});
|
||||
|
||||
it('should handle empty variable names', () => {
|
||||
const content = 'Empty: {{}}, Valid: {{name}}';
|
||||
const result = extractTemplateVariables(content);
|
||||
expect(result).toEqual(['name']);
|
||||
});
|
||||
|
||||
it('should handle variables with only whitespace', () => {
|
||||
const content = 'Whitespace: {{ }}, Valid: {{name}}';
|
||||
const result = extractTemplateVariables(content);
|
||||
expect(result).toEqual(['name']);
|
||||
});
|
||||
|
||||
it('should ignore complex template expressions with dots and pipes', () => {
|
||||
const content =
|
||||
'Complex: {{steps.fetch_payment_data.data.payments.totalEdgeCount | number_format}}, Valid: {{simple_param}}';
|
||||
const result = extractTemplateVariables(content);
|
||||
expect(result).toEqual(['simple_param']);
|
||||
});
|
||||
|
||||
it('should handle complex mixed content', () => {
|
||||
const content = `
|
||||
Welcome {{user_name}}!
|
||||
|
||||
Your account details:
|
||||
- ID: {{user_id}}
|
||||
- Email: {{email_address}}
|
||||
- Invalid: {{user.email}}
|
||||
- Invalid: {{user name}}
|
||||
- Invalid: {{1invalid}}
|
||||
|
||||
Thank you for using {{app_name}}!
|
||||
`;
|
||||
const result = extractTemplateVariables(content);
|
||||
expect(result).toEqual(['user_name', 'user_id', 'email_address', 'app_name']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user