FluxyChat

Packages

@fluxy-chat/sdk

Client for a FluxyChat Worker (self-hosted or FluxyChat Cloud): rooms, messages, WebSockets, agents, and vertical SDKs.

Client for a FluxyChat Worker (self-hosted or FluxyChat Cloud): rooms, messages, WebSockets, agents, and vertical SDKs.

For React hooks (useChat, useInbox, FluxyRealtimeProvider), install @fluxy-chat/react alongside this package.

The SDK talks to your Worker URL. It does not include LLM API keys — only your Fluxy project API key or member JWT.

Install

npm install @fluxy-chat/sdk zustand
# React apps also need:
npm install @fluxy-chat/react react
# or
pnpm add @fluxy-chat/sdk @fluxy-chat/react zustand

Peer dependencies: install react (18+) when you use hooks from @fluxy-chat/react, and zustand (5+) for createFluxyRoomSession or room store helpers. The SDK has no runtime npm dependencies beyond protocol/types — only your Worker URL is contacted over the network (Socket network-access note).

Bundle size

Import only what your app needs — the full dist/index.js artifact is ~112 KB uncompressed; tree-shaken app bundles (client + hooks via @fluxy-chat/react) are typically much smaller. Compare gzip size in your bundler (Vite/webpack) when evaluating against other chat SDKs.

Browser vs Worker runtime

ImportUse inContents
@fluxy-chat/sdkBrowser, Node scripts, React/React NativeFluxyChatClient, hooks (transitional), types, client-safe helpers
@fluxy-chat/reactReact appsuseChat, FluxyRealtimeProvider, inbox hooks (re-exported from SDK during split)
@fluxy-chat/sdk/worker-runtimeCloudflare Worker, Node agent servicesAgent loop, sandbox, HITL approval store, TTS/image stubs wired on the Worker

Do not import @fluxy-chat/sdk/worker-runtime from browser bundles — those factories expect KV/D1 and Worker APIs. The FluxyChat Worker ships its own implementations under apps/worker/src/lib/; the SDK subpath is for custom Workers that embed the same agent helpers.

Quick local smoke test (monorepo):

pnpm run first-message

Errors and connection status

Typed errors (REST + chat)

SDK class / codeHTTP / WSUser action
FluxyTokenExpiredError / token_expired401, WS 1008Mint fresh JWT via POST /auth/token
FluxyNotMemberError / not_member403, WS 1008 ForbiddenAdd member to room or join with correct JWT
FluxyAnonymousNotAllowedErrorWS 1008Use authenticated JWT, not anonymous
FluxyAuthError / auth_refused401, WS 1008Check API key (server) or JWT claims
RateLimitError / FluxyRateLimitError / RATE_LIMITED429Wait retryAfterMs, backoff, reduce send rate
LockError / FluxyLockError / LOCK_ACQUISITION_FAILED409Retry send or refresh thread lock
NotImplementedError / FluxyNotImplementedError501Feature not on this adapter/runtime
FluxyConnectionErrorWS abnormal closeAuto-reconnect; check network
FluxySendErrorWait until socket open or use REST fallback

Use describeConnectionError() from @fluxy-chat/sdk for UI copy. Full troubleshooting: Integration troubleshooting guide.

Connection status labels (Portal parity)

statusUI label (getConnectionStatusLabel)
connectedConnected
connectingConnecting…
reconnectingReconnecting in Ns…
degradedDegraded — realtime limited
degraded-httpDegraded — HTTP fallback active
blockedConnection blocked
disconnectedDisconnected
import { getConnectionStatusLabel } from "@fluxy-chat/sdk";

const label = getConnectionStatusLabel(connectionState.status, {
  includeTransport: true,
  nextRetryAt: connectionState.nextRetryAt,
});

Vanilla store (Vue, Solid, Node)

import { createFluxyRoomSession } from "@fluxy-chat/sdk";

const { store, stop } = createFluxyRoomSession({
  roomId: "my-room",
  client,
});

const unsub = store.subscribe((state) => {
  console.log(state.messages, state.connectionState);
});

store.getState().sendMessage("hello");
store.getState().sendMessage("", null, undefined, {
  templateId: "tpl_…",
  templateVars: { name: "Ada" },
});

// cleanup: unsub(); stop();

What you must configure

