Skip to content

Conversation

@tomerqodo
Copy link

@tomerqodo tomerqodo commented Jan 29, 2026

Benchmark PR from agentic-review-benchmarks#3

Summary by CodeRabbit

Release Notes

  • New Features

    • Added a new template transform node type for workflows, enabling flexible template rendering with improved error handling and validation.
  • Tests

    • Significantly expanded test coverage for template transformation features and edge cases.

✏️ Tip: You can customize this high-level summary in your review settings.

laipz8200 and others added 6 commits January 25, 2026 12:04
…de and threaded it through DifyNodeFactory so TemplateTransform nodes receive the dependency by default, keeping behavior unchanged unless an override is provided. Changes are in `api/core/workflow/nodes/template_transform/template_transform_node.py` and `api/core/workflow/nodes/node_factory.py`.

**Commits**
- chore(workflow): identify TemplateTransform dependency on CodeExecutor
- feat(workflow): add CodeExecutor constructor injection to TemplateTransformNode (defaulting to current behavior)
- feat(workflow): inject CodeExecutor from DifyNodeFactory when creating TemplateTransform nodes

**Tests**
- Not run (not requested)

Next step: run `make lint` and `make type-check` if you want to validate the backend checks.
…Transform to use it, keeping CodeExecutor as the default adapter while preserving current behavior. Updates are in `api/core/workflow/nodes/template_transform/template_renderer.py`, `api/core/workflow/nodes/template_transform/template_transform_node.py`, `api/core/workflow/nodes/node_factory.py`, and `api/tests/unit_tests/core/workflow/nodes/template_transform/template_transform_node_spec.py`.

Commit-style summary:
- feat(template-transform): add Jinja2 template renderer abstraction with CodeExecutor adapter
- refactor(template-transform): use renderer in node/factory and update unit test patches

Tests not run (not requested).
…ode creation to return TemplateTransformNode directly for template-transform nodes in `api/core/workflow/nodes/node_factory.py`.

Commit-style summary:
- refactor(template-transform): derive TemplateRenderError from ValueError
- refactor(node-factory): instantiate TemplateTransformNode directly with injected renderer

