Skip to content

fix: render rubric value with vars before grading#8084

Open
Jah-yee wants to merge 1 commit intopromptfoo:mainfrom
Jah-yee:fix/defaultTest-llm-rubric-vars
Open

fix: render rubric value with vars before grading#8084
Jah-yee wants to merge 1 commit intopromptfoo:mainfrom
Jah-yee:fix/defaultTest-llm-rubric-vars

Conversation

@Jah-yee
Copy link

@Jah-yee Jah-yee commented Mar 10, 2026

When llm-rubric assertion is defined in defaultTest, template variables like {{myVar}} were not being resolved - the rubric received the literal string {{myVar}} instead of the test case's variable value.

This fix renders the rubric value with nunjucks using the vars before passing it to the grading LLM context.

Fixes #7861

When llm-rubric assertion is defined in defaultTest, template variables
like {{myVar}} were not being resolved - the rubric received the literal
string {{myVar}} instead of the test case's variable value.

This fix renders the rubric value with nunjucks using the vars before
passing it to the grading LLM context.
@Jah-yee Jah-yee requested a review from a team as a code owner March 10, 2026 21:43
@Jah-yee Jah-yee requested a review from MrFlounder March 10, 2026 21:43
Copy link
Contributor

@promptfoo-scanner promptfoo-scanner bot left a comment

Choose a reason for hiding this comment

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

👍 All Clear

I reviewed the changes that render the rubric with Nunjucks variables before invoking the grading LLM. I traced inputs (rubric, vars, llmOutput) through prompt construction and the provider call and looked for exploit paths across the six LLM security classes. No medium-or-higher severity LLM security vulnerabilities introduced by this PR were found.

Minimum severity threshold: 🟡 Medium | To re-scan after changes, comment @promptfoo-scanner
Learn more


Was this helpful?  👍 Yes  |  👎 No 

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 10, 2026

📝 Walkthrough

Walkthrough

The matchesLlmRubric function in src/matchers.ts has been updated to render rubric values with template variables prior to passing them to the LLM. When the rubric is a string, it is processed via nunjucks.renderString to expand template variables; otherwise, it is JSON-stringified. The rendered rubric is then substituted in place of the original rubric value throughout the prompt construction and provider invocation logic. No changes were made to error handling or control flow.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: rendering rubric values with template variables before grading.
Description check ✅ Passed The description clearly explains the problem, solution, and references the linked issue #7861 that this PR addresses.
Linked Issues check ✅ Passed The code changes directly address issue #7861 by implementing template variable rendering in the rubric before LLM evaluation.
Out of Scope Changes check ✅ Passed All changes in src/matchers.ts are focused on the rubric rendering fix for the defaultTest llm-rubric issue with no extraneous modifications.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

Copy link
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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/matchers.ts`:
- Around line 637-642: The code re-renders string rubrics and stringifies object
rubrics in matchesLlmRubric, which corrupts literal {{...}} tokens and flattens
structured rubrics; remove the second nunjucks.renderString and stop using
JSON.stringify(rubric). Instead, use the incoming rubric value as-is: if rubric
is a string, use it directly (do not re-render) and if rubric is an object, keep
the object (do not stringify) so property access (rubric.foo) still works;
ensure both the local grading flow that sets renderedRubric and the remote path
that calls doRemoteGrading receive the raw rubric unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a45f2bea-b15c-47c0-80ea-d5de99024f12

📥 Commits

Reviewing files that changed from the base of the PR and between 757d6be and 4d8f1a0.

📒 Files selected for processing (1)
  • src/matchers.ts

Comment on lines +637 to +642
// Render the rubric value with vars so that template variables like {{myVar}}
// are expanded before being passed to the grading LLM.
const renderedRubric =
typeof rubric === 'string'
? nunjucks.renderString(rubric, vars || {})
: JSON.stringify(rubric);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify that llm-rubric values are already rendered before matchesLlmRubric
# and that the remote-grading branch still uses the raw rubric.

set -euo pipefail

echo "== matchesLlmRubric call site =="
rg -n -C3 'return matchesLlmRubric\(' src/assertions/llmRubric.ts

echo
echo "== upstream render of assertion string values =="
rg -n -C4 'renderedValue = nunjucks\.renderString\(renderedValue, resolvedVars\)' src/assertions/index.ts

echo
echo "== remote llm-rubric branch in matchesLlmRubric =="
rg -n -C4 "task: 'llm-rubric'|rubric,|vars: vars \|\| \{\}" src/matchers.ts

Repository: promptfoo/promptfoo

Length of output: 2166


Remove the second Nunjucks render and avoid stringifying object rubrics.

String llm-rubric values are already Nunjucks-rendered before matchesLlmRubric is called (at src/assertions/index.ts:389), so the render at lines 641 is a second pass that can corrupt literal {{...}} text from vars. Additionally, JSON.stringify(rubric) flattens object rubrics, breaking structured property access like rubric.foo when object access is enabled. The remote-grading path (lines 622–632) bypasses this entirely by passing the raw rubric to doRemoteGrading, so any fix must address both branches consistently.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/matchers.ts` around lines 637 - 642, The code re-renders string rubrics
and stringifies object rubrics in matchesLlmRubric, which corrupts literal
{{...}} tokens and flattens structured rubrics; remove the second
nunjucks.renderString and stop using JSON.stringify(rubric). Instead, use the
incoming rubric value as-is: if rubric is a string, use it directly (do not
re-render) and if rubric is an object, keep the object (do not stringify) so
property access (rubric.foo) still works; ensure both the local grading flow
that sets renderedRubric and the remote path that calls doRemoteGrading receive
the raw rubric unchanged.

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.

llm-rubric assertions in defaultTest cannot access test case variables via {{varName}} template syntax

1 participant