PieceWho sets itNotes
Worker baseUrlYoue.g. https://fluxychat-worker.<account>.workers.dev or your custom domain
Project API key (fc_…)Worker / consoleMint JWTs via POST /auth/token with header X-Fluxy-Api-Keyserver-side only
Member JWTYour backend or Fluxychat consolePassed to FluxyChatClient / useChat as token
LLM provider keysWorker secrets or consoleFor agents; never embed in the npm package

Minimal backend (mint JWT)

curl -X POST "$WORKER_URL/auth/token" \
  -H "Content-Type: application/json" \
  -H "X-Fluxy-Api-Key: fc_your_project_key" \
  -d '{"userId":"alice","roles":["member"],"ttlSeconds":3600}'

Use the returned token in the browser.

Quick start (React)

Quick smoke test run this before writing SDK code

# Set these in your shell or .env.local first.
export WORKER_URL=https://your-worker.example.workers.dev
export JWT=eyJ...                              # member JWT from /auth/token
export ROOM_ID=general

# 1. Send a message
curl -sS -X POST "$WORKER_URL/messages" \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d "{\"roomId\":\"$ROOM_ID\",\"content\":\"hello from the smoke test\"}"

# 2. Read it back
curl -sS "$WORKER_URL/api/messages?roomId=$ROOM_ID&limit=1" \
  -H "Authorization: Bearer $JWT"
# Verified against @fluxy-chat/sdk@0.5.0

If both calls return 200 and the message id round-trips, your Worker URL, JWT, and room are wired correctly. Skip to Option A below.

Option A — explicit client

import { FluxyChatClient } from "@fluxy-chat/sdk";
import { useChat } from "@fluxy-chat/react";

const client = new FluxyChatClient({
  baseUrl: process.env.NEXT_PUBLIC_FLUXYCHAT_WORKER_URL!,
  userId: "alice",
  token: memberJwtFromYourBackend,
});

function Room({ roomId }: { roomId: string }) {
  const {
    messages,
    sendMessage,
    connectionState,
    retryMessage,
    loadMore,
    hasMore,
    isLoadingMore,
  } = useChat({ roomId, client, markReadLatest: true });
  // connectionState.nextRetryAt → "Reconnecting in 3s…"
  // messages[].deliveryStatus → pending | sent | failed
  // render messages; call loadMore() when the user scrolls to the top
}
// Verified against @fluxy-chat/sdk@0.4.2  2026-06-26

Room catch-up + drafts

const catchUp = await client.getRoomCatchUp(roomId);
// { unreadCount, lastReadMessageId, firstUnreadMessageId }

await client.putRoomDraft(roomId, { content: "…", replyToId: null });
const draft = await client.getRoomDraft(roomId);

// Ephemeral message (1 hour TTL)
await client.createMessage(roomId, "self-destructs", null, undefined, undefined, {
  expiresInSeconds: 3600,
});

Rooms unread + notifications

const rooms = await client.listRooms(); // may include unreadCount per room
const notes = await client.listNotifications({ unreadOnly: true });
await client.markNotificationRead(notes[0].id);
// useNotifications(client) — React hook for in-app notification inbox

Option B — FluxyRealtimeProvider (hosted Next.js or custom mint)

Wrap your app (or chat layout) once. The provider refreshes the member JWT before expiry and on auth errors.

import { FluxyRealtimeProvider, useChat } from "@fluxy-chat/react";

export function ChatLayout({ children }: { children: React.ReactNode }) {
  return (
    <FluxyRealtimeProvider
      workerUrl={process.env.NEXT_PUBLIC_FLUXYCHAT_WORKER_URL!}
      connectUrl="/api/fluxy/connect"
    >
      {children}
    </FluxyRealtimeProvider>
  );
}

function Room({ roomId }: { roomId: string }) {
  const { messages, sendMessage, loadMore, hasMore } = useChat({ roomId });
  // …
}

For your own backend mint flow, pass authTokenProvider=\{() => fetch("/api/chat-token").then(r => r.json())\} instead of connectUrl.

Pagination

GET /api/messages supports a before cursor (createdAt of the oldest visible message). The SDK sorts history chronologically and exposes:

  • hasMore — another page may exist
  • isLoadingMoreloadMore() in flight
  • loadMore() — prepends older messages

Live snapshot (getParticipants)

GET /rooms/:id/live returns the room's Pusher-style channel stats plus a members: [\{ userId, userInfo \}] array (aggregated across shards for supergroup rooms, P10-SB8). Use it from the SDK to know "who's connected right now" without waiting for the next presence WS event:

