Skip to content

Commit e3f0e0e

Browse files
aditik0303claude
andcommitted
chore(governance): apply review feedback (no import-time registration, framework-only can_handle)
Mirror radu's LangChain-adapter review across the LlamaIndex adapter: - __init__: drop the import-time registration side-effect; registration only via the uipath.governance.adapters entry point. - can_handle: claim only a real workflows.Workflow; remove the duck-typed (run / Workflow-shaped name) fallback. - docstring: 'governance host' instead of uipath-runtime internals. - tests: can_handle uses a real stepped Workflow; a duck-typed look-alike is now rejected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent fabadc4 commit e3f0e0e

3 files changed

Lines changed: 29 additions & 35 deletions

File tree

packages/uipath-llamaindex/src/uipath_llamaindex/governance/__init__.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
11
"""Governance integration for ``uipath-llamaindex``.
22
3-
Registers :class:`LlamaIndexAdapter` with the global adapter registry in
4-
``uipath.core.adapters`` so ``uipath.runtime.governance.GovernanceRuntime`` can
5-
attach the LlamaIndex-specific governance (BEFORE_MODEL, AFTER_MODEL, TOOL_CALL)
6-
when it sees a LlamaIndex workflow/agent.
3+
Registers :class:`LlamaIndexAdapter` with the adapter registry in
4+
``uipath.core.adapters`` so the governance host can attach the
5+
LlamaIndex-specific governance (BEFORE_MODEL, AFTER_MODEL, TOOL_CALL) when it
6+
sees a LlamaIndex workflow/agent.
77
88
Registration is **idempotent**: calling :func:`register_governance_adapter`
99
twice is a no-op on the second call.
1010
11-
Wiring:
12-
1. Importing this module triggers registration as a side-effect, so any
13-
caller that does ``import uipath_llamaindex.governance`` is opted in.
14-
2. The package also exposes :func:`register_governance_adapter` as an entry
15-
point under ``uipath.governance.adapters`` so the registry's entry-point
16-
discovery can plug us in without an explicit import.
11+
Wiring: the package exposes :func:`register_governance_adapter` as an entry
12+
point under ``uipath.governance.adapters``. The governance adapter discovery
13+
path calls it to register the adapter. Importing this module does not, by
14+
itself, mutate the global registry.
1715
"""
1816

1917
from __future__ import annotations
@@ -46,9 +44,6 @@ def register_governance_adapter() -> None:
4644
logger.debug("Registered uipath-llamaindex governance adapter")
4745

4846

49-
# Side-effect registration on module import.
50-
register_governance_adapter()
51-
5247

5348
__all__ = [
5449
"GovernanceEventHandler",

packages/uipath-llamaindex/src/uipath_llamaindex/governance/adapter.py

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
where it is fed back to the model as input (analogous to how the OpenAI adapter
2323
handles its missing tool-args).
2424
25-
Chain-level boundaries (BEFORE_AGENT / AFTER_AGENT) are owned by the runtime
26-
wrapper layer in ``uipath-runtime`` and are intentionally not fired here.
25+
Chain-level boundaries (BEFORE_AGENT / AFTER_AGENT) are owned by the
26+
governance host and are intentionally not fired here.
2727
2828
Contracts and the evaluator protocol come from ``uipath-core``; this package
2929
contributes only the LlamaIndex-specific implementation and self-registers it
@@ -43,8 +43,8 @@
4343
from typing import Any, Dict, List
4444
from uuid import uuid4
4545

46-
from llama_index.core.instrumentation import (
47-
get_dispatcher, # type: ignore[attr-defined]
46+
from llama_index.core.instrumentation import ( # type: ignore[attr-defined]
47+
get_dispatcher,
4848
)
4949
from llama_index.core.instrumentation.event_handlers.base import ( # type: ignore[attr-defined]
5050
BaseEventHandler,
@@ -77,24 +77,12 @@ def name(self) -> str:
7777
return "LlamaIndex"
7878

7979
def can_handle(self, agent: Any) -> bool:
80-
"""Return True if this looks like a LlamaIndex workflow/agent."""
80+
"""Return True only for a LlamaIndex ``Workflow`` (incl. agent workflows)."""
8181
try:
8282
from workflows import Workflow
83-
84-
if isinstance(agent, Workflow):
85-
return True
8683
except ImportError:
87-
pass
88-
89-
# Duck-typed fallback: a workflow/agent exposes ``run`` and a workflow
90-
# step surface (``_get_steps`` / ``steps``) or a Workflow-shaped name.
91-
if hasattr(agent, "run") and (
92-
hasattr(agent, "_get_steps")
93-
or hasattr(agent, "steps")
94-
or type(agent).__name__.endswith(("Workflow", "Agent"))
95-
):
96-
return True
97-
return False
84+
return False
85+
return isinstance(agent, Workflow)
9886

9987
def attach(
10088
self,

packages/uipath-llamaindex/tests/governance/test_adapter.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,22 @@ def _handler(ev: FakeEvaluator) -> GovernanceEventHandler:
8787
# --------------------------------------------------------------------------
8888

8989

90-
def test_can_handle_workflow_like():
91-
assert LlamaIndexAdapter().can_handle(FakeWorkflow()) is True
90+
def test_can_handle_real_workflow():
91+
from workflows import Workflow, step
92+
from workflows.events import StartEvent, StopEvent
9293

94+
class _RealWorkflow(Workflow):
95+
@step
96+
async def go(self, ev: StartEvent) -> StopEvent:
97+
return StopEvent()
9398

94-
def test_can_handle_rejects_plain_object():
99+
assert LlamaIndexAdapter().can_handle(_RealWorkflow()) is True
100+
101+
102+
def test_can_handle_rejects_non_workflow():
103+
# A duck-typed look-alike (has run / Workflow-shaped name) must NOT be
104+
# claimed — only a real workflows.Workflow is.
105+
assert LlamaIndexAdapter().can_handle(FakeWorkflow()) is False
95106
assert LlamaIndexAdapter().can_handle(object()) is False
96107

97108

0 commit comments

Comments
 (0)