Use polling instead of SSE for environments that can't maintain long-lived HTTP connections.
When to Use Polling
Some environments cannot hold open Server-Sent Events (SSE) connections:
- Convex actions — HTTP requests must complete within a timeout
- Cloudflare Workers — no long-lived inbound connections
- Restricted edge runtimes — firewalls or proxies that drop idle connections
- Serverless functions — Lambda, Cloud Functions with short timeouts
In these cases, set stream: false to switch from SSE to lightweight polling. The SDK automatically polls a status endpoint and only fetches full data when the status changes.
Client-Level Default
Set polling as the default transport for all operations:
1import { inference } from '@inferencesh/sdk';23const client = inference({4 apiKey: 'inf_your_key',5 stream: false, // Use polling instead of SSE6 pollIntervalMs: 2000, // Poll every 2 seconds (default)7});All client.run(), agent.sendMessage(), and AgentChatProvider calls will use polling unless overridden.
Task Polling
Override the transport per-call with stream: false on run():
1const result = await client.run(2 { app: 'infsh/flux', input: { prompt: 'A sunset' } },3 {4 stream: false,5 pollIntervalMs: 3000, // Optional: override interval6 onUpdate: (task) => {7 console.log('Status:', task.status);8 },9 }10);1112console.log('Output:', result.output);How it works:
- Task is created via
POST /apps/run(same as streaming) - SDK polls
GET /tasks/{id}/statuseverypollIntervalMs - When the status changes, it fetches the full task via
GET /tasks/{id} onUpdatefires with the full task data- Promise resolves on completion, rejects on failure or cancellation (the error message comes from the task's
errorfield when present)
When status polling cannot recover (for example repeated network errors), set maxReconnects on run() options (default 5) to control retry behavior.
Agent Polling
Imperative SDK
1const client = inference({ apiKey: 'inf_your_key' });23const agent = client.agent('my-team/support-agent@latest');45const response = await agent.sendMessage('Hello!', {6 stream: false,7 pollIntervalMs: 2000,8 onMessage: (message) => {9 console.log('Message:', message.content);10 },11 onChat: (chat) => {12 console.log('Chat status:', chat.status);13 },14 onToolCall: (invocation) => {15 console.log('Tool call:', invocation.name);16 },17});How it works:
- Message is sent via
POST /agents/run(same as streaming) - SDK polls
GET /chats/{id}/statuseverypollIntervalMs - When the status changes, it fetches the full chat via
GET /chats/{id} - New and updated messages are dispatched to
onMessage - Client tool invocations (
awaiting_input) are dispatched toonToolCall - Promise resolves when the chat becomes
idle
React Provider
1import { AgentChatProvider, useAgentChat } from '@inferencesh/sdk/agent';23function App() {4 return (5 <AgentChatProvider6 client={client}7 agentConfig={{ agent: 'my-team/support-agent@latest' }}8 stream={false}9 pollIntervalMs={2000}10 >11 <ChatUI />12 </AgentChatProvider>13 );14}The provider uses the same polling mechanism internally. All hooks (useAgentChat, useAgentActions) work identically regardless of transport.
Configuration Reference
| Option | Type | Default | Scope |
|---|---|---|---|
stream | boolean | true | Client, run(), sendMessage(), Provider |
pollIntervalMs | number | 2000 | Client, run(), sendMessage(), Provider |
maxReconnects | number | 5 | run() when stream: false |
Precedence: Per-call options override provider props, which override client defaults.
Comparison: Streaming vs Polling
| SSE (default) | Polling | |
|---|---|---|
| Latency | Real-time | Up to pollIntervalMs delay |
| Partial updates | Yes (onPartialUpdate) | No (full fetch only) |
| Connection | Long-lived HTTP | Short-lived requests |
| Edge compatible | No | Yes |
| Bandwidth | Lower (deltas only) | Higher (status checks + full fetches) |
Use SSE when you can. Use polling when you must.