Skip to content

refactor(core): drop AdapterRegistry + BaseAdapter; keep EvaluatorProtocol#1761

Open
viswa-uipath wants to merge 8 commits into
mainfrom
feat/adapter-fix
Open

refactor(core): drop AdapterRegistry + BaseAdapter; keep EvaluatorProtocol#1761
viswa-uipath wants to merge 8 commits into
mainfrom
feat/adapter-fix

Conversation

@viswa-uipath

@viswa-uipath viswa-uipath commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Delete the AdapterRegistry / BaseAdapter / GovernedAgentBase plumbing from uipath-core, plus the uipath.governance.adapters entry-point group and get_adapter_registry / reset_adapter_registry helpers
  • Keep EvaluatorProtocol — the one contract framework plugins still consume
  • Bump uipath-core to 0.5.23 and refresh the three uv.lock files

Why

The adapter registry was a second plugin-discovery system keyed on the same fact (which framework is active) that UiPathRuntimeFactoryRegistry already resolves statically. It existed to support an open-PR pattern where the runtime layer would sniff the framework off an opaque agent — that approach is being abandoned in favor of framework plugins wiring governance at their own native seam (callback handlers / hook lists), so the registry becomes dead weight.

The only known external consumer is the unmerged uipath-langchain PR #899, which is being reshaped to consume EvaluatorProtocol directly through its factory. A grep across the monorepo (.py / .toml / .md / .rst / .json) for AdapterRegistry / BaseAdapter / GovernedAgentBase / get_adapter_registry / reset_adapter_registry returns zero hits outside the deleted files.

Changes

Action Path
Delete packages/uipath-core/src/uipath/core/adapters/base.py
Delete packages/uipath-core/src/uipath/core/adapters/registry.py
Delete packages/uipath-core/tests/adapters/test_base.py
Delete packages/uipath-core/tests/adapters/test_registry.py
Update packages/uipath-core/src/uipath/core/adapters/__init__.py — exports trimmed to EvaluatorProtocol
Update packages/uipath-core/pyproject.toml0.5.22 → 0.5.23
Update three uv.lock files for the workspace

Net diff: −962 LOC.

Test plan

  • uv run ruff check src/ tests/ — clean
  • uv run mypy src/ — clean (45 source files)
  • uv run pytest230 passed, 1 skipped in uipath-core
  • Monorepo grep confirms no remaining references to deleted symbols
  • CI on PR for uipath / uipath-platform packages
  • Coordinate with uipath-langchain PR chore: validate required files on push #899 reshape (see below)

Coordination

Downstream uipath-runtime-python and uipath-langchain-python are not yet merged, so no shipped consumer breaks. Merge order if this lands first:

  1. This PR (uipath-core deletion + version bump) — ready now
  2. uipath-runtime-python adds optional evaluator kwarg to the factory protocol — pending
  3. uipath-langchain-python PR chore: validate required files on push #899 reshaped to factory-driven GovernanceCallbackHandler wiring (and to subclass langchain_core.callbacks.BaseCallbackHandler properly) — pending

🤖 Generated with Claude Code

Development Packages

uipath

[project]
dependencies = [
  # Exact version (copy-paste ready):
  "uipath==2.11.13.dev1017616968",

  # Any version from this PR (uncomment to use a range instead):
  # "uipath>=2.11.13.dev1017610000,<2.11.13.dev1017620000",
]

[[tool.uv.index]]
name = "testpypi"
url = "https://test.pypi.org/simple/"
publish-url = "https://test.pypi.org/legacy/"
explicit = true

[tool.uv.sources]
uipath = { index = "testpypi" }
uipath-platform = { index = "testpypi" }
uipath-core = { index = "testpypi" }

[tool.uv]
override-dependencies = ["uipath-platform==0.1.78.dev1017616968", "uipath-core==0.5.23.dev1017616968"]

uipath-core

[project]
dependencies = [
  # Exact version (copy-paste ready):
  "uipath-core==0.5.23.dev1017616969",

  # Any version from this PR (uncomment to use a range instead):
  # "uipath-core>=0.5.23.dev1017610000,<0.5.23.dev1017620000",
]

[[tool.uv.index]]
name = "testpypi"
url = "https://test.pypi.org/simple/"
publish-url = "https://test.pypi.org/legacy/"
explicit = true

[tool.uv.sources]
uipath-core = { index = "testpypi" }

uipath-platform

[project]
dependencies = [
  # Exact version (copy-paste ready):
  "uipath-platform==0.1.78.dev1017616969",

  # Any version from this PR (uncomment to use a range instead):
  # "uipath-platform>=0.1.78.dev1017610000,<0.1.78.dev1017620000",
]

[[tool.uv.index]]
name = "testpypi"
url = "https://test.pypi.org/simple/"
publish-url = "https://test.pypi.org/legacy/"
explicit = true