const live = await client.getRoomLive("lobby");
// { occupied, online, subscriptionCount, userCount, users[], members: [{ userId, userInfo }], socketIds[] }

// Just the participants slice
const participants = await client.getRoomParticipants("lobby");

// React hook exposes a live snapshot in the store
const { live, loadLive } = useChat({ roomId: "lobby" });
await loadLive(); // refresh on demand

userInfo reflects whatever was passed in the WS presenceInfo query (or the JWT name / agent profile). For agent-typed participants, userInfo.agentId is set; consumers can branch on that.

Connection resilience

connectRoom() (used by useChat / createFluxyRoomSession) includes:

  • Exponential backoff reconnectconnectionState.status, nextRetryAt, reconnectAttempt
  • Outbound queuesendJson queues while connecting or reconnecting (cap 100 frames, 5 min TTL); flush on open. Inspect with getOutboundQueueDepth().
  • Heartbeat — client sends \{ type: "ping" \} every 25s by default; server replies \{ type: "pong" \}. Disable with heartbeatIntervalMs: 0 on connectRoom options.
  • WS connect snapshotreplay=connect + replayLimit query params; server sends \{ type: "replay", messages \} (or history by default). Set replay: "off" via connect(roomId, \{ replay: "off" \}) for heavy rooms.
  • REST history replay after reconnect only if no WS snapshot arrived first (replayHistoryOnReconnect, default true)
  • Streaming edit batching — rapid edit events with streaming: true are coalesced (~80ms) to reduce React re-renders during agent token streams
  • SSE / polling fallback when reconnect attempts are exhausted (see transport fallback doc in monorepo)
const conn = client.connectRoom(roomId, {
  heartbeatIntervalMs: 25_000,
  onOutboundQueueDrop: (n) => console.warn("dropped", n),
});

Reconnect backoff defaults — FluxyChat vs Fluxy reference

computeReconnectBackoffMs(attempt, baseMs, maxMs) is min(maxMs, baseMs * 2^attempt), capped internally at attempt ≤ 6 and bounded by maxReconnectAttempts (default 8). The two default profiles produce the schedule below:

AttemptFluxyChat default (500ms / 20s)Fluxy reference (1s / 8s)
0500 ms1 000 ms
11 000 ms2 000 ms
22 000 ms4 000 ms
34 000 ms8 000 ms (capped)
48 000 ms8 000 ms
516 000 ms8 000 ms
620 000 ms (capped)8 000 ms
720 000 ms8 000 ms
Total wall time (8 tries)≈ 71.5 s≈ 47 s

Why we keep the wider window (current default)

  • Shorter transient drops recover faster. Mobile networks flap in the 1–3 s window; a 500 ms first step lands a reconnect before most apps show a "disconnected" toast, which is what the dashboard UX relies on (connectionState.status is rendered in the room header).
  • Longer outages still give up reasonably fast. The 20 s cap means a 10-minute Worker outage costs ~30 reconnect attempts' worth of traffic, and the SSE/polling fallback (useChat) kicks in well before users notice.
  • It's configurable per-room. Call sites that want the Fluxy-style curve set baseBackoffMs: 1_000, maxBackoffMs: 8_000 on connectRoom options; see the P11-B2 entry in ROADMAP_EXECUTION.md.

When to flip to the Fluxy profile

  • Heavy rooms (≥ 1k concurrent sockets) where each reconnect attempt costs meaningful origin CPU on the Worker, and you'd rather batch retries at 8 s.
  • Backend-driven bots / workers where the long backoff is fine because the agent is the only writer.
  • Network profiles known to be slow (satellite, intermittent VPNs) where the extra 500 ms either way is in the noise.

When to keep the current default

  • Consumer chat UIs, mobile-first apps, anything where the user perceives the first 1–2 s after a drop.
  • The dashboard, agent chat, and any room where presenceInfo is shown live.
// Match the Fluxy-style curve (1s base, 8s cap)
const conn = client.connectRoom(roomId, {
  baseBackoffMs: 1_000,
  maxBackoffMs: 8_000,
});

See Connection state for reconnect backoff tuning. The defaults are not changing in this minor; P11-B2 stays in the roadmap as a documented decision rather than a code change.

Self-host vs hosted cloud

  • Self-host: deploy apps/worker from the monorepo, run D1 migrations, set secrets. See apps/worker/.dev.vars.example.
  • Hosted cloud: use the Fluxychat dashboard on Vercel; sign in with Clerk; project + API keys are provisioned for you.

