Skip to content
Open
17 changes: 15 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ readme = { file = "README.md", content-type = "text/markdown" }
requires-python = ">=3.11"
dependencies = [
"uipath>=2.10.79, <2.11.0",
"uipath-core>=0.5.17, <0.6.0",
"uipath-core>=0.5.18, <0.6.0",
"uipath-platform>=0.1.61, <0.2.0",
"uipath-runtime>=0.11.0, <0.12.0",
"uipath-runtime>=0.11.0.dev1001180449,<0.11.0.dev1001190000",
"langgraph>=1.1.8, <2.0.0",
"langchain-core>=1.2.11, <2.0.0",
Comment on lines 8 to 13
"langgraph-checkpoint-sqlite>=3.0.3, <4.0.0",
Expand Down Expand Up @@ -63,6 +63,9 @@ register = "uipath_langchain.middlewares:register_middleware"
[project.entry-points."uipath.runtime.factories"]
langgraph = "uipath_langchain.runtime:register_runtime_factory"

[project.entry-points."uipath.governance.adapters"]
langchain = "uipath_langchain.governance:register_governance_adapter"

[project.urls]
Homepage = "https://uipath.com"
Repository = "https://github.com/UiPath/uipath-langchain-python"
Expand Down Expand Up @@ -154,6 +157,16 @@ exclude_lines = [

[tool.uv]
exclude-newer = "2 days"
# uipath-runtime is pinned to a dev pre-release served from testpypi.
# uipath==2.10.79 transitively pins uipath-runtime>=0.11.0,<0.12.0,
# which excludes pre-releases (PEP 440: 0.11.0.dev* sorts below 0.11.0),
# so we need both the prerelease allowance and an explicit override to
# bypass the umbrella's stable-only constraint.
prerelease = "allow"
override-dependencies = ["uipath-runtime>=0.11.0.dev1001180449,<0.11.0.dev1001190000"]

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

Comment on lines +168 to +170
[tool.uv.exclude-newer-package]
uipath = false
Expand Down
65 changes: 65 additions & 0 deletions src/uipath_langchain/governance/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"""Governance integration for ``uipath-langchain``.

Registers :class:`LangChainAdapter` with the global adapter registry in
``uipath.core.adapters`` so ``uipath.runtime.governance.GovernanceRuntime``
can attach the LangChain-specific inner hooks (BEFORE_MODEL,
AFTER_MODEL, TOOL_CALL, AFTER_TOOL) when it sees a LangChain or
LangGraph agent.

Registration is **idempotent**: calling :func:`register_governance_adapter`
twice is a no-op on the second call.

Wiring:
1. Importing this module triggers registration as a side-effect, so
any caller that does ``import uipath_langchain.governance`` is
opted in.
2. The package also exposes :func:`register_governance_adapter` as an
entry point under ``uipath.governance.adapters`` so an upstream
discoverer (or ``uipath-core`` if/when it grows entry-point
discovery) can plug us in without an explicit import.
"""

from __future__ import annotations

import logging

from uipath.core.adapters import get_adapter_registry

from .adapter import (
GovernanceCallbackHandler,
GovernedLangChainAgent,
LangChainAdapter,
)

logger = logging.getLogger(__name__)

_registered: bool = False


def register_governance_adapter() -> None:
"""Register :class:`LangChainAdapter` with the global registry.

Idempotent — safe to call multiple times.
"""
global _registered
if _registered:
return
registry = get_adapter_registry()
if any(a.name == "LangChain" for a in registry.get_all()):
_registered = True
return
registry.register(LangChainAdapter())
_registered = True
logger.debug("Registered uipath-langchain governance adapter")


# Side-effect registration on module import.
register_governance_adapter()


__all__ = [
"GovernanceCallbackHandler",
"GovernedLangChainAgent",
"LangChainAdapter",
"register_governance_adapter",
]
Loading
Loading