Skip to content

LangGraph plugin samples#289

Open
DABH wants to merge 15 commits intotemporalio:mainfrom
DABH:langgraph-samples
Open

LangGraph plugin samples#289
DABH wants to merge 15 commits intotemporalio:mainfrom
DABH:langgraph-samples

Conversation

@DABH
Copy link
Copy Markdown

@DABH DABH commented Apr 14, 2026

Summary

Add samples demonstrating the Temporal LangGraph plugin, which runs LangGraph workflows as durable Temporal workflows. Each graph node or @task executes as a Temporal activity with automatic retries, timeouts, and crash recovery.

Samples are provided for both the Graph API (declarative StateGraph with nodes and edges) and the Functional API (imperative @task / @entrypoint decorators).

Sample Graph API Functional API Description
Hello World Minimal sample — single node/task that processes a query string. Start here.
Human-in-the-loop Chatbot that uses interrupt() to pause for human approval, Temporal signals to receive feedback, and queries to expose the pending draft.
Continue-as-new Multi-stage data pipeline that uses continue-as-new with task result caching so previously-completed stages are not re-executed.
ReAct Agent Tool-calling agent loop. Graph API uses add_conditional_edges; Functional API uses a while loop.
Control Flow Parallel task execution, for loops, and if/else branching — patterns that are natural in the Functional API.
LangSmith Tracing Combines LangGraphPlugin with Temporal's LangSmithPlugin for durable execution + full LLM observability. Requires API keys.

Key Features Demonstrated

  • Durable execution — Every graph node / @task runs as a Temporal activity with configurable timeouts and retry policies.
  • Human-in-the-loop — LangGraph's interrupt() pauses the graph; Temporal signals deliver human input; queries expose pending state to UIs.
  • Continue-as-new with cachingget_cache() captures completed task results; passing the cache to the next execution avoids re-running them.
  • Conditional routing — Graph API's add_conditional_edges and Functional API's native if/else/while for agent loops.
  • Parallel execution — Functional API launches multiple tasks concurrently by creating futures before awaiting them.
  • LangSmith observabilityLangSmithPlugin on the client + LangGraphPlugin on the worker for full trace propagation through Temporal workflows.

Related PRs

Test plan

  • Samples are not runnable until the SDK PR lands; verify after merge of AI-36: Add LangGraph plugin sdk-python#1448
  • Run each sample with uv run langgraph_plugin/<api>/<sample>/run_worker.py + run_workflow.py
  • LangSmith tracing samples require ANTHROPIC_API_KEY and LANGCHAIN_API_KEY

Seven samples demonstrating the Temporal LangGraph plugin across both the
Graph API and Functional API:

- Human-in-the-loop: interrupt() + Temporal signals for chatbot approval
- Continue-as-new: task result caching across workflow boundaries
- ReAct agent: tool-calling loop with conditional edges / while loop
- Control flow (Functional API only): parallel, for-loop, if/else

Related SDK PR: temporalio/sdk-python#1448
@DABH DABH requested a review from a team as a code owner April 14, 2026 23:09
@CLAassistant
Copy link
Copy Markdown

CLAassistant commented Apr 14, 2026

CLA assistant check
All committers have signed the CLA.

@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

This comment was marked as outdated.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new langgraph_plugin/ sample suite to demonstrate running LangGraph workflows as durable Temporal workflows via the Temporal LangGraph plugin, covering both LangGraph Graph API and Functional API patterns.

Changes:

  • Introduces 7 new LangGraph+Temporal sample workflows (human-in-the-loop, continue-as-new w/ caching, ReAct agent, control-flow).
  • Adds a new langgraph dependency group and includes langgraph_plugin in the build packages list.
  • Updates repository documentation to link to the new sample suite and provides a dedicated README for running the samples.

Reviewed changes