Full operator docs: Dashboard integration.

Agents

Agent invokes run on the Worker (POST /agents/:id/invoke or @handle in a room message). Configure provider keys on the Worker or per-project in the console.

  • invokeAgentRest(agentId, roomId, content, \{ replyTo \}) — REST invoke with optional thread parent message id.
  • getAgentRuns(agentId) — run history including tool_calls when tools were used.
  • Live room events (WebSocket): tool_call, tool_result, tool_error, agentRun (latency, tokens, status).

History replay (heavy rooms)

const { messages, loadHistory, historyLoaded } = useChat({
  roomId,
  replay: "request", // skip REST + WS history on connect
});
// later: await loadHistory();

Default is replay: "connect". Pass replayHistoryOnReconnect: false to connectRoom if you manage history yourself.

Custom bot streaming (FluxyMessageStream)

For bots outside the built-in agent runtime, stream into one message row over WebSocket:

import { FluxyChatClient, FluxyMessageStream } from "@fluxy-chat/sdk";

const connection = client.connectRoom(roomId);
// connectRoom() auto-connects  no .connect() needed
const stream = new FluxyMessageStream(connection, agentUserId, { parentId: null });
stream.push("Hello ");
stream.end();
// Verified against @fluxy-chat/sdk@0.4.2  2026-06-26

See docs/cookbook/bot-streaming-fluxy-message-stream.md in the monorepo.

P12 / open beta APIs (2026)

FeatureSDK method
AI image generationgenerateAiImage(roomId, prompt, opts?) — requires AI_IMAGE_GENERATION_ENABLED on Worker
Composer tool promptsbuildDeepResearchPrompt(), buildWebSearchPrompt(), buildImageGenerationCaption()
AI reply suggestionssuggestReplies(roomId, parentId?)
Thread TL;DRsummarizeThread(messageId)
Full-text searchsearchMessages(\{ q, roomId?, from?, to? \})
Unified inboxgetInbox(), snoozeRoom(), createInboxFollowUp()
Room exportexportRoomMarkdown(roomId), exportRoomPdf(roomId)
Custom domains (admin)listCustomDomains(), createCustomDomain(), …
Embed config (admin)getEmbedConfig(), updateEmbedConfig()
Quiet hoursgetQuietHoursPreferences(), updateQuietHoursPreferences()
Digest preferencesgetDigestPreferences(), updateDigestPreferences()
Agent handoffgetRoomHandoff(), requestRoomHandoff(), resolveRoomHandoff()
Agent queuegetAgentQueue(), claimAgentTask(), resolveAgentTask()
Feature flags (P12-J)getFeatureFlags() — backoff applied on room session connect
Public host / embedgetPublicHostConfig(), getPublicEmbedConfig()

Docs in monorepo: docs/README.md · deploy: docs/operations/open-beta-deploy-guide.md

Pusher Channels parity (P9)

FluxyChat maps Pusher Channels features to rooms + JWT. Full matrix: Pusher Channels parity.

FeatureSDK API
Presence / subscription countWS events: subscription_succeeded, member_joined, member_left, subscription_count
Cache channelconnect(roomId, \{ cache: true \})
E2E encrypted roomgetRoomE2eKey(roomId) + encrypted sends
User channelsignIn(\{ userId, roles, ttlSeconds \}), connectUser(), triggerUserEvent(), useUserChannel()
Multi-room HTTP triggertriggerEvents(\{ roomIds, name, data, excludeSocketId \})
Exclude senderexcludeSocketId on trigger (no connection.socketId in the SDK)
Connection stateconnectionState, state_change event
Global bindingconnection.onAnyEvent() / connection.offAnyEvent(), useChat(\{ onAnyEvent \})
WatchlistlistWatchlist(), addWatchlistTarget(), removeWatchlistTarget()
Terminate connectionsterminateUserConnections(userId)
Public roomRoom type: "public" — any project member may connect (JWT still required)
// signIn() mints a member JWT using the apiKey configured on the client
const signed = await client.signIn({ userId: "alice", roles: ["member"], ttlSeconds: 3600 });
// For React: prefer the `useUserChannel` hook  it wraps the WS lifecycle.
// For non-React: use `client.connectUser()` directly (returns a raw WebSocket).
const userWs = client.connectUser(signed.userId);
userWs.onmessage = (event) => console.log("user-channel:", event.data);

await client.triggerEvents({
  roomIds: ["lobby", "scores"],
  name: "leaderboard",
  data: { top: 3 },
});

// onAnyEvent lives on the room connection, not the client
const conn = client.connectRoom("lobby");
conn.onAnyEvent((type, payload) => {
  if (type.startsWith("client-")) return;
});
// Verified against @fluxy-chat/sdk@0.4.2  2026-06-26
import { useUserChannel } from "@fluxy-chat/sdk";

function Inbox({ userId }: { userId: string }) {
  const { events, connectionState } = useUserChannel({ userId });
  // …
}

P10 — Sendbird / Sent / remaining Pusher

See docs/competitive-parity-p10.md.

FeatureSDK API
Live channel statsgetRoomLive(roomId)
Pin messagepinMessage(roomId, messageId | null)
Terminate one socketterminateRoomConnection(roomId, socketId)
Poll messagecreatePoll(), votePoll(), getPoll() — WS poll_updated
Block user (global)blockUser(), unblockUser(), listBlocks()
Guest open channelFluxyChatClient.joinPublicRoomAsGuest(baseUrl, roomId)
Pusher channel authauthorizeChannel(socketId, roomIdOrChannel)
Message translationtranslateMessage(messageId, targetLang, sourceLang?)
Delivery receiptsmarkMessageDelivered(), getMessageDeliveries() — WS delivery_updated
FCM push devicesregisterPushDevice(), unregisterPushDevice(), listPushDevices()
Sent contact syncsyncSentContact(e164, userId?)
SMS OTP loginFluxyChatClient.requestSmsOtp() / verifySmsOtp() (API key)
Supergroup shardsPATCH /rooms/:id \{ shardCount: 4 \} — see docs/supergroup-room-sharding.md
const guest = await FluxyChatClient.joinPublicRoomAsGuest(workerUrl, "lobby");
const guestClient = new FluxyChatClient({
  baseUrl: workerUrl,
  userId: guest.userId,
  token: guest.token,
});
const channelAuth = await client.authorizeChannel(socketId, "private-room-lobby");
await client.translateMessage(messageId, "it");
await client.markMessageDelivered(messageId);
await client.registerPushDevice("fcm", fcmToken);

Architecture features

FluxyChat includes a full-stack adapter system, streaming markdown renderer, card builder, and AI tool presets — all designed for multi-platform chat deployments.

FeatureWhat it does
Multi-platform adaptersPluggable adapter system (Web, WhatsApp, Telegram, Slack, Discord, Teams, Email, SMS, Webhook, Matrix) with unified thread ID encoding and channel mapping
Streaming markdownReal-time markdown rendering with table buffering, code fence tracking, and inline marker healing for partial bold/strikethrough/backtick sequences
Card builderComposable card elements (Text, Button, Image, Divider, Table, Fields) with renderers for fallback text, Markdown, Slack Block Kit, and Teams Adaptive Cards
AI tool presetsPre-configured tool groups (reader, messenger, moderator) with per-tool approval gates for enterprise governance
Tool overridesCustomize tool descriptions, titles, and approval requirements per agent profile without duplicating tool code
Message formatCanonical mdast AST format for messages, with serialization/deserialization and typed stream chunks (markdown_text, task_update, plan_update)
SentMessage factoryPost methods return objects with .edit(), .delete(), .addReaction(), .removeReaction() for cleaner message lifecycle management
// Multi-platform adapter example
import { getAdapter, dispatchThreadEvent, dispatchMessageEvent } from "@fluxy-chat/sdk";

const adapter = getAdapter("web");
const threadId = adapter.encodeThreadId({ userId, roomId }); // "web:{userId}:{roomId}"

// Streaming markdown
import { StreamingMarkdownRenderer } from "@fluxy-chat/sdk";
const renderer = new StreamingMarkdownRenderer();
renderer.push("**bold** and `code`");
const html = renderer.getHtml(); // renders incrementally

// Card builder
import { Card, Text, Button, cardToMarkdown } from "@fluxy-chat/sdk";
const card = Card(Text("Hello"), Button("Click me", "https://example.com"));
const markdown = cardToMarkdown(card);

P22–P25: AI-Native Architecture (2026-07)

Adopted from the Vercel Chat SDK and AI SDK architecture. See ROADMAP_EXECUTION.md for full details.

