Add LangChain/LangGraph agent SDK and langgraph protocol - #115
Draft
dmaniloff wants to merge 7 commits into
Draft
Conversation
Introduce a LangChain 1.x agent SDK alongside the existing MCP SDK, and wire the orchestrator to drive agents served by the native LangGraph Agent Server. - sdk.py: extract shared ControlPlaneClient + ToolContext (previously in mcp_sdk.py) so both SDKs build on one control-plane seam - langchain_sdk.py: MidojoToolkit wraps tools as LangChain tools that record calls and read/write env via the control plane - mcp_sdk.py: re-export ControlPlaneClient/ToolContext from sdk - agent_client.py: LangGraphAgentClient talks to a LangGraph Agent Server (langgraph_sdk) over HTTP - orchestrator.py: add `langgraph` protocol and --graph-name - suites/weather/langchain_agent: create_agent-based weather agent served by `langgraph dev` (graph.py + langgraph.json) - suites/weather/deploy: kustomize manifests (control plane + agent Deployment/Service + run Job) for OpenShift/ROSA - Containerfile: install the `langchain` extra - tests: cover the langchain SDK; adjust mcp_sdk tests for the refactor Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Diego Maniloff <diego.maniloff@gmail.com>
In-cluster OpenShift builds pulling `python:3.12-slim` hit Docker Hub's anonymous pull-rate limit (shared build-node egress IP). Switch to registry.access.redhat.com/ubi9/python-312, which the build pulls from Red Hat's registry (no Docker Hub limit) and is the appropriate base for an OpenShift/ROSA deployment. Run build steps as USER 0, drop back to 1001; the existing chgrp/chmod keeps the tree arbitrary-UID friendly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Diego Maniloff <diego.maniloff@gmail.com>
Plain `pip install ".[suites,langchain]"` ignores uv.lock and backtracks for many minutes resolving the a2a-sdk -> google-api-core transitive tree (observed 370+ version probes and still going). Install uv and use `uv pip install`, whose resolver handles this in seconds. uv targets UBI's active virtualenv ($VIRTUAL_ENV=/opt/app-root), so console scripts stay on PATH. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Diego Maniloff <diego.maniloff@gmail.com>
The in-cluster binary Docker-strategy build pushes to the OpenShift internal registry; reference that ImageStream so pods in the midojo-weather namespace pull it via the default service account (no external registry / pull secret needed). Verified end-to-end on ROSA: control plane + LangGraph agent + orchestrator Job run the full weather 4x4 matrix. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Diego Maniloff <diego.maniloff@gmail.com>
ControlPlaneClient.record_function_call swallowed all httpx errors (try/except HTTPError: pass) and never checked the response status. A failing POST — e.g. a stale/unset /current eval — would silently drop the call from the log while the tool's env mutations still persisted, producing evals with real side effects but zero recorded function calls. Let the POST error propagate and add raise_for_status(), matching get_environment/put_environment. Recording failures now surface instead of corrupting the function-call log. The forward-raises LangChain test used a dead control-plane URL and relied on the swallow; point it at the live test app so the asserted RuntimeError is no longer masked by the recording POST. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Diego Maniloff <diego.maniloff@gmail.com>
Four tests hand-built the same live-control-plane toolkit (MidojoToolkit.__new__ + _client/_real_tools/_tools). Collapse that into a `toolkit` fixture. No behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Diego Maniloff <diego.maniloff@gmail.com>
MidojoToolkit.__init__ hard-built its own ControlPlaneClient from a URL, so tests had to bypass __init__ (MidojoToolkit.__new__ + private attrs) to inject an ASGI-backed client. Accept an optional `client` instead; `control_plane_url` stays as the convenience path. Tests now construct the toolkit normally via the fixture, dropping the __new__ hack. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Diego Maniloff <diego.maniloff@gmail.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.
Summary
Adds a LangChain 1.x agent SDK to midojo alongside the existing MCP SDK, and wires the orchestrator to drive agents served by the native LangGraph Agent Server (
langgraph dev/langgraph up) over HTTP. Includes a working weather agent and OpenShift/ROSA deploy manifests.Authoring uses
create_agent(LangChain's "highly customizable harness"); midojo's customization is the man-in-the-middle tool layer (MidojoToolkit) plus the suite's system prompt and model. Becausecreate_agentcompiles to a LangGraph graph, it's served with the framework-native Agent Server — no hand-rolled FastAPI.What's included
src/midojo/sdk.py— extracts the sharedControlPlaneClient+ToolContext(previously inmcp_sdk.py) so both SDKs build on one control-plane seam.src/midojo/langchain_sdk.py—MidojoToolkitwraps tools as LangChain tools that record function calls and read/write env via the control plane.src/midojo/mcp_sdk.py— re-exportsControlPlaneClient/ToolContextfromsdk(back-compat).agent_client.py—LangGraphAgentClienttalks to a LangGraph Agent Server vialanggraph_sdk.orchestrator.py— newlanggraphprotocol +--graph-name.suites/weather/langchain_agent/—create_agent-based weather agent (graph.py+langgraph.json) plus a one-shot CLI runner.suites/weather/deploy/— kustomize manifests: control-plane + agent Deployment/Service + run Job (arbitrary-UID / restricted-SCC friendly).Containerfile— installs thelangchainextra.Testing
uv run pytest— 170 passed (addstests/test_langchain_sdk.py; adjuststest_mcp_sdk.pyfor the refactor).qwen3thinking model): control plane +langgraph dev+midojo-run --protocol langgraphover the full weather 4×4 matrix — man-in-the-middle injection and grading both work.Not included (intentionally)
Cluster deploy of the image + the actual ROSA run are the next step (needs a published image + a registry the cluster can pull from). The LLM creds Secret (
weather-llm-creds) is created out-of-band — seeagent-secret.example.yaml.🤖 Generated with Claude Code