Copilot reviewed 24 out of 34 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
pyproject.toml Adds langgraph dependency group, includes langgraph_plugin in wheel packages, adjusts lint/test tasks, and adds mypy override.
README.md Links the new langgraph_plugin samples from the repo root README.
langgraph_plugin/README.md Adds usage documentation and a sample matrix for the new suite.
langgraph_plugin/init.py Declares the new top-level sample package.
langgraph_plugin/graph_api/init.py Declares Graph API samples namespace.
langgraph_plugin/graph_api/react_agent/init.py Declares Graph API ReAct agent package.
langgraph_plugin/graph_api/react_agent/workflow.py Implements Graph API ReAct agent workflow and graph definition.
langgraph_plugin/graph_api/react_agent/run_worker.py Worker wiring for Graph API ReAct agent sample.
langgraph_plugin/graph_api/react_agent/run_workflow.py Starter script for Graph API ReAct agent sample.
langgraph_plugin/graph_api/human_in_the_loop/init.py Declares Graph API human-in-the-loop package.
langgraph_plugin/graph_api/human_in_the_loop/workflow.py Implements Graph API interrupt + Temporal signal/query human approval flow.
langgraph_plugin/graph_api/human_in_the_loop/run_worker.py Worker wiring for Graph API human-in-the-loop sample.
langgraph_plugin/graph_api/human_in_the_loop/run_workflow.py Starter script for Graph API human-in-the-loop sample.
langgraph_plugin/graph_api/continue_as_new/init.py Declares Graph API continue-as-new package.
langgraph_plugin/graph_api/continue_as_new/workflow.py Implements Graph API pipeline w/ continue-as-new + cache handoff.
langgraph_plugin/graph_api/continue_as_new/run_worker.py Worker wiring for Graph API continue-as-new sample.
langgraph_plugin/graph_api/continue_as_new/run_workflow.py Starter script for Graph API continue-as-new sample.
langgraph_plugin/functional_api/init.py Declares Functional API samples namespace.
langgraph_plugin/functional_api/react_agent/init.py Declares Functional API ReAct agent package.
langgraph_plugin/functional_api/react_agent/workflow.py Implements Functional API ReAct agent via @task + @entrypoint.
langgraph_plugin/functional_api/react_agent/run_worker.py Worker wiring for Functional API ReAct agent sample.
langgraph_plugin/functional_api/react_agent/run_workflow.py Starter script for Functional API ReAct agent sample.
langgraph_plugin/functional_api/human_in_the_loop/init.py Declares Functional API human-in-the-loop package.
langgraph_plugin/functional_api/human_in_the_loop/workflow.py Implements Functional API interrupt + signal/query human approval flow.
langgraph_plugin/functional_api/human_in_the_loop/run_worker.py Worker wiring for Functional API human-in-the-loop sample.
langgraph_plugin/functional_api/human_in_the_loop/run_workflow.py Starter script for Functional API human-in-the-loop sample.
langgraph_plugin/functional_api/control_flow/init.py Declares Functional API control-flow package.
langgraph_plugin/functional_api/control_flow/workflow.py Implements Functional API sample demonstrating parallelism + branching.
langgraph_plugin/functional_api/control_flow/run_worker.py Worker wiring for Functional API control-flow sample.
langgraph_plugin/functional_api/control_flow/run_workflow.py Starter script for Functional API control-flow sample.
langgraph_plugin/functional_api/continue_as_new/init.py Declares Functional API continue-as-new package.
langgraph_plugin/functional_api/continue_as_new/workflow.py Implements Functional API pipeline w/ continue-as-new + cache handoff.
langgraph_plugin/functional_api/continue_as_new/run_worker.py Worker wiring for Functional API continue-as-new sample.
langgraph_plugin/functional_api/continue_as_new/run_workflow.py Starter script for Functional API continue-as-new sample.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread langgraph_plugin/graph_api/human_in_the_loop/workflow.py Outdated
Comment thread langgraph_plugin/graph_api/human_in_the_loop/workflow.py Outdated
Comment thread langgraph_plugin/functional_api/human_in_the_loop/workflow.py
Comment thread langgraph_plugin/graph_api/continue_as_new/workflow.py Outdated
Comment thread langgraph_plugin/functional_api/continue_as_new/workflow.py
Comment thread langgraph_plugin/README.md
@DABH DABH mentioned this pull request Apr 15, 2026
Combines LangGraphPlugin (durable execution) with LangSmithPlugin
(observability) for full tracing of LLM calls through Temporal workflows.
Comment thread langgraph_plugin/functional_api/langsmith_tracing/README.md Outdated
Comment thread langgraph_plugin/functional_api/langsmith_tracing/README.md Outdated
Comment thread langgraph_plugin/functional_api/langsmith_tracing/README.md Outdated
Comment thread langgraph_plugin/functional_api/langsmith_tracing/workflow.py Outdated
Comment thread langgraph_plugin/functional_api/langsmith_tracing/workflow.py
Comment thread langgraph_plugin/functional_api/langsmith_tracing/workflow.py Outdated
Comment thread langgraph_plugin/graph_api/langsmith_tracing/README.md Outdated
Comment thread langgraph_plugin/functional_api/continue_as_new/README.md Outdated
Comment thread langgraph_plugin/functional_api/continue_as_new/README.md Outdated
DABH added 3 commits April 18, 2026 17:24
- graphs parameter is now a list, not a dict
- No graph()/entrypoint() lookup functions — reference objects directly
- No entrypoints parameter on LangGraphPlugin
- Use set_cache()/get_cache() for continue-as-new caching
- Update tests and READMEs accordingly
# Conflicts:
#	pyproject.toml
#	uv.lock
The plugin API has evolved past PR #1448:
- LangGraphPlugin(graphs=...) now takes dict[str, StateGraph], not list
- Same for entrypoints (dict[str, Pregel])
- Each node/task must declare execute_in: "activity" | "workflow" in metadata
- Workflows look up registered graphs/entrypoints via graph(name) /
  entrypoint(name) instead of importing them directly
