Skip to content

feat: add Mustache template support for prompts#9876

Merged
ogabrielluiz merged 83 commits into
mainfrom
mustache
Jan 8, 2026
Merged

feat: add Mustache template support for prompts#9876
ogabrielluiz merged 83 commits into
mainfrom
mustache

Conversation

@ogabrielluiz
Copy link
Copy Markdown
Contributor

@ogabrielluiz ogabrielluiz commented Sep 15, 2025

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

  • "Use Double Brackets" toggle: New advanced setting in the Prompt component to switch between {variable} (default) and {{variable}} syntax
  • MustachePromptModal: Dedicated modal for editing Mustache templates with live preview and variable detection
  • Variable highlighting: Visual feedback for detected {{variables}} in templates
  • Consistent UX: MustachePromptModal behaves identically to PromptModal (backend validation, toast notifications)

Backend

  • Message class enhancements: Support for Mustache template format with secure rendering
  • API validation: /validate/prompt endpoint supports mustache parameter
  • Variable extraction: Correctly extracts variables from both {var} and {{var}} syntax
  • Security hardening:
    • Only simple variables like {{variable}} allowed
    • Blocks dangerous patterns: {{{, {{#, {{/, {{^, {{&, {{>, {{!, {{.
    • Single-pass replacement prevents injection attacks
  • Friendly error messages: Backend catches cryptic Mustache parser errors and returns user-friendly messages
  • Dynamic mode switching: Template field type updates when toggling between modes, cleaning up old variables

Frontend Utilities

  • mustacheUtils.ts: Validation utilities mirroring backend security (for future frontend validation)
  • Proper TypeScript types: No any types, proper interfaces for non-standard browser APIs

Testing

  • Playwright E2E tests for double brackets toggle functionality
  • Python unit tests for PromptComponent with use_double_brackets BoolInput
  • Unit tests for MustachePromptComponent and variable extraction
  • Security tests for mustache_security utilities

Implementation Details

Variable Extraction

  • F-string mode (default): Only extracts {variable}
  • Mustache mode: Only extracts {{variable}}
  • Switching modes cleans up variables from the previous syntax

Security Model

The safe_mustache_render function 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

  • Validation errors no longer break component creation
  • Graceful error handling with debug logging
  • Clear error messages for invalid syntax (e.g., "Invalid template syntax. Check that all {{variables}} have matching closing braces.")

Dependencies

  • Added mustache and @types/mustache packages

Files Changed

  • Frontend: Modal, component, parameter rendering, and utility updates
  • Backend: API validation, message schema, and security utilities
  • Tests: Comprehensive test coverage for all new functionality
  • Starter projects: Updated with new use_double_brackets field

- 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
…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.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Sep 15, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Introduces 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

Cohort / File(s) Summary
Core backend mustache rendering and security
src/backend/base/langflow/schema/message.py, src/backend/base/langflow/utils/mustache_security.py, src/backend/base/langflow/utils/constants.py
Adds safe mustache rendering and template validation; updates Message to support template_format (including async from_template_and_variables); includes "mustache" in DIRECT_TYPES.
Backend API and validation flow
src/backend/base/langflow/api/v1/base.py, src/backend/base/langflow/base/prompts/api_utils.py
Extends ValidatePromptRequest with boolean mustache; validate_prompt accepts is_mustache and switches variable extraction path accordingly.
Backend components and input types
src/backend/base/langflow/components/prompts/mustache_prompt.py, src/backend/base/langflow/inputs/input_mixin.py, src/backend/base/langflow/components/deactivated/vectara_self_query.py
Adds MustachePromptComponent with build/update hooks; introduces FieldTypes.MUSTACHE_PROMPT; removes inline mypy ignores in a deactivated component.
Backend tests
src/backend/tests/integration/components/prompts/test_mustache_prompt.py, src/backend/tests/unit/components/prompts/test_mustache_prompt_component.py, src/backend/tests/unit/schema/test_mustache_template_processing.py, src/backend/tests/unit/utils/test_mustache_security.py
Adds integration and unit tests covering mustache component behavior, Message formatting/async construction, and mustache security utilities.
Frontend mustache UI and wiring
src/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.tsx, src/frontend/src/modals/mustachePromptModal/index.tsx, src/frontend/src/components/core/parameterRenderComponent/index.tsx, src/frontend/src/constants/constants.ts, src/frontend/src/controllers/API/queries/nodes/use-post-validate-prompt.ts, src/frontend/package.json
Adds MustachePromptAreaComponent and MustachePromptModal; wires new "mustache" input type into ParameterRenderComponent; adds dialog subtitle; API payload now includes mustache; adds mustache deps.
Frontend utils and types
src/frontend/src/modals/promptModal/utils/var-highlight-html.tsx, src/frontend/src/types/components/index.ts
Updates varHighlightHTML to accept addCurlyBraces option; extends IVarHighlightType with optional addCurlyBraces.
Frontend tests
src/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.test.tsx, src/frontend/src/components/core/parameterRenderComponent/index.test.tsx
Adds tests for mustache highlighting logic and prop/type validation for parameter renderer and mustache component.

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
Loading
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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested labels

enhancement, size:XXL, lgtm

Suggested reviewers

  • Cristhianzl
  • mfortman11
  • edwinjosechittilappilly

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 78.89% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The pull request title clearly and concisely summarizes the primary change of adding Mustache template support for prompts and aligns with the changeset’s main objective.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch mustache

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ogabrielluiz ogabrielluiz changed the title Add Mustache template support across components feat: Add Mustache template support across components Sep 15, 2025
@github-actions github-actions Bot added the enhancement New feature or request label Sep 15, 2025
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_template

Add 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 as StrInput, 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.loads with a clear error to avoid leaking a raw JSONDecodeError to 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 VectaraSelfQueryRetrieverComponent and name = "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 nit

Consider 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, "&lt;")
-    .replace(/>/g, "&gt;")
-    // 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, "&lt;").replace(/>/g, "&gt;"); // 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

📥 Commits

Reviewing files that changed from the base of the PR and between 8220836 and 3ad0da0.

⛔ Files ignored due to path filters (1)
  • src/frontend/package-lock.json is 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.py
  • src/backend/base/langflow/components/deactivated/vectara_self_query.py
  • src/backend/base/langflow/api/v1/base.py
  • src/backend/base/langflow/utils/constants.py
  • src/backend/tests/unit/schema/test_mustache_template_processing.py
  • src/backend/base/langflow/utils/mustache_security.py
  • src/backend/tests/unit/components/prompts/test_mustache_prompt_component.py
  • src/backend/base/langflow/inputs/input_mixin.py
  • src/backend/tests/unit/utils/test_mustache_security.py
  • src/backend/base/langflow/base/prompts/api_utils.py
  • src/backend/base/langflow/components/prompts/mustache_prompt.py
  • src/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.py
  • src/backend/tests/unit/schema/test_mustache_template_processing.py
  • src/backend/tests/unit/components/prompts/test_mustache_prompt_component.py
  • src/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 icon attribute to a string matching the frontend icon mapping exactly (case-sensitive).

Files:

  • src/backend/tests/integration/components/prompts/test_mustache_prompt.py
  • src/backend/base/langflow/components/deactivated/vectara_self_query.py
  • src/backend/tests/unit/components/prompts/test_mustache_prompt_component.py
  • src/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.py
  • src/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.ts
  • src/frontend/src/components/core/parameterRenderComponent/index.tsx
  • src/frontend/src/components/core/parameterRenderComponent/index.test.tsx
  • src/frontend/src/modals/mustachePromptModal/index.tsx
  • src/frontend/src/constants/constants.ts
  • src/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.tsx
  • src/frontend/src/modals/promptModal/utils/var-highlight-html.tsx
  • src/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.test.tsx
  • src/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.tsx
  • src/frontend/src/components/core/parameterRenderComponent/index.test.tsx
  • src/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.tsx
  • src/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.tsx
  • src/frontend/src/components/core/parameterRenderComponent/index.test.tsx
  • src/frontend/src/components/core/parameterRenderComponent/components/mustachePromptComponent/index.tsx
  • src/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.py
  • src/backend/tests/unit/components/prompts/test_mustache_prompt_component.py
  • src/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.tsx
  • src/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 icon attribute 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.py
  • src/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.tsx
  • src/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.tsx
  • src/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.tsx
  • src/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.tsx
  • 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/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 — LGTM

Optional prop is harmless and aligns with updated var-highlighting.

src/backend/base/langflow/utils/constants.py (1)

72-76: DIRECT_TYPES includes "mustache" — LGTM

Backend 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 — LGTM

Matches DIRECT_TYPES and frontend work.

src/frontend/src/constants/constants.ts (1)

160-162: MUSTACHE_PROMPT_DIALOG_SUBTITLE — LGTM

Clear 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 — verified

mustachePromptModal 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 accepts template_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.

Comment on lines 126 to 131
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)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
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.

Comment on lines +11 to +14
display_name: str = "Prompt"
description: str = "Create a prompt template with dynamic variables."
icon = "prompts"
trace_type = "prompt"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ 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.

Suggested change
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.

Comment on lines +243 to +249
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
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
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.

Comment on lines +10 to +18
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
]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
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()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
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.

Comment on lines +100 to +134
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()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
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.

Comment on lines +192 to +195
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"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
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).

Comment on lines +1 to +37
// 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");
});
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
// 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();
});
});

Comment on lines +102 to +109
postValidatePrompt(
{
name: field_name,
template: inputValue,
frontend_node: nodeClass!,
mustache: true,
},
{
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
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.

Comment on lines +7 to +10
if (addCurlyBraces) {
return `<span class="font-semibold chat-message-highlight">{${name}}</span>`;
}
return `<span class="font-semibold chat-message-highlight">${name}</span>`;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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, "&amp;")
+    .replace(/</g, "&lt;")
+    .replace(/>/g, "&gt;")
+    .replace(/"/g, "&quot;")
+    .replace(/'/g, "&#39;");
+  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.

Suggested change
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, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#39;");
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.
@erichare
Copy link
Copy Markdown
Collaborator

@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.
@ogabrielluiz ogabrielluiz enabled auto-merge January 2, 2026 19:48
@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Jan 2, 2026
@github-actions github-actions Bot removed the enhancement New feature or request label Jan 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request fast-track Skip tests and sends PR into the merge queue needs-docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants