If you’ve built an agent UI before, you know the uncomfortable truth: most “progress” indicators are vibes.
A spinner means something is happening… probably.
But users don’t need theater — they need truth: what’s running right now, how far along it is, and what the agent is doing to their filesystem.
In this short video, I show how to stream custom, TypeScript-safe events from a LangGraph tool call directly into a React UI.
🎥 Video: https://youtu.be/3daSUNpWErQ
What you’ll build
A simple pattern:
1) Your tool emits events (progress/status/file ops) while it runs
2) The frontend subscribes and renders those events immediately
3) Type guards keep the UI logic safe and predictable
No polling loops. No guessing. No “thinking…” placeholders.
1) Emit typed custom events from a tool call
Inside the tool call, write custom events as the work progresses:
config.writer?.({
type: "progress",
id: analysisId, // stable id => update in place
step: steps[i].step,
message: steps[i].message,
progress: Math.round(((i + 1) / steps.length) * 100),
totalSteps: steps.length,
currentStep: i + 1,
toolCall: config.toolCall,
} satisfies ProgressData);
This is the key shift: tools aren’t just functions — they’re event producers.
2) Receive those events in React
In the UI, pass a handler into the stream hook:
onCustomEvent: handleCustomEvent,
Now every event emitted by your tool arrives in the client as it happens.
3) Narrow event types and update UI state predictably
Treat incoming events as unknown, then narrow with type guards and update state maps keyed by id:
if (isProgressData(data)) { /* update progress */ }
else if (isStatusData(data)) { /* update status */ }
else if (isFileStatusData(data)) { /* update file ops */ }
This keeps the frontend stable:
- progress updates in place
- minimal re-renders
- no stringly-typed event spaghetti
Why it matters (beyond “nice UI”)
When the UI reflects real execution:
- users trust the agent more
- debugging becomes dramatically easier
- failures are understandable without digging through logs
- you can build better UX: step indicators, timelines, file operation feeds, etc.
If you build something with this pattern, I’d love to see it — share a screenshot or link in the comments.
Top comments (0)