Skip to content

feat: nested paths in {{input.a.b}} / {{config.a.b}} placeholders - #76

Merged
Bbenchaya merged 2 commits into
intuit:mainfrom
maximilianfeix:feature/61-nested-placeholder-paths
Oct 29, 2026
Merged

Bbenchaya merged 2 commits into
intuit:mainfrom
maximilianfeix:feature/61-nested-placeholder-paths

Conversation

@maximilianfeix

Copy link
Copy Markdown
Contributor

Checklist

🚨 Please review this repository's contribution guidelines.

  • I've read and agree to the project's contribution guidelines.
  • I'm requesting to pull a topic/feature/bugfix branch.
  • I checked that my code additions will pass code linting checks and unit tests.
  • I updated unit and integration tests (if applicable).
  • I'm ready to notify the team of this contribution.

Description

{{input.a.b.c}} and {{config.a.b.c}} now read nested values. Integer segments index lists ({{input.items.0.sku}}), so both optional parts of the issue are in.

  • The single-segment lookup runs first and is unchanged, so a top-level key works exactly like before (that includes a key that happens to contain a dot).
  • A missing segment anywhere in the path is handled like a missing field today: | default(...) if given, otherwise the <customer.id> marker plus the debug log.
  • A nested None resolves to None, same as fix: resolve placeholders whose value is None #72.
  • The input and config branches were the same code twice, so they now share _resolve_ref.

Tests: TestValueResolverNestedPaths (8 tests, 7 fail on main). Docs tables in matchers-and-resolvers.md and mock-format.md updated, plus a changelog entry under Added.

Fixes #61

@Bbenchaya Bbenchaya left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nice, this covers everything in #61 including both optional parts, and folding the input/config branches into _resolve_ref is a good cleanup. Verified locally against d671944: 7 of the 8 new tests fail on main, 510 pass with the patch, ruff check/ruff format --check/mypy src/ clean. Also applies cleanly on the current main tip (bf2f877, after #75 and #73). Probed a few extra cases (dotted top-level key precedence, tuple indexing, out-of-range index, path into a scalar, default('x.y') with a dot in the literal, config_data precedence) and they all behave as documented.

One small fix before I approve:

_lookup_path: segment.isdigit() → segment.isdecimal(). isdigit() accepts characters int() rejects, e.g. '²'.isdigit() is True but int('²') raises, so {{input.items.².sku}} raises ValueError out of the resolver, which otherwise never raises on bad input. isdecimal() is the exact predicate for what int() accepts (Arabic-Indic ١ still works, superscripts don't). Contrived input, but it's the only throwing path in the resolver and it's a one-word change.

Non-blocking:

  • This commit is authored as 44erxyz <moonxyz@outlook.de> rather than the noreply address on your previous PRs. Just a heads-up in case that email isn't verified on your GitHub account, so the commit gets attributed to you.
  • README.md, docs/guides/langgraph-integration.md and docs/architecture/overview.md also have placeholder tables with {{input.field}}. #61 only named the two files you updated, so this is fine as is; a row in those would be a nice touch if you're in there anyway.

Separately, while probing I hit a pre-existing bug that is not this PR's: PLACEHOLDER_PATTERN with fullmatch treats "{{input.a}}-{{input.b}}" as a single expression (the lazy .+? is defeated by fullmatch), so it comes back as the literal string. With any leading text it works. I'll file that as its own issue.

🤖 Review assisted by AI (Cursor)

@maximilianfeix

maximilianfeix commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor Author

Thanks for the thorough review. Pushed bf11c40:

  • _lookup_path now uses segment.isdecimal(), with a regression test for {{input.items.².sku}} (falls back to the marker / the default instead of raising).
  • Added the nested-path row to the placeholder tables in README.md, docs/guides/langgraph-integration.md and docs/architecture/overview.md.
  • The new commit uses my noreply address; the first one was authored with a local git identity, which a squash merge will fold away.

511 tests pass, ruff check, ruff format --check and mypy src/ are clean.

str.isdigit() accepts characters such as '²' that int() raises on, so
{{input.items.².sku}} raised ValueError out of the resolver. isdecimal()
is the predicate that matches what int() accepts.

Also adds the nested-path row to the remaining placeholder tables.
@maximilianfeix
maximilianfeix force-pushed the feature/61-nested-placeholder-paths branch from be66928 to bf11c40 Compare October 10, 2026 17:22

This branch was successfully deployed

1 active deployment
pypi — bf11c405 Deployed Oct 29, 2026 by Bbenchaya via Tag & Publish #51
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.

feat: ValueResolver — support nested paths in {{input.a.b}} / {{config.a.b}}

2 participants