Nested Subgraphs¶
nested-subgraphs shows that LGOS serves graphs whose work runs inside nested
LangGraph subgraphs. It is a deterministic transport example: a fake chat model
streams fixed text, and the graph calls no provider. One request crosses two
subgraph levels. The child subgraph emits a status and streams a draft, then
its grandchild subgraph pauses for human review and streams the answer after
resumption. The same graph runs in the foreground or in the background worker.
deep-research uses the same mechanisms with a
real model, private subgraph state, and parallel subgraphs.
All levels share one state schema whose messages channel uses
add_messages, so each compiled subgraph runs directly as a node and its
messages reach the root without wrapper code. LGOS's default adapters pass the
request messages in and return the final message, which answer writes.
LangGraph Topology¶
The native xray view qualifies nested nodes with their subgraph path.
graph TD;
__start__ --> draft["child:draft"];
answer["child:grandchild:answer"] --> __end__;
subgraph child
draft --> review["child:grandchild:review"];
subgraph grandchild
review --> answer;
end
end
Request Flow¶
A streaming foreground request pauses in the grandchild, and its answer
resumes there. R1 and R2 label the two Response IDs of one graph run.
sequenceDiagram
actor User
participant UI as Chainlit / Open WebUI
box LGOS API process
participant API as /v1/responses
participant Child as child subgraph
participant Grandchild as grandchild subgraph
end
participant DB as PostgreSQL checkpointer
User->>UI: Send a prompt
UI->>API: responses.create, stream=true
API->>Child: Run draft
Child-->>API: Status and draft tokens
API-->>UI: Commentary, then streamed draft
Child->>Grandchild: Run review
Grandchild->>DB: Save the pause
API-->>UI: R1 completes with an lgos_interrupt call
User-->>UI: Approve or reject
UI->>API: previous_response_id=R1<br/>function_call_output
API->>Grandchild: Resume at review, then answer
Grandchild-->>API: Answer tokens
API->>DB: Delete the checkpoint
API-->>UI: R2 streams the final answer
Each step exercises an LGOS path from inside a subgraph:
| LGOS path | Behavior in this graph |
|---|---|
| Token streaming | draft runs one level down; its fake-model tokens still stream as answer text. |
| Status | The status_event() from draft becomes Responses commentary. |
| Interrupt | review runs two levels down; its interrupt() pauses the whole run, and R1 carries one lgos_interrupt call. |
| Resumption | LangGraph reruns review with the answer and then runs answer; the draft and its status do not repeat. |
| Background | The worker runs the same graph without streaming, pauses at review, and resumes there. |
Non-streaming and background requests receive no commentary or draft text: the paused Response carries only the review call, and the resumed Response carries the final answer. Chat Completions rejects the model because interrupts require the Responses API.
The review offers approve and reject without free text. The graph reports
the answer it receives and takes no action, so either choice finishes the run.
Persistence And Ownership¶
The root graph compiles with the API's PostgreSQL checkpointer and declares
BACKGROUND and INTERRUPTS. The subgraphs compile without a checkpointer and
inherit the root's, which stores their paused state under nested checkpoint
namespaces of the same thread. LGOS deletes the checkpoint after the resumed run
finishes; the demo API deletes runs left paused longer than
LGOS_INTERRUPT_TTL_MINUTES.
The API and the background worker register the same graph and share the checkpointer and run coordinator, so either process can resume a pause. Hatchet stores background Responses. The graph uses no Store, and the UI owns the conversation history. For the shared continuation rules, see Resuming an interrupt.
Try It¶
Select nested-subgraphs in Chainlit or
Open WebUI and send Quarterly risks. The status and
Draft from the child subgraph: Quarterly risks appear before the review.
Approve it to see The grandchild subgraph resumed with: approve.
To run both legs in the worker, start the background services described in
Docker Compose, enable Run in background
before sending, and keep it enabled when answering. The
Background Interrupt Python SDK example
also runs this graph with model = "nested-subgraphs" and without its
metadata setting.
The implementation is in
demo/api/src/lgos_demo_api/graphs/nested_subgraphs.py.