Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
134 commits
Select commit Hold shift + click to select a range
78ac5a4
initial analysis
jp-agenta May 21, 2026
9e49938
another pass
jp-agenta May 21, 2026
ab57b84
update analysis
jp-agenta May 21, 2026
8456117
initial implementation
jp-agenta May 21, 2026
0cae109
fix findings
jp-agenta May 22, 2026
057a296
fix new findings
jp-agenta May 22, 2026
a7a7b1d
CR cleanup
jp-agenta May 22, 2026
687c924
fix CR
jp-agenta May 22, 2026
3ba7d97
more CR
jp-agenta May 22, 2026
860b9dd
docs(mustache): escape analysis + decision, how-to escaping, JSDoc fix
jp-agenta May 22, 2026
f04efcf
Add web hand-off
jp-agenta May 22, 2026
9383ae1
Merge branch 'release/v0.100.1' into feat/add-mustache-rendering
jp-agenta May 22, 2026
92bda84
fix(mustache): match {{ name }} whitespace, correct token/format docs
jp-agenta May 22, 2026
6332c0d
bump py deps
jp-agenta May 22, 2026
8744281
docs(mustache): fix JSON-whitespace claim and pre-render framing
jp-agenta May 22, 2026
8818af5
docs(mustache): note effect on curly/jinja2/fstring renderers
jp-agenta May 22, 2026
abe3576
feat(frontend): preserve native JSON in evaluator execution inputs
ardaerzin May 25, 2026
fe7b85f
feat(frontend): promote V2 view-mode primitives to @agenta/entity-ui
ardaerzin May 25, 2026
fbcb9e2
feat(frontend): add PlaygroundInputsBody for V2-aligned input UX
ardaerzin May 25, 2026
5144cce
feat(frontend): add inputs visibility rule for the playground inputs …
ardaerzin May 25, 2026
cace2ec
feat(frontend): add TemplateFormatPicker for the playground
ardaerzin May 25, 2026
42047fd
fix(frontend): wire @agenta/entity-ui/template-format subpath export
ardaerzin May 25, 2026
b0a1dda
feat(frontend): wire PlaygroundInputsBody into SingleLayout (feature-…
ardaerzin May 25, 2026
5483ec0
Merge remote-tracking branch 'origin/feat/add-mustache-rendering' int…
ardaerzin May 25, 2026
ba5fa4c
chore(frontend): reconcile post-merge with #4393's canonical helpers
ardaerzin May 25, 2026
6a84b7a
chore(frontend): fix import order in SingleLayout (move workspace imp…
ardaerzin May 25, 2026
df52f5f
feat(frontend): default the new playground inputs body ON
ardaerzin May 26, 2026
1a5b70e
fix(frontend): editor accepts mustache section close tags `{{/name}}`
ardaerzin May 26, 2026
030f438
docs(testing): add mustache + native-JSON QA testset fixture
ardaerzin May 26, 2026
e742a03
fix(frontend): validator accepts JSONPath rooted at testcase columns
ardaerzin May 26, 2026
56bbed7
fix(frontend): extractor skips mustache block markers; parser handles…
ardaerzin May 26, 2026
ac0c65c
fix(frontend): visibility atom dereferences entity.data
ardaerzin May 26, 2026
2b20b95
fix(frontend): native JSON survives the completion+chat request body …
ardaerzin May 26, 2026
699cdd3
feat(frontend): wire PlaygroundInputsBody into ComparisonLayout
ardaerzin May 26, 2026
d9424b7
feat(frontend): grouped evaluator layout uses PlaygroundInputsBody
ardaerzin May 26, 2026
2854349
feat(frontend): surface TemplateFormatPicker in playground section he…
ardaerzin May 26, 2026
c50c72c
Merge branch 'release/v0.100.2' into feat/add-mustache-rendering
jp-agenta May 26, 2026
728f415
Merge branch 'release/v0.100.2' into feat/add-mustache-rendering
ardaerzin May 26, 2026
faa41f4
fix(frontend): mustache section openers surface as input ports
ardaerzin May 27, 2026
cb10e2e
feat(frontend): schema-aware default view + chip for draft inputs
ardaerzin May 27, 2026
e4194a2
feat(frontend): seed object drafts with the expected sub-fields
ardaerzin May 27, 2026
83693af
fix(frontend): match prompt-config dropdown styling on ViewTypeSelect
ardaerzin May 27, 2026
d8db84d
feat(frontend): infer `array` type for mustache section-opener-only p…
ardaerzin May 27, 2026
ef6aef1
feat(frontend): array drafts default to JSON view (not Form)
ardaerzin May 27, 2026
2ad40f2
fix(frontend): restore "View as ▾" trigger label, keep simplified list
ardaerzin May 27, 2026
89f73b3
fix(frontend): right-align per-field "View as ▾" with card-level drop…
ardaerzin May 27, 2026
c76295e
fix(frontend): nested FormView labels match parent VariableCard style
ardaerzin May 27, 2026
37c99ff
fix(frontend): drop FormView right padding so leaf cards align with l…
ardaerzin May 27, 2026
7150093
feat(frontend): align playground input cards with input-ux mockup
ardaerzin May 27, 2026
52967ae
fix(frontend): label/chip/controls live INSIDE the variable card border
ardaerzin May 27, 2026
aefed44
fix(frontend): no inner border on hover/focus in VariableCard editors
ardaerzin May 27, 2026
88f5911
fix(frontend): don't seed YAML buffer with flow-style `[]` / `{}`
ardaerzin May 27, 2026
0bdfc93
fix(frontend): JSON / YAML always at the bottom of the view-mode list
ardaerzin May 27, 2026
acf98ab
feat(frontend): typeahead suggests field names after `{{#` / `{{^`
ardaerzin May 27, 2026
9ca1d8f
fix(frontend): JSON / YAML modes never auto-parse strings (gap-04 at …
ardaerzin May 27, 2026
8d088ad
fix(frontend): chat-mode variable cards are editable (match MessagesF…
ardaerzin May 27, 2026
d43c52e
fix(frontend): unreferenced columns are editable when expanded
ardaerzin May 27, 2026
2eb1f94
fix(frontend): gate mustache-specific affordances by templateFormat
ardaerzin May 27, 2026
b83dee2
Merge remote-tracking branch 'origin/feat/add-mustache-rendering' int…
ardaerzin May 27, 2026
f69a76e
fix(frontend): CodeRabbit review pass — formatting + targeted bugs
ardaerzin May 27, 2026
4ba4738
fix(frontend): thread active templateFormat into chat-mode variable i…
ardaerzin May 27, 2026
70d354c
revert(frontend): remove template_format picker from prompt section h…
ardaerzin May 28, 2026
7b216ed
fix(frontend): loosen JSONPath validation; reject `$<not-dot>` form
ardaerzin May 28, 2026
f3af845
fix(frontend): keep unreferenced-columns footer collapsed across migr…
ardaerzin May 28, 2026
a52ca93
fix(frontend): stop FormView leaf editor from remounting on every key…
ardaerzin May 28, 2026
82a663b
fix(frontend): preserve curly literal-key semantics for `{{foo.bar}}`
ardaerzin May 28, 2026
f6de9b5
Merge branch 'main' into feat/add-mustache-rendering
bekossy May 29, 2026
67af747
Merge branch 'feat/add-mustache-rendering' into fe-feat/mustache-support
bekossy May 29, 2026
242f25e
Merge branch 'main' into feat/add-mustache-rendering
bekossy May 31, 2026
a052891
Merge branch 'feat/add-mustache-rendering' into fe-feat/mustache-support
bekossy May 31, 2026
11ee49b
Merge branch 'main' into feat/add-mustache-rendering
junaway Jun 1, 2026
8b7731d
Merge branch 'feat/add-mustache-rendering' into fe-feat/mustache-support
junaway Jun 1, 2026
17df11c
web regex fix
jp-agenta Jun 1, 2026
d9066e6
Merge branch 'feat/add-mustache-rendering' into fe-feat/mustache-support
junaway Jun 1, 2026
e08cb4e
fix(frontend): chat playground — single testcase only + hide implicit…
ardaerzin Jun 1, 2026
693ac24
fix(frontend): mustache token regex — re-include sigil'd variables (`…
ardaerzin Jun 1, 2026
e26ca33
fix(frontend): merge schema sub-paths into form when value is non-empty
ardaerzin Jun 1, 2026
b77e1eb
docs(qa): summarise mustache QA pass — 4 fixed, 3 deferred
ardaerzin Jun 1, 2026
577da0e
fix(frontend): render Radio rows in single-select tables, not Checkboxes
ardaerzin Jun 1, 2026
5c637ca
docs(qa): note Radio-row fix for #6
ardaerzin Jun 1, 2026
4dd4359
docs(qa): add #8 + #9 from Kaosiso's later thread replies
ardaerzin Jun 1, 2026
3731ac9
fix(frontend): preserve original template_format as picker option aft…
ardaerzin Jun 1, 2026
909ba25
fix(frontend): reset original-format escape hatch on revision change
ardaerzin Jun 1, 2026
1e6dfa9
fix(frontend): always order Text before Markdown in chat view-mode dr…
ardaerzin Jun 1, 2026
c1c1a8e
docs(frontend): clarify no-long-string-logic policy in getViewOptions
ardaerzin Jun 1, 2026
f4e0807
fix(frontend): keep cursor inside token when typing into auto-closed …
ardaerzin Jun 1, 2026
a127516
Merge branch 'main' into feat/add-mustache-rendering
ardaerzin Jun 1, 2026
8dd4da1
Merge branch 'feat/add-mustache-rendering' into fe-feat/mustache-support
ardaerzin Jun 1, 2026
396ecd5
docs(qa): document tracing investigation findings on #1
ardaerzin Jun 1, 2026
9cb2242
docs(qa): mark #1 (tracing) resolved — branch fully synced, traces wo…
ardaerzin Jun 1, 2026
f59b702
fix(frontend): surface shape conflict when prompt deepens past user-t…
ardaerzin Jun 1, 2026
fa88012
feat(frontend): warn users about one-way curly/fstring migration
ardaerzin Jun 1, 2026
08b0efd
fix(frontend): move curly-migration warning banner below the action bar
ardaerzin Jun 1, 2026
1cb0b1b
fix(frontend): drop removed nested sub-keys from form, mirror top-lev…
ardaerzin Jun 1, 2026
e6e7e7a
fix(frontend): rework shape-conflict banner layout — button no longer…
ardaerzin Jun 1, 2026
da8b302
fix(frontend): shape-conflict banner — visible code chip + real butto…
ardaerzin Jun 1, 2026
200385e
fix(frontend): recurse schema-strict merge so renamed nested keys dis…
ardaerzin Jun 1, 2026
445de19
feat(frontend): nested stash footer mirrors top-level unused-columns …
ardaerzin Jun 1, 2026
f7d73ea
bump py deps
jp-agenta Jun 2, 2026
5d5bdf3
Merge branch 'release/v0.100.9' into feat/add-mustache-rendering
junaway Jun 2, 2026
af01f19
Merge branch 'feat/add-mustache-rendering' into fe-feat/mustache-support
Copilot Jun 2, 2026
93f12d9
Merge branch 'release/v0.100.9' into fe-feat/mustache-support
junaway Jun 2, 2026
c6b7c09
docs: mustache section support RFC
ardaerzin Jun 2, 2026
8a7326b
feat(frontend): track mustache section depth in variable walker
ardaerzin Jun 2, 2026
ac1461f
feat(frontend): tokenize structural mustache tags + suppress close-ta…
ardaerzin Jun 2, 2026
6fce343
fix(frontend): route playground inputs body colors through dark-mode …
ardaerzin Jun 2, 2026
9f9e608
fix(frontend): clamp inputs-body flex chain so compare columns stop o…
ardaerzin Jun 2, 2026
0a60e33
fix(frontend): defensive re-write on refine apply to defeat editor re…
ardaerzin Jun 2, 2026
7011ff4
fix(frontend): drop chat-message editor debounce to fix Refine Prompt…
ardaerzin Jun 2, 2026
611fe92
feat(frontend): mustache AST parser + scope-aware variable discovery
ardaerzin Jun 2, 2026
4921982
fix(frontend): route FormView leaf-card colors through theme tokens
ardaerzin Jun 2, 2026
00c50a5
fix(frontend): theme-aware ViewTypeSelect trigger + match config-mess…
ardaerzin Jun 2, 2026
e5eac49
fix(frontend): unify view-mode dropdown + theme caret color across ed…
ardaerzin Jun 2, 2026
8c9b8ef
fix(frontend): editor focus border matches hover so focused inputs ar…
ardaerzin Jun 2, 2026
5b3d0f6
fix(frontend): rename "String" view-mode label to "Text" at the source
ardaerzin Jun 2, 2026
f900349
fix(frontend): apply focus-border fix to SharedEditorImpl (the file a…
ardaerzin Jun 2, 2026
5e03dfc
fix(frontend): unify input placeholder to "Enter a value"
ardaerzin Jun 2, 2026
5f239c1
fix(frontend): mark unauthored values (empty / null / {} / []) as draft
ardaerzin Jun 2, 2026
97127e8
feat(frontend): infer array-of-objects schema for section-opener ports
ardaerzin Jun 2, 2026
749dfe2
feat(frontend): form-array editor with +Add row for array-of-objects …
ardaerzin Jun 2, 2026
79d2381
docs: update mustache RFC with ship status + nested-opener limitation
ardaerzin Jun 2, 2026
a75873c
feat(frontend): infer array-of-objects schema for nested mustache sec…
ardaerzin Jun 2, 2026
5a475b4
docs: mark nested section-opener inference as shipped in RFC
ardaerzin Jun 2, 2026
4719221
fix(frontend): walker skips empty section names + cover typing-state …
ardaerzin Jun 2, 2026
2e825a7
fix(frontend): FormView threads schema per-level so nested arrays use…
ardaerzin Jun 2, 2026
823bea5
fix(frontend): ObjectRows iterates schema keys so newly-added prompt …
ardaerzin Jun 2, 2026
8f08e4f
fix(frontend): array-row remove button rides label row so nested fiel…
ardaerzin Jun 2, 2026
36dd634
chore(frontend): local-dev mock for the refine-prompt tool
ardaerzin Jun 2, 2026
ac69b91
chore(frontend): auto-fall-back refine mock when AI service is unavai…
ardaerzin Jun 2, 2026
7b90f4f
fix(frontend): suppress global error overlay so refine mock fallback …
ardaerzin Jun 2, 2026
8500849
Merge branch 'release/v0.101.0' into fe-feat/mustache-support
bekossy Jun 3, 2026
1e8591e
fix(frontend): save top-level input_keys for mustache prompts (not do…
ardaerzin Jun 3, 2026
d55a654
fix(frontend): new LLM judges default to mustache + persist the format
ardaerzin Jun 3, 2026
e4cb39d
Merge branch 'fe-feat/mustache-support' of https://github.com/Agenta-…
ardaerzin Jun 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
509 changes: 509 additions & 0 deletions QA_INVENTORY.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ async def my_random_evaluator(capital: str):
description="Use an LLM to judge if the previous answer is correct",
#
correct_answer_key="capital",
model="openai/gpt-4o-mini",
model="gpt-5.4-mini",
prompt_template=[
{
"role": "system",
Expand Down
21 changes: 16 additions & 5 deletions api/oss/src/resources/evaluators/evaluators.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@
},
"strict": True,
},
"version": "4",
"version": "5",
"template_format": "mustache",
},
},
{
Expand Down Expand Up @@ -114,7 +115,8 @@
},
"strict": True,
},
"version": "4",
"version": "5",
"template_format": "mustache",
},
},
{
Expand Down Expand Up @@ -158,7 +160,8 @@
},
"strict": True,
},
"version": "4",
"version": "5",
"template_format": "mustache",
},
},
{
Expand Down Expand Up @@ -203,7 +206,8 @@
},
"strict": True,
},
"version": "4",
"version": "5",
"template_format": "mustache",
},
},
],
Expand Down Expand Up @@ -284,10 +288,17 @@
"x-ag-ui-advanced": False,
"description": "Select a response format to structure how your evaluation results are returned.",
},
"template_format": {
"label": "Template Format",
"type": "hidden",
"default": "mustache",
"description": "The template format used to render the prompt", # ignored by the FE
"x-ag-ui-advanced": False,
},
"version": {
"label": "Version",
"type": "hidden",
"default": "4",
"default": "5",
"description": "The version of the evaluator", # ignore by the FE
"x-ag-ui-advanced": False,
},
Expand Down
2 changes: 1 addition & 1 deletion api/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ dependencies = [
"httpx>=0.28,<0.29",
"structlog>=25,<26",
"python-dotenv>=1,<2",
"python-multipart>=0.0.29,<0.0.30",
"python-multipart>=0.0.30,<0.0.31",
"cryptography>=48,<49",
"sqlalchemy>=2,<3",
"sqlalchemy-utils>=0.42,<0.43",
Expand Down
433 changes: 233 additions & 200 deletions api/uv.lock

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions clients/python/uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 17 additions & 22 deletions docs/design/prompt-runtime-unification/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,7 @@ The current system makes those answers difficult because runtime behavior and fr
All three services should share the same building blocks but currently don't:

- **Provider/model resolution.** Chat and completion use workflow provider settings; the judge manually extracts a fixed provider-key set and therefore cannot reliably use custom or self-hosted models configured in the UI.
- **Rendering.** Each service has different rendering behavior:
- `PromptTemplate.format` raises on Jinja errors; `_format_with_template` returns the original content with a warning.
- Chat and completion recursively render `llm_config.response_format`. The judge builds `response_format` from `response_type` / `json_schema` and does not render variables inside `json_schema`.
- **Rendering.** The services now share more renderer infrastructure than before, but they still differ in configuration shape and runtime entrypoint. Chat and completion render from `parameters.prompt`, while the judge still uses its flat evaluator config and separate handler path.
- **Config.** The judge does not allow configuring `temperature`. It currently sends a hard-coded `temperature=0.01`, which some models reject as an unsupported optional parameter.
- **Output.** Completion, chat, and judge return different output shapes. Shared runtime code should stop before handler-specific output normalization.

Expand Down Expand Up @@ -97,7 +95,7 @@ Example.
{"profile": {"name": "Ada"}}
```

`profile` is a JSON object. The runtime can access `{{profile.name}}`, `{{profile.tags.0}}`, or `{{profile}}` (renders as compact JSON text).
`profile` is a JSON object. The runtime can access `{{profile.name}}`, `{{$.profile.tags[0]}}`, or `{{profile}}` (renders as compact JSON text).

```json
{"profile": "{\"name\":\"Ada\"}"}
Expand All @@ -123,7 +121,7 @@ Example.

Three substitution formats plus one full templating engine:

- **`mustache`** — `{{variable}}` substitution. **The default for new apps.** `{{a.b}}` always means nested access (`a` then property `b`). Supports JSONPath (`{{$.profile.name}}`) and JSON Pointer (`{{/profile/name}}`). JSON objects and arrays render as compact JSON text when inserted as whole values into a string template. We use the name "mustache" for recognizability; we do not implement the full mustache spec (no sections or partials) — just variable substitution with our path enhancements.
- **`mustache`** — Mustache rendering for new apps. **The default for new apps.** Tags that start with `{{$` are resolved as JSONPath expressions against the render context and substituted into the rendered output last, as inert data (never re-parsed) — they are shielded from the Mustache engine, not fed back through it. Ordinary Mustache behavior handles plain tags such as `{{name}}`, dotted names such as `{{profile.name}}`, and standard Mustache sections. Partials are not supported in Agenta runtime and must fail clearly if present. JSON objects and arrays render as compact JSON text when inserted as whole values into a string template.

- **`curly`** — `{{variable}}` substitution. **Deprecated.** Same syntax as `mustache`, but the resolver applies literal-key-first lookup: if a top-level key is literally named `foo.bar`, `{{foo.bar}}` returns that key's value before nested traversal is attempted. This is what keeps old apps that have variables with literal dots in their names working. Not surfaced in the playground for new apps; existing apps keep their declared format.

Expand Down Expand Up @@ -269,13 +267,9 @@ Builds on WP-B1.

Builds on WP-B1.

- Add `mustache` as a new template-format option in the runtime. Semantics: `{{variable}}` substitution; `{{a.b}}` is nested access only (no literal-key-first); JSONPath and JSON Pointer supported.
- `mustache` becomes the runtime default for new apps. Existing apps continue to use the format they declared.
- **Brace escaping.** `mustache` ships with an explicit escape mechanism so users can include literal `{{` / `}}` in prompts (e.g., few-shot examples that show LLM output formatting). `curly` and `fstring` keep their current escape semantics:
- `fstring` already escapes via `{{` → `{` and `}}` → `}` (Python `str.format` rule).
- `jinja2` already supports `{% raw %}…{% endraw %}` blocks.
- `curly` has no escape today. Adding one to `curly` is non-trivial because the existing `\{\{\s*(.*?)\s*\}\}` regex captures the inner braces of `{{{{x}}}}` as part of the variable name. We document the gap in the rendering appendix and recommend `jinja2` for prompts that need literal braces; the cleanest place to land a real fix is `mustache`, which is greenfield. Whether to also retrofit an escape into `curly` is an open question for WP-B3 (decision factor: how many existing apps need literal `{{` in their prompts).
- See [appendix-rendering-edge-cases.md](appendix-rendering-edge-cases.md) for the current escape behavior of every mode and the expected behavior for `mustache`.
- Add `mustache` as a new template-format option in the runtime. Semantics: tags that start with `{{$` are resolved as JSONPath expressions and substituted as inert data after rendering (never re-parsed); all other tags render through a Mustache engine. Partials are unsupported and fail clearly.
- `mustache` becomes the default rendering format for newly created apps / prompt configs. Existing apps continue to use the format they declared.
- See [appendix-rendering-edge-cases.md](appendix-rendering-edge-cases.md) for the current escape behavior of every mode.

### Frontend

Expand All @@ -292,8 +286,8 @@ The same UX pattern lives in playground inputs, the testset editor, observabilit
Depends on WP-B3 (`mustache` available) and WP-F1 (type switching available).

- Send testcase data as native JSON when the stored type is JSON. No `JSON.stringify` in request construction.
- In `mustache` mode, `{{a.b}}` is treated as a single variable `a` (object) with `.b` as a property accessor. The playground's variable discovery creates one variable `a` of type object that the user fills with JSON.
- `curly` mode is hidden from new-app creation flows. Existing apps still on `curly` continue to work — the literal-key-first behavior is preserved for them.
- In `mustache` mode, `{{$.a.b}}` is the explicit JSONPath escape hatch. Plain Mustache tags such as `{{a}}` or `{{profile.name}}` follow ordinary Mustache rendering behavior. The playground's variable discovery for nested JSON is still a frontend concern.
- The frontend honors the WP-B3 `mustache` default and hides `curly` from the format list unless the current old app already has `curly` selected. Existing apps still on `curly` continue to work — the literal-key-first behavior is preserved for them.

#### WP-F3 — Variable discovery (autocomplete)

Expand All @@ -306,19 +300,18 @@ A nicety on top of WP-F2.

#### WP-D1 — Documentation and SDK examples

- Publish prompt templating docs covering `mustache` (default for new apps), `curly` (legacy compat), `fstring`, and `jinja2`. Spell out the dot-semantics distinction between `mustache` and `curly`.
- Publish prompt templating docs covering `mustache` (default for new apps), `curly` (legacy compat), `fstring`, and `jinja2`. Spell out the JSONPath shield-and-substitute rule for `mustache` and the literal-key-first distinction of `curly`.
- Publish the variable matrix by service and interface.
- Add SDK / local examples for completion, chat, and LLM-as-a-judge.
- Document escaping rules, JSON vs. stringified JSON, JSONPath, and JSON Pointer.
- Document escaping rules, JSON vs. stringified JSON, and JSONPath. Document JSON Pointer only for legacy `curly` semantics if it remains supported there.

Reference template examples:

```text
Hello {{name}}
Profile JSON: {{profile}}
Profile name: {{profile.name}}
First tag: {{profile.tags.0}}
JSON Pointer: {{/profile/name}}
First tag: {{$.profile.tags[0]}}
JSONPath: {{$.profile.name}}
```

Expand All @@ -344,16 +337,17 @@ The work packages have a natural order:
2. **WP-B2** stands up message and JSON-return rendering on the helper, and aligns Jinja error behavior.
3. **WP-B3** adds `mustache` as a new format.
4. **WP-F1** lands the same JSON/string switching pattern in playground / testset / observability / evaluation.
5. **WP-F2** flips playground execution to send native JSON and switches new apps to `mustache`. Curly stays for legacy apps only.
5. **WP-F2** flips playground execution to send native JSON and hides `curly` from new-app format selection. Curly stays visible for legacy apps that already use it.
6. **WP-F3** adds autocomplete on top.
7. **WP-D1** publishes the templating docs, variable matrix, and SDK examples.

## Test Plan

### Backend runtime

- The low-level rendering helper resolves top-level, nested, JSONPath, and JSON Pointer references in `mustache` and `curly` modes.
- `curly` preserves literal-key-first behavior on dotted keys; `mustache` does not (treats them as nested).
- The low-level rendering helper keeps current `curly` behavior and adds `mustache` support.
- In `mustache` mode, only tags that start with `{{$` are resolved through JSONPath (shielded from the engine and substituted last as inert data); other tags render through the Mustache engine.
- `curly` preserves literal-key-first behavior on dotted keys.
- Whole-object insertion renders as compact JSON text in both modes.
- `fstring` and `jinja2` behavior is preserved.
- Stringified JSON inputs are treated as strings (no auto-parse).
Expand Down Expand Up @@ -383,7 +377,7 @@ The work packages have a natural order:

### Documentation

- Examples cover string, JSON object, array, nested access, JSONPath, JSON Pointer, messages, and brace escaping in each format.
- Examples cover string, JSON object, array, JSONPath, Mustache dotted names, messages, and brace escaping in each format.
- Variable matrix covers completion, chat, judge, and the four interfaces (Direct API/SDK, evaluator playground, evaluation service offline, evaluation service online).

## Future Directions
Expand Down Expand Up @@ -428,6 +422,7 @@ Each work package gets its own subfolder with research, plan, implementation not

- [`wp-b1-runtime-foundation/`](wp-b1-runtime-foundation/README.md) — judge backend patch (provider/secret resolution + temperature removal) and the low-level rendering helper extraction.
- [`wp-b2-rendering-unification/`](wp-b2-rendering-unification/README.md) - shared message rendering, JSON-return rendering, judge `json_schema` rendering, and Jinja error alignment.
- [`wp-b3-mustache-rendering/`](wp-b3-mustache-rendering/README.md) - `mustache` runtime format, `{{$...}}` JSONPath shield-and-substitute resolution, `mystace` rendering, and clear partial failures.

Subfolders for the remaining work packages will be added as each is picked up.

Expand Down
Loading
Loading