@dreamlake/chat-embed
v0.5.0
Published
Dream Chat as a native React component — the hosted-gateway studio chat (<DreamStudioChat gateway getToken/>) rendered directly in a host application's document (no iframe), so the composer's DOM picker and screenshot tools operate on the host app.
Downloads
771
Keywords
Readme
@dreamlake/chat-embed
Dream Chat as a native React component — the full studio chat column (transcript + composer with attachments, @-mentions, slash commands, DOM picker, draw/screenshot) bound to a Dream Chat hosted gateway, rendered directly in your application's document. No iframe: the composer's DOM-picker and screenshot tools operate on YOUR app, and what the user picks reaches the agent as structured context.
import { DreamStudioChat } from '@dreamlake/chat-embed'
import '@dreamlake/chat-embed/styles.css'
<DreamStudioChat
gateway="https://chat-gw.dreamlake.ai"
getToken={async ({ reason }) => {
// Your backend mints a short-lived embed token via the gateway's
// POST /v1/embed-tokens (tenant API key — server-side only).
const r = await fetch('/api/chat-token', { method: 'POST' })
return (await r.json()).token
}}
/>Requirements
- React 19 (
react/react-dompeers), browser only — render behind your framework's client-only escape under SSR. - One instance per page (the chat stack routes through page-wide state).
- Give the parent element a real height (the component is
h-full). - The gateway must allow your origin (
CORS_ORIGINS). - For pixel parity load Inter Tight + JetBrains Mono (system fallbacks otherwise).
styles.cssis fully scoped to the chat subtrees (every selector sits under:is(.dreamstudio-chat-root, .dreamstudio-chat-portal)) — it never restyles the host page, and Tailwind hosts need no cascade-layer wrappers around the import.
API
DreamStudioChatProps / DreamStudioChatHandle in dist/index.d.ts are the
complete reference. Summary:
gateway— hosted gateway base URL.getToken({reason})— called at boot ('initial'), ~60s before token expiry ('expiring'), and after a gateway 401 ('rejected'). Failures retry on a slow cadence.session/model/permission/theme/className/style/showHeader/showSessionDrawer.- Host context (each prop's name states its cadence):
page— the host page the user is on (a path). Live: keep it equal to your current route and every message carries it as page context; the composer shows a page chip the user can toggle off.sessionContext— free-text briefing about your app/page. Per-session: captured when each new chat session starts, injected invisibly into its first message (restored sessions are not re-briefed).hostCommands— thehost-messagepayload types youronHostMessagehandler understands ({type, description, payloadExample?}). Per-session likesessionContext: the agent is taught the transport automatically; this list teaches it your app's vocabulary.messageContext— free-text CURRENT STATE of your page (open panel, selected entity, statuses). Live, per-message likepage: every message carries it as a<host_context>block. Keep it short — it re-sends in full each turn.showPageChip—falsehides the composer's page chip and forces page context ON wheneverpageis set (product embeds: the page is your app's own state, not a user choice). Defaulttrue.
- Events:
onReady,onConnected,onConnectError,onSession,onTurnStart,onTurnEnd,onAssistantMessage,onHostMessage(structured events the agent pushes to your app — treat payloads as untrusted input and dispatch on atypewhitelist),onError(code:'auth'= token loss, already being refreshed). - Ref handle:
send(text),interrupt(),newSession(),updateToken(token).
Page-aware chat with agent→page refresh, end to end:
<DreamStudioChat
gateway="https://chat-gw.dreamlake.ai"
getToken={getToken}
page={`/projects/${projectId}`}
sessionContext={`You are embedded on the project page for "${projectId}".`}
hostCommands={[{
type: 'project-updated',
description: 'after you change this project, so the page can refresh',
payloadExample: { type: 'project-updated', project: projectId },
}]}
onHostMessage={({ payload }) => {
const type = payload && typeof payload === 'object'
? (payload as { type?: unknown }).type : undefined
if (type === 'project-updated') refetchProject()
}}
/>Theming: omit theme to inherit your document's data-theme attribute
('dark' enables dark mode), or force it per instance.
localStorage keys written on your origin: chat-mode,
chat-global-permission, chat-global-model, chat-global-effort,
chat-page-context, composer input-cache keys, and
simple-chat:session:<base> (per-user session restore).
Development
The component's source lives in the studio-app tree
(components/embed/HostedChat.tsx) and is bundled from there in place —
design/internals: studio-app/docs/design/hosted-chat.md.
pnpm --filter @dreamlake/chat-embed run build # dist/index.js + styles.css + index.d.ts
pnpm --filter @dreamlake/chat-embed run typecheck # includes the types-sync drift guard
pnpm --filter @dreamlake/chat-embed run smoke # packaging regression checks
pnpm -C studio-app test:embed-lib # all three (pre-publish gate)Publishing: bump version, add a CHANGELOG entry, run the gate, then
pnpm --filter @dreamlake/chat-embed publish --access public.
Local consumption from a sibling checkout uses a file: dependency — pnpm
copies it at install time, so rebuilds need a reinstall in the consumer.