[tool.uv.sources]
uipath-platform = { index = "testpypi" }
uipath-core = { index = "testpypi" }

[tool.uv]
override-dependencies = ["uipath-core==0.5.23.dev1017616969"]

…tocol

The adapter-registry plugin-discovery system in uipath-core was a
parallel keyed-by-agent-type dispatcher for a fact already known
statically: the runtime-factory registry has picked the framework by
the time anything needs an "adapter". The two registries existed only
to support an open-PR pattern (#125/#126) where the runtime layer
sniffed the framework off an opaque agent. With that approach
abandoned in favor of framework plugins wiring governance at their
native seam (callback handlers, hook lists), the registry, the
BaseAdapter abstraction, and their per-package entry-point group are
all dead weight.

Deletions
- src/uipath/core/adapters/base.py — BaseAdapter + GovernedAgentBase.
  No internal consumers; the only external one (uipath-langchain
  PR #899) is unmerged and is being reshaped to consume
  EvaluatorProtocol directly via its factory.
- src/uipath/core/adapters/registry.py — AdapterRegistry,
  get_adapter_registry, reset_adapter_registry, the
  `uipath.governance.adapters` entry-point group, and the
  side-effect discovery on first call.
- tests/adapters/test_base.py and tests/adapters/test_registry.py.

Kept
- src/uipath/core/adapters/evaluator.py — EvaluatorProtocol is the
  one contract framework plugins still consume. Plugin factories
  accept an evaluator at create_runtime() time and wire it into
  their own callback seam.
- tests/adapters/test_evaluator.py — protocol-conformance unchanged.

Net diff: ~960 LOC removed. uipath-core 0.5.22 → 0.5.23. uv.lock files
regenerated in uipath-core, uipath-platform, and uipath (workspace
editable-path deps, so they pick up 0.5.23 immediately).

Verified: ruff clean, mypy clean (45 source files), 230 passed +
1 skipped in uipath-core's test suite. Monorepo grep for
AdapterRegistry / BaseAdapter / GovernedAgentBase / get_adapter_registry
/ reset_adapter_registry returns zero hits outside the deleted files
across .py/.toml/.md/.rst/.json.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 25, 2026 03:09
@github-actions github-actions Bot added test:uipath-langchain Triggers tests in the uipath-langchain-python repository test:uipath-runtime test:uipath-integrations labels Jun 25, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 removes the adapter-registry plumbing from uipath-core (adapter base class, registry singleton, and related tests) while preserving EvaluatorProtocol as the remaining contract for framework governance integrations. It also bumps uipath-core’s version and refreshes workspace lockfiles to reflect the new core version and updated uv lock metadata.

Changes:

  • Deleted BaseAdapter / AdapterRegistry / singleton helpers (and their tests), leaving only EvaluatorProtocol under uipath.core.adapters.
  • Updated uipath.core.adapters public exports/documentation accordingly.
  • Bumped uipath-core to 0.5.23 and refreshed uv.lock files across packages.

Reviewed changes

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

Show a summary per file
File Description
packages/uipath/uv.lock Refresh lock metadata and update editable uipath-core version reference to 0.5.23.
packages/uipath-platform/uv.lock Refresh lock metadata and update editable uipath-core version reference to 0.5.23.
packages/uipath-core/uv.lock Update uipath-core package version entry to 0.5.23 in the lock.
packages/uipath-core/tests/adapters/test_registry.py Remove tests for deleted adapter registry behavior.
packages/uipath-core/tests/adapters/test_base.py Remove tests for deleted adapter base/proxy behavior.
packages/uipath-core/src/uipath/core/adapters/registry.py Delete adapter registry + entry-point discovery implementation.
packages/uipath-core/src/uipath/core/adapters/base.py Delete adapter base class and governed proxy base.
packages/uipath-core/src/uipath/core/adapters/init.py Trim exports to only EvaluatorProtocol and update docstring.
packages/uipath-core/pyproject.toml Bump package version from 0.5.22 to 0.5.23.

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

Comment thread packages/uipath-core/pyproject.toml
@viswa-uipath viswa-uipath added the build:dev Create a dev build from the pr label Jun 25, 2026
viswa-uipath and others added 6 commits June 25, 2026 11:14
Closes doc item 1.2 — every ``evaluate_*`` method on
``EvaluatorProtocol`` returned ``-> Any``, forcing callers to downcast
to the type they already knew the concrete evaluator was returning.
The concrete ``GovernanceEvaluator`` in uipath-runtime-python already
declares ``-> AuditRecord`` on each per-hook method, so narrowing the
protocol contract is structurally compatible — no behavior change, no
downstream code change required.

Narrows the six evaluate_* return types (before_agent / after_agent /
before_model / after_model / tool_call / after_tool) from Any to
AuditRecord, imports the type from uipath.core.governance.models, and
refreshes the class docstring (was claiming the protocol is
intentionally Any because the audit record "lives in the plugin
package" — but AuditRecord lives right here in uipath-core).

Verified
- ruff clean, mypy clean (45 source files), 230 passed + 1 skipped in
  uipath-core.
- uipath-runtime-python's test suite (357 passed + 1 skipped) keeps
  green when this version of uipath-core is installed — the protocol-
  conformance tests in test_evaluator.py still pass because the
  concrete GovernanceEvaluator was already returning AuditRecord from
  every evaluate_* method.

Rides on the same 0.5.23 version bump as the previous commit — both
changes ship together as one public-surface change on uipath-core.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Unblocks architecture-review §2.4 on the uipath-runtime side. The
prescription there is to hoist the policy fetch from the runtime-layer
``PolicyLoader`` (which today spins a daemon thread inside an async
runtime and blocks on ``threading.Event.wait(timeout=10s)``) up to the
async host: the CLI calls ``await provider.get_policy_async(ctx)``
itself, builds the ``PolicyIndex``, and passes the resolved index +
mode into ``GovernanceRuntime``. The runtime collapses to a pure,
synchronous-to-construct decorator — no thread, no Event, no
``is_conversational`` in the ctor.

For that to type-check on the runtime side, the structural
``GovernancePolicyProvider`` Protocol in uipath-core needs to declare
``get_policy_async``. The concrete platform provider
(``UiPathPlatformGovernanceProvider``) already implements it; the
contract was just lying about what providers expose.

Changes
- ``GovernancePolicyProvider`` now declares both ``get_policy`` and
  ``async get_policy_async``. Both required (the platform impl ships
  both today, and the doc's recommended caller path is the async
  variant — sync stays for non-event-loop callers like integration
  tests and CLI tools).
- ``_FakePolicyProvider`` in the conformance tests grew the async
  method and a separate ``async_calls`` recorder.
- New ``test_policy_round_trip_async`` exercises the async path via
  ``@pytest.mark.asyncio`` and pins that the two entry points are
  independent (calling one doesn't touch the other's recorder).

Verified
- uipath-core: ruff clean, mypy clean (45 source files), 32
  governance tests passed.
- uipath-platform: protocol-conformance tests still pass
  (9 passed) — ``UiPathPlatformGovernanceProvider`` already exposed
  ``get_policy_async``, so the now-stricter protocol still accepts it
  structurally.

No version bump — rides on the unreleased 0.5.23 that already carries
PR #1761's §1.1 (adapter-registry deletion) and §1.2 (typed
EvaluatorProtocol returns).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…it empty

Lets the runtime layer (uipath-runtime-python) stop carrying ``trace_id``
through ``UiPathGovernedRuntime`` / ``GuardrailCompensator``. The runtime
emits compensation requests with ``trace_id=""`` and the platform fills
in the canonical agent trace id at HTTP-call time via the existing
``resolve_trace_id()`` helper — same fallback ``track_event`` (PR #1745)
already uses.

uipath-core
- ``GovernRequest.trace_id`` relaxes from required ``str`` to ``str = ""``
  default. Docstring documents the platform-side self-resolve contract
  so wire callers know an empty value is legitimate.

uipath-platform
- ``GovernanceService._compensate`` / ``_compensate_async`` now call a
  new ``_resolve_request_trace_id()`` helper before the POST. When
  ``request.trace_id`` is empty the helper resolves via
  ``resolve_trace_id()`` (env → LLMOps external span → OTel current
  span). Caller-supplied values win — the runtime captures live OTel
  context across its background-pool hop via
  ``contextvars.copy_context()``, so when the worker calls
  ``provider.compensate(...)`` the platform-side resolver sees the
  agent's live span and returns the same canonical id.

Caller-supplied non-empty trace ids continue to pass through unchanged.

Tests
- uipath-core governance suite: 32 passed.
- uipath-platform governance service suite: 27 passed.
- ruff + mypy clean on ``src/uipath/core/governance`` and
  ``src/uipath/platform/governance``.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Valentina Bojan <valentina.bojan@uipath.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Ruff format collapses the three-line def to a single line; CI lint
runs ruff with --check and failed on the prior commit. No behavior
change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
66.7% Coverage on New Code (required ≥ 90%)

See analysis details on SonarQube Cloud

2.11.13 is already taken by another PR/publish; bumping to keep the
release on this branch publishable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

🚨 Heads up: uipath-langchain cross-tests are FAILING 🚨

Your changes may break the uipath-langchain-python integration.

⚠️ These checks are NOT enforced by branch protection rules. Please review the failures before merging.

🔍 Inspect the failed run →

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build:dev Create a dev build from the pr test:uipath-integrations test:uipath-langchain Triggers tests in the uipath-langchain-python repository test:uipath-runtime

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants