Repository navigation
fix(llm): support [key] lookup on nested dicts in template placeholders - #8142
ANDROIDHASSAN wants to merge 3 commits into
Conversation
safe_render turns nested dicts into SimpleNamespace for dotted access, which has no __getitem__, so {user[name]} rendered empty although the key exists. Use a namespace subclass that keeps item access.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
The _Namespace subclass changed {user} from namespace(...) to _Namespace(...). Keep the type name; add a guard case.
RaphaelFakhri
left a comment
There was a problem hiding this comment.
I checked out 83d5ed9 and ran the change against main with a set of edge-case templates outside the new test. Results match plain str.format on the dict in every case I tried:
{user[a.b]}(key with a dot) rendersdot,{user[name][0]}rendersA, and{user[name]:>6}and{user[name]!r}keep the spec and conversion. All of these render empty onmain.{items[0][name]}on a list of dicts and{nested_list[xs][0][q]}resolve, since lists stay unconverted.{user[missing]},{user[account][missing]},{user[__dict__]}and{user[__class__]}render empty and log through the existing handler. Item lookup reads only__dict__, so it adds no attribute access beyond what dotted lookup already allows.{user[0]}with a string key"0"renders empty, same asstr.format, which turns a digit-only index into anint.{user},{user!r}and nested values rendernamespace(...)on Python 3.10, 3.11, 3.12, 3.13 and 3.14, so the__name__override holds across the supported range.
tests/test_chat_ctx.py passes (93 passed, 1 skipped), and the new test fails 4 of 6 cases with utils/misc.py reverted.
One optional follow-up: the safe_render docstring still describes only dotted access. Since keys such as support-tier are now reachable only through [key], you could mention that form there too.
…m-access # Conflicts: # tests/test_chat_ctx.py
Problem:
safe_render(used byInstructions.renderandInstructions.resolve_template) converts nested dicts toSimpleNamespaceso templates can use dotted access like{user.name}. That conversion drops item access:SimpleNamespacehas no__getitem__, so the standardstr.formatlookup{user[name]}raisesTypeError. The error is caught, logged as a missing placeholder, and the field renders empty, even though the key is present indata:This also breaks keys that are not valid identifiers, which only
[key]can reach, such as{user[support-tier]}.Fix: convert nested dicts to a small
SimpleNamespacesubclass that also implements__getitem__from its__dict__. Dotted access is unchanged and[key]works again, as with a plainstr.formaton the dict. The subclass keeps thenamespacetype name, so a whole-dict placeholder such as{user.account}still rendersnamespace(plan='pro'). A missing key still raisesKeyError, so it still renders empty and logs through the existing handler in_Fmt.get_field.Tests
Six
nested-dict-*cases added to the parametrizedtest_renderintests/test_instructions.py(moved there fromtest_chat_ctx.pyafter #8510 folded the instructions tests into that module).{user[name]},{user[account][plan]},{user.account[plan]}and{user[support-tier]}each fail onmainwith an empty render.{user.name}and{user.account}pass onmainand stay as guards for dotted access and for the renderednamespace(...)repr.ruff format,ruff checkandmake type-checkare clean.Scope: only
safe_renderinutils/misc.pyand its test cases. Missing-placeholder handling,Nonerendering and the logged list of available paths are unchanged. Lists insidedataare not converted, so{items[0][name]}behaves as before.