Python: [BREAKING] bound PowerFx state construction - #8511
Jose Alvarez (jpalvarezl) wants to merge 5 commits into
Conversation
Validate structural budgets before declarative state copies and PowerFx symbol conversion. Preserve copy isolation and temporary bindings, reject budget failures explicitly, and add focused boundary regressions. Fixed limits and the new Core hook require compatibility and dependency-floor review before release. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Validate structural budgets before declarative state copies and PowerFx symbol conversion. Preserve copy isolation and temporary bindings, reject budget failures explicitly, and add focused boundary regressions. Fixed limits and the new Core hook require compatibility and dependency-floor review before release. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
Declarative’s dependency range still permits Core releases without the newly required State._validate hook.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds bounded traversal and conversion for PowerFx state to prevent excessive or cyclic state construction.
Changes:
- Adds shared depth, node, and text-size budgets.
- Validates Core state before copying and propagates budget errors.
- Documents limits and adds boundary/regression tests.
File summaries
| File | Description |
|---|---|
python/packages/core/agent_framework/_workflows/_state.py |
Adds pre-copy state validation hook. |
python/packages/core/tests/workflow/test_state.py |
Tests validation visibility and failure behavior. |
python/packages/declarative/agent_framework_declarative/_workflows/_powerfx_limits.py |
Implements structural budgets and cycle detection. |
python/packages/declarative/agent_framework_declarative/_workflows/_declarative_base.py |
Applies budgets to state, configuration, and symbols. |
python/packages/declarative/agent_framework_declarative/_workflows/_state.py |
Applies limits to legacy PowerFx evaluation. |
python/packages/declarative/tests/test_powerfx_safe.py |
Adds budget and state-integrity regressions. |
python/packages/declarative/README.md |
Documents PowerFx state limits. |
Review details
- Files reviewed: 7/7 changed files
- Comments generated: 1
- Review effort level: Balanced
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
Code Coverage OverviewLanguages: Python Python / code-coverage/pythonThe overall line coverage in commit 7768d9f in the Show a line coverage summary of the most covered files.
Updated |
Preserve the original implementation commit and adopt the published review baseline without changing the published source tree. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Reviewer attention: proposed state-construction limitsPlease review the numerical defaults and their compatibility impact explicitly. The reasons for having separate depth, cardinality, and payload-size bounds are stronger than the evidence for these exact numbers: they are provisional engineering choices, not production-workload-derived thresholds, latency/memory guarantees, or limits copied from the .NET implementation.
Counting and failure semantics matter: shared values count at each occurrence, including the .NET's configurable expression-length and formula-call-depth limits address different dimensions; they do not justify these state-size numbers. Likewise, these checks do not impose a hard expression deadline or sandbox application-defined Python copy/conversion hooks. The boundary regressions verify that the implementation enforces its chosen contract and preserves ordinary behavior; they do not establish that these exact defaults suit every supported workload. Please flag legitimate state shapes that require different defaults, especially conversation histories and structured tool results, so we can adjust the proposed policy before this is accepted. |
There was a problem hiding this comment.
MAF Automated Review — Iteration 1
Result: No findings
Scope: full PR (1 commit(s)): 3182665daf58
Model: gpt-5.6-sol-fast
Overview
This PR adds per-traversal depth, node, and text budgets around declarative state copying and PowerFx symbol conversion. Pre-copy validation, incremental converted-output accounting, cycle detection, explicit budget-error propagation, and temporary-binding cleanup are backed by focused boundary and state-isolation tests. No non-duplicative Critical, High, or Medium finding remains after source and test verification.
Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
No publishable findings remained after source verification for this scope.
Remove the detailed package README section and document per-traversal counting next to the budget implementation. Preserve the limits, runtime behavior, and method error documentation. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Preserve both the workflow traversal error import and the state-construction budget imports. Retain upstream traversal and expression-output changes alongside the existing state bounds. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Motivation & Context
Declarative expression evaluation copies workflow state and constructs PowerFx
symbols, including data not referenced by the expression. Bound that
construction work and report explicit errors instead of silently truncating
values.
This PR includes both the Core pre-copy validation hook and its Declarative
consumer, with regression coverage for both packages.
Description & Review Guide
What are the major changes? Add a shared structural budget for raw state
and converted symbols. Validate stored state before defensive copying through
an internal Core
State._validatehook, retaining pending-first visibilityand copy isolation. Count converted output incrementally, reject cycles,
avoid eager whole-value debug formatting, and propagate budget errors through
legacy evaluation rather than taking its fallback path. Preserve MessageText
source/data separation and temporary-binding cleanup. Add small boundary and
real-State regressions. Document counting semantics beside the implementation,
without adding a package README section.
What is the impact of these changes? The proposed fixed limits are depth
64 (root depth zero), 10,000 visited values including mapping keys and
containers, and 1,048,576 aggregate string characters or binary bytes per
traversal. Repeated references and compatibility aliases count at each
occurrence. These are proposed compatibility choices for maintainer review,
not limits inherited from the .NET implementation. Previously accepted larger
or cyclic state raises
ValueError, including during declarative snapshot/writepaths. Normal within-budget types, namespaces, and temporary-state cleanup are
preserved. This patch does not introduce retained-engine caching, select only
referenced namespaces, impose a hard expression deadline, sandbox application-defined
Python copy/conversion hooks, or establish a global workflow/YAML loading budget.
What do you want reviewers to focus on? Review the proposed limits and
pre-copy validation boundary. The Core implementation and tests are already
included in this same PR; no separate Core implementation PR is required.
Release preparation requirement: the updated Declarative package must
require a Core release that contains
State._validate. The currentagent-framework-core>=1.19.0,<2metadata admits published Core 1.19.0,which lacks that hook. During the next coordinated release, include both
changes, assign the package versions, raise Declarative's minimum Core
version accordingly while preserving
<2, update the lockfile, and validatethe packaged dependency combination. Publish the compatible Core package
before publishing the updated Declarative package. Do not ship the new
Declarative code with the unchanged minimum dependency.
This version-floor update is handled during coordinated release preparation,
rather than guessing a future version or requiring that it already be on
PyPI before this source change can merge. Documenting that release obligation
does not mean the metadata has already been updated or that mixed-package
installations have been validated.
Related Issue
No public issue is linked.
Contribution Checklist
breaking changelabel (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.The original patch's selected state, PowerFx, executor, and factory suites
passed (585 tests, no skips) using an editable Core/Declarative pair.
Source/test Pyright and changed-file Ruff checks also passed on that original
baseline. The earlier package-wide Poe hook had a documented exception for
unrelated formatting; that historical result is not an all-hooks pass.
After merging upstream main in
7768d9f2c039ed361c2d40b642ca06efafc16231,the combined state, traversal, expression-output, and function-tool selection
passed on Python 3.11: 701 tests, no failures or skips. Merged-source Pyright
and all applicable conflict-file and merge-commit hooks passed without skip
overrides. The full repository test suite and released-package compatibility
checks have not been run locally.