Prompt for human feedback in LangGraph HITL sample (#324) · temporalio/samples-python@64e2cc2 · GitHub
Skip to content

Commit 64e2cc2

Browse files
authored
Prompt for human feedback in LangGraph HITL sample (#324)
* Prompt for human feedback in LangGraph HITL sample The graph_api human-in-the-loop sample previously auto-approved the draft and used a hardcoded placeholder response, so running it didn't actually involve a human. Now the draft is generated by an LLM, the runner prompts interactively at the terminal for approval or revision feedback, and the review node revises the draft with the LLM based on that feedback. Tests mock the chat model so they stay deterministic and offline. * Only require AI SDK team review for langgraph_plugin * Revert: restore SDK team review for langgraph_plugin CODEOWNERS
1 parent bfec885 commit 64e2cc2

4 files changed

Lines changed: 104 additions & 65 deletions

File tree

‎langgraph_plugin/graph_api/human_in_the_loop/README.md‎

Lines changed: 5 additions & 3 deletions

‎langgraph_plugin/graph_api/human_in_the_loop/run_workflow.py‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@ async def main() -> None:
2727

2828
print(f"Draft for review: {draft}")
2929

30-
# Send approval via signal (a UI would trigger this)
31-
await handle.signal(ChatbotWorkflow.provide_feedback, "approve")
30+
# Prompt for human feedback instead of auto-approving.
31+
feedback = await asyncio.to_thread(
32+
input, "Enter 'approve' to accept, or type revision feedback: "
33+
)
34+
await handle.signal(ChatbotWorkflow.provide_feedback, feedback)
3235

3336
result = await handle.result()
3437
print(f"Final response: {result}")

‎langgraph_plugin/graph_api/human_in_the_loop/workflow.py‎

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from datetime import timedelta
88

9+
from langchain.chat_models import init_chat_model
910
from langchain_core.runnables import RunnableConfig
1011
from langgraph.checkpoint.memory import InMemorySaver
1112
from langgraph.graph import START, StateGraph
@@ -20,21 +21,25 @@ class State(TypedDict):
2021

2122

2223
async def generate_draft(state: State) -> dict[str, str]:
23-
"""Generate a draft response. Replace with an LLM call in production."""
24-
return {
25-
"value": (
26-
f"Here's my response to '{state['value']}': "
27-
"The answer is 42. Let me know if this helps!"
28-
)
29-
}
24+
"""Generate a draft response with an LLM."""
25+
response = await init_chat_model("claude-sonnet-4-6").ainvoke(
26+
f"Please respond concisely to: {state['value']}"
27+
)
28+
return {"value": str(response.content)}
3029

3130

3231
async def human_review(state: State) -> dict[str, str]:
33-
"""Present draft to human for review via interrupt."""
32+
"""Present draft to human for review via interrupt; revise with LLM on feedback."""
3433
feedback = interrupt(state["value"])
3534
if feedback == "approve":
3635
return {"value": state["value"]}
37-
return {"value": f"[Revised] {state['value']} (incorporating feedback: {feedback})"}
36+
response = await init_chat_model("claude-sonnet-4-6").ainvoke(
37+
"Revise the following draft according to the reviewer's feedback. "
38+
"Output only the revised draft, with no preamble.\n\n"
39+
f"Draft:\n{state['value']}\n\n"
40+
f"Feedback:\n{feedback}"
41+
)
42+
return {"value": str(response.content)}
3843

3944

4045
def make_chatbot_graph() -> StateGraph:
Lines changed: 80 additions & 51 deletions

0 commit comments

Comments
 (0)