feat(guardrails): add HITL escalation for decorator-style guardrails [AL-289]#894
Open
apetraru-uipath wants to merge 3 commits into
Conversation
…[AL-289] Publish the guardrail runtime context (scope / stage / component) around each action call in the LangChain adapter, mirroring the middleware path, so a decorator @guardrail(action=EscalateAction(...)) can derive Component / ExecutionStage at runtime instead of requiring them hardcoded. The action call sites already let GraphInterrupt propagate (they catch only GuardrailBlockException), so interrupt-based escalation suspends correctly with no exception-handling change. - _langchain_adapter.py: add _run_action() helper that publishes GuardrailActionContext for tool/llm/agent pre+post, reusing EscalateAction + _action_context from the middleware escalation (PR #888). - joke-agent-decorator: add an AGENT-scope EMAIL-PII EscalateAction example on create_joke_agent, env-configurable app name/folder, plus README scenarios. - tests: adapter context-publishing unit tests; decorator escalation integration test (suspend -> approve -> reject) alongside the middleware one. Verified live against Guardrail.Escalation.Action.App.2: suspend (Component=Agent, ExecutionStage=PreExecution), approve completes, reject terminates. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds HITL escalation parity for decorator-style guardrails by publishing guardrail runtime context (scope/stage/component) around action invocations in the LangChain/LangGraph @guardrail adapter, enabling EscalateAction to derive Component and ExecutionStage at runtime (matching the middleware behavior introduced in #888).
Changes:
- Add
_run_action()helper in the decorator adapter to publish/resetGuardrailActionContextviaContextVararound each action call and to convertGuardrailBlockExceptionintoAgentRuntimeErrorwhile lettingGraphInterruptbubble up. - Add unit and integration coverage validating context publishing, reset semantics, PASS behavior (no action), and interrupt propagation/resume for decorator escalation.
- Update the
joke-agent-decoratorsample to demonstrate AGENT-scope EMAIL PII escalation and bump itsuipath-langchaindependency constraint to the current SDK range.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
src/uipath_langchain/guardrails/_langchain_adapter.py |
Publishes guardrail action context around decorator-path action calls via _run_action() for TOOL/LLM/AGENT scopes. |
tests/guardrails/test_adapter_context_publishing.py |
New unit tests asserting context publication/reset and GraphInterrupt propagation for decorator adapter call sites. |
tests/cli/test_guardrails_in_langgraph.py |
Adds decorator-path escalation E2E tests verifying interrupt → resume behavior and payload parity with middleware. |
samples/joke-agent-decorator/graph.py |
Demonstrates agent-scope EscalateAction configured via env vars for the escalation action app. |
samples/joke-agent-decorator/README.md |
Documents the new decorator-path escalation scenario and how to run/resume. |
samples/joke-agent-decorator/pyproject.toml |
Updates the sample’s uipath-langchain version constraint to >=0.11.13,<0.12.0. |
…-289] Add a TestDecoratorEscalation case that resumes with Approve and no ReviewedInputs: the run completes on the original input (the action returns None, so the adapter leaves the message untouched) and does not re-suspend despite the input still tripping the guardrail on replay. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add an 'Escalation action (human-in-the-loop)' subsection to the decorator pattern docs: same EscalateAction as middleware, on an agent/LLM/tool factory; Component/ExecutionStage derived automatically from the inferred scope; recipient example; with a note that node/plain-function targets (core @guardrail) still escalate but don't populate the context fields. Co-Authored-By: Claude Opus 4.8 (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.
What changed?
Brings the HITL escalation capability added for middleware guardrails in #888 to the decorator path (
@guardrail(action=EscalateAction(...)))._langchain_adapter.py— adds a_run_action()helper that publishes the guardrail runtime context (scope/stage/component) on aContextVararound each action call (tool/LLM/agent, PRE+POST), mirroring the middleware's_base.py. This letsEscalateActionderiveComponent/ExecutionStageat runtime instead of requiring them hardcoded.EscalateActionand_action_contextare reused unchanged from feat: add EscalateAction HITL middleware action for guardrails [AL-289] #888.GuardrailBlockException, so a LangGraphGraphInterruptraised by the escalation propagates naturally and the run suspends.samples/joke-agent-decorator— adds an AGENT-scope EMAIL-PIIEscalateActiononcreate_joke_agent(env-configurable app name/folder, same app as the middleware sample), plus README scenarios. Bumps the sample'suipath-langchainconstraint to>=0.11.13, <0.12.0to match the current SDK and the middleware sample.@guardrailescalation — those go through the core@guardrailinuipath-python, which doesn't publish context.How has this been tested?
tests/guardrails/test_adapter_context_publishing.py— asserts the adapter publishesGuardrailActionContext(scope/stage/component) for tool/LLM/agent, resets it afterward, skips the action on PASS, and re-raisesGraphInterrupt.TestDecoratorEscalationintests/cli/test_guardrails_in_langgraph.py— real adapter +EscalateAction+ LangGraphinterrupt/Commandresume withMemorySaver: suspend payload (Component=Agent,ExecutionStage=PreExecution, JSONToolInputs), approve substitutes the reviewed input, reject raisesAgentRuntimeError. Payload matches the middleware flavor.ruff check,ruff format --check,mypyall clean.Guardrail.Escalation.Action.App.2(alpha / APetraruTenant): suspend creates the Action Center task withComponent=Agent/ExecutionStage=PreExecution; approve resumes and completes; reject terminates withAgentRuntimeError: PII detected: Email.Are there any breaking changes?
None.