Serve over AG-UI — langstage-agui¶
langstage-agui ships with langstage-core. It serves any LangGraph
CompiledGraph as an AG-UI HTTP endpoint,
so AG-UI clients (CopilotKit, React/Vue/Angular components, your own frontend) can
talk to it. It also runs one turn from the terminal, which makes it a handy
preflight for any agent.
Three questions, three flags¶
langstage-agui --agent my_agent.py:graph --show-config # does the config resolve an agent?
langstage-agui --agent my_agent.py:graph --verify # does it load and run a turn?
langstage-agui --agent my_agent.py:graph -m "hi there" # what does it say?
No agent yet? Each works keyless with --demo (the echo agent) or --demo=tools
(the rich demo: tool calls, reasoning and an interrupt):
langstage-agui --demo --verify # ok: one turn completed cleanly
langstage-agui --demo=tools -m "use a tool" # prints the demo tool's answer
langstage-agui --demo=tools -m "use a tool" --json # the typed TurnResult as JSON
langstage-agui --demo=tools -m "ask me" # pauses on an interrupt: exit 2
langstage-agui --show-config --json # resolved config as JSON
| Flag | What it does |
|---|---|
-a, --agent SPEC |
The agent (module:attr or path/to/file.py:attr). Falls back to LANGSTAGE_AGENT_SPEC / [agent] spec. |
--demo, --demo=tools |
A keyless demo agent: the echo stub, or the rich-frame tool demo. |
--host, --port, --path, --name |
Where to serve, and the agent name AG-UI clients see. |
--cors [ORIGIN,…] |
Allow browser frontends on other origins. Off by default; see below. |
--show-config |
Print the resolved config and exit. Add --json for JSON. |
--verify |
Run one keyless probe turn and report whether the agent works. |
-m, --message TEXT |
Run one turn with your prompt, print the reply, exit. |
--json |
With -m, print the TurnResult as JSON. With --show-config, print the config as JSON. |
--version |
Print the langstage-core version. |
What each one checks:
--verifyfails an agent that won't load, a graph that isn't runnable (for example aStateGraphyou forgot to.compile()), a turn that errors, and a turn that completes with no output at all. It's keyless, so it fits a CI or deploy gate.-m/--messageruns your prompt and prints the answer to stdout. With--jsonyou get the typedTurnResult(text,tool_calls,extractions,reasoning,outcome,interrupt,error,traceback).--verify,-mand--jsonkeep the agent's import-timeprints off stdout, so the output stays machine-readable.
Exit codes follow the family contract: 0 success, 1 failure, 2 paused on an
interrupt, 64 usage error. See Exit codes.
Serving¶
- The port is bound before the
Serving … at <url>banner prints, so a busy port is a clean one-lineerror: cannot serve at <url>: …, not a success banner followed by a crash. - A graph compiled without a checkpointer gets an in-memory one attached (on a copy; your graph object isn't changed). AG-UI needs threaded state for interrupts and resume.
- Keys in a
[configurable]table inlangstage.tomlare passed to the graph'sconfig["configurable"], when serving and under-m.thread_idis always set per run.
From Python:
from langstage_core import load_agent_spec
from langstage_core.agui import build_app
graph = load_agent_spec("langstage_core.demo.stub:graph") # or your own CompiledGraph
app = build_app(graph) # an ASGI (FastAPI) app; run it with uvicorn
serve(graph, host=..., port=...) builds and runs the app in one call. It binds
first, and raises OSError for a busy port.
Browser frontends on another origin (CORS)¶
By default the server sends no CORS headers, so only same-origin pages and
non-browser clients can call it. A frontend dev server on another port (say
http://localhost:5173 calling http://localhost:8050) needs an opt-in:
langstage-agui --demo=tools --cors # any localhost / 127.0.0.1 / [::1] origin
langstage-agui --demo=tools --cors http://localhost:5173 # exactly these origins (comma-separated)
"*" is honored only if you pass it explicitly. It is never a default.
Credentials (cookies) are never allowed cross-origin.
The web app's CORS is different
langstage run has its own setting, LANGSTAGE_CORS_ORIGINS. It allows
loopback origins by default, and origins you list get credentialed access,
because the web app supports HTTP Basic Auth. langstage-agui has no auth and
never allows credentials. See Web.
Notes for AG-UI client authors¶
- Use a new message id for every turn. The adapter dedupes messages by id, so a reused id silently drops the later turn.
- An agent failure is a terminal
RUN_ERRORevent. - An interrupt arrives as a
CUSTOMon_interruptevent. Resume by starting a new run on the same thread withRunAgentInput.resume(ag-ui-langgraph 0.0.43 and later). The olderforwardedProps.command.resumewire still works but is deprecated. The decision payload is described in Human-in-the-loop. - The in-process frames that the surfaces use are built from the same events. See the frame reference.