feat: add Mustache template support for prompts#9876
Conversation
- Implement MustachePromptModal component with support for editing and validating Mustache templates. - Integrate with alert store for success, error, and notice alerts. - Utilize Mustache library for parsing and highlighting template variables. - Include UI components like Textarea, Badge, and Button for user interaction. - Add functionality to handle variable checking and prompt validation via API.
- Introduced `MustachePromptModal` for handling Mustache-specific prompts. - Updated `PromptAreaComponent` to conditionally render `MustachePromptModal` based on the `mustache` prop. - Enhanced `parameterRenderComponent` to recognize and handle "mustache" type templates. - Modified `varHighlightHTML` utility to optionally add curly braces around variable names. - Extended `usePostValidatePrompt` API call to include a `mustache` flag. - Updated component types to include `mustache` and `addCurlyBraces` options.
…mixin - Updated `format_text` and `from_template_and_variables` methods to accept a `template_format` parameter, allowing for different template formats. - Modified `ChatPromptTemplate.from_messages` to include `template_format` parameter. - Added `MUSTACHE_PROMPT` to the `InputTypes` enum in `input_mixin.py`.
…e templates - Introduce `MustachePromptComponent` class to create prompt templates with dynamic variables using mustache syntax. - Add `build_prompt`, `_update_template`, `post_code_processing`, and `_get_fallback_input` methods to handle prompt creation and processing. - Update `validate_prompt` function in `api_utils.py` to support mustache template variable extraction. - Import `mustache_template_vars` for handling mustache-specific template variables.
- Bump @types/mustache from 4.2.5 to 4.2.6 - Add @xyflow/react at version 12.3.6 - Update ace-builds from 1.35.0 to 1.41.0 - Add moment-timezone at version 0.5.48 - Update mustache version to 4.2.0 - Add rehype-raw at version 6.1.1 - Remove unused @napi-rs/nice dependencies from package-lock.json
…with enhanced styling and functionality
…nent for mustache prompt rendering
…e processing - Introduced integration tests for MustachePromptComponent covering various scenarios including basic functionality, multiple variables, missing variables, and complex logic. - Added unit tests for Message class to validate mustache template processing, including handling of special characters, lists, and conditional logic. - Ensured robust coverage for edge cases such as empty templates and missing variables.
…reaComponent - Introduced TypeScript tests for ParameterRenderComponent to validate props interface. - Added comprehensive tests for MustachePromptAreaComponent focusing on mustache variable highlighting and props validation. - Ensured robust coverage for various input scenarios, including handling of special characters and complex mustache variables.
…alidation tests
- Updated the highlighting logic to only support simple mustache variables ({{variable_name}}) and exclude complex syntax.
- Enhanced unit tests to validate that complex mustache variables, variables with spaces, and invalid characters are not highlighted.
- Added tests for various edge cases, including variables starting with numbers and those containing special operators.
- Ensured comprehensive coverage for the MustachePromptAreaComponent's behavior in handling mustache templates.
- Added a new utility module for mustache template security, including validation and safe rendering functions. - Updated the Message class to support mustache template formatting using the new secure renderer. - Ensured that only simple variable substitutions are allowed in mustache templates to enhance security.
… security - Updated tests for MustachePromptComponent to ensure only simple variables are processed and complex syntax is rejected. - Added new tests for validating mustache templates, including checks for invalid variable names and complex syntax. - Introduced integration tests for mustache security utilities, ensuring robust validation and safe rendering of templates. - Enhanced coverage for various edge cases, including nested objects and handling of None values.
- Introduced a new constant for the mustache prompt dialog subtitle to guide users on using double curly brackets for variable introduction. - Updated the MustachePromptModal to utilize the new subtitle constant, enhancing clarity and user experience.
- Changed the display name from "Mustache Prompt" to "Prompt" to simplify the component's identification and improve user experience.
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughIntroduces mustache template support across backend and frontend: new mustache-safe rendering and validation utilities, Message API changes to support template formats, a MustachePrompt component and UI modal, API payload and validation updates, input type additions, constants updates, and comprehensive tests. Also adds frontend mustache dependencies. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant FE as Frontend: MustachePromptModal
participant API as Backend API: POST /validate_prompt
participant VAL as validate_prompt()
participant SEC as mustache_security
FE->>API: Validate { name, template, frontend_node, mustache: true }
API->>VAL: validate_prompt(template, is_mustache=true)
alt is_mustache
VAL->>VAL: extract_input_variables_from_prompt()
else default
VAL->>VAL: mustache_template_vars()
end
VAL->>SEC: validate_mustache_template(template)
SEC-->>VAL: ok or error
VAL-->>API: { inputVariables, frontend_node | errors }
API-->>FE: Response
note over FE: Update UI and nodeClass based on response
sequenceDiagram
autonumber
participant Comp as MustachePromptComponent
participant Msg as Message
participant SEC as safe_mustache_render
participant CPT as ChatPromptTemplate
Comp->>Msg: from_template_and_variables(template, template_format="mustache", vars)
Msg->>Msg: format_text(template_format="mustache")
Msg->>SEC: safe_mustache_render(template, vars)
SEC-->>Msg: rendered text
Msg->>CPT: from_messages(template_format="mustache", ...)
CPT-->>Msg: prompt messages JSON
Msg-->>Comp: Message instance (text, prompt)
Comp->>Comp: set status to rendered text
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 10
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
src/frontend/src/constants/constants.ts (1)
655-675: Frontend supported types missing "mustache"LANGFLOW_SUPPORTED_TYPES doesn’t list "mustache". This can hide or block mustache fields in the UI.
Apply:
export const LANGFLOW_SUPPORTED_TYPES = new Set([ "str", "bool", "float", "code", "prompt", + "mustache", "file", "int", "dict", "NestedDict", "table", "link", "slider", "tab", "sortableList", "connect", "auth", "query", "mcp", "tools", ]);src/backend/base/langflow/base/prompts/api_utils.py (1)
205-229: Propagate is_mustache through process_prompt_templateAdd an optional keyword param is_mustache to process_prompt_template and forward it to validate_prompt; update mustache-specific callers to pass is_mustache=True.
-def process_prompt_template( - template: str, name: str, custom_fields: dict[str, list[str]] | None, frontend_node_template: dict[str, Any] -): +def process_prompt_template( + template: str, + name: str, + custom_fields: dict[str, list[str]] | None, + frontend_node_template: dict[str, Any], + *, + is_mustache: bool = False, +): @@ - input_variables = validate_prompt(template) + input_variables = validate_prompt(template, is_mustache=is_mustache)Files to change:
- Update src/backend/base/langflow/base/prompts/api_utils.py (signature + call above).
- Update mustache callers to pass the flag: src/backend/base/langflow/components/prompts/mustache_prompt.py (both call sites).
Other callers (e.g. api/v1/validate.py, components/processing/prompt.py) can remain unchanged (default is_mustache=False).src/backend/base/langflow/api/v1/base.py (1)
24-30: Forward mustache flag to validator (is_mustache)post_validate_prompt does not forward ValidatePromptRequest.mustache; process_prompt_template calls validate_prompt(template) without is_mustache, so mustache templates are always treated as non-mustache.
- src/backend/base/langflow/api/v1/validate.py — pass prompt_request.mustache into process_prompt_template.
- src/backend/base/langflow/base/prompts/api_utils.py — add is_mustache: bool = False to process_prompt_template signature and call validate_prompt(template, is_mustache=is_mustache).
🧹 Nitpick comments (23)
src/backend/base/langflow/components/deactivated/vectara_self_query.py (4)
57-59: Potential iteration bug: StrInput vs expected list.
for meta in self.metadata_field_info:assumes an iterable of JSON strings. The input is declared asStrInput, which is a single string—this will iterate characters. If multiple entries are needed, use a list input or parse a JSON array.Option A (preferred): switch to a list input (e.g.,
ListStrInput) and keep the loop.Option B: accept a single JSON array and parse once:
- metadata_field_obj = [] - for meta in self.metadata_field_info: - meta_obj = json.loads(meta) + metadata_field_obj = [] + for meta_obj in json.loads(self.metadata_field_info): if "name" not in meta_obj or "description" not in meta_obj or "type" not in meta_obj: msg = "Incorrect metadata field info format." raise ValueError(msg)
59-62: Harden JSON parsing; raise consistent ValueError on bad JSON.Wrap
json.loadswith a clear error to avoid leaking a rawJSONDecodeErrorto users.- meta_obj = json.loads(meta) + try: + meta_obj = json.loads(meta) + except json.JSONDecodeError as e: + raise ValueError("Invalid JSON in metadata_field_info entry") from e
12-18: Typo in class/name: “Retriver” → “Retriever”.Public identifiers should be spelled correctly to aid discoverability and future grep.
Consider renaming the class to
VectaraSelfQueryRetrieverComponentandname = "VectaraSelfQueryRetriever". If rename churn is undesirable here (deactivated module), at least add an alias.
70-76: Use explicit keyword args for SelfQueryRetriever.from_llm.Repo pins langchain 0.3.21; from_llm signature is (llm, vectorstore, document_contents, metadata_field_info, ...) — positional args bind correctly today, but switch to explicit keywords to future‑proof against signature drift. (python.langchain.com)
- return SelfQueryRetriever.from_llm( - self.llm, - self.vectorstore, - self.document_content_description, - metadata_field_obj, - verbose=True, - ) + return SelfQueryRetriever.from_llm( + llm=self.llm, + vectorstore=self.vectorstore, + document_contents=self.document_content_description, + metadata_field_info=metadata_field_obj, + verbose=True, + )src/frontend/package.json (1)
31-31: Mustache deps added — OK; minor packaging nitConsider moving @types/mustache to devDependencies (types are build-time only) to keep runtime deps lean. If you prefer consistency with existing @types entries under dependencies, feel free to skip.
Apply if desired:
"dependencies": { - "@types/mustache": "^4.2.6", "mustache": "^4.2.0", }, "devDependencies": { + "@types/mustache": "^4.2.6", }Also applies to: 56-56
src/backend/tests/unit/utils/test_mustache_security.py (2)
19-44: Add coverage for triple‑mustache (“{{{var}}}”) as disallowed complex syntax.Your validator blocks
{{&var}}but not{{{var}}}, which is another unescaped form. Add assertions so the tests protect against regressions.Apply this addition (new test):
def test_validate_rejects_triple_mustache(): """Triple-mustache (unescaped) must be rejected.""" with pytest.raises(ValueError, match="Complex mustache syntax is not allowed"): validate_mustache_template("Hello {{{name}}}")
105-109: Also assert safe renderer rejects triple‑mustache.Add this test:
def test_safe_render_rejects_triple_mustache(): """safe_mustache_render must reject triple-mustache.""" with pytest.raises(ValueError, match="Complex mustache syntax is not allowed"): safe_mustache_render("Value: {{{secret}}}", {"secret": "x"})src/backend/tests/unit/components/prompts/test_mustache_prompt_component.py (2)
135-158: Invalid-variable checks should exercise validation, not build.build_prompt doesn’t validate names; validation occurs via process_prompt_template during to_frontend_node/post_code_processing. Change these to call component.to_frontend_node() (or the validate API) and assert on the exception there.
Example change for the first case:
- with pytest.raises(ValueError, match="Invalid mustache variable"): - await component.build_prompt() + with pytest.raises(ValueError, match="Invalid mustache variable"): + component.to_frontend_node()Repeat for the other two cases.
40-46: Mark async tests with pytest.mark.asyncio.Per guidelines, decorate async tests to ensure proper execution.
- async def test_mustache_prompt_component_latest(self, component_class, default_kwargs): + @pytest.mark.asyncio + async def test_mustache_prompt_component_latest(self, component_class, default_kwargs): @@ - async def test_build_prompt_basic(self, component_class): + @pytest.mark.asyncio + async def test_build_prompt_basic(self, component_class): @@ - async def test_build_prompt_multiple_variables(self, component_class): + @pytest.mark.asyncio + async def test_build_prompt_multiple_variables(self, component_class): @@ - async def test_build_prompt_missing_variable(self, component_class): + @pytest.mark.asyncio + async def test_build_prompt_missing_variable(self, component_class): @@ - async def test_build_prompt_no_variables(self, component_class): + @pytest.mark.asyncio + async def test_build_prompt_no_variables(self, component_class): @@ - async def test_build_prompt_empty_template(self, component_class): + @pytest.mark.asyncio + async def test_build_prompt_empty_template(self, component_class): @@ - async def test_build_prompt_dot_notation_variables(self, component_class): + @pytest.mark.asyncio + async def test_build_prompt_dot_notation_variables(self, component_class): @@ - async def test_status_is_set_after_build(self, component_class): + @pytest.mark.asyncio + async def test_status_is_set_after_build(self, component_class):Also applies to: 47-54, 55-62, 63-71, 72-79, 80-87, 88-99, 211-221
src/backend/tests/unit/schema/test_mustache_template_processing.py (1)
165-175: Add pytest.mark.asyncio to async tests.Ensure async tests run under pytest’s async loop.
+import pytest @@ - async def test_from_template_and_variables_mustache(self): + @pytest.mark.asyncio + async def test_from_template_and_variables_mustache(self): @@ - async def test_from_template_and_variables_mustache_complex(self): + @pytest.mark.asyncio + async def test_from_template_and_variables_mustache_complex(self): @@ - async def test_from_template_and_variables_mustache_no_variables(self): + @pytest.mark.asyncio + async def test_from_template_and_variables_mustache_no_variables(self):Also applies to: 176-189, 190-196
src/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.tsx (2)
27-40: Memoize and centralize highlighting to avoid drift and extra work.Compute coloredContent with useMemo and reuse the shared varHighlightHTML utility used by the modal for consistency.
+import { useMemo } from "react"; +import { varHighlightHTML } from "@/modals/promptModal/utils/var-highlight-html"; @@ - const coloredContent = (typeof value === "string" ? value : "") - // escape HTML first - .replace(/</g, "<") - .replace(/>/g, ">") - // highlight only simple mustache variables {{variable_name}} - no complex syntax - .replace( - /\{\{([a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*)\}\}/g, - (match, varName) => { - return `<span class="chat-message-highlight">{{${varName}}}</span>`; - }, - ) - // preserve new-lines - .replace(/\n/g, "<br />"); + const coloredContent = useMemo(() => { + const safe = typeof value === "string" ? value : ""; + const escaped = safe.replace(/</g, "<").replace(/>/g, ">"); // keep default escaping + // Only highlight simple variables; keep addCurlyBraces to true to match preview + const highlighted = escaped.replace( + /\{\{([a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*)\}\}/g, + (_m, v) => varHighlightHTML({ word: v, addCurlyBraces: true }), + ); + return highlighted.replace(/\n/g, "<br />"); + }, [value]);
58-61: Minor UX: fallback test id when id is empty.data-testid becomes empty when id is "". Provide a stable fallback.
- id={id} - data-testid={id} + id={id} + data-testid={id || `${field_name || "mustache"}-preview`}src/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.test.tsx (3)
4-23: Test helper duplicates component logic; import or extract shared utility.These tests validate a local helper, not the component. Extract the highlighting into a shared util (already exists: var-highlight-html) and test that, or render the component.
161-211: Add real component render tests.Cover: placeholder when empty, icon visibility toggle, opening modal on click, setValue callback, readonly/disabled behavior. Mock MustachePromptModal.
Example outline (React Testing Library):
// Pseudocode render(<MustachePromptAreaComponent value="Hello {{name}}" field_name="template" nodeClass={{}} handleOnNewValue={fn} handleNodeClass={fn2} />); expect(screen.getByTestId(/template-preview/)).toBeInTheDocument(); expect(screen.queryByTestId(/icon-Scan|lock/)).toBeNull(); await user.click(screen.getByTestId("button_open_mustache_prompt_modal")); expect(mockModalOpen).toHaveBeenCalled();
154-158: Expectation mixes escaping semantics.Escaping “{{>partial}}” to “{{>partial}}” stems from global '>' escaping in the helper, not Mustache semantics. That’s fine for preview, but clarify via a comment or assert separately to reduce confusion.
src/backend/base/langflow/components/prompts/mustache_prompt.py (1)
24-29: Optionally validate before render.If invalid variables must fail fast at build time, call the same validate_prompt used in process_prompt_template before rendering.
Example:
# before calling Message.from_template_and_variables # validate_prompt(self._attributes.get("template", ""))src/backend/base/langflow/schema/message.py (1)
258-261: Async method without awaits.from_template_and_variables is async but contains no awaits, adding unnecessary async overhead and forcing callers to await.
Either remove async or justify upcoming awaits:
- async def from_template_and_variables(cls, template: str, template_format="f-string", **variables): + def from_template_and_variables(cls, template: str, template_format="f-string", **variables): instance = cls(template=template, variables=variables) - text = instance.format_text(template_format) + text = instance.format_text(template_format)If external callers rely on async, keep the signature but add a TODO with rationale.
src/frontend/src/modals/mustachePromptModal/index.tsx (6)
111-117: Dead code: reassigning field_name has no effect.field_name is a local prop binding; reassigning it post‑request isn’t used later and doesn’t update callers.
Remove this block or plumb a setter if you intend to persist the derived name.
- if (field_name === "") { - field_name = Array.isArray( - apiReturn?.frontend_node?.custom_fields?.[""], - ) - ? (apiReturn?.frontend_node?.custom_fields?.[""][0] ?? "") - : (apiReturn?.frontend_node?.custom_fields?.[""] ?? ""); - }
145-151: Harden error handling to avoid undefined access.error.response may be undefined; current code can throw in onError.
Apply:
- return setErrorData({ - title: PROMPT_ERROR_ALERT, - list: [error.response.data.detail ?? ""], - }); + return setErrorData({ + title: PROMPT_ERROR_ALERT, + list: [error?.response?.data?.detail || String(error?.message || error) || ""], + });
77-84: Regex over-matches Mustache (triple braces, sections).The current pattern highlights {{{var}}} as {{ {var }} and may catch sections/partials. Limit to simple variables only.
Apply:
- .replace(/\{\{(.+?)\}\}/g, (match, p1) => { - return varHighlightHTML({ name: match, addCurlyBraces: false }); - }) + // Highlight only simple double‑brace variables (exclude triple braces and sections/partials) + .replace(/\{\{(?![#^\/!>])([^}]+?)\}\}(?!\})/g, (match) => + varHighlightHTML({ name: match, addCurlyBraces: false }), + )This avoids {{{unescaped}}}, {{#section}}, {{/section}}, {{>partial}}, etc.
174-181: Caret restoration uses DOM CaretPosition offset as linear index.offset is relative to a node, not the textarea value; setSelectionRange with it is unreliable.
Simplify fallback to place caret at end when returning to edit mode:
- if ("caretPositionFromPoint" in document) { - let range = (document as any).caretPositionFromPoint(x, y)?.offset ?? 0; - if (range) { - const position = range; - textArea.setSelectionRange(position, position); - } - } + // Simple, robust fallback + const position = textArea.value.length; + textArea.setSelectionRange(position, position);If precise restoration is required, track selectionStart/End before switching to preview and restore them.
47-47: Remove unused ref.divRefPrompt is declared but never used.
Apply:
- const divRefPrompt = useRef(null);
63-65: Avoid console.error in UI component.Route parse errors to alerts/logging or strip in production.
Apply:
- console.error("Error parsing Mustache template:", error); + // Optional: forward to alert store or dev-only log + if (process.env.NODE_ENV !== "production") { + /* eslint-disable no-console */ + console.warn("Mustache parse error:", error); + }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
src/frontend/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (22)
src/backend/base/langflow/api/v1/base.py(1 hunks)src/backend/base/langflow/base/prompts/api_utils.py(2 hunks)src/backend/base/langflow/components/deactivated/vectara_self_query.py(1 hunks)src/backend/base/langflow/components/prompts/mustache_prompt.py(1 hunks)src/backend/base/langflow/inputs/input_mixin.py(2 hunks)src/backend/base/langflow/schema/message.py(3 hunks)src/backend/base/langflow/utils/constants.py(1 hunks)src/backend/base/langflow/utils/mustache_security.py(1 hunks)src/backend/tests/integration/components/prompts/test_mustache_prompt.py(1 hunks)src/backend/tests/unit/components/prompts/test_mustache_prompt_component.py(1 hunks)src/backend/tests/unit/schema/test_mustache_template_processing.py(1 hunks)src/backend/tests/unit/utils/test_mustache_security.py(1 hunks)src/frontend/package.json(2 hunks)src/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.test.tsx(1 hunks)src/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.tsx(1 hunks)src/frontend/src/components/core/parameterRenderComponent/index.test.tsx(1 hunks)src/frontend/src/components/core/parameterRenderComponent/index.tsx(2 hunks)src/frontend/src/constants/constants.ts(1 hunks)src/frontend/src/controllers/API/queries/nodes/use-post-validate-prompt.ts(2 hunks)src/frontend/src/modals/mustachePromptModal/index.tsx(1 hunks)src/frontend/src/modals/promptModal/utils/var-highlight-html.tsx(1 hunks)src/frontend/src/types/components/index.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (13)
{src/backend/**/*.py,tests/**/*.py,Makefile}
📄 CodeRabbit inference engine (.cursor/rules/backend_development.mdc)
{src/backend/**/*.py,tests/**/*.py,Makefile}: Run make format_backend to format Python code before linting or committing changes
Run make lint to perform linting checks on backend Python code
Files:
src/backend/tests/integration/components/prompts/test_mustache_prompt.pysrc/backend/base/langflow/components/deactivated/vectara_self_query.pysrc/backend/base/langflow/api/v1/base.pysrc/backend/base/langflow/utils/constants.pysrc/backend/tests/unit/schema/test_mustache_template_processing.pysrc/backend/base/langflow/utils/mustache_security.pysrc/backend/tests/unit/components/prompts/test_mustache_prompt_component.pysrc/backend/base/langflow/inputs/input_mixin.pysrc/backend/tests/unit/utils/test_mustache_security.pysrc/backend/base/langflow/base/prompts/api_utils.pysrc/backend/base/langflow/components/prompts/mustache_prompt.pysrc/backend/base/langflow/schema/message.py
src/backend/tests/**/*.py
📄 CodeRabbit inference engine (.cursor/rules/testing.mdc)
src/backend/tests/**/*.py: Unit tests for backend code must be located in the 'src/backend/tests/' directory, with component tests organized by component subdirectory under 'src/backend/tests/unit/components/'.
Test files should use the same filename as the component under test, with an appropriate test prefix or suffix (e.g., 'my_component.py' → 'test_my_component.py').
Use the 'client' fixture (an async httpx.AsyncClient) for API tests in backend Python tests, as defined in 'src/backend/tests/conftest.py'.
When writing component tests, inherit from the appropriate base class in 'src/backend/tests/base.py' (ComponentTestBase, ComponentTestBaseWithClient, or ComponentTestBaseWithoutClient) and provide the required fixtures: 'component_class', 'default_kwargs', and 'file_names_mapping'.
Each test in backend Python test files should have a clear docstring explaining its purpose, and complex setups or mocks should be well-commented.
Test both sync and async code paths in backend Python tests, using '@pytest.mark.asyncio' for async tests.
Mock external dependencies appropriately in backend Python tests to isolate unit tests from external services.
Test error handling and edge cases in backend Python tests, including using 'pytest.raises' and asserting error messages.
Validate input/output behavior and test component initialization and configuration in backend Python tests.
Use the 'no_blockbuster' pytest marker to skip the blockbuster plugin in tests when necessary.
Be aware of ContextVar propagation in async tests; test both direct event loop execution and 'asyncio.to_thread' scenarios to ensure proper context isolation.
Test error handling by mocking internal functions using monkeypatch in backend Python tests.
Test resource cleanup in backend Python tests by using fixtures that ensure proper initialization and cleanup of resources.
Test timeout and performance constraints in backend Python tests using 'asyncio.wait_for' and timing assertions.
Test Langflow's Messag...
Files:
src/backend/tests/integration/components/prompts/test_mustache_prompt.pysrc/backend/tests/unit/schema/test_mustache_template_processing.pysrc/backend/tests/unit/components/prompts/test_mustache_prompt_component.pysrc/backend/tests/unit/utils/test_mustache_security.py
src/backend/**/components/**/*.py
📄 CodeRabbit inference engine (.cursor/rules/icons.mdc)
In your Python component class, set the
iconattribute to a string matching the frontend icon mapping exactly (case-sensitive).
Files:
src/backend/tests/integration/components/prompts/test_mustache_prompt.pysrc/backend/base/langflow/components/deactivated/vectara_self_query.pysrc/backend/tests/unit/components/prompts/test_mustache_prompt_component.pysrc/backend/base/langflow/components/prompts/mustache_prompt.py
src/backend/base/langflow/components/**/*.py
📄 CodeRabbit inference engine (.cursor/rules/backend_development.mdc)
src/backend/base/langflow/components/**/*.py: Add new backend components to the appropriate subdirectory under src/backend/base/langflow/components/
Implement async component methods using async def and await for asynchronous operations
Use asyncio.create_task for background work in async components and ensure proper cleanup on cancellation
Use asyncio.Queue for non-blocking queue operations in async components and handle timeouts appropriately
Files:
src/backend/base/langflow/components/deactivated/vectara_self_query.pysrc/backend/base/langflow/components/prompts/mustache_prompt.py
src/frontend/src/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/frontend_development.mdc)
src/frontend/src/**/*.{ts,tsx,js,jsx}: All frontend TypeScript and JavaScript code should be located under src/frontend/src/ and organized into components, pages, icons, stores, types, utils, hooks, services, and assets directories as per the specified directory layout.
Use React 18 with TypeScript for all UI components in the frontend.
Format all TypeScript and JavaScript code using the make format_frontend command.
Lint all TypeScript and JavaScript code using the make lint command.
Files:
src/frontend/src/types/components/index.tssrc/frontend/src/components/core/parameterRenderComponent/index.tsxsrc/frontend/src/components/core/parameterRenderComponent/index.test.tsxsrc/frontend/src/modals/mustachePromptModal/index.tsxsrc/frontend/src/constants/constants.tssrc/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.tsxsrc/frontend/src/modals/promptModal/utils/var-highlight-html.tsxsrc/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.test.tsxsrc/frontend/src/controllers/API/queries/nodes/use-post-validate-prompt.ts
src/frontend/src/types/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/frontend_development.mdc)
All TypeScript type definitions should be placed in the types directory.
Files:
src/frontend/src/types/components/index.ts
src/frontend/src/components/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/frontend_development.mdc)
All components should be styled using Tailwind CSS utility classes.
Files:
src/frontend/src/components/core/parameterRenderComponent/index.tsxsrc/frontend/src/components/core/parameterRenderComponent/index.test.tsxsrc/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.tsxsrc/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.test.tsx
src/frontend/src/@(components|hooks)/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/frontend_development.mdc)
Implement dark mode support in components and hooks where needed.
Files:
src/frontend/src/components/core/parameterRenderComponent/index.tsxsrc/frontend/src/components/core/parameterRenderComponent/index.test.tsxsrc/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.tsxsrc/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.test.tsx
src/backend/tests/unit/**/*.py
📄 CodeRabbit inference engine (.cursor/rules/backend_development.mdc)
Test component integration within flows using create_flow, build_flow, and get_build_events utilities
Files:
src/backend/tests/unit/schema/test_mustache_template_processing.pysrc/backend/tests/unit/components/prompts/test_mustache_prompt_component.pysrc/backend/tests/unit/utils/test_mustache_security.py
src/frontend/**/*.@(test|spec).{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/testing.mdc)
src/frontend/**/*.@(test|spec).{ts,tsx,js,jsx}: Frontend test files should be located in 'src/frontend/' and use '.test.{ts,tsx,js,jsx}' or '.spec.{ts,tsx,js,jsx}' extensions.
Test both sync and async code paths in frontend test files.
Mock external dependencies appropriately in frontend test files to isolate unit tests from external services.
Test error handling and edge cases in frontend test files.
Validate input/output behavior and test component initialization and configuration in frontend test files.
Each frontend test should have a clear description or comment explaining its purpose, especially for complex setups or mocks.
Files:
src/frontend/src/components/core/parameterRenderComponent/index.test.tsxsrc/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.test.tsx
src/backend/tests/unit/components/**/*.py
📄 CodeRabbit inference engine (.cursor/rules/backend_development.mdc)
src/backend/tests/unit/components/**/*.py: Mirror the component directory structure for unit tests in src/backend/tests/unit/components/
Use ComponentTestBaseWithClient or ComponentTestBaseWithoutClient as base classes for component unit tests
Provide file_names_mapping for backward compatibility in component tests
Create comprehensive unit tests for all new components
Files:
src/backend/tests/unit/components/prompts/test_mustache_prompt_component.py
src/backend/**/*component*.py
📄 CodeRabbit inference engine (.cursor/rules/icons.mdc)
In your Python component class, set the
iconattribute to a string matching the frontend icon mapping exactly (case-sensitive).
Files:
src/backend/tests/unit/components/prompts/test_mustache_prompt_component.py
src/frontend/@(package*.json|tsconfig.json|tailwind.config.*|vite.config.*)
📄 CodeRabbit inference engine (.cursor/rules/frontend_development.mdc)
Frontend configuration files such as package.json, tsconfig.json, and Tailwind/Vite configs must be maintained and updated as needed.
Files:
src/frontend/package.json
🧠 Learnings (8)
📚 Learning: 2025-07-18T18:25:54.486Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/backend_development.mdc:0-0
Timestamp: 2025-07-18T18:25:54.486Z
Learning: Applies to src/backend/tests/unit/components/**/*.py : Create comprehensive unit tests for all new components
Applied to files:
src/backend/tests/integration/components/prompts/test_mustache_prompt.pysrc/backend/tests/unit/components/prompts/test_mustache_prompt_component.py
📚 Learning: 2025-07-21T14:16:14.125Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-07-21T14:16:14.125Z
Learning: Applies to src/frontend/**/*.@(test|spec).{ts,tsx,js,jsx} : Validate input/output behavior and test component initialization and configuration in frontend test files.
Applied to files:
src/frontend/src/components/core/parameterRenderComponent/index.test.tsxsrc/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.test.tsx
📚 Learning: 2025-07-21T14:16:14.125Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-07-21T14:16:14.125Z
Learning: Applies to src/frontend/**/*.@(test|spec).{ts,tsx,js,jsx} : Each frontend test should have a clear description or comment explaining its purpose, especially for complex setups or mocks.
Applied to files:
src/frontend/src/components/core/parameterRenderComponent/index.test.tsxsrc/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.test.tsx
📚 Learning: 2025-07-21T14:16:14.125Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-07-21T14:16:14.125Z
Learning: Applies to src/frontend/**/*.@(test|spec).{ts,tsx,js,jsx} : Mock external dependencies appropriately in frontend test files to isolate unit tests from external services.
Applied to files:
src/frontend/src/components/core/parameterRenderComponent/index.test.tsxsrc/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.test.tsx
📚 Learning: 2025-07-21T14:16:14.125Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-07-21T14:16:14.125Z
Learning: Applies to src/frontend/**/*.@(test|spec).{ts,tsx,js,jsx} : Test error handling and edge cases in frontend test files.
Applied to files:
src/frontend/src/components/core/parameterRenderComponent/index.test.tsxsrc/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.test.tsx
📚 Learning: 2025-07-18T18:27:12.609Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/frontend_development.mdc:0-0
Timestamp: 2025-07-18T18:27:12.609Z
Learning: Applies to src/frontend/src/**/__tests__/**/*.{ts,tsx,js,jsx} : All frontend code should be tested using appropriate component and integration tests.
Applied to files:
src/frontend/src/components/core/parameterRenderComponent/index.test.tsx
📚 Learning: 2025-07-21T14:16:14.125Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-07-21T14:16:14.125Z
Learning: Applies to src/backend/tests/**/*.md : Create comprehensive unit tests for all new components. If unit tests are incomplete, create a Markdown file with manual testing steps in the same directory as the unit tests, using the same filename as the component but with a '.md' extension.
Applied to files:
src/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.test.tsx
📚 Learning: 2025-07-18T18:27:12.609Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/frontend_development.mdc:0-0
Timestamp: 2025-07-18T18:27:12.609Z
Learning: Applies to src/frontend/@(package*.json|tsconfig.json|tailwind.config.*|vite.config.*) : Frontend configuration files such as package.json, tsconfig.json, and Tailwind/Vite configs must be maintained and updated as needed.
Applied to files:
src/frontend/package.json
🧬 Code graph analysis (11)
src/backend/tests/integration/components/prompts/test_mustache_prompt.py (3)
src/backend/base/langflow/components/prompts/mustache_prompt.py (1)
MustachePromptComponent(10-60)src/backend/base/langflow/schema/message.py (1)
Message(40-290)src/backend/tests/integration/utils.py (2)
pyleak_marker(193-198)run_single_component(148-184)
src/frontend/src/components/core/parameterRenderComponent/index.tsx (1)
src/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.tsx (1)
MustachePromptAreaComponent(16-102)
src/backend/tests/unit/schema/test_mustache_template_processing.py (1)
src/backend/base/langflow/schema/message.py (3)
Message(40-290)format_text(243-255)from_template_and_variables(258-275)
src/backend/tests/unit/components/prompts/test_mustache_prompt_component.py (5)
src/backend/base/langflow/components/prompts/mustache_prompt.py (1)
MustachePromptComponent(10-60)src/backend/base/langflow/schema/message.py (1)
Message(40-290)src/backend/tests/base.py (1)
ComponentTestBaseWithClient(159-160)src/backend/base/langflow/custom/custom_component/component.py (1)
to_frontend_node(912-964)src/backend/base/langflow/inputs/input_mixin.py (1)
FieldTypes(12-34)
src/frontend/src/modals/mustachePromptModal/index.tsx (6)
src/frontend/src/types/components/index.ts (1)
PromptModalType(662-672)src/frontend/src/modals/promptModal/utils/var-highlight-html.tsx (1)
varHighlightHTML(3-11)src/frontend/src/constants/constants.ts (3)
MAX_WORDS_HIGHLIGHT(95-95)MUSTACHE_PROMPT_DIALOG_SUBTITLE(160-161)EDIT_TEXT_PLACEHOLDER(721-721)src/frontend/src/constants/alerts_constants.tsx (4)
TEMP_NOTICE_ALERT(52-52)PROMPT_SUCCESS_ALERT(56-56)BUG_ALERT(13-13)PROMPT_ERROR_ALERT(19-20)src/frontend/src/utils/utils.ts (1)
classNames(32-34)src/frontend/src/utils/reactflowUtils.ts (1)
handleKeyDown(939-964)
src/backend/tests/unit/utils/test_mustache_security.py (1)
src/backend/base/langflow/utils/mustache_security.py (2)
safe_mustache_render(49-84)validate_mustache_template(21-46)
src/backend/base/langflow/base/prompts/api_utils.py (1)
src/backend/base/langflow/interface/utils.py (1)
extract_input_variables_from_prompt(62-83)
src/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.tsx (4)
src/frontend/src/components/core/parameterRenderComponent/types.ts (1)
PromptAreaComponentType(81-83)src/frontend/src/utils/utils.ts (1)
cn(36-38)src/frontend/src/components/common/genericIconComponent/index.tsx (1)
ForwardedIconComponent(15-146)src/frontend/src/modals/mustachePromptModal/index.tsx (1)
MustachePromptModal(28-302)
src/frontend/src/modals/promptModal/utils/var-highlight-html.tsx (1)
src/frontend/src/types/components/index.ts (1)
IVarHighlightType(290-293)
src/backend/base/langflow/components/prompts/mustache_prompt.py (5)
src/backend/base/langflow/base/prompts/api_utils.py (1)
process_prompt_template(205-228)src/backend/base/langflow/inputs/input_mixin.py (1)
FieldTypes(12-34)src/backend/base/langflow/inputs/inputs.py (2)
DefaultPromptField(650-657)PromptInput(119-120)src/backend/base/langflow/schema/message.py (2)
Message(40-290)from_template_and_variables(258-275)src/backend/base/langflow/template/utils.py (1)
update_template_values(61-67)
src/backend/base/langflow/schema/message.py (1)
src/backend/base/langflow/utils/mustache_security.py (1)
safe_mustache_render(49-84)
🔇 Additional comments (12)
src/frontend/src/types/components/index.ts (1)
291-293: IVarHighlightType: addCurlyBraces optional — LGTMOptional prop is harmless and aligns with updated var-highlighting.
src/backend/base/langflow/utils/constants.py (1)
72-76: DIRECT_TYPES includes "mustache" — LGTMBackend type surface aligned with new FieldTypes.
src/backend/base/langflow/inputs/input_mixin.py (2)
4-4: Import consolidation — LGTM
25-26: FieldTypes.MUSTACHE_PROMPT added — LGTMMatches DIRECT_TYPES and frontend work.
src/frontend/src/constants/constants.ts (1)
160-162: MUSTACHE_PROMPT_DIALOG_SUBTITLE — LGTMClear guidance for users on {{}} usage.
src/frontend/src/controllers/API/queries/nodes/use-post-validate-prompt.ts (2)
16-16: Payload adds mustache flag — LGTM
33-37: Wire flag through request body — verifiedmustachePromptModal passes mustache: true (src/frontend/src/modals/mustachePromptModal/index.tsx:107); promptModal omits the flag (src/frontend/src/modals/promptModal/index.tsx) — no changes required.
src/frontend/src/components/core/parameterRenderComponent/index.tsx (1)
20-20: Mustache input wiring mirrors “prompt” correctly; nice, incremental change.Props passthrough, readonly parity, and id prefix look consistent.
Please verify:
- Types/registrations: “mustache” is included wherever input types are enumerated (frontend types and backend schemas), and no dead branches remain.
- Add a minimal runtime test that renders ParameterRenderComponent with
templateData={{ type: "mustache", name: "template" }}and asserts the mustache prompt button is present (getByTestId("button_open_mustache_prompt_modal")). This guards the new switch case.Also applies to: 193-201
src/backend/tests/unit/schema/test_mustache_template_processing.py (1)
46-56: Confirm renderer behavior matches security policy.These tests depend on sections and lists being supported by safe_mustache_render. If the security layer restricts them, adjust either the renderer or tests accordingly. Don’t let component and schema tests diverge.
Also applies to: 57-66
src/backend/base/langflow/components/prompts/mustache_prompt.py (1)
16-18: Confirm PromptInput field_type supports FieldTypes.MUSTACHE_PROMPT.PromptInput defaults to FieldTypes.PROMPT; you override it here. Ensure serialization/validation paths accept "mustache".
src/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.tsx (1)
1-1: No change required — default import is valid.
The module exports ForwardedIconComponent both as a named export (line 15) and as the default export (line 162), so the existing default import is correct.Likely an incorrect or invalid review comment.
src/backend/base/langflow/schema/message.py (1)
271-271: ChatPromptTemplate.from_messages acceptstemplate_format— verify your pinned langchain-core version.ChatPromptTemplate.from_messages accepts a template_format parameter in current langchain_core API. (python.langchain.com) Typing for the "jinja2" option was added in PR #24144 (merged 2024-07-16). (github.com)
If you must support older langchain-core releases (pre‑Jul 16, 2024), remove the arg for compatibility (or persist template_format separately); otherwise keeping it is fine.
| def validate_prompt(prompt_template: str, *, silent_errors: bool = False, is_mustache: bool = False) -> list[str]: | ||
| if is_mustache: | ||
| input_variables = extract_input_variables_from_prompt(prompt_template) | ||
| else: | ||
| input_variables = mustache_template_vars(prompt_template) | ||
|
|
There was a problem hiding this comment.
Parser selection is inverted for is_mustache
When is_mustache=True you should use mustache_template_vars; current code uses the Python Formatter extractor and vice versa. This breaks variable extraction and can invalidate prompts.
Fix:
-def validate_prompt(prompt_template: str, *, silent_errors: bool = False, is_mustache: bool = False) -> list[str]:
- if is_mustache:
- input_variables = extract_input_variables_from_prompt(prompt_template)
- else:
- input_variables = mustache_template_vars(prompt_template)
+def validate_prompt(prompt_template: str, *, silent_errors: bool = False, is_mustache: bool = False) -> list[str]:
+ if is_mustache:
+ # Mustache templates use {{var}} syntax
+ input_variables = list(mustache_template_vars(prompt_template))
+ else:
+ # Default: Python-style {var} extraction
+ input_variables = extract_input_variables_from_prompt(prompt_template)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| def validate_prompt(prompt_template: str, *, silent_errors: bool = False, is_mustache: bool = False) -> list[str]: | |
| if is_mustache: | |
| input_variables = extract_input_variables_from_prompt(prompt_template) | |
| else: | |
| input_variables = mustache_template_vars(prompt_template) | |
| def validate_prompt(prompt_template: str, *, silent_errors: bool = False, is_mustache: bool = False) -> list[str]: | |
| if is_mustache: | |
| # Mustache templates use {{var}} syntax | |
| input_variables = list(mustache_template_vars(prompt_template)) | |
| else: | |
| # Default: Python-style {var} extraction | |
| input_variables = extract_input_variables_from_prompt(prompt_template) |
🤖 Prompt for AI Agents
In src/backend/base/langflow/base/prompts/api_utils.py around lines 126 to 131,
the conditional that chooses the parser is inverted: when is_mustache=True it
incorrectly calls the Python Formatter extractor and when False it calls
mustache_template_vars; swap the branches so that is_mustache=True uses
mustache_template_vars(prompt_template) and the else branch uses
extract_input_variables_from_prompt(prompt_template), preserving the existing
silent_errors behavior and return type.
| display_name: str = "Prompt" | ||
| description: str = "Create a prompt template with dynamic variables." | ||
| icon = "prompts" | ||
| trace_type = "prompt" |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Rename component for clarity and to satisfy tests.
Use “Mustache Prompt” to distinguish from the existing Prompt component.
- display_name: str = "Prompt"
+ display_name: str = "Mustache Prompt"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| display_name: str = "Prompt" | |
| description: str = "Create a prompt template with dynamic variables." | |
| icon = "prompts" | |
| trace_type = "prompt" | |
| display_name: str = "Mustache Prompt" | |
| description: str = "Create a prompt template with dynamic variables." | |
| icon = "prompts" | |
| trace_type = "prompt" |
🤖 Prompt for AI Agents
In src/backend/base/langflow/components/prompts/mustache_prompt.py around lines
11 to 14, the component's display_name is currently "Prompt" which conflicts
with an existing component and fails tests; change display_name to "Mustache
Prompt" (leave description, icon, and trace_type unchanged) so the component is
uniquely identified and tests pass.
| def format_text(self, template_format="f-string"): | ||
| if template_format == "mustache": | ||
| # Use our secure mustache renderer | ||
| variables_with_str_values = dict_values_to_string(self.variables) | ||
| formatted_prompt = safe_mustache_render(self.template, variables_with_str_values) | ||
| self.text = formatted_prompt | ||
| return formatted_prompt |
There was a problem hiding this comment.
Mustache rendering: don’t stringify variables (breaks dot-path lookups).
safe_mustache_render supports dot notation and expects nested dicts/objects. Converting values to strings prevents nested access and causes incorrect substitutions.
Apply this diff:
- if template_format == "mustache":
- # Use our secure mustache renderer
- variables_with_str_values = dict_values_to_string(self.variables)
- formatted_prompt = safe_mustache_render(self.template, variables_with_str_values)
+ if template_format == "mustache":
+ # Use our secure mustache renderer (preserve nested structures for dot-paths)
+ vars_for_mustache = getattr(self, "variables", {}) or {}
+ formatted_prompt = safe_mustache_render(self.template, vars_for_mustache)
self.text = formatted_prompt
return formatted_prompt📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| def format_text(self, template_format="f-string"): | |
| if template_format == "mustache": | |
| # Use our secure mustache renderer | |
| variables_with_str_values = dict_values_to_string(self.variables) | |
| formatted_prompt = safe_mustache_render(self.template, variables_with_str_values) | |
| self.text = formatted_prompt | |
| return formatted_prompt | |
| def format_text(self, template_format="f-string"): | |
| if template_format == "mustache": | |
| # Use our secure mustache renderer (preserve nested structures for dot-paths) | |
| vars_for_mustache = getattr(self, "variables", {}) or {} | |
| formatted_prompt = safe_mustache_render(self.template, vars_for_mustache) | |
| self.text = formatted_prompt | |
| return formatted_prompt |
🤖 Prompt for AI Agents
In src/backend/base/langflow/schema/message.py around lines 243-249, the code
stringifies variables before calling safe_mustache_render which breaks dot-path
lookups and nested access; instead pass the original nested self.variables
directly to safe_mustache_render (remove the call to dict_values_to_string),
assign the returned formatted_prompt to self.text and return it so mustache
rendering can resolve nested keys correctly.
| DANGEROUS_PATTERNS = [ | ||
| re.compile(r"\{\{#"), # Conditionals/sections start | ||
| re.compile(r"\{\{/"), # Conditionals/sections end | ||
| re.compile(r"\{\{\^"), # Inverted sections | ||
| re.compile(r"\{\{&"), # Unescaped variables | ||
| re.compile(r"\{\{>"), # Partials | ||
| re.compile(r"\{\{!"), # Comments | ||
| re.compile(r"\{\{\."), # Current context | ||
| ] |
There was a problem hiding this comment.
Block triple‑mustache (“{{{var}}}”) as unescaped output.
Currently not caught by DANGEROUS_PATTERNS; validation should reject it to align with “simple variables only.”
Apply this diff:
DANGEROUS_PATTERNS = [
+ re.compile(r"\{\{\{"), # Triple-mustache (unescaped)
re.compile(r"\{\{#"), # Conditionals/sections start
re.compile(r"\{\{/"), # Conditionals/sections end
re.compile(r"\{\{\^"), # Inverted sections
re.compile(r"\{\{&"), # Unescaped variables
re.compile(r"\{\{>"), # Partials
re.compile(r"\{\{!"), # Comments
re.compile(r"\{\{\."), # Current context
]📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| DANGEROUS_PATTERNS = [ | |
| re.compile(r"\{\{#"), # Conditionals/sections start | |
| re.compile(r"\{\{/"), # Conditionals/sections end | |
| re.compile(r"\{\{\^"), # Inverted sections | |
| re.compile(r"\{\{&"), # Unescaped variables | |
| re.compile(r"\{\{>"), # Partials | |
| re.compile(r"\{\{!"), # Comments | |
| re.compile(r"\{\{\."), # Current context | |
| ] | |
| DANGEROUS_PATTERNS = [ | |
| re.compile(r"\{\{\{"), # Triple-mustache (unescaped) | |
| re.compile(r"\{\{#"), # Conditionals/sections start | |
| re.compile(r"\{\{/"), # Conditionals/sections end | |
| re.compile(r"\{\{\^"), # Inverted sections | |
| re.compile(r"\{\{\&"), # Unescaped variables | |
| re.compile(r"\{\{>"), # Partials | |
| re.compile(r"\{\{!"), # Comments | |
| re.compile(r"\{\{\."), # Current context | |
| ] |
🤖 Prompt for AI Agents
In src/backend/base/langflow/utils/mustache_security.py around lines 10 to 18,
the DANGEROUS_PATTERNS list misses the triple‑mustache unescaped output pattern
(e.g. "{{{var}}}") so validation allows unescaped output; add a compiled regex
for the triple‑mustache opening (for example re.compile(r"\{\{\{")) to the list
with a comment indicating "Unescaped triple‑mustache" so the validator rejects
triple curly braces and enforces simple variables only.
|
|
||
| from tests.integration.utils import pyleak_marker, run_single_component | ||
|
|
||
| pytestmark = pyleak_marker() |
There was a problem hiding this comment.
Async tests lack an asyncio marker; add a module-level marker to ensure proper event loop handling.
Without it, coroutine tests may be skipped or error under default pytest settings.
Apply this diff:
-pytestmark = pyleak_marker()
+pytestmark = [pyleak_marker(), pytest.mark.asyncio]📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| pytestmark = pyleak_marker() | |
| pytestmark = [pyleak_marker(), pytest.mark.asyncio] |
🤖 Prompt for AI Agents
In src/backend/tests/integration/components/prompts/test_mustache_prompt.py
around line 7, tests that use coroutines need an asyncio marker; update the
module-level pytestmark to include pytest.mark.asyncio (and ensure pytest is
imported) so pytest uses the asyncio event loop for async tests — e.g., combine
the existing pyleak_marker() into a list with pytest.mark.asyncio and assign it
to pytestmark.
| async def test_build_prompt_rejects_complex_mustache(self, component_class): | ||
| """Test that complex mustache syntax is rejected.""" | ||
| # Test conditional syntax | ||
| component = component_class( | ||
| template="{{#show_greeting}}Hello {{name}}!{{/show_greeting}}", | ||
| name="World", | ||
| show_greeting=True, | ||
| ) | ||
| with pytest.raises(ValueError, match="Complex mustache syntax is not allowed"): | ||
| await component.build_prompt() | ||
|
|
||
| # Test inverted section | ||
| component = component_class( | ||
| template="{{^is_empty}}Not empty{{/is_empty}}", | ||
| is_empty=False, | ||
| ) | ||
| with pytest.raises(ValueError, match="Complex mustache syntax is not allowed"): | ||
| await component.build_prompt() | ||
|
|
||
| # Test unescaped variable | ||
| component = component_class( | ||
| template="{{&unescaped_html}}", | ||
| unescaped_html="<script>alert('test')</script>", | ||
| ) | ||
| with pytest.raises(ValueError, match="Complex mustache syntax is not allowed"): | ||
| await component.build_prompt() | ||
|
|
||
| # Test partial | ||
| component = component_class( | ||
| template="{{>header}}", | ||
| header="Header content", | ||
| ) | ||
| with pytest.raises(ValueError, match="Complex mustache syntax is not allowed"): | ||
| await component.build_prompt() | ||
|
|
There was a problem hiding this comment.
Inconsistent policy: sections/inverted rejected here but allowed in Message tests.
This suite raises on sections/inverted, while src/backend/tests/unit/schema/test_mustache_template_processing.py asserts they render. Pick one policy. If sections are allowed (recommended), update these tests to assert rendered text; keep rejecting only unsafe tags ({{& }} and partials) if that’s the policy.
Suggested update (allow sections/inverted, still reject unescaped/partials):
- with pytest.raises(ValueError, match="Complex mustache syntax is not allowed"):
- await component.build_prompt()
+ result = await component.build_prompt()
+ assert result.text == "Hello World!"
@@
- with pytest.raises(ValueError, match="Complex mustache syntax is not allowed"):
- await component.build_prompt()
+ result = await component.build_prompt()
+ assert result.text == "Not empty"
@@
- with pytest.raises(ValueError, match="Complex mustache syntax is not allowed"):
+ with pytest.raises(ValueError):
await component.build_prompt()
@@
- with pytest.raises(ValueError, match="Complex mustache syntax is not allowed"):
+ with pytest.raises(ValueError):
await component.build_prompt()📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| async def test_build_prompt_rejects_complex_mustache(self, component_class): | |
| """Test that complex mustache syntax is rejected.""" | |
| # Test conditional syntax | |
| component = component_class( | |
| template="{{#show_greeting}}Hello {{name}}!{{/show_greeting}}", | |
| name="World", | |
| show_greeting=True, | |
| ) | |
| with pytest.raises(ValueError, match="Complex mustache syntax is not allowed"): | |
| await component.build_prompt() | |
| # Test inverted section | |
| component = component_class( | |
| template="{{^is_empty}}Not empty{{/is_empty}}", | |
| is_empty=False, | |
| ) | |
| with pytest.raises(ValueError, match="Complex mustache syntax is not allowed"): | |
| await component.build_prompt() | |
| # Test unescaped variable | |
| component = component_class( | |
| template="{{&unescaped_html}}", | |
| unescaped_html="<script>alert('test')</script>", | |
| ) | |
| with pytest.raises(ValueError, match="Complex mustache syntax is not allowed"): | |
| await component.build_prompt() | |
| # Test partial | |
| component = component_class( | |
| template="{{>header}}", | |
| header="Header content", | |
| ) | |
| with pytest.raises(ValueError, match="Complex mustache syntax is not allowed"): | |
| await component.build_prompt() | |
| async def test_build_prompt_rejects_complex_mustache(self, component_class): | |
| """Test that complex mustache syntax is rejected.""" | |
| # Test conditional syntax | |
| component = component_class( | |
| template="{{#show_greeting}}Hello {{name}}!{{/show_greeting}}", | |
| name="World", | |
| show_greeting=True, | |
| ) | |
| result = await component.build_prompt() | |
| assert result.text == "Hello World!" | |
| # Test inverted section | |
| component = component_class( | |
| template="{{^is_empty}}Not empty{{/is_empty}}", | |
| is_empty=False, | |
| ) | |
| result = await component.build_prompt() | |
| assert result.text == "Not empty" | |
| # Test unescaped variable | |
| component = component_class( | |
| template="{{&unescaped_html}}", | |
| unescaped_html="<script>alert('test')</script>", | |
| ) | |
| with pytest.raises(ValueError): | |
| await component.build_prompt() | |
| # Test partial | |
| component = component_class( | |
| template="{{>header}}", | |
| header="Header content", | |
| ) | |
| with pytest.raises(ValueError): | |
| await component.build_prompt() |
🤖 Prompt for AI Agents
In src/backend/tests/unit/components/prompts/test_mustache_prompt_component.py
around lines 100 to 134 the test currently rejects complex mustache
sections/inverted sections but other tests allow them; to reconcile, change the
assertions for the conditional and inverted-section cases to expect successful
rendering (assert the built prompt contains the expected text) while keeping the
tests that raise ValueError for unescaped variables ({{& }}) and partials ({{>
}}) so only unsafe tags remain rejected; update the two with pytest.raises
blocks for sections/inverted to instead await component.build_prompt() and
assert the resulting string equals the expected rendered output.
| assert component.display_name == "Mustache Prompt" | ||
| assert component.description == "Create a prompt template with dynamic variables." | ||
| assert component.icon == "prompts" | ||
| assert component.trace_type == "prompt" |
There was a problem hiding this comment.
Fix metadata mismatch: display_name assertion vs component value.
Tests expect "Mustache Prompt" but the component sets display_name to "Prompt". Align them—prefer renaming the component for clarity.
Apply this diff in src/backend/base/langflow/components/prompts/mustache_prompt.py:
- display_name: str = "Prompt"
+ display_name: str = "Mustache Prompt"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| assert component.display_name == "Mustache Prompt" | |
| assert component.description == "Create a prompt template with dynamic variables." | |
| assert component.icon == "prompts" | |
| assert component.trace_type == "prompt" | |
| # File: src/backend/base/langflow/components/prompts/mustache_prompt.py | |
| class MustachePrompt: | |
| display_name: str = "Mustache Prompt" | |
| description: str = "Create a prompt template with dynamic variables." | |
| icon: str = "prompts" | |
| trace_type: str = "prompt" |
🤖 Prompt for AI Agents
In src/backend/tests/unit/components/prompts/test_mustache_prompt_component.py
around lines 192-195 the test asserts display_name == "Mustache Prompt" while
the component in src/backend/base/langflow/components/prompts/mustache_prompt.py
currently sets display_name to "Prompt"; update the component's display_name to
"Mustache Prompt" to match the test (search the file for the display_name
assignment and rename it), and run tests to ensure no other callers rely on the
old value (if they do, update those references accordingly).
| // TypeScript-only test to verify component props interface | ||
| // This test doesn't run any actual component code to avoid Jest configuration issues | ||
|
|
||
| describe("ParameterRenderComponent Types", () => { | ||
| it("should accept correct props type", () => { | ||
| // This test verifies that the component accepts the correct props structure | ||
| const baseProps = { | ||
| handleOnNewValue: jest.fn(), | ||
| name: "test-field", | ||
| nodeId: "test-node-id", | ||
| editNode: false, | ||
| handleNodeClass: jest.fn(), | ||
| nodeClass: { | ||
| description: "Test component", | ||
| template: {}, | ||
| display_name: "Test Component", | ||
| documentation: "Test component documentation", | ||
| }, | ||
| disabled: false, | ||
| templateValue: "Hello {{name}}!", | ||
| }; | ||
|
|
||
| // Test different template data types | ||
| const mustacheTemplateData = { type: "mustache", name: "template" }; | ||
| const promptTemplateData = { type: "prompt", name: "template" }; | ||
|
|
||
| // If this compiles without TypeScript errors, the types are correct | ||
| expect(baseProps).toBeDefined(); | ||
| expect(baseProps.nodeClass.description).toBe("Test component"); | ||
| expect(baseProps.nodeClass.display_name).toBe("Test Component"); | ||
| expect(baseProps.nodeClass.documentation).toBe( | ||
| "Test component documentation", | ||
| ); | ||
| expect(mustacheTemplateData.type).toBe("mustache"); | ||
| expect(promptTemplateData.type).toBe("prompt"); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
This “types-only” test doesn’t actually validate types or behavior.
It neither imports the component nor uses its props type, so it can’t fail on interface drift; it also doesn’t exercise the new mustache branch. Replace with a compile‑time props check plus a lightweight render assertion.
Apply this diff:
-// TypeScript-only test to verify component props interface
-// This test doesn't run any actual component code to avoid Jest configuration issues
-
-describe("ParameterRenderComponent Types", () => {
- it("should accept correct props type", () => {
- // This test verifies that the component accepts the correct props structure
- const baseProps = {
- handleOnNewValue: jest.fn(),
- name: "test-field",
- nodeId: "test-node-id",
- editNode: false,
- handleNodeClass: jest.fn(),
- nodeClass: {
- description: "Test component",
- template: {},
- display_name: "Test Component",
- documentation: "Test component documentation",
- },
- disabled: false,
- templateValue: "Hello {{name}}!",
- };
-
- // Test different template data types
- const mustacheTemplateData = { type: "mustache", name: "template" };
- const promptTemplateData = { type: "prompt", name: "template" };
-
- // If this compiles without TypeScript errors, the types are correct
- expect(baseProps).toBeDefined();
- expect(baseProps.nodeClass.description).toBe("Test component");
- expect(baseProps.nodeClass.display_name).toBe("Test Component");
- expect(baseProps.nodeClass.documentation).toBe(
- "Test component documentation",
- );
- expect(mustacheTemplateData.type).toBe("mustache");
- expect(promptTemplateData.type).toBe("prompt");
- });
-});
+import React from "react";
+import { render, screen } from "@testing-library/react";
+import { ParameterRenderComponent } from "./index";
+
+describe("ParameterRenderComponent — mustache rendering", () => {
+ it("renders MustachePromptAreaComponent when type is 'mustache'", () => {
+ type Props = Parameters<typeof ParameterRenderComponent>[0];
+ // Compile-time props conformance (fails if props drift):
+ const baseProps: Omit<Props, "templateData" | "templateValue"> = {
+ handleOnNewValue: jest.fn(),
+ name: "template",
+ nodeId: "node-1",
+ editNode: false,
+ handleNodeClass: jest.fn(),
+ nodeClass: {
+ description: "Test component",
+ template: {},
+ display_name: "Test Component",
+ documentation: "Test component documentation",
+ } as any,
+ disabled: false,
+ placeholder: "placeholder",
+ isToolMode: false,
+ };
+ const mustacheTemplateData = { type: "mustache", name: "template" } as const;
+
+ render(
+ <ParameterRenderComponent
+ {...(baseProps as Props)}
+ templateData={mustacheTemplateData as any}
+ templateValue="Hello {{name}}!"
+ />,
+ );
+ // The MustachePromptAreaComponent exposes this test id on its button
+ expect(
+ screen.getByTestId("button_open_mustache_prompt_modal"),
+ ).toBeInTheDocument();
+ });
+});📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // TypeScript-only test to verify component props interface | |
| // This test doesn't run any actual component code to avoid Jest configuration issues | |
| describe("ParameterRenderComponent Types", () => { | |
| it("should accept correct props type", () => { | |
| // This test verifies that the component accepts the correct props structure | |
| const baseProps = { | |
| handleOnNewValue: jest.fn(), | |
| name: "test-field", | |
| nodeId: "test-node-id", | |
| editNode: false, | |
| handleNodeClass: jest.fn(), | |
| nodeClass: { | |
| description: "Test component", | |
| template: {}, | |
| display_name: "Test Component", | |
| documentation: "Test component documentation", | |
| }, | |
| disabled: false, | |
| templateValue: "Hello {{name}}!", | |
| }; | |
| // Test different template data types | |
| const mustacheTemplateData = { type: "mustache", name: "template" }; | |
| const promptTemplateData = { type: "prompt", name: "template" }; | |
| // If this compiles without TypeScript errors, the types are correct | |
| expect(baseProps).toBeDefined(); | |
| expect(baseProps.nodeClass.description).toBe("Test component"); | |
| expect(baseProps.nodeClass.display_name).toBe("Test Component"); | |
| expect(baseProps.nodeClass.documentation).toBe( | |
| "Test component documentation", | |
| ); | |
| expect(mustacheTemplateData.type).toBe("mustache"); | |
| expect(promptTemplateData.type).toBe("prompt"); | |
| }); | |
| }); | |
| import React from "react"; | |
| import { render, screen } from "@testing-library/react"; | |
| import { ParameterRenderComponent } from "./index"; | |
| describe("ParameterRenderComponent — mustache rendering", () => { | |
| it("renders MustachePromptAreaComponent when type is 'mustache'", () => { | |
| type Props = Parameters<typeof ParameterRenderComponent>[0]; | |
| // Compile-time props conformance (fails if props drift): | |
| const baseProps: Omit<Props, "templateData" | "templateValue"> = { | |
| handleOnNewValue: jest.fn(), | |
| name: "template", | |
| nodeId: "node-1", | |
| editNode: false, | |
| handleNodeClass: jest.fn(), | |
| nodeClass: { | |
| description: "Test component", | |
| template: {}, | |
| display_name: "Test Component", | |
| documentation: "Test component documentation", | |
| } as any, | |
| disabled: false, | |
| placeholder: "placeholder", | |
| isToolMode: false, | |
| }; | |
| const mustacheTemplateData = { type: "mustache", name: "template" } as const; | |
| render( | |
| <ParameterRenderComponent | |
| {...(baseProps as Props)} | |
| templateData={mustacheTemplateData as any} | |
| templateValue="Hello {{name}}!" | |
| />, | |
| ); | |
| // The MustachePromptAreaComponent exposes this test id on its button | |
| expect( | |
| screen.getByTestId("button_open_mustache_prompt_modal"), | |
| ).toBeInTheDocument(); | |
| }); | |
| }); |
| postValidatePrompt( | ||
| { | ||
| name: field_name, | ||
| template: inputValue, | ||
| frontend_node: nodeClass!, | ||
| mustache: true, | ||
| }, | ||
| { |
There was a problem hiding this comment.
Non-null assertion on nodeClass can crash at runtime.
Comment says nodeClass is often null; using nodeClass! risks sending undefined and failing the request.
Apply this diff to build a safe payload:
- postValidatePrompt(
- {
- name: field_name,
- template: inputValue,
- frontend_node: nodeClass!,
- mustache: true,
- },
+ const payload = {
+ name: field_name,
+ template: inputValue,
+ mustache: true,
+ ...(nodeClass ? { frontend_node: nodeClass } : {}),
+ };
+ postValidatePrompt(
+ payload,
{📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| postValidatePrompt( | |
| { | |
| name: field_name, | |
| template: inputValue, | |
| frontend_node: nodeClass!, | |
| mustache: true, | |
| }, | |
| { | |
| const payload = { | |
| name: field_name, | |
| template: inputValue, | |
| mustache: true, | |
| ...(nodeClass ? { frontend_node: nodeClass } : {}), | |
| }; | |
| postValidatePrompt( | |
| payload, | |
| { |
🤖 Prompt for AI Agents
In src/frontend/src/modals/mustachePromptModal/index.tsx around lines 102 to
109, the code uses a non-null assertion nodeClass! when building the payload
which can crash if nodeClass is null; modify the code to guard against null by
checking if nodeClass is present before calling postValidatePrompt (return or
show validation error if missing), or build the payload without frontend_node
when nodeClass is null (e.g., omit the key or set it to null/undefined) so you
never send an undefined value; ensure any downstream callers tolerate the
missing frontend_node or handle the early return with user feedback.
| if (addCurlyBraces) { | ||
| return `<span class="font-semibold chat-message-highlight">{${name}}</span>`; | ||
| } | ||
| return `<span class="font-semibold chat-message-highlight">${name}</span>`; |
There was a problem hiding this comment.
Curly braces are wrong for Mustache; also escape the variable name.
Mustache uses double braces, not single. Escaping prevents HTML injection in the returned string.
Apply this diff:
export default function varHighlightHTML({
name,
addCurlyBraces,
}: IVarHighlightType): string {
- if (addCurlyBraces) {
- return `<span class="font-semibold chat-message-highlight">{${name}}</span>`;
- }
- return `<span class="font-semibold chat-message-highlight">${name}</span>`;
+ const escaped = String(name)
+ .replace(/&/g, "&")
+ .replace(/</g, "<")
+ .replace(/>/g, ">")
+ .replace(/"/g, """)
+ .replace(/'/g, "'");
+ if (addCurlyBraces) {
+ return `<span class="font-semibold chat-message-highlight">{{${escaped}}}</span>`;
+ }
+ return `<span class="font-semibold chat-message-highlight">${escaped}</span>`;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (addCurlyBraces) { | |
| return `<span class="font-semibold chat-message-highlight">{${name}}</span>`; | |
| } | |
| return `<span class="font-semibold chat-message-highlight">${name}</span>`; | |
| export default function varHighlightHTML({ | |
| name, | |
| addCurlyBraces, | |
| }: IVarHighlightType): string { | |
| const escaped = String(name) | |
| .replace(/&/g, "&") | |
| .replace(/</g, "<") | |
| .replace(/>/g, ">") | |
| .replace(/"/g, """) | |
| .replace(/'/g, "'"); | |
| if (addCurlyBraces) { | |
| return `<span class="font-semibold chat-message-highlight">{{${escaped}}}</span>`; | |
| } | |
| return `<span class="font-semibold chat-message-highlight">${escaped}</span>`; | |
| } |
🤖 Prompt for AI Agents
In src/frontend/src/modals/promptModal/utils/var-highlight-html.tsx around lines
7 to 10, the code returns single curly braces and inserts the raw variable name
into HTML; change the returned string to use Mustache double braces when
addCurlyBraces is true (i.e., "{{name}}") and ensure the variable name is
HTML-escaped before interpolation to prevent injection. Update the function to
call an existing HTML-escape utility (or implement a small escape function) and
use the escaped value in both branches, and when addCurlyBraces is true wrap the
escaped name with double braces rather than single.
- Introduced MustachePromptComponent to create prompt templates with dynamic variables. - Updated imports and exports in the processing module to include the new component. - Implemented methods for building prompts and updating templates, enhancing flexibility in prompt generation.
- Adjusted the order of input variable extraction in the validate_prompt function to ensure correct handling of Mustache templates. - Enhanced the process_prompt_template function to accept an is_mustache parameter, improving flexibility in template validation.
…d async updates - Updated imports to reflect the new module structure under lfx. - Added a validation step for Mustache templates to improve security. - Refactored the post_code_processing method to an async update_frontend_node method for better performance and compatibility with async workflows.
- Updated the from_template_and_variables and from_template methods to accept a template_format parameter, improving flexibility in template processing. - Ensured backward compatibility with previous versions while enhancing the functionality for template formatting options.
- Introduced 'mustache' as a new type in the DIRECT_TYPES list to support enhanced template processing capabilities. - This addition aligns with recent updates to template handling and validation in the codebase.
|
@ogabrielluiz LGTM once merge conflicts are resolved, just checking if we need the updates to package-lock, ad .secrets.baseline? |
…nused packages - Added peer: true to several dependencies to indicate peer dependency requirements. - Removed unused dependencies related to @napi-rs/nice and its variants.
# Conflicts: # src/lfx/src/lfx/_assets/component_index.json
# Conflicts: # src/lfx/src/lfx/_assets/component_index.json
Summary
This PR adds Mustache template support to Langflow's Prompt component, allowing users to create prompts using
{{variable}}syntax alongside the existing{variable}f-string syntax via a simple toggle.Key Changes
User-Facing
{variable}(default) and{{variable}}syntax{{variables}}in templatesBackend
/validate/promptendpoint supportsmustacheparameter{var}and{{var}}syntax{{variable}}allowed{{{,{{#,{{/,{{^,{{&,{{>,{{!,{{.Frontend Utilities
mustacheUtils.ts: Validation utilities mirroring backend security (for future frontend validation)anytypes, proper interfaces for non-standard browser APIsTesting
use_double_bracketsBoolInputImplementation Details
Variable Extraction
{variable}{{variable}}Security Model
The
safe_mustache_renderfunction performs a single-pass replacement of all{{variable}}patterns. Variable values that themselves contain mustache-like patterns (e.g.,"{{other}}") are treated as literal strings, preventing injection attacks.Error Handling
Dependencies
mustacheand@types/mustachepackagesFiles Changed
use_double_bracketsfield