Async and the response node
Topologies run asynchronously. A command is fire-and-forget, but a query needs to send a result back to the caller once the process finishes. Pulse handles this with a response node and a pair of reply headers.
Command vs query #
kind is derived from the topology, not declared:
- A topology that contains a response node is a
query. It returns data. - A topology without one is a
command. It is fire-and-forget.
The response node #
Add a response node as the terminal step of a topology when you want it to return a payload. When the process reaches the response node, the data at that point is sent back to whoever started the run.
flowchart LR
Start["Event start"] --> Work["Worker nodes"]
Work --> Resp["Response node"]
Resp --> Caller["Reply to the caller"]
Reply headers #
When you run a query, pass a callback so Pulse knows where to deliver the result:
curl -X POST https://your-instance.example.com/mcp/run \
-H "X-Auth: <AGENT_API_KEY>" \
-H "Content-Type: application/json" \
-d '{
"tool": "topology:weather-report",
"args": { "city": "Brno" },
"reply_to": "https://your-agent.example.com/pulse/callback",
"reply_id": "req-42"
}'
| Field | Purpose |
|---|---|
reply_to | Where the response node posts the result. |
reply_id | Your correlation id, echoed back so you can match the response to the request. |
The initial run response returns status: "pending". The actual payload arrives later, at reply_to, carrying your reply_id.
reply-to and reply-id travel as protected headers through the whole topology, so they survive every hop and reach the response node unchanged.
Output is returned verbatim #
By default a query result is returned as the topology produced it. It is not sent back through the model. A response can carry sensitive data, so any formatting should happen inside the topology. See output handling for the opt-in exception.
Where to go next #
- Caller identity: act on behalf of the real user.
- Manifest and run: the run request and response.