Skip to content

feat(governance): GovernanceRuntime wrapper + runtime registry wiring#126

Open
aditik0303 wants to merge 3 commits into
feat/governance-delegation-guardfrom
feat/governance-wrapper-wiring
Open

feat(governance): GovernanceRuntime wrapper + runtime registry wiring#126
aditik0303 wants to merge 3 commits into
feat/governance-delegation-guardfrom
feat/governance-wrapper-wiring

Conversation

@aditik0303

Copy link
Copy Markdown

Stacked PR 7/7 — part of splitting feat/governance-core into reviewable slices. Base: feat/governance-delegation-guard. 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 onto feat/agentic-governance. feat/governance-core kept untouched as backup.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a governance integration layer at the runtime boundary by wiring a feature-flag–gated wrapper into the runtime factory registry, so newly created runtimes can be transparently wrapped with GovernanceRuntime when governance is enabled.

Changes:

  • Add apply_governance_wrapper (lazy-import, FF-gated) and re-export it from uipath.runtime.
  • Wrap UiPathRuntimeFactoryRegistry.get() results by default via UiPathWrappedRuntimeFactory, with an apply_wrappers=False escape hatch.
  • Add a new governance runtime wrapper implementation (uipath.runtime.governance.wrapper) plus extensive tests and docs for wrapper behavior.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
tests/test_wrapper.py Adds boundary tests for apply_governance_wrapper (FF gate, lazy import, fail-open behavior).
tests/test_wrapper_internals.py Adds unit tests for GovernanceRuntime helper internals and module entry points (governance_wrapper, wrap_agent).
tests/test_registry.py Updates registry tests for new apply_wrappers behavior and adds wrapper-specific coverage.
tests/test_dispose_isolation.py Adds isolation tests ensuring GovernanceRuntime.dispose() runs all cleanup steps and only propagates delegate disposal errors.
src/uipath/runtime/wrapper.py Introduces the FF-gated, lazy-import runtime wrapper entry point (apply_governance_wrapper).
src/uipath/runtime/registry.py Adds UiPathWrappedRuntimeFactory and apply_wrappers plumbing to auto-apply governance on runtime creation.
src/uipath/runtime/governance/wrapper.py Adds the GovernanceRuntime implementation (adapter wrapping, evaluator lifecycle, input/output extraction, dispose behavior).
src/uipath/runtime/init.py Re-exports governance wrapper API (GOVERNANCE_FEATURE_FLAG, apply_governance_wrapper).
docs/runtime-wrapper-extension.md Documents the governance integration point, flag semantics, and recommended testing approach.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +339 to +353
# Bind the model-name ContextVar so adapters running in this
# runtime's context see the right value under concurrent
# agents. The token is stashed so dispose() can reset the
# var — without that, the value leaks into sibling tasks
# that inherit this context and outlive the runtime.
model_name = self._extract_model_name(delegate, context)
self._model_name = model_name
self._model_name_token = _current_model_name.set(model_name)

# Record agent-type before the policy prefetch fires so the
# fetch can ask the server for the matching container key
# (conversational vs autonomous).
set_agent_conversational(
self._extract_is_conversational(delegate, context)
)
# full chat history (e.g. ``{"messages": [...]}``). Pass
# ``latest_only=True`` so governance evaluates the most
# recent user message and not the entire transcript.
agent_input = _extract_governable_text(input, latest_only=True)
Comment on lines +405 to +420
# Try nested delegate chain (unwrap wrappers)
if not model_name:
inner = getattr(delegate, "_delegate", None) or getattr(
delegate, "delegate", None
)
while inner and not model_name:
agent_def = getattr(inner, "_agent_definition", None)
if agent_def:
settings = getattr(agent_def, "settings", None)
if settings:
model_name = getattr(settings, "model", None) or ""
break
inner = getattr(inner, "_delegate", None) or getattr(
inner, "delegate", None
)

Comment on lines +216 to +222
# Last-resort: walk public attributes on opaque objects (e.g. a
# framework-specific result class without model_dump/dict).
public = {
name: getattr(value, name)
for name in dir(value)
if not name.startswith("_") and not callable(getattr(value, name, None))
}
Comment thread docs/runtime-wrapper-extension.md Outdated
Comment on lines +327 to +336
if not is_governance_enabled():
self._init_failed = True
self._evaluator_ready = True # don't try to materialise later
logger.info(
"GovernanceRuntime initialized as no-op: governance feature "
"flag is OFF (agent='%s', runtime_id='%s')",
self._agent_name,
runtime_id,
)
return
@aditik0303 aditik0303 force-pushed the feat/governance-delegation-guard branch from aeb0d94 to 0664ff6 Compare June 16, 2026 11:03
@aditik0303 aditik0303 force-pushed the feat/governance-wrapper-wiring branch from f1a607b to ff14f22 Compare June 16, 2026 11:03
@aditik0303 aditik0303 force-pushed the feat/governance-delegation-guard branch from 0664ff6 to 58c7baf Compare June 17, 2026 06:54
@aditik0303 aditik0303 force-pushed the feat/governance-wrapper-wiring branch from ff14f22 to 2fb2248 Compare June 17, 2026 06:57
@aditik0303 aditik0303 force-pushed the feat/governance-delegation-guard branch from 58c7baf to 20fe69c Compare June 17, 2026 08:35
@aditik0303 aditik0303 force-pushed the feat/governance-wrapper-wiring branch from 2fb2248 to 1a9ce83 Compare June 17, 2026 08:36
@aditik0303 aditik0303 force-pushed the feat/governance-delegation-guard branch from 20fe69c to d1d42d6 Compare June 19, 2026 08:08
@aditik0303 aditik0303 force-pushed the feat/governance-wrapper-wiring branch from 1a9ce83 to da816b2 Compare June 19, 2026 08:08
aditik0303 and others added 3 commits June 19, 2026 16:55
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… FF gate (no-op when OFF, single dispose token); latest_only only for conversational agents; depth-cap model-name delegate walk; guard getattr in text extractor; doc is_governance_enabled name

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ts._helpers

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@aditik0303 aditik0303 force-pushed the feat/governance-delegation-guard branch from d1d42d6 to 61e9ff7 Compare June 19, 2026 11:25
@aditik0303 aditik0303 force-pushed the feat/governance-wrapper-wiring branch from da816b2 to 10b949f Compare June 19, 2026 11:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants