feat(governance): delegation guard#125
Closed
aditik0303 wants to merge 3 commits into
Closed
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds an async-aware delegation depth guard for agents, ensuring delegation depth is enforced consistently across both sync (invoke) and async (ainvoke) call paths while avoiding per-agent ContextVar leaks.
Changes:
- Implement delegation guard that wraps both
invokeandainvoke, preserving coroutine-ness for async methods. - Track delegation depth via a single module-level
ContextVarkeyed byid(agent)and clean up entries on uninstall. - Add comprehensive tests covering sync/async behavior, lifecycle (install/uninstall), env overrides, and leak/regression scenarios.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| tests/test_delegation_guard.py | Adds test coverage for sync/async delegation depth enforcement, lifecycle semantics, env overrides, and ContextVar leak prevention. |
| src/uipath/runtime/governance/delegation_guard.py | Introduces the delegation guard implementation with async support, shared ContextVar tracking, and uninstall cleanup. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
a019ade to
6af3c9f
Compare
aeb0d94 to
0664ff6
Compare
6af3c9f to
f7cc79e
Compare
0664ff6 to
58c7baf
Compare
f7cc79e to
94cea5b
Compare
58c7baf to
20fe69c
Compare
94cea5b to
ce18588
Compare
20fe69c to
d1d42d6
Compare
ce18588 to
e186f5f
Compare
d1d42d6 to
61e9ff7
Compare
e186f5f to
5812bbf
Compare
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ethod is actually patched; correct _resolve_max_depth docstring (install-time) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Closes architecture-review §2.3 — the delegation guard monkey-patched agent ``invoke``/``ainvoke`` methods in place via ``setattr``, naming no framework but mutating framework-owned objects through their private shapes. Fragile, depends on agent internals, and the runtime layer shouldn't be reaching into objects it didn't construct. Correct seam is the framework callback handler, which already receives ``parent_run_id`` on every callback and can derive delegation depth from the run tree without touching the agent. That work lives on the LangChain side (uipath-langchain-python PR #899, which is done) — so the runtime-side module is dead weight. Deletions - src/uipath/runtime/governance/delegation_guard.py (265 LOC) — ``install_delegation_guard`` / ``uninstall_delegation_guard``, the per-agent ContextVar depth tracking, the setattr-based wrap. - tests/test_delegation_guard.py (320 LOC) — the entire test suite for the deleted module. Verification - Monorepo grep for ``delegation_guard``, ``install_delegation_guard``, ``uninstall_delegation_guard``, ``ASI-02``, ``Excessive Agency``, and ``UIPATH_GOVERNANCE_MAX_DELEGATION_DEPTH``: zero hits outside the deleted files. The module was self-contained. - ruff clean, mypy clean (11 source files), 357 passed + 1 skipped (pre-existing wrapper skip). Net diff: −585 LOC. After this PR's rebase onto #124, the branch contains only deletions on top of the evaluator slice. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
61e9ff7 to
95cbcb2
Compare
viswa-uipath
added a commit
that referenced
this pull request
Jun 25, 2026
…Runtime Closes architecture-review §2.1 + §2.2 — the UiPathWrappedRuntimeFactory bolted governance onto the generic runtime-factory registry (apply_wrappers=True turned every registered factory into a different type, breaking isinstance checks), and the second GovernanceRuntime in governance/wrapper.py reached into delegate._agent_definition / framework-specific private attrs through a 10-level walk to install framework-blind callbacks. Both patterns the doc unambiguously says to delete. Composition belongs in the host's decorator chain, FF-gated, where UiPathResumableRuntime already wraps the framework runtime; this PR's wrapper machinery was an end-run around that. Deletions - src/uipath/runtime/governance/wrapper.py (1002 LOC) — the second GovernanceRuntime with _AGENT_ATTRS / _replace_agent_in_delegate / model-context-var introspection. - src/uipath/runtime/wrapper.py (55 LOC) — the lazy-import dispatch shim that called the deleted governance_wrapper. - tests/test_dispose_isolation.py, tests/test_wrapper.py, tests/test_wrapper_internals.py (~650 LOC combined) — entire test suites for the deleted modules. Updates - src/uipath/runtime/registry.py — UiPathWrappedRuntimeFactory class and the apply_wrappers kwarg removed from get(). The registry returns the registered factory unchanged; cross-cutting concerns (governance, audit, …) are composed by the host into the decorator chain, not auto-applied here. - src/uipath/runtime/__init__.py — drop GOVERNANCE_FEATURE_FLAG / apply_governance_wrapper exports. - tests/test_registry.py — strip every apply_wrappers=False kwarg (the kwarg is gone) and drop the wrapping-behaviour section + its fixtures. Conflict resolution The rebase onto #125's tip replayed the upstream e186f5f commit (a cosmetic helper-import touch) into three test files that my PR #122/#123/#124 refactors had already rewritten end-to-end. HEAD-side resolution kept the refactored form in test_evaluator.py, test_evaluator_operators.py, test_guardrail_compensation.py — the incoming side referenced symbols (governance.audit, governance.config, tests._helpers.reset_enforcement_mode) that the post-rebase stack no longer ships. Verification - Monorepo grep for UiPathWrappedRuntimeFactory, apply_wrappers, apply_governance_wrapper, governance_wrapper, and the deleted module import paths: zero hits. - ruff clean, mypy clean (45 source files), 357 passed + 1 skipped. Net diff on top of #125's tip: −2005 / +38 LOC = −1967 net. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked PR 6/7 — part of splitting
feat/governance-coreinto reviewable slices. Base:feat/governance-evaluator. One logical slice (branch is cumulative so CI is green). Merge in order #1 → #7 and delete each branch on merge so the next PR auto-retargets ontofeat/agentic-governance.feat/governance-corekept untouched as backup.