Tests not run (not requested).
…ts/core/workflow/nodes/template_transform/template_transform_node_spec.py`)

chore(type-check): ran `make type-check` (basedpyright clean, 0 errors)

No errors reported.
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@coderabbitai
Copy link

coderabbitai bot commented Jan 29, 2026

Walkthrough

Introduces a pluggable template rendering abstraction for template transform nodes. A new Jinja2TemplateRenderer protocol and CodeExecutorJinja2TemplateRenderer implementation decouple template rendering from direct CodeExecutor usage. Factory wiring updated to support TEMPLATE_TRANSFORM node type with configurable renderer dependency injection.

Changes

Cohort / File(s) Summary
Template Renderer Abstraction
api/core/workflow/nodes/template_transform/template_renderer.py
New module introducing TemplateRenderError exception, Jinja2TemplateRenderer protocol, and CodeExecutorJinja2TemplateRenderer concrete implementation that delegates template rendering to CodeExecutor.execute_workflow_code_template.
Node Implementation Updates
api/core/workflow/nodes/template_transform/template_transform_node.py
Refactors template rendering to use pluggable template_renderer dependency (injected via constructor) instead of direct CodeExecutor calls. Updates error handling from CodeExecutionError to TemplateRenderError and enforces maximum output length validation.
Factory Integration
api/core/workflow/nodes/node_factory.py
Extends DifyNodeFactory.__init__ with template_renderer parameter and wires TemplateTransformNode instantiation with renderer dependency propagation.
Test Coverage Expansion
api/tests/unit_tests/core/workflow/nodes/template_transform/template_transform_node_spec.py
Updates mocks from CodeExecutor.execute_workflow_code_template to CodeExecutorJinja2TemplateRenderer.render_template and replaces CodeExecutionError with TemplateRenderError. Adds comprehensive test scenarios covering template features (booleans, nested structures, loops, filters, escaping, unicode, error cases).

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant TemplateTransformNode
    participant Jinja2TemplateRenderer
    participant CodeExecutor
    
    Client->>TemplateTransformNode: Execute node with template & variables
    TemplateTransformNode->>Jinja2TemplateRenderer: render_template(template, variables)
    Jinja2TemplateRenderer->>CodeExecutor: execute_workflow_code_template(JINJA2, template, variables)
    CodeExecutor-->>Jinja2TemplateRenderer: {result: rendered_string}
    Jinja2TemplateRenderer-->>TemplateTransformNode: rendered_string
    TemplateTransformNode->>TemplateTransformNode: Validate output length
    TemplateTransformNode-->>Client: {output: rendered_string}
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A template's born with a renderer's grace,
No more code paths in a tangled place,
Inject and plug, let the abstractions play,
Jinja2 sings in a modular way,
Tests bloom abundant, nine-fold they say!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive The PR description is minimal and vague, containing only 'Benchmark PR from https://...' without substantive details about changes, motivation, or context required by the template. Provide a comprehensive summary explaining what changed, why, and any dependencies. Include before/after context and complete the checklist items in the template.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'refactor(workflow): add Jinja2 renderer abstraction for template transform' clearly and concisely describes the main change: introducing a Jinja2 renderer abstraction for template transformation in the workflow system.
Docstring Coverage ✅ Passed Docstring coverage is 88.10% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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

Copy link

@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: 1

🤖 Fix all issues with AI agents
In `@api/core/workflow/nodes/template_transform/template_renderer.py`:
- Around line 29-40: The render_template method (render_template) currently
returns result.get("result") which can be None, contradicting the declared
return type str; change the implementation to treat a missing/None result as an
error: after calling self._code_executor.execute_workflow_code_template
(CodeLanguage.JINJA2), validate that result.get("result") is a non-None string
and if it is None (or not a str) raise TemplateRenderError with a clear message
instead of returning None so callers expecting a str won't receive None; keep
the signature as -> str and ensure TemplateRenderError is raised for
missing/None results.
🧹 Nitpick comments (1)
api/core/workflow/nodes/node_factory.py (1)

63-63: Consider using self._code_executor for consistency.

Line 63 passes the raw code_executor parameter to CodeExecutorJinja2TemplateRenderer, while line 49 already resolved code_executor or CodeExecutor to self._code_executor. Using the resolved value would be more consistent.

♻️ Suggested change
-        self._template_renderer = template_renderer or CodeExecutorJinja2TemplateRenderer(code_executor)
+        self._template_renderer = template_renderer or CodeExecutorJinja2TemplateRenderer(self._code_executor)
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 917af6d and 24297d2.

📒 Files selected for processing (4)
  • api/core/workflow/nodes/node_factory.py
  • api/core/workflow/nodes/template_transform/template_renderer.py
  • api/core/workflow/nodes/template_transform/template_transform_node.py
  • api/tests/unit_tests/core/workflow/nodes/template_transform/template_transform_node_spec.py
🧰 Additional context used
🧬 Code graph analysis (4)
api/core/workflow/nodes/template_transform/template_transform_node.py (1)
api/core/workflow/nodes/template_transform/template_renderer.py (5)
  • CodeExecutorJinja2TemplateRenderer (21-40)
  • Jinja2TemplateRenderer (13-18)
  • TemplateRenderError (9-10)
  • render_template (16-18)
  • render_template (29-40)
api/core/workflow/nodes/node_factory.py (4)
api/core/workflow/nodes/template_transform/template_renderer.py (2)
  • CodeExecutorJinja2TemplateRenderer (21-40)
  • Jinja2TemplateRenderer (13-18)
api/core/workflow/nodes/template_transform/template_transform_node.py (1)
  • TemplateTransformNode (22-92)
api/core/workflow/enums.py (1)
  • NodeType (36-85)
api/core/workflow/nodes/base/node.py (1)
  • graph_init_params (244-245)
api/tests/unit_tests/core/workflow/nodes/template_transform/template_transform_node_spec.py (1)
api/core/workflow/nodes/template_transform/template_renderer.py (1)
  • TemplateRenderError (9-10)
api/core/workflow/nodes/template_transform/template_renderer.py (1)
api/core/helper/code_executor/code_executor.py (4)
  • CodeExecutionError (29-30)
  • CodeExecutor (56-156)
  • CodeLanguage (43-46)
  • execute_workflow_code_template (142-156)
🔇 Additional comments (7)
api/core/workflow/nodes/template_transform/template_renderer.py (1)

9-18: LGTM on the abstraction design.

The TemplateRenderError exception and Jinja2TemplateRenderer protocol provide a clean abstraction for template rendering with proper separation of concerns. This enables easy testing and alternative implementations.

api/core/workflow/nodes/template_transform/template_transform_node.py (2)

26-41: Clean dependency injection pattern.

The constructor properly accepts an optional template_renderer with a sensible default. Using a keyword-only parameter (*,) enforces explicit naming at call sites, improving readability.


68-79: Depends on render_template returning non-None.

The code assumes rendered is a string (calls len(rendered) on line 69 and uses it in outputs). This will work correctly once the return type issue in template_renderer.py is addressed to guarantee a non-None return.

api/core/workflow/nodes/node_factory.py (1)

117-124: LGTM on TEMPLATE_TRANSFORM node wiring.

The factory correctly handles the new node type with proper dependency injection, matching the pattern established for CodeNode.

api/tests/unit_tests/core/workflow/nodes/template_transform/template_transform_node_spec.py (3)

130-165: Correctly updated patch target and return values.

The tests properly patch CodeExecutorJinja2TemplateRenderer.render_template and return plain strings instead of dictionaries, matching the new abstraction's interface.


197-215: Error handling test correctly uses TemplateRenderError.

The test properly validates that TemplateRenderError exceptions are caught and result in a FAILED status with the error message propagated.


433-1151: Comprehensive test coverage for template features.

Excellent coverage of edge cases including:

  • Boolean values and conditionals
  • Nested dictionaries
  • Various Jinja2 filters (upper, lower, length, default, escape)
  • Multiline templates and whitespace control
  • Unicode and special characters
  • Numeric edge cases (zero, negative, large numbers, float precision)
  • Empty collections

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +29 to +40
def render_template(self, template: str, variables: Mapping[str, Any]) -> str:
try:
result = self._code_executor.execute_workflow_code_template(
language=CodeLanguage.JINJA2, code=template, inputs=variables
)
except CodeExecutionError as exc:
raise TemplateRenderError(str(exc)) from exc

rendered = result.get("result")
if rendered is not None and not isinstance(rendered, str):
raise TemplateRenderError("Template render result must be a string.")
return rendered
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Return type mismatch: method can return None but signature declares str.

The method signature declares -> str, but result.get("result") on line 37 can return None when the key is absent. Line 40 then returns this potentially None value.

This causes downstream issues in template_transform_node.py where len(rendered) (line 69) would raise TypeError if rendered is None.

Either:

  1. Update the return type to str | None and handle None in callers, or
  2. Raise TemplateRenderError when the result is missing/None
🐛 Proposed fix (option 2 - enforce non-None return)
         rendered = result.get("result")
         if rendered is not None and not isinstance(rendered, str):
             raise TemplateRenderError("Template render result must be a string.")
+        if rendered is None:
+            raise TemplateRenderError("Template render returned no result.")
         return rendered
📝 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 render_template(self, template: str, variables: Mapping[str, Any]) -> str:
try:
result = self._code_executor.execute_workflow_code_template(
language=CodeLanguage.JINJA2, code=template, inputs=variables
)
except CodeExecutionError as exc:
raise TemplateRenderError(str(exc)) from exc
rendered = result.get("result")
if rendered is not None and not isinstance(rendered, str):
raise TemplateRenderError("Template render result must be a string.")
return rendered
def render_template(self, template: str, variables: Mapping[str, Any]) -> str:
try:
result = self._code_executor.execute_workflow_code_template(
language=CodeLanguage.JINJA2, code=template, inputs=variables
)
except CodeExecutionError as exc:
raise TemplateRenderError(str(exc)) from exc
rendered = result.get("result")
if rendered is not None and not isinstance(rendered, str):
raise TemplateRenderError("Template render result must be a string.")
if rendered is None:
raise TemplateRenderError("Template render returned no result.")
return rendered
🤖 Prompt for AI Agents
In `@api/core/workflow/nodes/template_transform/template_renderer.py` around lines
29 - 40, The render_template method (render_template) currently returns
result.get("result") which can be None, contradicting the declared return type
str; change the implementation to treat a missing/None result as an error: after
calling self._code_executor.execute_workflow_code_template
(CodeLanguage.JINJA2), validate that result.get("result") is a non-None string
and if it is None (or not a str) raise TemplateRenderError with a clear message
instead of returning None so callers expecting a str won't receive None; keep
the signature as -> str and ensure TemplateRenderError is raised for
missing/None results.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants