Frontend Integration Overview
v7 canonical entry point
v7 ships a new chat-handler quartet: handleChatStream (server), prepareHelixChatRequest + prepareHelixReconnectRequest (client), and useHelixChat (React — recommended) / useResumeClientTools (React — lower-level). Examples on this page that reference the legacy useChat({ initialMessages, isLoading, handleInputChange }) AI SDK v4 API are kept for archival reference only — see Frontend / @helix-agents/ai-sdk for the canonical v7 wiring (DefaultChatTransport + the prepare-helpers + useHelixChat).
Frontend integration connects your Helix Agents backend to user interfaces. The @helix-agents/ai-sdk package transforms Helix's streaming protocol into the Vercel AI SDK UI Data Stream format, enabling real-time chat UIs with useChat and other AI SDK hooks.
Why Frontend Integration Matters
AI agents produce:
- Streaming text - Token-by-token responses
- Tool invocations - Tools being called and their results
- Thinking/reasoning - Internal reasoning traces
- Custom events - Application-specific data
- Final outputs - Structured results
Frontend integration delivers these events to your UI in real-time, enabling:
- Progressive text rendering
- Tool call visualization
- Thinking/reasoning displays
- Status indicators
- Error handling
Architecture
graph TB
subgraph Backend ["Backend"]
Executor["<b>Agent Executor</b><br/>Helix Chunks"]
StreamMgr["<b>Stream Manager</b><br/>Helix Chunks"]
Handler["<b>handleChatStream</b><br/>Transform ↓<br/>AI SDK Events"]
Executor --> StreamMgr --> Handler
end
Handler -->|"SSE (Server-Sent Events)"| UseChat
subgraph Frontend ["Frontend"]
UseChat["<b>useChat Hook (Vercel AI SDK)</b><br/>messages, input, handleSubmit, ..."]
subgraph Components ["React Components"]
C1["Message list"]
C2["Tool call displays"]
C3["Input form"]
end
UseChat --> Components
endDeployment Modes
The v7 chat handler works in two deployment modes:
| Mode | When to Use | Backend |
|---|---|---|
| Direct | API routes run in same process as agent | Redis, Memory, or direct DO binding |
| DO Client | Frontend separate from Durable Objects | HTTP to AgentServer DO |
Direct Mode is simpler - your API route has direct access to stores:
import { handleChatStream, buildSnapshot } from '@helix-agents/ai-sdk';
const deps = { executor, stateStore, streamManager, agent: MyAgent, contentReplayEnabled: true };
const dispatchChat = (params) => handleChatStream(deps, params);
const getSnapshot = (sessionId) => buildSnapshot(deps, { sessionId });DO Mode uses the Cloudflare chat-handler factory:
import { createCloudflareChatHandler } from '@helix-agents/ai-sdk/cloudflare';
const chat = createCloudflareChatHandler({
namespace: env.AGENTS,
agentName: 'chat',
});
const dispatchChat = (params) => chat.handleChat(params);
const getSnapshot = (sessionId) => chat.getSnapshot({ sessionId });See AI SDK Package for detailed setup.
Server-Sent Events (SSE)
SSE provides real-time, server-to-client streaming:
sequenceDiagram
participant Server
participant Client
Server->>Client: text-delta: "Hello "
Server->>Client: text-delta: "world"
Server->>Client: tool-input-available
Server->>Client: tool-output-available
Server->>Client: finishBenefits over WebSockets:
- Simpler (one-way communication)
- Automatic reconnection
- Works through proxies/CDNs
- Native browser support
Stream Protocol Transformation
Helix internal chunks are transformed to AI SDK UI events:
| Helix Chunk | AI SDK Event | Notes |
|---|---|---|
text_delta | text-delta | Token-by-token text |
thinking | reasoning-delta | Reasoning traces |
tool_start | tool-input-available | Tool call complete |
tool_end | tool-output-available | Tool result |
custom | data-{eventName} | Custom events |
error | error | Error events |
output | data-output | Final structured output |
Quick Start
Backend Setup
import { handleChatStream, buildSnapshot } from '@helix-agents/ai-sdk';
import { JSAgentExecutor } from '@helix-agents/runtime-js';
import { InMemoryStateStore, InMemoryStreamManager } from '@helix-agents/store-memory';
import { VercelAIAdapter } from '@helix-agents/llm-vercel';
// Create stores and executor
const stateStore = new InMemoryStateStore();
const streamManager = new InMemoryStreamManager();
const executor = new JSAgentExecutor(stateStore, streamManager, new VercelAIAdapter());
// Shared deps bundle — feeds every server helper.
const deps = {
executor,
stateStore,
streamManager,
agent: MyAgent,
contentReplayEnabled: true,
} as const;
// Chat dispatch (path: POST /api/chat/:id) — returns a web Response.
export const dispatchChat = (params) => handleChatStream(deps, params);
// SSR / hydrate snapshot (path: GET /api/chat/:id/snapshot).
export const getSnapshot = (sessionId) => buildSnapshot(deps, { sessionId });
// Use with your framework
// See Framework Examples for Express, Hono, etc.Frontend Setup
import { useChat } from 'ai/react';
function ChatComponent() {
const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({
api: '/api/chat',
});
return (
<div>
{messages.map((msg) => (
<Message key={msg.id} message={msg} />
))}
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} />
<button type="submit" disabled={isLoading}>Send</button>
</form>
</div>
);
}Package Contents
The @helix-agents/ai-sdk package provides:
handleChatStream
The canonical v7 chat dispatcher — accepts the parsed { sessionId, messages } body (plus the incoming Request) and returns a web Response carrying an SSE body. Dispatches one of seven paths internally (fresh turn, continuing turn, resume after tool/approval, abandonment recovery, active-stream attach, terminal-stream replay, stale-runId rejection).
import { handleChatStream } from '@helix-agents/ai-sdk';
const deps = { executor, stateStore, streamManager, agent: MyAgent };
// Same function handles POST (new message) and GET (resume).
const response = await handleChatStream(deps, {
sessionId,
messages: body.messages ?? [],
request: req,
});buildSnapshot
Standalone SSR-hydration helper. Returns a FrontendSnapshot with the state, persisted messages, current stream sequence, and status — suitable for hydrating useChat({ messages }).
import { buildSnapshot } from '@helix-agents/ai-sdk';
const snapshot = await buildSnapshot(
{ executor, stateStore, streamManager, agent: MyAgent, contentReplayEnabled: true },
{ sessionId }
);StreamTransformer
Converts Helix chunks to AI SDK events:
import { StreamTransformer } from '@helix-agents/ai-sdk';
const transformer = new StreamTransformer();
for await (const chunk of helixStream) {
const { events } = transformer.transform(chunk);
for (const event of events) {
yield event;
}
}Message Converter
Converts Helix messages to AI SDK v6 UIMessage format:
import { convertToUIMessages } from '@helix-agents/ai-sdk';
const helixMessages = await stateStore.getMessages(sessionId);
const uiMessages = convertToUIMessages(helixMessages.messages);
// Use as initialMessages in useChat
const { messages } = useChat({
initialMessages: uiMessages,
});Typed Errors
Structured error handling:
import {
FrontendHandlerError,
ValidationError,
StreamNotFoundError,
StreamFailedError,
} from '@helix-agents/ai-sdk';
try {
return await dispatchChat({
sessionId,
messages: body.messages ?? [],
request: req,
});
} catch (error) {
if (error instanceof FrontendHandlerError) {
return Response.json({ error: error.message, code: error.code }, { status: error.statusCode });
}
throw error;
}Framework Compatibility
handleChatStream returns a standard web Response (status + headers + SSE body). Hono / Fastify / Cloudflare Workers can return it directly; Express uses the pipeWebResponseToExpress / createWebResponseExpressMiddleware adapters from @helix-agents/ai-sdk/adapters/express.
This works with any HTTP framework:
- Express
- Hono
- Fastify
- Cloudflare Workers
- Vercel Functions
- AWS Lambda
Stream Resumability
SSE supports automatic reconnection. handleChatStream extracts the resume cursor from incoming request headers (X-Resume-From-Sequence, Last-Event-ID, X-Existing-Message-Id) and replays the run from that position:
// Client reconnects with Last-Event-ID header (or X-Resume-From-Sequence).
// handleChatStream picks path 5 (active-stream attach) or path 6 (terminal replay).
const response = await handleChatStream(deps, {
sessionId,
messages: [],
request: req,
});This enables:
- Network resilience
- Client reconnection
- Page refresh handling
Next Steps
- AI SDK Package - Deep dive into the package
- React Integration - Building React UIs
- Framework Examples - Express, Hono, etc.
@helix-agents/ai-sdkREADME — composability ladder —useHelixChat,useHelixSendAutomaticallyWhen, andcreateHelixSendAutomaticallyWhen