- get_cache/set_cache replaced by cache() and graph(name, cache=...) /
  entrypoint(name, cache=...)

Other changes:
- State schemas converted from primitives (str, int) to TypedDict, since
  langgraph's StateT is bound to TypedDict / dataclass / pydantic models
- Module-level graph instances replaced with make_<name>_graph() factories
  because LangGraphPlugin mutates node metadata in-place at construction
  time, which prevented reuse across tests
- langgraph dep group now pulls langchain, langchain-anthropic, and
  temporalio[langgraph,langsmith] so the langsmith_tracing samples and
  human_in_the_loop's RunnableConfig usage actually resolve
@DABH DABH force-pushed the langgraph-samples branch from 3ebfbd2 to 9c06edd Compare April 29, 2026 04:05
DABH added 3 commits April 28, 2026 23:15
These features rely on contextvars propagation through asyncio.create_task(),
which is only available in Python 3.11+. On 3.10 they hang rather than fail
cleanly, so CI sat for an hour before today's fix landed.

Mirrors the pytestmark skipif used in sdk-python's own contrib/langgraph
tests.
- Drop cross-references between Functional API and Graph API READMEs so
  each stands alone (review comment 1)
- Combine run_worker.py + run_workflow.py into a single main.py for the
  langsmith_tracing samples to reduce setup steps (review comment 2)
- Fix workflow -> Workflow casing (review comment 3)
- Alias temporalio's entrypoint and graph helpers as temporal_entrypoint /
  temporal_graph at import sites to avoid the langgraph.func.entrypoint
  collision (review comment 4)
- Demonstrate @Traceable in three places in both langsmith_tracing samples:
  on the Activity/task itself, on a helper called from the Activity, and
  on a helper called from the Workflow (review comment 5)
- Drop unnecessary single-task list comprehension for activity_options in
  hello_world and langsmith_tracing functional samples (review comment 6)
- Spell out 'temporal server start-dev' in every sample README's
  prerequisites (review comment 7)
- Fix stale README references to get_cache() now that the API is cache()
  (review comment 8)
- Rename arbitrarily-named ETL pipeline functions in continue_as_new to
  honest math names (double / add_50 / triple) per review comment 9
@DABH DABH requested a review from brianstrauch April 29, 2026 06:30
Comment thread .github/workflows/ci.yml
Comment on lines +37 to +38
# (see [tool.uv.sources] in pyproject.toml). Drop this step once the SDK
# ships a release that includes the LangGraph plugin.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just leave this step? I assume we'll need to constantly add and remove it as we write new plugins + samples.

@@ -0,0 +1,36 @@
# Continue-as-New with Caching (Functional API)

Demonstrates combining Temporal's continue-as-new with LangGraph's task result caching to avoid re-executing completed `@task` functions across workflow boundaries.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's actually OUR task result caching, right?

Comment on lines +86 to +92
activity_options = {
t.func.__name__: {
"execute_in": "activity",
"start_to_close_timeout": timedelta(seconds=30),
}
for t in all_tasks
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels like we're hacking around our own limitations here. Let's just be explicit everywhere or make this more user friendly.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(My vote is to be more explicit, that was the point of making this change anyways)

@@ -0,0 +1,37 @@
# Human-in-the-Loop Chatbot (Functional API)

Demonstrates using LangGraph's `interrupt()` to pause an entrypoint for human review, combined with Temporal signals and queries for asynchronous feedback, using the imperative `@task`/`@entrypoint` style.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Signals and Queries are important to mention here, but the real star of the show is wait_condition which can wait indefinitely

Comment on lines +45 to +51
activity_options = {
t.func.__name__: {
"execute_in": "activity",
"start_to_close_timeout": timedelta(seconds=30),
}
for t in all_tasks
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hacky

@@ -0,0 +1,37 @@
# LangSmith Tracing (Functional API)

Demonstrates combining `LangGraphPlugin` (durable task execution) with Temporal's `LangSmithPlugin` (observability) for full tracing of LLM calls through Temporal workflows, using LangGraph's `@task` and `@entrypoint` decorators.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant, tracing = observability

Suggested change
Demonstrates combining `LangGraphPlugin` (durable task execution) with Temporal's `LangSmithPlugin` (observability) for full tracing of LLM calls through Temporal workflows, using LangGraph's `@task` and `@entrypoint` decorators.
Demonstrates combining `LangGraphPlugin` (durable task execution) with Temporal's `LangSmithPlugin` for full tracing of LLM calls through Temporal workflows, using LangGraph's `@task` and `@entrypoint` decorators.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants