Skip to content

Every HITL approve/reject leaks forwardedProps.command.resume is deprecated ... into the conversation — self-inflicted, and the CLI already filters its sibling warning (#103) but not this one #126

Description

@dkedar7

Summary

On the headline human-in-the-loop feature, every time a user approves or rejects an interrupt() in the interactive CLI, this line is printed into the conversation, jammed onto the spinner line right before the agent's post-resume reply:

forwardedProps.command.resume is deprecated; please send RunAgentInput.resume[] (thread_id='…', run_id='…')

The user did nothing wrong — the warning is self-inflicted: langstage-core's resume path sends the deprecated forwarded_props.command.resume, so ag-ui-langgraph logs the deprecation on 100% of HITL resumes. It reads exactly like an error, and it lands right above the correct answer — which is the same UX problem the CLI already fixed for a sibling ag_ui_langgraph.agent warning in #103, except this one slips through the filter.

Severity: minor today (cosmetic noise), but see the forward-compat risk below — the path it uses is documented as slated for removal, at which point HITL resume breaks outright.

Environment

  • langstage-cli 0.6.30 (from PyPI, clean venv)
  • langstage-core 1.0.34, ag-ui-langgraph 0.0.43, langgraph 1.2.11
  • Python 3.11, Linux

Minimal repro

hitl.py — a keyless interrupt agent (no API key, no model):

# hitl.py
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import MessagesState
from langgraph.types import interrupt
from langgraph.checkpoint.memory import MemorySaver
from langchain_core.messages import AIMessage

def ask(state):
    decision = interrupt({"action": "delete_all", "question": "Approve?"})
    return {"messages": [AIMessage(content=f"Decision was: {decision!r}")]}

g = StateGraph(MessagesState)
g.add_node("ask", ask)
g.add_edge(START, "ask")
g.add_edge("ask", END)
graph = g.compile(checkpointer=MemorySaver())
langstage-cli -a hitl.py:graph
# type a message, e.g.  do it
# at the "Action Required" menu, press Enter (Approve all actions)

Evidence (literal terminal output, ANSI stripped)

Approve path:

⠋ Thinking... 0sforwardedProps.command.resume is deprecated; please send RunAgentInput.resume[] (thread_id='b8b3e0e6-…', run_id='b56d14e0-…')
⏺ Decision was: {'decisions': [{'type': 'approve'}]}

Reject path (identical warning):

⠋ Thinking... 0sforwardedProps.command.resume is deprecated; please send RunAgentInput.resume[] (thread_id='203db3e5-…', run_id='7abaf222-…')
⏺ Decision was: {'decisions': [{'type': 'reject'}]}

Reproduces deterministically on both approve and reject. It does not appear on any non-HITL turn (plain agents, tool-calling agents) — it is specific to the resume path. Note it even concatenates onto the Thinking... 0s spinner line (no leading newline), making it look even more like a broken/error output.

Expected vs actual

  • Expected: approving/rejecting a HITL action prints only the agent's resulting reply. No internal deprecation warning in the conversation.
  • Actual: every approve/reject prints the forwardedProps.command.resume is deprecated … line into the visible output, right before the reply.

Root cause

  1. langstage_core/agui/__init__.py builds the resume as the deprecated shape — forwarded_props = {"command": {"resume": resume}} (the iter_chunk_frames / resume builder, ~lines 605 and 855) — rather than the AG-UI-standard RunAgentInput.resume[].
  2. ag_ui_langgraph/agent.py:255 therefore logs, via logging.getLogger("ag_ui_langgraph.agent"):
    "forwardedProps.command.resume is deprecated; please send RunAgentInput.resume[] (thread_id=%r, run_id=%r)".
  3. The CLI already recognizes that ag_ui_langgraph.agent warnings pollute the resume UX and installs a surgical filter around the resume block — _quiet_agui_resume_json_warning() at langstage_cli/cli.py:1662 (added for HITL: answering a plain-string interrupt() leaks an ag_ui_langgraph WARNING (failed to parse resume_input as JSON, treating as string ...) onto the console on every free-text response #103). But that filter drops only the message containing "failed to parse resume_input as JSON" (_AGUI_RESUME_JSON_WARNING, cli.py:142/160). This deprecation warning rides the same logger with a different message, so it passes the filter and reaches the console.

Forward-compat risk (why this is worth fixing beyond cosmetics)

The warning itself says the path it uses is deprecated; ag-ui-langgraph's own docstrings note legacy forwardedProps.command.resume support is kept only "until they adopt RunAgentInput.resume[]." When the deprecated path is eventually removed upstream, HITL resume stops working entirely — and because the offending call lives in the shared langstage-core, that breakage would hit every LangStage surface, not just the CLI.

Suggested fix

Preferred — fix the cause in langstage-core: build resume as the AG-UI-standard RunAgentInput.resume[...] instead of forwarded_props.command.resume. That silences the warning at the source and removes the forward-compat risk for every surface.

CLI-local stopgap (if a core release lags): broaden the existing #103 filter to also drop the "forwardedProps.command.resume is deprecated" message — it's on the same ag_ui_langgraph.agent logger the filter is already attached to, so it's a one-line addition to _DropResumeJSONWarning. (Suppressing the symptom leaves the latent breakage, so this is a stopgap, not the fix.)


Filed by the nightly dogfood routine. Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingroutineFiled by the daily power-user dogfooding routine

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions