[ Agent Infrastructure ]

Energent AI

Production-grade AI agent dashboard with live computer use

THE CHALLENGE

The Vercel AI SDK computer-use demo provides a minimal proof of concept, but it is not production-ready. VNC state and chat state are coupled, causing the viewer to re-initialize on every message. Type boundaries between SDK packages are inconsistent, leading to type assertions throughout the codebase. There is no observability into individual tool call durations or session lifecycle.

ROLE:Full-Stack Developer
YEAR:2026
TYPE:Assessment Project
STATUS:Public

TECH STACK

Next.jsTypeScriptVercel AI SDKZustandReact.memoVNCWebSocketsTailwind CSS
I

Engineering Approach

Store Isolation by Design

Separated VNC session state from chat/event state into two completely independent Zustand stores before writing any UI. Store boundaries were an architectural decision made upfront, not a refactor after noticing performance issues.

Type System Traced, Not Hacked

Instead of suppressing TypeScript errors with type assertions, traced the full AI SDK type hierarchy through @ai-sdk/ui-utils to find the correct type boundary. Refactored message handling to use UIMessage consistently at the UI layer.

Explicit Render Control

Wrapped VNCViewer in React.memo with a custom equality comparator rather than relying on default shallow comparison. This gives precise control over when the VNC connection re-initializes, preventing drops during active agent sessions.

Stale Closure Prevention

Used useRef for per-tool-call duration tracking instead of useState, ensuring event callbacks always read current values without causing re-renders or capturing stale closures.

II

Key Technical Decisions

The choices that shaped the architecture and determined long-term maintainability.

Two Isolated Zustand Stores

Event pipeline and session management live in completely separate stores with no cross-subscription.

WHY

VNC re-renders are expensive and disruptive — they drop the live connection. A shared store means any chat update triggers a VNC diff. Isolation ensures the viewer only re-renders when session state genuinely changes.

React.memo with Custom Comparator

VNCViewer is wrapped in React.memo with an explicit equality function instead of the default shallow comparison.

WHY

Default shallow comparison still triggers re-renders on object prop identity changes even when values are identical. The explicit comparator gives deterministic control over re-initialization.

UIMessage at the UI Layer

Standardized on UIMessage from @ai-sdk/ui-utils as the type used across all UI components handling messages.

WHY

The Message type lives at the core SDK layer and does not carry UI-specific fields. Using it at the UI layer forces type assertions. UIMessage is the correct boundary type and eliminates the mismatch entirely.

useRef for Duration Tracking

Start timestamps for tool calls are stored in a ref, updated via onFinish message parts.

WHY

Storing timestamps in state would trigger re-renders on every tool call start. A ref holds mutable values without affecting the render cycle, and always gives callbacks access to the current value.

III

Challenges & Solutions

[ CHALLENGE ]

VNC viewer was re-initializing on every chat message, causing live connection drops during active agent sessions.

[ SOLUTION ]

Isolated VNC session state into a dedicated Zustand store with no subscriptions to chat state. Added React.memo with an explicit comparator to VNCViewer, ensuring re-renders only trigger on genuine session changes.

[ CHALLENGE ]

Message vs UIMessage type conflict between @ai-sdk/react and @ai-sdk/ui-utils caused TypeScript errors throughout the message handling pipeline.

[ SOLUTION ]

Traced the full type hierarchy through the AI SDK packages to identify the correct type boundary. Refactored all UI-layer message handling to use UIMessage consistently, eliminating every type assertion.

[ CHALLENGE ]

Per-tool-call duration tracking via event callbacks was reading stale start timestamps due to closure capture at registration time.

[ SOLUTION ]

Moved timestamp storage from state to useRef, giving all callbacks a mutable reference that always points to the current value regardless of when the closure was created.

IV

Outcomes & Impact

The dashboard runs stable agent sessions with zero VNC connection drops on chat updates, a fully type-safe message pipeline with no assertions, and accurate per-tool-call duration data visible in the event timeline.

0
Type assertions in codebase
2
Isolated Zustand stores
0
VNC drops on chat update

KEY TAKEAWAYS

Architectural decisions about state boundaries have to be made before writing UI, not after. Retrofitting store isolation into a coupled system costs far more than designing the boundary upfront.