fix: LangGraph Executor HITL and E2E Tests#1518
Conversation
There was a problem hiding this comment.
Pull request overview
Updates the LangGraph BYO executor’s HITL interrupt/resume wiring and adds an E2E test + sample updates to validate invoking a LangGraph-based agent using a mocked OpenAI endpoint.
Changes:
- Switch LangGraph currency sample from
langchain-google-genai/Gemini tolangchain-openai/OpenAI and update related config/secrets. - Rework
kagent-langgraphexecutor interrupt handling to emitadk_request_confirmation-shapedDataParts and forward richer resume payloads. - Add a new Go E2E test and mock responses for invoking the LangGraph currency agent; update Makefile to build/push the sample image.
Reviewed changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| python/uv.lock | Lockfile update reflecting dependency switch to langchain-openai and related resolution changes. |
| python/samples/langgraph/currency/pyproject.toml | Replace langchain-google-genai dependency with langchain-openai. |
| python/samples/langgraph/currency/currency/agent.py | Swap model provider to ChatOpenAI and update model name. |
| python/samples/langgraph/currency/agent.yaml | Update env var and secret refs from Google to OpenAI. |
| python/packages/kagent-langgraph/src/kagent/langgraph/_executor.py | Implement LangGraph-specific HITL interrupt event emission and richer resume payload forwarding. |
| go/core/test/e2e/mocks/invoke_langgraph_agent.json | Add mock OpenAI chat-completions for the currency sample flow. |
| go/core/test/e2e/invoke_api_test.go | Add E2E test that deploys and invokes the LangGraph currency agent (sync + streaming). |
| Makefile | Build/push the langgraph-currency sample image in push-test-agent. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
|
|
||
| # Create resume input | ||
| resume_input = Command(resume={"decisions": [{"type": decision_type}]}) | ||
| resume_input = Command(resume=resume_value) |
python/packages/kagent-langgraph/src/kagent/langgraph/_executor.py
Outdated
Show resolved
Hide resolved
Signed-off-by: Jet Chiang <pokyuen.jetchiang-ext@solo.io>
e30f3e2 to
3ccb54e
Compare
| tool_call_id = tool_call["id"] | ||
|
|
||
| if tool_name in TOOLS_REQUIRING_APPROVAL: | ||
| # Pause execution and ask the user for approval. |
There was a problem hiding this comment.
Note to users: interrupt allows the user to set arbitrary data in the graph state, this can literally be anything you want, as long as it matches the response in Command (this is unlike the HITL mechanism in ADK which only has specific fields). However, in order for our executor to work with our HITL flow we require your interrupt function to be called with the specific structure below.
This is not a limitation, you are welcome to use any interrupt mechanisms, you will just need to modify the executor to handle that specific response and convert that to a protocol message in Kagent's HITL flow documented in docs/architecture/human-in-the-loop.md. The default Kagent HITL flow is not as versatile as langgraph because it's designed around ADK rather than langgraph.
In ADK, HITL will propagate through subagents, but since our langgraph SDK does not yet support "subgraphs", that feature will not be available here. You can implement this yourself using the same logic.
See https://docs.langchain.com/oss/python/langgraph/interrupts for how HITL works in langgraph.
Tested the new HITL flow with a langgraph BYO agent and it works. However, unlike ADK declarative where you can just specify tools requiring approval in CRD, the developer using
kagent-langgraphwill need to setup their graph in a specific way following the above documentation. Most existing graphs usinginterrupt()mechanism should be compatible, but a more comprehensive testing would help to fully verify it especially for complex graphs.I have provided an example in the
samplesfolder to show how to do that for starters.