P22 — Adapter Pattern, Streaming Markdown, Cards, Tool Presets

FeatureSDK export
Multi-platform adaptersgetAdapter(slug), listAdapters(), BaseAdapter
WebAdapterRegistered by default in worker
FormatConvertertoAst(text), fromAst(ast), renderPostable(message)
StreamingMarkdownRenderernew StreamingMarkdownRenderer().push(), .getHtml(), .finish()
Card builder (function API)Card, Section, Text, Button, LinkButton, Actions, Image, Divider, Field, Fields, Table, CardLink
Card builder (JSX)/** @jsxImportSource @fluxy-chat/sdk */ — custom JSX runtime, no React needed
Card renderingcardToMarkdown(card), cardToFallbackText(card)
AI tool presetsgetToolPreset("reader" | "messenger" | "moderator")
Tool overridesapplyToolOverrides(tools, overrides)
Concurrency strategiesdrop, queue, debounce, burst, concurrent
Message formatmdast AST canonical format, StreamChunk union type
SerializationtoJSON() / fromJSON() with _type discriminator
SentMessage factory.edit(), .delete(), .addReaction(), .removeReaction()
Transcripts APIappend(), list(), count(), delete()
Custom emojicreateEmoji(), getEmoji() with platform-specific maps
Callback URLsEncode callback tokens in button values for server-side routing
ErrorsChatError, RateLimitError, LockError, NotImplementedError
LoggerConsoleLogger with child loggers and log levels
Thread statePer-thread key-value with TTL
Mock adapterMockAdapter for testing

P23 — AI SDK Core Features

FeatureSDK export
Stream resumptionclient.resumeStream(streamId), client.getActiveStreams(roomId)
Human-in-the-loop approvalneedsApproval flag, approval workflow UI cards
MCP clientcreateMcpClient(\{ transport, url \}).listTools(), .listResources(), .readResource()
MCP tool conversionconvertMcpTools(mcpTools) → FluxyChat tool definitions
LLM middlewarewrapLanguageModel(), transformParams(), wrapGenerate(), wrapStream()
Middleware compositioncomposeMiddleware([mw1, mw2, ...])
DevTools web UIVisual inspector for LLM calls, tool calls, token usage
OpenTelemetryGenAI semantic conventions, @ai-sdk/otel compatible
Per-step performanceModel output timing, streaming speed, tool execution time
WorkflowAgentnew WorkflowAgent(\{ agentId, model, tools \}).step(), .run()
Typed runtime contextdefineContext(schema) for type-safe cross-step data
Sandbox sessionsSandboxSession for isolated code execution
Realtime voiceBidirectional voice-to-voice AI with tool calling
Scoped tool contextPer-tool secret/config isolation via contextSchema

P24 — AI SDK Medium Features

FeatureSDK export
Tool call streamingonInputStart / onInputDelta / onInputAvailable callbacks
Multi-step loop controlmaxSteps, stopWhen, isStepCount, hasToolCall, isLoopFinished
Provider-defined toolsProvider supplies schema, developer provides execute
Provider-executed toolsServer-side tools (web search, code execution)
Pluggable transportDefaultChatTransport, ChatTransport interface
Typed UIMessageGeneric type parameter for end-to-end type safety
Data partsStream arbitrary typed data alongside text
extractReasoningMiddlewareextractReasoningMiddleware()
RAG middlewarecreateRagMiddleware(\{ retrieve \})
Provider-level middlewarewrapProvider(provider, [middleware])
Image generationgenerateImage() API
Speech generationgenerateSpeech() (TTS)
useObject hookuseObject() — stream structured JSON from LLM
Structured outputgenerateObject(), streamObject() with Zod schemas
MCP AppsSandboxed iframe rendering of tool UIs
Slash commandsCross-platform /command handling

P25 — AI SDK Low Features

FeatureSDK export
experimental_throttleConfigurable render throttle for streaming
smoothStreamFlicker-free text streaming
Ephemeral messagesUser-only visible with DM fallback
Cosine similaritycosineSimilarity(a, b) utility
Strict tool callingstrict: true schema enforcement
sendAutomaticallyWhenAuto-submit when all tool results available
Sensitive context controlsPrevent secrets in telemetry

Guides with examples: docs/guides/

Support

Questions: fluxychat@outlook.com · Issues: github.com/AlessandroFare/fluxychat/issues

License

MIT — see LICENSE.

On this page