@openhex-ai/agent-sdk 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/react/ChatWidget.tsx","../../src/react/ChatBox.tsx","../../src/react/useOpenhexChat.ts","../../src/chat/events.ts","../../src/http/sse.ts","../../src/http/backoff.ts","../../src/errors.ts","../../src/chat/chatClient.ts","../../src/transport.ts","../../src/http/httpClient.ts","../../src/react/auth.ts","../../src/react/fold.ts","../../src/react/styles.ts","../../src/react/MarkdownView.tsx","../../src/react/markdown.ts","../../src/react/icons.tsx"],"sourcesContent":["/**\n * `<ChatWidget>` — a floating launcher bubble that opens a {@link ChatBox}\n * panel. The turnkey \"chat box on your page\" component: mount it once, pass a\n * token + agentId, and you get an Intercom-style widget that is full-screen on\n * mobile and a corner panel on desktop.\n *\n * Open state can be uncontrolled (`defaultOpen`) or controlled\n * (`open` + `onOpenChange`).\n */\nimport { useCallback, useState, type CSSProperties } from 'react';\nimport { ChatBox } from './ChatBox';\nimport { useInjectStyles } from './styles';\nimport { ChatIcon, CloseIcon } from './icons';\nimport type { ChatWidgetProps } from './types';\n\nexport function ChatWidget(props: ChatWidgetProps) {\n const {\n position = 'bottom-right',\n launcherIcon,\n launcherLabel = 'Open chat',\n defaultOpen = false,\n open: controlledOpen,\n onOpenChange,\n accentColor,\n injectStyles = true,\n className,\n ...boxProps\n } = props;\n\n useInjectStyles(injectStyles);\n const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);\n const isControlled = controlledOpen != null;\n const open = isControlled ? controlledOpen : uncontrolledOpen;\n\n const setOpen = useCallback(\n (next: boolean) => {\n if (!isControlled) setUncontrolledOpen(next);\n onOpenChange?.(next);\n },\n [isControlled, onOpenChange]\n );\n\n const launcherStyle: CSSProperties | undefined = accentColor\n ? { background: accentColor }\n : undefined;\n\n return (\n <>\n {open && (\n <div\n className={`ohx-panel ${position}`}\n role=\"dialog\"\n aria-label={boxProps.title ?? 'Chat'}\n >\n <ChatBox\n {...boxProps}\n accentColor={accentColor}\n className={`ohx-panel-inner${className ? ` ${className}` : ''}`}\n injectStyles={false}\n header={\n boxProps.header !== undefined ? (\n boxProps.header\n ) : (\n <div className=\"ohx-header\">\n {boxProps.avatarUrl && (\n <img className=\"ohx-avatar\" src={boxProps.avatarUrl} alt=\"\" />\n )}\n <div className=\"ohx-header-text\">\n <span className=\"ohx-title\">{boxProps.title ?? 'Chat'}</span>\n {boxProps.subtitle && <span className=\"ohx-subtitle\">{boxProps.subtitle}</span>}\n </div>\n <button\n type=\"button\"\n className=\"ohx-icon-btn\"\n onClick={() => setOpen(false)}\n aria-label=\"Close chat\"\n title=\"Close\"\n >\n <CloseIcon />\n </button>\n </div>\n )\n }\n />\n </div>\n )}\n <button\n type=\"button\"\n className={`ohx-launcher ${position}${open ? ' open-hidden' : ''}`}\n style={launcherStyle}\n onClick={() => setOpen(!open)}\n aria-label={open ? 'Close chat' : launcherLabel}\n aria-expanded={open}\n >\n {open ? <CloseIcon width={22} height={22} /> : (launcherIcon ?? <ChatIcon />)}\n </button>\n </>\n );\n}\n","/**\n * `<ChatBox>` — a complete, embeddable chat panel.\n *\n * Drop it into any layout (it fills its parent by default) and it renders a\n * header, a scrolling transcript, and a composer, wired to\n * {@link useOpenhexChat}. Zero external dependencies, themeable with a single\n * `accentColor` / `theme` prop, and responsive down to mobile.\n */\nimport {\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n} from 'react';\nimport { useOpenhexChat } from './useOpenhexChat';\nimport { useInjectStyles } from './styles';\nimport { Markdown } from './MarkdownView';\nimport { SendIcon, StopIcon } from './icons';\nimport type { ChatBoxProps, ChatMessage, ChatTheme } from './types';\n\n/** Resolve `auto` against the OS preference (re-evaluates on change). */\nfunction useResolvedTheme(theme: ChatTheme): 'light' | 'dark' {\n const getSystem = (): 'light' | 'dark' =>\n typeof window !== 'undefined' &&\n window.matchMedia &&\n window.matchMedia('(prefers-color-scheme: dark)').matches\n ? 'dark'\n : 'light';\n const [system, setSystem] = useState<'light' | 'dark'>(getSystem);\n useEffect(() => {\n if (theme !== 'auto' || typeof window === 'undefined' || !window.matchMedia) return;\n const mq = window.matchMedia('(prefers-color-scheme: dark)');\n const onChange = () => setSystem(mq.matches ? 'dark' : 'light');\n mq.addEventListener('change', onChange);\n return () => mq.removeEventListener('change', onChange);\n }, [theme]);\n return theme === 'auto' ? system : theme;\n}\n\nconst dim = (v: number | string | undefined): string | undefined =>\n typeof v === 'number' ? `${v}px` : v;\n\nfunction TypingDots() {\n return (\n <span className=\"ohx-typing\" aria-label=\"Assistant is typing\">\n <span />\n <span />\n <span />\n </span>\n );\n}\n\nfunction MessageBubble({ m, showToolCalls }: { m: ChatMessage; showToolCalls?: boolean }) {\n const showTyping = m.role === 'assistant' && m.text.length === 0 && (m.pending || m.streaming);\n return (\n <div className={`ohx-row ${m.role}`}>\n <div className={`ohx-bubble${m.error ? ' error' : ''}`}>\n {showTyping ? <TypingDots /> : <Markdown text={m.text} />}\n {showToolCalls && m.toolCalls && m.toolCalls.length > 0 && (\n <div className=\"ohx-tools\">\n {m.toolCalls.map((t, i) => (\n <span className=\"ohx-tool\" key={t.id ?? i}>\n {t.name}\n </span>\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n\nexport function ChatBox(props: ChatBoxProps) {\n const {\n title = 'Chat',\n subtitle,\n placeholder = 'Type a message…',\n greeting,\n avatarUrl,\n theme = 'light',\n accentColor,\n height,\n width,\n className,\n header,\n emptyState,\n footer,\n disabled = false,\n injectStyles = true,\n showToolCalls = false,\n } = props;\n\n useInjectStyles(injectStyles);\n const resolvedTheme = useResolvedTheme(theme);\n const chat = useOpenhexChat(props);\n const [input, setInput] = useState('');\n\n const scrollRef = useRef<HTMLDivElement>(null);\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n // Keep the transcript pinned to the newest message as it streams in.\n useLayoutEffect(() => {\n const el = scrollRef.current;\n if (el) el.scrollTop = el.scrollHeight;\n }, [chat.messages]);\n\n // Auto-grow the composer.\n useLayoutEffect(() => {\n const ta = textareaRef.current;\n if (!ta) return;\n ta.style.height = 'auto';\n ta.style.height = `${Math.min(ta.scrollHeight, 140)}px`;\n }, [input]);\n\n const submit = useCallback(() => {\n const text = input.trim();\n if (!text || chat.isResponding || disabled) return;\n setInput('');\n void chat.send(text);\n }, [input, chat, disabled]);\n\n const onKeyDown = useCallback(\n (e: KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey && !e.nativeEvent.isComposing) {\n e.preventDefault();\n submit();\n }\n },\n [submit]\n );\n\n const rootStyle = useMemo<CSSProperties>(() => {\n const s: CSSProperties = {};\n if (height != null) s.height = dim(height);\n if (width != null) s.width = dim(width);\n if (height == null) s.height = '100%';\n if (accentColor) (s as Record<string, string>)['--ohx-accent'] = accentColor;\n return s;\n }, [height, width, accentColor]);\n\n const showGreeting = chat.messages.length === 0 && chat.status !== 'connecting';\n const respondingLabel = chat.status === 'connecting' ? 'Connecting…' : subtitle;\n\n return (\n <div\n className={`ohx-root${className ? ` ${className}` : ''}`}\n data-theme={resolvedTheme}\n style={rootStyle}\n >\n {header === false ? null : header != null ? (\n header\n ) : (\n <div className=\"ohx-header\">\n {avatarUrl && <img className=\"ohx-avatar\" src={avatarUrl} alt=\"\" />}\n <div className=\"ohx-header-text\">\n <span className=\"ohx-title\">{title}</span>\n {(respondingLabel || chat.isResponding) && (\n <span className=\"ohx-subtitle\">\n {chat.isResponding ? respondingLabel || 'Typing…' : subtitle}\n </span>\n )}\n </div>\n </div>\n )}\n\n <div className=\"ohx-messages\" ref={scrollRef}>\n {showGreeting ? (\n emptyState != null ? (\n emptyState\n ) : greeting ? (\n <MessageBubble\n m={{ id: 'greeting', role: 'assistant', text: greeting, createdAt: 0 }}\n />\n ) : (\n <div className=\"ohx-empty\">Ask me anything to get started.</div>\n )\n ) : (\n chat.messages.map(m => <MessageBubble key={m.id} m={m} showToolCalls={showToolCalls} />)\n )}\n </div>\n\n {chat.status === 'error' && chat.error && (\n <div className=\"ohx-error-bar\" role=\"alert\">\n <span>{chat.error.message || 'Something went wrong.'}</span>\n <button type=\"button\" className=\"ohx-retry\" onClick={chat.retry}>\n Retry\n </button>\n </div>\n )}\n\n <div className=\"ohx-composer\">\n <textarea\n ref={textareaRef}\n className=\"ohx-textarea\"\n rows={1}\n value={input}\n placeholder={placeholder}\n disabled={disabled}\n onChange={e => setInput(e.target.value)}\n onKeyDown={onKeyDown}\n aria-label=\"Message\"\n />\n {chat.isResponding ? (\n <button\n type=\"button\"\n className=\"ohx-send stop\"\n onClick={chat.interrupt}\n aria-label=\"Stop\"\n title=\"Stop\"\n >\n <StopIcon />\n </button>\n ) : (\n <button\n type=\"button\"\n className=\"ohx-send\"\n onClick={submit}\n disabled={disabled || input.trim().length === 0}\n aria-label=\"Send\"\n title=\"Send\"\n >\n <SendIcon />\n </button>\n )}\n </div>\n\n {footer === false ? null : footer != null ? (\n <div className=\"ohx-footer\">{footer}</div>\n ) : (\n <div className=\"ohx-footer\">Powered by Openhex</div>\n )}\n </div>\n );\n}\n","/**\n * `useOpenhexChat` — the headless chat state hook.\n *\n * Wraps an {@link AgentChatClient} conversation in React state: it owns the\n * message list, streams each turn's reply into the last bubble, and exposes\n * `send` / `interrupt` / `retry` / `clear`. Build any UI on top of it, or use\n * the batteries-included {@link ChatBox} / {@link ChatWidget}.\n */\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { extractText, extractToolCalls, isAgentRecord } from '../chat/events';\nimport type { Conversation } from '../chat/chatClient';\nimport { resolveChatClient } from './auth';\nimport { foldRecords } from './fold';\nimport type {\n ChatMessage,\n ChatStatus,\n ChatToolCall,\n UseOpenhexChatOptions,\n UseOpenhexChatResult,\n} from './types';\n\n/** Monotonic id source for bubbles (stable React keys within a session). */\nfunction useIdFactory(): () => string {\n const counter = useRef(0);\n return useCallback(() => `m${counter.current++}`, []);\n}\n\nexport function useOpenhexChat(options: UseOpenhexChatOptions): UseOpenhexChatResult {\n const {\n agentId,\n conversationId: initialConversationId,\n senderName,\n senderAvatar,\n loadHistory = true,\n idleTimeoutMs,\n onTurnComplete,\n onError,\n } = options;\n\n const nextId = useIdFactory();\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [status, setStatus] = useState<ChatStatus>('idle');\n const [error, setError] = useState<Error | null>(null);\n const [conversationId, setConversationId] = useState<string | undefined>(initialConversationId);\n\n // Resolve the underlying client once per connection identity. `getToken` /\n // `fetch` identity intentionally isn't part of the key: `getToken` is\n // re-invoked per request anyway, so a new closure need not rebuild.\n const client = useMemo(\n () => resolveChatClient(options),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [options.client, options.baseUrl, options.token, options.actAs, options.loginType]\n );\n\n // The stateful conversation handle. Recreated when the client or the\n // routing target changes.\n const convoRef = useRef<Conversation | null>(null);\n useMemo(() => {\n convoRef.current = client.conversation({\n conversationId: initialConversationId,\n targetAgentIds: agentId ? [agentId] : undefined,\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, initialConversationId, agentId]);\n\n const abortRef = useRef<AbortController | null>(null);\n const lastUserTextRef = useRef<string | null>(null);\n // Latest callbacks without making them a dependency of `send`.\n const cbRef = useRef({ onTurnComplete, onError });\n cbRef.current = { onTurnComplete, onError };\n\n // Load prior history for a resumed conversation, once.\n const historyLoadedFor = useRef<string | null>(null);\n useEffect(() => {\n if (!loadHistory || !initialConversationId) return;\n if (historyLoadedFor.current === initialConversationId) return;\n historyLoadedFor.current = initialConversationId;\n let cancelled = false;\n (async () => {\n try {\n const { entries } = await client.messages(initialConversationId);\n if (cancelled) return;\n const prior = foldRecords(\n entries.map(e => e.data),\n 'h'\n );\n // Only seed if the user hasn't started typing/sending already.\n setMessages(cur => (cur.length === 0 ? prior : cur));\n } catch (err) {\n cbRef.current.onError?.(err instanceof Error ? err : new Error(String(err)));\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [client, initialConversationId, loadHistory]);\n\n const patch = useCallback((id: string, next: Partial<ChatMessage>) => {\n setMessages(cur => cur.map(m => (m.id === id ? { ...m, ...next } : m)));\n }, []);\n\n const runTurn = useCallback(\n async (text: string) => {\n const convo = convoRef.current;\n if (!convo) {\n const e = new Error(\n 'No target agent: pass { agentId } (for a new conversation) or { conversationId }.'\n );\n cbRef.current.onError?.(e);\n setError(e);\n setStatus('error');\n return;\n }\n\n lastUserTextRef.current = text;\n setError(null);\n const assistantId = nextId();\n setMessages(cur => [\n ...cur,\n { id: nextId(), role: 'user', text, createdAt: Date.now() },\n {\n id: assistantId,\n role: 'assistant',\n text: '',\n createdAt: Date.now(),\n pending: true,\n streaming: true,\n },\n ]);\n setStatus('connecting');\n\n const controller = new AbortController();\n abortRef.current = controller;\n let acc = '';\n let streaming = false;\n const tools: ChatToolCall[] = [];\n\n try {\n for await (const record of convo.stream(text, {\n signal: controller.signal,\n idleTimeoutMs,\n senderName,\n senderAvatar,\n })) {\n if (convo.id) setConversationId(convo.id);\n if (!isAgentRecord(record)) continue;\n acc += extractText(record);\n for (const t of extractToolCalls(record)) tools.push(t);\n patch(assistantId, {\n text: acc,\n pending: false,\n streaming: true,\n toolCalls: tools.length ? [...tools] : undefined,\n });\n if (!streaming) {\n streaming = true;\n setStatus('streaming');\n }\n }\n // Turn ended (result seen, or interrupted by the user's abort).\n const empty = acc.length === 0 && tools.length === 0;\n if (empty) {\n setMessages(cur => cur.filter(m => m.id !== assistantId));\n } else {\n patch(assistantId, { streaming: false, pending: false });\n }\n setStatus('idle');\n if (!empty) {\n cbRef.current.onTurnComplete?.({\n id: assistantId,\n role: 'assistant',\n text: acc,\n createdAt: Date.now(),\n toolCalls: tools.length ? tools : undefined,\n });\n }\n } catch (err) {\n const e = err instanceof Error ? err : new Error(String(err));\n // A user-initiated interrupt aborts the controller; that surfaces as\n // a clean stop, not an error.\n if (controller.signal.aborted) {\n const empty = acc.length === 0 && tools.length === 0;\n if (empty) setMessages(cur => cur.filter(m => m.id !== assistantId));\n else patch(assistantId, { streaming: false, pending: false });\n setStatus('idle');\n return;\n }\n patch(assistantId, { streaming: false, pending: false, error: true });\n setError(e);\n setStatus('error');\n cbRef.current.onError?.(e);\n } finally {\n if (abortRef.current === controller) abortRef.current = null;\n }\n },\n // `status` is read for a micro-optimization only; excluded to keep `send`\n // stable across renders.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [idleTimeoutMs, senderName, senderAvatar, nextId, patch]\n );\n\n const send = useCallback(\n async (text: string) => {\n const trimmed = text.trim();\n if (!trimmed || abortRef.current) return;\n await runTurn(trimmed);\n },\n [runTurn]\n );\n\n const interrupt = useCallback(() => {\n const convo = convoRef.current;\n // Stop reading the stream locally...\n abortRef.current?.abort();\n // ...and ask the server to stop the running turn.\n void convo?.interrupt().catch(() => {});\n }, []);\n\n const retry = useCallback(() => {\n if (abortRef.current) return;\n const last = lastUserTextRef.current;\n if (last) void runTurn(last);\n }, [runTurn]);\n\n const clear = useCallback(() => {\n abortRef.current?.abort();\n abortRef.current = null;\n lastUserTextRef.current = null;\n historyLoadedFor.current = null;\n setMessages([]);\n setError(null);\n setStatus('idle');\n setConversationId(undefined);\n convoRef.current = client.conversation({\n targetAgentIds: agentId ? [agentId] : undefined,\n });\n }, [client, agentId]);\n\n // Abort any in-flight turn on unmount.\n useEffect(() => () => abortRef.current?.abort(), []);\n\n const isResponding = status === 'connecting' || status === 'streaming';\n\n return {\n messages,\n status,\n error,\n conversationId,\n isResponding,\n send,\n interrupt,\n retry,\n clear,\n };\n}\n","/**\n * Helpers for interpreting conversation stream records.\n *\n * The wire protocol nests the agent-runtime event inside `record.raw`.\n * These functions encapsulate the discriminants the user-side apps key\n * on (turn completion, text extraction, tool calls) so consumers don't\n * reach into `raw` by hand.\n */\nimport type { ContentBlock } from '../types/messages';\nimport type { ChatStreamRecord } from './types';\n\n/** True when a record is from the agent (1:1 `assistant` or multi-agent `agent`). */\nexport function isAgentRecord(record: ChatStreamRecord): boolean {\n return record.sender === 'assistant' || record.sender === 'agent';\n}\n\n/** True when a record marks the end of an agent turn. */\nexport function isTurnComplete(record: ChatStreamRecord): boolean {\n return isAgentRecord(record) && record.raw?.type === 'result';\n}\n\n/** True when a record is an interruption acknowledgement. */\nexport function isInterrupt(record: ChatStreamRecord): boolean {\n return record.sender === 'system' && (record.raw as { subtype?: string })?.subtype === 'interrupt';\n}\n\n/** Content blocks inside a record's message, if any. */\nfunction contentBlocks(record: ChatStreamRecord): ContentBlock[] {\n const msg = (record.raw as { message?: unknown }).message;\n if (msg && typeof msg === 'object' && Array.isArray((msg as { content?: unknown }).content)) {\n return (msg as { content: ContentBlock[] }).content;\n }\n return [];\n}\n\n/** Extract plain text from a record (empty string if none). */\nexport function extractText(record: ChatStreamRecord): string {\n // A user message can be a bare string.\n if (record.raw?.type === 'user' && typeof (record.raw as { message?: unknown }).message === 'string') {\n return (record.raw as { message: string }).message;\n }\n return contentBlocks(record)\n .filter((b): b is Extract<ContentBlock, { type: 'text' }> => b.type === 'text')\n .map((b) => b.text)\n .join('');\n}\n\n/** Extract tool_use calls from a record (empty array if none). */\nexport function extractToolCalls(\n record: ChatStreamRecord,\n): Array<{ id?: string; name: string; input: Record<string, unknown> }> {\n return contentBlocks(record)\n .filter((b): b is Extract<ContentBlock, { type: 'tool_use' }> => b.type === 'tool_use')\n .map((b) => ({ id: b.id, name: b.name, input: b.input }));\n}\n","/**\n * Server-Sent Events parser.\n *\n * Turns a `ReadableStream<Uint8Array>` (a fetch response body) into an\n * async iterable of parsed SSE messages. Handles the platform's wire\n * quirks: `id:` cursor lines, `: heartbeat` / `: <padding>` comment lines\n * (the ALB-flush padding), multi-line `data:` fields, and the `[DONE]`\n * sentinel.\n */\n\nexport interface SSEMessage {\n /** Last `id:` seen — the resumable cursor (Redis stream id). */\n id?: string;\n /** `event:` field, if any. */\n event?: string;\n /** Concatenated `data:` payload (newline-joined per the SSE spec). */\n data: string;\n}\n\n/** Strip exactly one leading space after the colon, per the SSE spec. */\nfunction fieldValue(raw: string): string {\n return raw.startsWith(' ') ? raw.slice(1) : raw;\n}\n\n/**\n * Parse an SSE byte stream into messages. Yields one {@link SSEMessage}\n * per event (blank-line terminated). Comment lines (starting with `:`)\n * are ignored except that they keep the connection's `lastId` intact.\n */\nexport async function* parseSSEStream(\n stream: ReadableStream<Uint8Array>,\n signal?: AbortSignal,\n): AsyncGenerator<SSEMessage, void, void> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let dataLines: string[] = [];\n let eventType: string | undefined;\n let lastId: string | undefined;\n\n const onAbort = () => {\n reader.cancel().catch(() => {});\n };\n if (signal) {\n if (signal.aborted) onAbort();\n else signal.addEventListener('abort', onAbort, { once: true });\n }\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n\n // Process complete lines; keep the trailing partial in `buffer`.\n let nlIndex: number;\n while ((nlIndex = buffer.indexOf('\\n')) !== -1) {\n let line = buffer.slice(0, nlIndex);\n buffer = buffer.slice(nlIndex + 1);\n if (line.endsWith('\\r')) line = line.slice(0, -1);\n\n if (line === '') {\n // Blank line — dispatch the accumulated event.\n if (dataLines.length > 0) {\n yield { id: lastId, event: eventType, data: dataLines.join('\\n') };\n }\n dataLines = [];\n eventType = undefined;\n continue;\n }\n if (line.startsWith(':')) continue; // comment / heartbeat / padding\n\n const colon = line.indexOf(':');\n const field = colon === -1 ? line : line.slice(0, colon);\n const rawVal = colon === -1 ? '' : line.slice(colon + 1);\n const val = fieldValue(rawVal);\n\n switch (field) {\n case 'data':\n dataLines.push(val);\n break;\n case 'id':\n lastId = val;\n break;\n case 'event':\n eventType = val;\n break;\n // `retry` and unknown fields are ignored.\n }\n }\n }\n // Flush a final event with no trailing blank line.\n if (dataLines.length > 0) {\n yield { id: lastId, event: eventType, data: dataLines.join('\\n') };\n }\n } finally {\n signal?.removeEventListener('abort', onAbort);\n reader.releaseLock();\n }\n}\n","/**\n * Capped exponential backoff — mirrors the web client's SSE reconnect\n * policy (1s → 2s → 4s → 8s → 15s cap) so reconnection behavior matches\n * the user-side apps.\n */\nexport interface BackoffOptions {\n initialMs?: number;\n maxMs?: number;\n factor?: number;\n}\n\nexport class Backoff {\n private attempt = 0;\n private readonly initialMs: number;\n private readonly maxMs: number;\n private readonly factor: number;\n\n constructor(opts: BackoffOptions = {}) {\n this.initialMs = opts.initialMs ?? 1_000;\n this.maxMs = opts.maxMs ?? 15_000;\n this.factor = opts.factor ?? 2;\n }\n\n /** Next delay in ms (advances the attempt counter). */\n next(): number {\n const delay = Math.min(this.maxMs, this.initialMs * Math.pow(this.factor, this.attempt));\n this.attempt += 1;\n return delay;\n }\n\n /** Reset after a successful connection. */\n reset(): void {\n this.attempt = 0;\n }\n}\n\n/** Promise that resolves after `ms`, rejecting if `signal` aborts first. */\nexport function delay(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(new DOMException('Aborted', 'AbortError'));\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(timer);\n reject(new DOMException('Aborted', 'AbortError'));\n };\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n","/**\n * Error types thrown by the Openhex Agent SDK.\n *\n * NOTE: scaffold only — these are the shapes consumers should `catch`;\n * the runtime throws them once wired up.\n */\n\n/** Base class for every error the SDK raises. */\nexport class OpenhexSdkError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'OpenhexSdkError';\n }\n}\n\n/** Thrown when no API key is resolvable from options or the environment. */\nexport class AuthenticationError extends OpenhexSdkError {\n constructor(message = 'No Openhex API key provided. Set OPENHEX_API_KEY or pass { apiKey }.') {\n super(message);\n this.name = 'AuthenticationError';\n }\n}\n\n/** Thrown when the platform rejects a request (non-2xx response). */\nexport class ApiError extends OpenhexSdkError {\n constructor(\n message: string,\n readonly status: number,\n readonly body?: unknown\n ) {\n super(message);\n this.name = 'ApiError';\n }\n}\n\n/** Thrown when an agent run aborts before producing a result. */\nexport class AbortError extends OpenhexSdkError {\n constructor(message = 'The agent run was aborted.') {\n super(message);\n this.name = 'AbortError';\n }\n}\n\n/**\n * Placeholder thrown by every scaffolded entry point until the runtime\n * is implemented. Lets the public surface compile and be imported while\n * making partial wiring obvious at call time.\n */\nexport class NotImplementedError extends OpenhexSdkError {\n constructor(what: string) {\n super(`Not implemented yet: ${what}. This is a scaffold — runtime lands in a follow-up MR.`);\n this.name = 'NotImplementedError';\n }\n}\n","/**\n * AgentChatClient — chat with a platform agent over the exact protocol\n * the user-side apps use (`conversationRoutes`).\n *\n * Endpoints (all under `/api/v2`):\n * POST /conversations/send — create/continue a conversation, route a message\n * GET /conversations/:id/stream — SSE record stream (resumable)\n * GET /conversations/:id/messages — full history (JSON)\n * GET /conversations/:id/history — paginated older history (JSON)\n * POST /conversations/:id/interrupt — interrupt the running turn\n *\n * Low-level methods (`send`, `stream`, `messages`, `history`, `interrupt`)\n * map 1:1 to the wire. High-level helpers (`runTurn`, `sendMessage`) add\n * turn isolation (resume the stream from the user message's event id),\n * reconnection, and an idle-timeout for cold-start pod provisioning.\n */\nimport { HttpClient } from '../http/httpClient';\nimport { parseSSEStream, type SSEMessage } from '../http/sse';\nimport { Backoff, delay } from '../http/backoff';\nimport { AbortError } from '../errors';\nimport { extractText, extractToolCalls, isTurnComplete } from './events';\nimport type {\n AgentTurn,\n ChatStreamRecord,\n HistoryPage,\n InterruptResult,\n SendRequest,\n SendResult,\n StreamOptions,\n TurnOptions,\n} from './types';\n\n/** Merge several abort signals into one, with cleanup. */\nfunction anySignal(signals: Array<AbortSignal | undefined>): {\n signal: AbortSignal;\n cleanup: () => void;\n} {\n const controller = new AbortController();\n const handlers: Array<[AbortSignal, () => void]> = [];\n for (const s of signals) {\n if (!s) continue;\n if (s.aborted) {\n controller.abort((s as AbortSignal & { reason?: unknown }).reason);\n break;\n }\n const handler = () => controller.abort((s as AbortSignal & { reason?: unknown }).reason);\n s.addEventListener('abort', handler, { once: true });\n handlers.push([s, handler]);\n }\n return {\n signal: controller.signal,\n cleanup: () => handlers.forEach(([s, h]) => s.removeEventListener('abort', h)),\n };\n}\n\n/** Parse an SSE message into a {@link ChatStreamRecord}, or null to skip. */\nfunction parseRecord(evt: SSEMessage): ChatStreamRecord | null {\n if (evt.data === '[DONE]') return null;\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(evt.data) as Record<string, unknown>;\n } catch {\n return null;\n }\n // Initial-load pagination marker and error frames aren't records.\n if (parsed._meta === true) return null;\n const record = parsed as unknown as ChatStreamRecord;\n if (evt.id) record.id = evt.id;\n return record;\n}\n\nexport class AgentChatClient {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Create or continue a conversation and route a message to its agent(s).\n * Returns immediately (non-blocking); consume {@link stream} for the reply.\n */\n async send(req: SendRequest, opts: { signal?: AbortSignal } = {}): Promise<SendResult> {\n return this.http.requestJson<SendResult>('/conversations/send', {\n method: 'POST',\n body: req,\n signal: opts.signal,\n });\n }\n\n /** Interrupt the conversation's currently-running turn. */\n async interrupt(conversationId: string, opts: { signal?: AbortSignal } = {}): Promise<InterruptResult> {\n return this.http.requestJson<InterruptResult>(`/conversations/${conversationId}/interrupt`, {\n method: 'POST',\n signal: opts.signal,\n });\n }\n\n /** Full conversation history (all messages as JSON). */\n async messages(\n conversationId: string,\n opts: { signal?: AbortSignal } = {},\n ): Promise<{ entries: Array<{ id: string; data: ChatStreamRecord }> }> {\n return this.http.requestJson(`/conversations/${conversationId}/messages`, { signal: opts.signal });\n }\n\n /** A page of older history, before a cursor. */\n async history(\n conversationId: string,\n params: { before: string; turns?: number; maxEntries?: number },\n opts: { signal?: AbortSignal } = {},\n ): Promise<HistoryPage> {\n const q = new URLSearchParams({ before: params.before });\n if (params.turns != null) q.set('turns', String(params.turns));\n if (params.maxEntries != null) q.set('maxEntries', String(params.maxEntries));\n return this.http.requestJson(`/conversations/${conversationId}/history?${q.toString()}`, {\n signal: opts.signal,\n });\n }\n\n /**\n * Open the conversation's SSE record stream. Yields every record\n * (replayed history then live tail), auto-reconnecting with capped\n * backoff on drop. The generator ends when the consumer breaks/returns\n * or `signal` aborts.\n */\n async *stream(\n conversationId: string,\n opts: StreamOptions = {},\n ): AsyncGenerator<ChatStreamRecord, void, void> {\n const { signal, reconnect = true } = opts;\n let cursor = opts.lastEventId;\n const backoff = new Backoff();\n const internal = new AbortController();\n const onAbort = () => internal.abort();\n if (signal) {\n if (signal.aborted) internal.abort();\n else signal.addEventListener('abort', onAbort, { once: true });\n }\n\n const buildPath = () => {\n const q = new URLSearchParams();\n if (cursor) q.set('lastEventId', cursor);\n if (opts.turns != null) q.set('turns', String(opts.turns));\n if (opts.maxEntries != null) q.set('maxEntries', String(opts.maxEntries));\n const qs = q.toString();\n return `/conversations/${conversationId}/stream${qs ? `?${qs}` : ''}`;\n };\n\n try {\n while (!internal.signal.aborted) {\n let body: ReadableStream<Uint8Array> | null = null;\n try {\n const response = await this.http.requestRaw(\n buildPath(),\n { signal: internal.signal, timeoutMs: 0 },\n 'text/event-stream',\n );\n body = response.body as ReadableStream<Uint8Array> | null;\n backoff.reset();\n } catch (err) {\n if (internal.signal.aborted) return;\n if (!reconnect) throw err;\n await delay(backoff.next(), internal.signal);\n continue;\n }\n\n if (body) {\n try {\n for await (const evt of parseSSEStream(body, internal.signal)) {\n if (evt.data === '[DONE]') return;\n const record = parseRecord(evt);\n if (!record) continue;\n cursor = record.id ?? evt.id ?? cursor;\n yield record;\n }\n } catch (err) {\n if (internal.signal.aborted) return;\n if (!reconnect) throw err;\n // fall through to reconnect\n }\n }\n\n if (!reconnect || internal.signal.aborted) return;\n await delay(backoff.next(), internal.signal);\n }\n } finally {\n signal?.removeEventListener('abort', onAbort);\n internal.abort();\n }\n }\n\n /**\n * Stream a single turn over an existing conversation: resume the event\n * stream strictly after `opts.lastEventId` (the user message's event id)\n * and stop at the agent's terminal `result`. Reconnects on drop; an\n * `idleTimeoutMs` gap with no events aborts (covers cold-start pod\n * provisioning). Use when you sent the message yourself via {@link send}.\n */\n async *resumeTurn(\n conversationId: string,\n opts: TurnOptions & { lastEventId?: string } = {},\n ): AsyncGenerator<ChatStreamRecord, void, void> {\n const { signal, idleTimeoutMs = 180_000 } = opts;\n const cursor = opts.lastEventId;\n const idleController = new AbortController();\n const merged = anySignal([signal, idleController.signal]);\n let idleTimer: ReturnType<typeof setTimeout> | undefined;\n const armIdle = () => {\n if (idleTimer) clearTimeout(idleTimer);\n idleTimer = setTimeout(() => idleController.abort(new Error('idle timeout')), idleTimeoutMs);\n };\n\n armIdle();\n try {\n for await (const record of this.stream(conversationId, {\n lastEventId: cursor,\n signal: merged.signal,\n })) {\n armIdle();\n yield record;\n if (isTurnComplete(record)) return;\n }\n if (idleController.signal.aborted && !signal?.aborted) {\n throw new AbortError('Turn timed out waiting for the agent to respond.');\n }\n } finally {\n if (idleTimer) clearTimeout(idleTimer);\n merged.cleanup();\n idleController.abort();\n }\n }\n\n /**\n * Send a message and stream just this turn's records, ending when the\n * agent's `result` event arrives.\n *\n * The message is sent first; the stream then resumes precisely from the\n * user message's event id, so only the agent's reply is surfaced — no\n * history, no heuristics. To learn the (possibly new) conversation id\n * while streaming, use {@link sendMessage} or the stateful\n * {@link Conversation}.\n *\n * The first message in a new conversation auto-provisions the agent's\n * pod, so the first turn can take tens of seconds before any record\n * arrives; `idleTimeoutMs` (default 180s) bounds the wait.\n */\n async *runTurn(req: SendRequest, opts: TurnOptions = {}): AsyncGenerator<ChatStreamRecord, void, void> {\n const result = await this.send(req, { signal: opts.signal });\n yield* this.resumeTurn(result.conversationId, { ...opts, lastEventId: result.userEventId });\n }\n\n /**\n * Send a message and resolve with the aggregated turn (assistant text,\n * tool calls, all records, conversation id, and a resume cursor).\n */\n async sendMessage(req: SendRequest, opts: TurnOptions = {}): Promise<AgentTurn> {\n const result = await this.send(req, { signal: opts.signal });\n const turn: AgentTurn = {\n conversationId: result.conversationId,\n text: '',\n toolCalls: [],\n records: [],\n sessionId: null,\n };\n for await (const record of this.resumeTurn(result.conversationId, {\n ...opts,\n lastEventId: result.userEventId,\n })) {\n turn.records.push(record);\n if (record.id) turn.lastEventId = record.id;\n if (record.sessionId) turn.sessionId = record.sessionId;\n if (record.sender === 'assistant' || record.sender === 'agent') {\n turn.text += extractText(record);\n turn.toolCalls.push(...extractToolCalls(record));\n }\n if (isTurnComplete(record)) turn.result = record.raw;\n }\n return turn;\n }\n\n /**\n * Start a stateful conversation handle that remembers its id across\n * turns. The first {@link Conversation.send} creates the conversation\n * (routed to `targetAgentIds`); subsequent sends continue it.\n */\n conversation(opts: { conversationId?: string; targetAgentIds?: string[] } = {}): Conversation {\n return new Conversation(this, opts.conversationId, opts.targetAgentIds);\n }\n}\n\n/**\n * A stateful 1:1 (or multi-agent) conversation. Tracks the conversation\n * id so you can `send` repeated turns without re-passing it, and continues\n * the same chat-group context each time.\n */\nexport class Conversation {\n constructor(\n private readonly client: AgentChatClient,\n private conversationId: string | undefined,\n private readonly targetAgentIds: string[] | undefined,\n ) {}\n\n /** The conversation id, once the first message has been sent. */\n get id(): string | undefined {\n return this.conversationId;\n }\n\n /** Build the send request for the next turn (create vs continue). */\n private buildRequest(message: string, extra?: Partial<SendRequest>): SendRequest {\n return this.conversationId\n ? { message, conversationId: this.conversationId, ...extra }\n : { message, targetAgentIds: this.targetAgentIds, ...extra };\n }\n\n /** Send a turn and resolve with the aggregated result. */\n async send(message: string, opts: TurnOptions & Partial<SendRequest> = {}): Promise<AgentTurn> {\n const turn = await this.client.sendMessage(this.buildRequest(message, opts), opts);\n this.conversationId = turn.conversationId;\n return turn;\n }\n\n /** Send a turn and stream its records as they arrive. */\n async *stream(\n message: string,\n opts: TurnOptions & Partial<SendRequest> = {},\n ): AsyncGenerator<ChatStreamRecord, void, void> {\n // Resolve/lock the conversation id up front so it's known while streaming.\n const sent = await this.client.send(this.buildRequest(message, opts), { signal: opts.signal });\n this.conversationId = sent.conversationId;\n yield* this.client.resumeTurn(sent.conversationId, {\n ...opts,\n lastEventId: sent.userEventId,\n });\n }\n\n /** Interrupt the running turn in this conversation. */\n async interrupt(): Promise<InterruptResult> {\n if (!this.conversationId) return { ok: true, interrupted: false, reason: 'No conversation yet' };\n return this.client.interrupt(this.conversationId);\n }\n}\n","/**\n * Transport layer.\n *\n * The transport is the seam between the SDK's agent loop and the Openhex\n * platform. Swapping it (HTTP today, websocket later, an in-memory fake\n * for tests) leaves the rest of the SDK untouched.\n *\n * NOTE: scaffold only — `HttpTransport` is a stub. The concrete\n * request/stream implementation lands in a follow-up MR.\n */\nimport type { AgentOptions } from './types/options';\nimport type { SDKMessage } from './types/messages';\nimport { NotImplementedError } from './errors';\n\n/** Normalized request to start an agent run. */\nexport interface RunRequest {\n prompt: string;\n options: AgentOptions;\n}\n\n/**\n * A transport knows how to open an agent run against the platform and\n * surface the resulting message stream.\n */\nexport interface Transport {\n /** Start a run and stream back {@link SDKMessage}s as they arrive. */\n run(request: RunRequest): AsyncGenerator<SDKMessage, void, void>;\n}\n\n/** Default transport: talks to the Openhex REST/streaming API over HTTPS. */\nexport class HttpTransport implements Transport {\n constructor(private readonly opts: { apiKey: string; baseUrl: string }) {}\n\n // eslint-disable-next-line require-yield\n async *run(_request: RunRequest): AsyncGenerator<SDKMessage, void, void> {\n throw new NotImplementedError('HttpTransport.run');\n }\n}\n\n/** Production default base URL for the Openhex platform API. */\nexport const DEFAULT_BASE_URL = 'https://api.openhex.tech';\n","/**\n * Thin HTTP layer for the Openhex platform API.\n *\n * Centralizes base-URL resolution, auth-header injection, JSON\n * (de)serialization, request timeouts, and error mapping so the chat\n * client (and future resource clients) stay focused on protocol logic.\n *\n * Auth mirrors the platform's user-side apps: an `Authorization: Bearer`\n * header carrying either a `mysta_*` API key or a JWT. Optional\n * `X-Login-Type` / `X-Act-As` headers match the app + service-account\n * impersonation paths.\n */\nimport { ApiError, AuthenticationError } from '../errors';\nimport { DEFAULT_BASE_URL } from '../transport';\n\n/** API version prefix every platform route lives under. */\nexport const API_PREFIX = '/api/v2';\n\nexport interface HttpClientConfig {\n /** API key or JWT. Falls back to `OPENHEX_API_KEY` when omitted. */\n apiKey?: string;\n /** Base URL of the platform API. Defaults to {@link DEFAULT_BASE_URL}. */\n baseUrl?: string;\n /**\n * Login type stamped as `X-Login-Type` (matches the web/app clients).\n * Only relevant for JWT auth; harmless to omit for API-key auth.\n */\n loginType?: string;\n /**\n * Service-account id to impersonate via `X-Act-As`. The caller must own\n * the service account (enforced server-side).\n */\n actAs?: string;\n /** Extra headers merged into every request. */\n headers?: Record<string, string>;\n /** Per-request timeout for non-streaming calls (ms). Default 30_000. */\n timeoutMs?: number;\n /** Override the global fetch (testing / custom agents). */\n fetch?: typeof fetch;\n}\n\nexport interface RequestOptions {\n method?: string;\n /** JSON-serializable request body. */\n body?: unknown;\n /** Extra/override headers for this request. */\n headers?: Record<string, string>;\n /** Caller-supplied abort signal (merged with the timeout signal). */\n signal?: AbortSignal;\n /** Override the default timeout for this request (ms). 0 disables it. */\n timeoutMs?: number;\n}\n\n/** Resolve the API key from explicit config or the environment, or throw. */\nfunction resolveApiKey(apiKey: string | undefined): string {\n const key = apiKey ?? (typeof process !== 'undefined' ? process.env?.OPENHEX_API_KEY : undefined);\n if (!key) throw new AuthenticationError();\n return key;\n}\n\n/** Combine an optional caller signal with a timeout into one signal. */\nfunction withTimeout(\n signal: AbortSignal | undefined,\n timeoutMs: number,\n): { signal: AbortSignal; cancel: () => void } {\n if (!timeoutMs || timeoutMs <= 0) {\n return { signal: signal ?? new AbortController().signal, cancel: () => {} };\n }\n const controller = new AbortController();\n const onAbort = () => controller.abort((signal as AbortSignal & { reason?: unknown })?.reason);\n if (signal) {\n if (signal.aborted) controller.abort();\n else signal.addEventListener('abort', onAbort, { once: true });\n }\n const timer = setTimeout(() => controller.abort(new Error(`Request timed out after ${timeoutMs}ms`)), timeoutMs);\n return {\n signal: controller.signal,\n cancel: () => {\n clearTimeout(timer);\n signal?.removeEventListener('abort', onAbort);\n },\n };\n}\n\nexport class HttpClient {\n private readonly apiKey: string;\n readonly baseUrl: string;\n private readonly loginType?: string;\n private readonly actAs?: string;\n private readonly extraHeaders: Record<string, string>;\n private readonly timeoutMs: number;\n private readonly fetchImpl: typeof fetch;\n\n constructor(config: HttpClientConfig = {}) {\n this.apiKey = resolveApiKey(config.apiKey);\n this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, '');\n this.loginType = config.loginType;\n this.actAs = config.actAs;\n this.extraHeaders = config.headers ?? {};\n this.timeoutMs = config.timeoutMs ?? 30_000;\n const f = config.fetch ?? (typeof fetch !== 'undefined' ? fetch : undefined);\n if (!f) {\n throw new Error('No fetch implementation available. Pass { fetch } in the client config.');\n }\n // Bind so `this` doesn't leak into the platform fetch.\n this.fetchImpl = f.bind(globalThis);\n }\n\n /** Build the full URL for an API path (prefixing `/api/v2` if needed). */\n url(path: string): string {\n if (/^https?:\\/\\//.test(path)) return path;\n const p = path.startsWith('/') ? path : `/${path}`;\n const withPrefix = p.startsWith(API_PREFIX) ? p : `${API_PREFIX}${p}`;\n return `${this.baseUrl}${withPrefix}`;\n }\n\n /** Headers common to every request. `accept` differs for SSE vs JSON. */\n buildHeaders(accept: string, extra?: Record<string, string>): Record<string, string> {\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n Accept: accept,\n ...this.extraHeaders,\n ...extra,\n };\n if (this.loginType) headers['X-Login-Type'] = this.loginType;\n if (this.actAs) headers['X-Act-As'] = this.actAs;\n return headers;\n }\n\n /** Map a non-2xx response to an {@link ApiError}, extracting `detail`. */\n private async toError(response: Response): Promise<ApiError> {\n let body: unknown;\n let detail: string | undefined;\n try {\n body = await response.json();\n detail = (body as { detail?: string })?.detail;\n } catch {\n try {\n detail = await response.text();\n } catch {\n /* ignore */\n }\n }\n if (response.status === 401 || response.status === 403) {\n return new ApiError(detail || 'Unauthorized', response.status, body);\n }\n return new ApiError(detail || `Request failed with status ${response.status}`, response.status, body);\n }\n\n /** Perform a JSON request and parse the response body. */\n async requestJson<T = unknown>(path: string, options: RequestOptions = {}): Promise<T> {\n const response = await this.requestRaw(path, options, 'application/json');\n if (response.status === 204) return undefined as T;\n return (await response.json()) as T;\n }\n\n /** Perform a request and return the raw {@link Response} (used for SSE). */\n async requestRaw(path: string, options: RequestOptions = {}, accept = 'application/json'): Promise<Response> {\n const { method = 'GET', body, headers, signal } = options;\n const timeoutMs = options.timeoutMs ?? this.timeoutMs;\n const { signal: combined, cancel } = withTimeout(signal, timeoutMs);\n\n const reqHeaders = this.buildHeaders(accept, headers);\n if (body !== undefined) reqHeaders['Content-Type'] = 'application/json';\n\n let response: Response;\n try {\n response = await this.fetchImpl(this.url(path), {\n method,\n headers: reqHeaders,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n signal: combined,\n });\n } finally {\n // For streaming responses we must NOT cancel the timeout here, or it\n // would abort mid-stream — callers of requestRaw for SSE pass\n // timeoutMs:0. For JSON it's already resolved.\n if (accept !== 'text/event-stream') cancel();\n }\n\n if (!response.ok) {\n if (accept !== 'text/event-stream') cancel();\n throw await this.toError(response);\n }\n return response;\n }\n}\n","/**\n * Browser-safe client resolution for the React chat layer.\n *\n * Turns the loose {@link OpenhexChatConnection} props into a concrete\n * {@link AgentChatClient}. The important bit is `getToken`: rather than\n * baking a token into the client at construction (the core `HttpClient`\n * reads `apiKey` once), we wrap `fetch` so a fresh token is injected on the\n * `Authorization` header of every request. That lets a browser widget rotate\n * an expiring member-session JWT without re-mounting.\n */\nimport { AgentChatClient } from '../chat/chatClient';\nimport { HttpClient } from '../http/httpClient';\nimport { OpenhexClient } from '../client';\nimport type { OpenhexChatConnection } from './types';\n\n/** A pre-built client is either the top-level client or the chat client. */\nfunction isAgentChatClient(c: unknown): c is AgentChatClient {\n return c instanceof AgentChatClient;\n}\n\n/**\n * Wrap a fetch so every request carries `Authorization: Bearer <token>` from\n * `getToken()`. Any auth header the caller set is overwritten, so the token\n * is always current.\n */\nfunction tokenInjectingFetch(\n baseFetch: typeof fetch,\n getToken: () => string | Promise<string>\n): typeof fetch {\n const wrapped = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const token = await getToken();\n const headers = new Headers(init?.headers ?? {});\n headers.set('Authorization', `Bearer ${token}`);\n return baseFetch(input, { ...init, headers });\n };\n return wrapped as typeof fetch;\n}\n\n/**\n * Resolve the {@link OpenhexChatConnection} props into an\n * {@link AgentChatClient}. Throws if neither a client nor any credential is\n * provided.\n */\nexport function resolveChatClient(conn: OpenhexChatConnection): AgentChatClient {\n if (conn.client) {\n return isAgentChatClient(conn.client) ? conn.client : conn.client.chat;\n }\n\n if (!conn.token && !conn.getToken) {\n throw new Error(\n 'useOpenhexChat needs a credential: pass { token } or { getToken } (a member session ' +\n 'token minted on your backend), or a ready-made { client }.'\n );\n }\n\n const baseFetch =\n conn.fetch ?? (typeof fetch !== 'undefined' ? fetch.bind(globalThis) : undefined);\n if (!baseFetch) {\n throw new Error('No fetch implementation available. Pass { fetch } in the connection options.');\n }\n\n const http = new HttpClient({\n // With `getToken`, the real token is injected per-request by the wrapped\n // fetch below; `apiKey` just satisfies HttpClient's non-empty check.\n apiKey: conn.token ?? 'session',\n baseUrl: conn.baseUrl,\n loginType: conn.loginType,\n actAs: conn.actAs,\n fetch: conn.getToken ? tokenInjectingFetch(baseFetch, conn.getToken) : baseFetch,\n });\n return new AgentChatClient(http);\n}\n\n/** Re-export so callers can narrow without importing the client module. */\nexport { OpenhexClient };\n","/**\n * Fold a chronological run of stream records into render-ready\n * {@link ChatMessage} bubbles.\n *\n * The wire emits one record per assistant/user event; the UI wants one\n * bubble per turn. This groups consecutive agent records into a single\n * assistant bubble and turns each user record into its own bubble — the same\n * grouping the live streaming path performs, reused for loading history.\n *\n * Pure and side-effect free so it can be unit-tested without React.\n */\nimport { extractText, extractToolCalls, isAgentRecord } from '../chat/events';\nimport type { ChatStreamRecord } from '../chat/types';\nimport type { ChatMessage } from './types';\n\n/** Fold records (oldest first) into chat bubbles, dropping empty ones. */\nexport function foldRecords(records: ChatStreamRecord[], idPrefix = 'h'): ChatMessage[] {\n const out: ChatMessage[] = [];\n let current: ChatMessage | null = null;\n let n = 0;\n\n const flush = () => {\n if (current && (current.text.length > 0 || (current.toolCalls?.length ?? 0) > 0)) {\n out.push(current);\n }\n current = null;\n };\n\n for (const record of records) {\n const createdAt = typeof record.timestamp === 'number' ? record.timestamp : 0;\n if (record.sender === 'user') {\n flush();\n const text = extractText(record);\n if (text.length > 0) {\n out.push({ id: `${idPrefix}${n++}`, role: 'user', text, createdAt });\n }\n continue;\n }\n if (isAgentRecord(record)) {\n if (!current) {\n current = {\n id: `${idPrefix}${n++}`,\n role: 'assistant',\n text: '',\n createdAt,\n toolCalls: [],\n };\n }\n current.text += extractText(record);\n const tools = extractToolCalls(record);\n if (tools.length > 0) current.toolCalls = [...(current.toolCalls ?? []), ...tools];\n continue;\n }\n // system / control records are not rendered as bubbles.\n }\n flush();\n // Normalize: drop the empty toolCalls array we seeded on assistant bubbles.\n return out.map(m =>\n m.toolCalls && m.toolCalls.length === 0 ? { ...m, toolCalls: undefined } : m\n );\n}\n","/**\n * Self-contained, scoped styles for the chat components.\n *\n * All selectors are namespaced under `.ohx-root` and every color is a CSS\n * custom property, so the widget themes with one prop and never leaks styles\n * into (or inherits surprises from) the host page. Injected once into\n * `<head>` at runtime; pass `injectStyles={false}` to ship your own CSS.\n */\nimport { useEffect } from 'react';\n\nexport const STYLE_ELEMENT_ID = 'ohx-chat-styles';\n\nexport const CHAT_CSS = `\n.ohx-root {\n --ohx-accent: #4f46e5;\n --ohx-accent-contrast: #ffffff;\n --ohx-bg: #ffffff;\n --ohx-surface: #f7f7f8;\n --ohx-fg: #1f2328;\n --ohx-muted: #6b7280;\n --ohx-border: #e5e7eb;\n --ohx-user-bg: var(--ohx-accent);\n --ohx-user-fg: var(--ohx-accent-contrast);\n --ohx-assistant-bg: #f1f2f4;\n --ohx-assistant-fg: #1f2328;\n --ohx-radius: 16px;\n --ohx-font: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"PingFang SC\", \"Microsoft YaHei\", sans-serif;\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n background: var(--ohx-bg);\n color: var(--ohx-fg);\n font-family: var(--ohx-font);\n font-size: 14px;\n line-height: 1.5;\n border: 1px solid var(--ohx-border);\n border-radius: var(--ohx-radius);\n overflow: hidden;\n min-height: 0;\n}\n.ohx-root[data-theme=\"dark\"] {\n --ohx-bg: #1b1c1f;\n --ohx-surface: #242629;\n --ohx-fg: #e8eaed;\n --ohx-muted: #9aa0a6;\n --ohx-border: #34363b;\n --ohx-assistant-bg: #2a2c30;\n --ohx-assistant-fg: #e8eaed;\n}\n.ohx-root *, .ohx-root *::before, .ohx-root *::after { box-sizing: border-box; }\n\n.ohx-header {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 12px 14px;\n border-bottom: 1px solid var(--ohx-border);\n background: var(--ohx-bg);\n flex: none;\n}\n.ohx-avatar {\n width: 34px; height: 34px; border-radius: 50%;\n object-fit: cover; flex: none;\n background: var(--ohx-surface);\n}\n.ohx-header-text { display: flex; flex-direction: column; min-width: 0; flex: 1; }\n.ohx-title { font-weight: 600; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.ohx-subtitle { font-size: 12px; color: var(--ohx-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.ohx-icon-btn {\n display: inline-flex; align-items: center; justify-content: center;\n width: 30px; height: 30px; border: none; border-radius: 8px;\n background: transparent; color: var(--ohx-muted); cursor: pointer;\n}\n.ohx-icon-btn:hover { background: var(--ohx-surface); color: var(--ohx-fg); }\n\n.ohx-messages {\n flex: 1 1 auto;\n min-height: 0;\n overflow-y: auto;\n padding: 16px;\n display: flex;\n flex-direction: column;\n gap: 10px;\n background: var(--ohx-bg);\n scroll-behavior: smooth;\n}\n.ohx-empty {\n margin: auto; text-align: center; color: var(--ohx-muted);\n font-size: 13px; padding: 24px; max-width: 80%;\n}\n\n.ohx-row { display: flex; width: 100%; }\n.ohx-row.user { justify-content: flex-end; }\n.ohx-row.assistant, .ohx-row.system { justify-content: flex-start; }\n.ohx-bubble {\n max-width: 82%;\n padding: 9px 13px;\n border-radius: 14px;\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n.ohx-row.user .ohx-bubble {\n background: var(--ohx-user-bg); color: var(--ohx-user-fg);\n border-bottom-right-radius: 4px;\n}\n.ohx-row.assistant .ohx-bubble {\n background: var(--ohx-assistant-bg); color: var(--ohx-assistant-fg);\n border-bottom-left-radius: 4px;\n}\n.ohx-bubble.error { border: 1px solid #ef4444; }\n.ohx-bubble .ohx-p { margin: 0 0 6px; }\n.ohx-bubble .ohx-p:last-child { margin-bottom: 0; }\n.ohx-bubble a { color: inherit; text-decoration: underline; }\n.ohx-row.assistant .ohx-bubble a { color: var(--ohx-accent); }\n.ohx-bubble > :first-child { margin-top: 0; }\n.ohx-bubble > :last-child { margin-bottom: 0; }\n.ohx-bubble .ohx-h { font-weight: 600; line-height: 1.3; margin: 12px 0 6px; }\n.ohx-bubble .ohx-h1 { font-size: 1.3em; }\n.ohx-bubble .ohx-h2 { font-size: 1.18em; }\n.ohx-bubble .ohx-h3 { font-size: 1.08em; }\n.ohx-bubble .ohx-h4, .ohx-bubble .ohx-h5, .ohx-bubble .ohx-h6 { font-size: 1em; }\n.ohx-bubble .ohx-ul, .ohx-bubble .ohx-ol { margin: 6px 0; padding-left: 1.35em; }\n.ohx-bubble .ohx-ul { list-style: disc; }\n.ohx-bubble .ohx-ol { list-style: decimal; }\n.ohx-bubble .ohx-ul li, .ohx-bubble .ohx-ol li { margin: 3px 0; }\n.ohx-bubble .ohx-ul li::marker, .ohx-bubble .ohx-ol li::marker { color: var(--ohx-muted); }\n.ohx-bubble .ohx-hr { border: none; border-top: 1px solid var(--ohx-border); margin: 12px 0; }\n.ohx-bubble .ohx-quote {\n margin: 6px 0; padding: 2px 0 2px 12px;\n border-left: 3px solid var(--ohx-border); color: var(--ohx-muted);\n}\n.ohx-code {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 0.9em; background: rgba(127,127,127,0.16);\n padding: 1px 5px; border-radius: 5px;\n}\n.ohx-pre {\n margin: 6px 0; padding: 10px 12px; border-radius: 10px;\n background: rgba(127,127,127,0.14); overflow-x: auto;\n}\n.ohx-pre code {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 0.86em; white-space: pre; background: none; padding: 0;\n}\n.ohx-tools { margin-top: 6px; display: flex; flex-wrap: wrap; gap: 4px; }\n.ohx-tool {\n font-size: 11px; color: var(--ohx-muted);\n background: rgba(127,127,127,0.12); border-radius: 6px; padding: 2px 7px;\n font-family: ui-monospace, monospace;\n}\n\n.ohx-typing { display: inline-flex; gap: 4px; padding: 3px 2px; align-items: center; }\n.ohx-typing span {\n width: 6px; height: 6px; border-radius: 50%;\n background: var(--ohx-muted); opacity: 0.5;\n animation: ohx-blink 1.2s infinite ease-in-out both;\n}\n.ohx-typing span:nth-child(2) { animation-delay: 0.18s; }\n.ohx-typing span:nth-child(3) { animation-delay: 0.36s; }\n@keyframes ohx-blink { 0%, 80%, 100% { transform: scale(0.7); opacity: 0.3; } 40% { transform: scale(1); opacity: 0.9; } }\n\n.ohx-error-bar {\n display: flex; align-items: center; justify-content: space-between; gap: 8px;\n margin: 0 16px 8px; padding: 8px 12px; font-size: 12px;\n color: #b91c1c; background: rgba(239,68,68,0.1);\n border: 1px solid rgba(239,68,68,0.3); border-radius: 8px;\n}\n.ohx-root[data-theme=\"dark\"] .ohx-error-bar { color: #fca5a5; }\n.ohx-retry {\n border: none; background: transparent; color: inherit; cursor: pointer;\n text-decoration: underline; font-weight: 600; font-size: 12px; white-space: nowrap;\n}\n\n.ohx-composer {\n display: flex; align-items: flex-end; gap: 8px;\n padding: 10px 12px; border-top: 1px solid var(--ohx-border);\n background: var(--ohx-bg); flex: none;\n}\n.ohx-textarea {\n flex: 1; resize: none; border: 1px solid var(--ohx-border);\n border-radius: 12px; padding: 9px 12px; max-height: 140px;\n font-family: inherit; font-size: 14px; line-height: 1.4;\n color: var(--ohx-fg); background: var(--ohx-surface); outline: none;\n}\n.ohx-textarea:focus { border-color: var(--ohx-accent); }\n.ohx-textarea::placeholder { color: var(--ohx-muted); }\n.ohx-send {\n display: inline-flex; align-items: center; justify-content: center;\n width: 38px; height: 38px; flex: none; border: none; border-radius: 12px;\n background: var(--ohx-accent); color: var(--ohx-accent-contrast); cursor: pointer;\n transition: opacity 0.15s;\n}\n.ohx-send:disabled { opacity: 0.45; cursor: not-allowed; }\n.ohx-send.stop { background: var(--ohx-surface); color: var(--ohx-fg); border: 1px solid var(--ohx-border); }\n.ohx-footer {\n text-align: center; font-size: 10px; color: var(--ohx-muted);\n padding: 0 0 8px; background: var(--ohx-bg); flex: none;\n}\n.ohx-footer a { color: var(--ohx-muted); }\n\n/* ---- Floating widget ---- */\n.ohx-launcher {\n position: fixed; z-index: 2147483000;\n width: 56px; height: 56px; border-radius: 50%; border: none;\n background: var(--ohx-accent, #4f46e5); color: #fff; cursor: pointer;\n box-shadow: 0 6px 24px rgba(0,0,0,0.22);\n display: inline-flex; align-items: center; justify-content: center;\n transition: transform 0.15s;\n}\n.ohx-launcher:hover { transform: scale(1.06); }\n.ohx-launcher.bottom-right { right: 20px; bottom: 20px; }\n.ohx-launcher.bottom-left { left: 20px; bottom: 20px; }\n.ohx-panel {\n position: fixed; z-index: 2147483000;\n width: 380px; height: min(620px, calc(100vh - 110px));\n box-shadow: 0 12px 40px rgba(0,0,0,0.24);\n border-radius: 18px;\n overflow: hidden;\n animation: ohx-pop 0.16s ease-out;\n}\n.ohx-panel.bottom-right { right: 20px; bottom: 88px; }\n.ohx-panel.bottom-left { left: 20px; bottom: 88px; }\n/* Inside a panel the wrapper owns the shape + shadow, so the ChatBox fills\n it squared (no double border / radius). */\n.ohx-root.ohx-panel-inner { border: none; border-radius: 0; height: 100%; width: 100%; }\n@keyframes ohx-pop { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }\n\n@media (max-width: 480px) {\n .ohx-panel {\n right: 0; left: 0; bottom: 0; top: 0;\n width: 100vw; height: 100vh; height: 100dvh;\n border-radius: 0;\n }\n .ohx-launcher.open-hidden { display: none; }\n}\n`;\n\n/** Inject the stylesheet once (idempotent). Pass `enabled=false` to skip. */\nexport function useInjectStyles(enabled: boolean): void {\n useEffect(() => {\n if (!enabled) return;\n if (typeof document === 'undefined') return;\n if (document.getElementById(STYLE_ELEMENT_ID)) return;\n const style = document.createElement('style');\n style.id = STYLE_ELEMENT_ID;\n style.textContent = CHAT_CSS;\n document.head.appendChild(style);\n // Intentionally not removed on unmount: multiple widgets share it and\n // re-injecting on every mount would thrash. It's a single static tag.\n }, [enabled]);\n}\n","/**\n * Renders the {@link parseMarkdown} tree to React elements.\n *\n * All text is passed as React children (auto-escaped) and link hrefs are\n * pre-sanitized in {@link parseMarkdown}, so there is no HTML injection path.\n */\nimport { Fragment, createElement } from 'react';\nimport { parseMarkdown, type Span } from './markdown';\n\nfunction InlineSpans({ spans }: { spans: Span[] }) {\n return (\n <>\n {spans.map((s, i) => {\n switch (s.type) {\n case 'code':\n return (\n <code key={i} className=\"ohx-code\">\n {s.text}\n </code>\n );\n case 'bold':\n return <strong key={i}>{s.text}</strong>;\n case 'italic':\n return <em key={i}>{s.text}</em>;\n case 'link':\n return (\n <a key={i} href={s.href} target=\"_blank\" rel=\"noopener noreferrer nofollow\">\n {s.text}\n </a>\n );\n default:\n return <Fragment key={i}>{s.text}</Fragment>;\n }\n })}\n </>\n );\n}\n\n/** Render a message body as a lightweight, safe Markdown subset. */\nexport function Markdown({ text }: { text: string }) {\n const blocks = parseMarkdown(text);\n return (\n <>\n {blocks.map((b, i) => {\n switch (b.type) {\n case 'code':\n return (\n <pre key={i} className=\"ohx-pre\">\n <code>{b.text}</code>\n </pre>\n );\n case 'heading': {\n const level = Math.min(6, Math.max(1, b.level));\n return createElement(\n `h${level}`,\n { key: i, className: `ohx-h ohx-h${level}` },\n <InlineSpans spans={b.spans} />\n );\n }\n case 'hr':\n return <hr key={i} className=\"ohx-hr\" />;\n case 'blockquote':\n return (\n <blockquote key={i} className=\"ohx-quote\">\n <InlineSpans spans={b.spans} />\n </blockquote>\n );\n case 'list': {\n const items = b.items.map((spans, j) => (\n <li key={j}>\n <InlineSpans spans={spans} />\n </li>\n ));\n return b.ordered ? (\n <ol key={i} className=\"ohx-ol\" start={b.start}>\n {items}\n </ol>\n ) : (\n <ul key={i} className=\"ohx-ul\">\n {items}\n </ul>\n );\n }\n default:\n return (\n <p key={i} className=\"ohx-p\">\n <InlineSpans spans={b.spans} />\n </p>\n );\n }\n })}\n </>\n );\n}\n","/**\n * A tiny, dependency-free, XSS-safe Markdown subset for chat bubbles.\n *\n * We deliberately do NOT pull in `react-markdown` & friends (the internal\n * webapp does) — an embeddable widget must stay light and safe. This parses a\n * useful subset into a plain data tree; the renderer maps it to React\n * elements, so every piece of text goes through React's escaping and no HTML\n * is ever injected. Link hrefs are sanitized to http/https/mailto.\n *\n * Supported: fenced code blocks, paragraphs, `inline code`, **bold**,\n * *italic* / _italic_, [links](url), and bare URL autolinking.\n */\n\n/** An inline span inside a paragraph. */\nexport type Span =\n | { type: 'text'; text: string }\n | { type: 'code'; text: string }\n | { type: 'bold'; text: string }\n | { type: 'italic'; text: string }\n | { type: 'link'; text: string; href: string };\n\n/** A block-level node. */\nexport type Block =\n | { type: 'code'; text: string; lang?: string }\n | { type: 'heading'; level: number; spans: Span[] }\n | { type: 'paragraph'; spans: Span[] }\n | { type: 'list'; ordered: boolean; start: number; items: Span[][] }\n | { type: 'blockquote'; spans: Span[] }\n | { type: 'hr' };\n\n/** Only allow safe URL schemes; everything else becomes plain text. */\nexport function sanitizeHref(href: string): string | null {\n const trimmed = href.trim();\n if (/^(https?:|mailto:)/i.test(trimmed)) return trimmed;\n // Protocol-relative and bare-domain links are treated as https.\n if (/^\\/\\//.test(trimmed)) return `https:${trimmed}`;\n if (/^www\\./i.test(trimmed)) return `https://${trimmed}`;\n return null;\n}\n\nconst INLINE = [\n { type: 'code' as const, re: /`([^`]+)`/ },\n { type: 'bold' as const, re: /\\*\\*([^*]+)\\*\\*/ },\n { type: 'italic' as const, re: /\\*([^*\\n]+)\\*|_([^_\\n]+)_/ },\n { type: 'link' as const, re: /\\[([^\\]]+)\\]\\(([^)\\s]+)\\)/ },\n { type: 'url' as const, re: /(https?:\\/\\/[^\\s<]+[^\\s<.,:;\"')\\]}]|www\\.[^\\s<]+[^\\s<.,:;\"')\\]}])/ },\n];\n\n/** Parse a single line/segment of text into inline spans. */\nexport function parseInline(input: string): Span[] {\n const spans: Span[] = [];\n let rest = input;\n\n while (rest.length > 0) {\n // Find the earliest-matching inline construct.\n let best: { index: number; length: number; span: Span } | null = null;\n for (const rule of INLINE) {\n const m = rule.re.exec(rest);\n if (!m || m.index == null) continue;\n if (best && m.index >= best.index) continue;\n let span: Span | null = null;\n if (rule.type === 'code') span = { type: 'code', text: m[1] };\n else if (rule.type === 'bold') span = { type: 'bold', text: m[1] };\n else if (rule.type === 'italic') span = { type: 'italic', text: m[1] ?? m[2] };\n else if (rule.type === 'link') {\n const href = sanitizeHref(m[2]);\n span = href ? { type: 'link', text: m[1], href } : { type: 'text', text: m[0] };\n } else if (rule.type === 'url') {\n const href = sanitizeHref(m[1]);\n span = href ? { type: 'link', text: m[1], href } : { type: 'text', text: m[0] };\n }\n if (span) best = { index: m.index, length: m[0].length, span };\n }\n\n if (!best) {\n spans.push({ type: 'text', text: rest });\n break;\n }\n if (best.index > 0) spans.push({ type: 'text', text: rest.slice(0, best.index) });\n spans.push(best.span);\n rest = rest.slice(best.index + best.length);\n }\n return spans;\n}\n\n/** Parse a whole message into block-level nodes. */\nexport function parseMarkdown(input: string): Block[] {\n const blocks: Block[] = [];\n const lines = input.replace(/\\r\\n/g, '\\n').split('\\n');\n let i = 0;\n let para: string[] = [];\n\n const flushPara = () => {\n if (para.length === 0) return;\n const text = para.join('\\n').trim();\n if (text) blocks.push({ type: 'paragraph', spans: parseInline(text) });\n para = [];\n };\n\n const LIST_ITEM = /^\\s*([-*+]|\\d+[.)])\\s+(.*)$/;\n\n while (i < lines.length) {\n const line = lines[i];\n\n // Fenced code block.\n const fence = /^```(.*)$/.exec(line);\n if (fence) {\n flushPara();\n const lang = fence[1].trim() || undefined;\n const code: string[] = [];\n i++;\n while (i < lines.length && !/^```/.test(lines[i])) {\n code.push(lines[i]);\n i++;\n }\n i++; // skip closing fence\n blocks.push({ type: 'code', text: code.join('\\n'), lang });\n continue;\n }\n\n const trimmed = line.trim();\n\n // Blank line — paragraph break.\n if (trimmed === '') {\n flushPara();\n i++;\n continue;\n }\n\n // Horizontal rule (--- *** ___), at least three, nothing else.\n if (/^(-{3,}|\\*{3,}|_{3,})$/.test(trimmed)) {\n flushPara();\n blocks.push({ type: 'hr' });\n i++;\n continue;\n }\n\n // ATX heading (# … ######).\n const heading = /^(#{1,6})\\s+(.*?)\\s*#*\\s*$/.exec(line);\n if (heading) {\n flushPara();\n blocks.push({ type: 'heading', level: heading[1].length, spans: parseInline(heading[2]) });\n i++;\n continue;\n }\n\n // Blockquote — consume consecutive `>` lines.\n if (/^\\s*>\\s?/.test(line)) {\n flushPara();\n const quote: string[] = [];\n while (i < lines.length && /^\\s*>\\s?/.test(lines[i])) {\n quote.push(lines[i].replace(/^\\s*>\\s?/, ''));\n i++;\n }\n blocks.push({ type: 'blockquote', spans: parseInline(quote.join('\\n').trim()) });\n continue;\n }\n\n // List — consume consecutive item lines (ordered or unordered).\n const firstItem = LIST_ITEM.exec(line);\n if (firstItem) {\n flushPara();\n const ordered = /\\d/.test(firstItem[1]);\n const start = ordered ? parseInt(firstItem[1], 10) || 1 : 1;\n const items: Span[][] = [];\n while (i < lines.length) {\n const m = LIST_ITEM.exec(lines[i]);\n if (m) {\n items.push(parseInline(m[2]));\n i++;\n } else if (lines[i].trim() !== '' && /^\\s+\\S/.test(lines[i]) && items.length > 0) {\n // Continuation line: fold wrapped text into the previous item.\n items[items.length - 1].push(...parseInline(' ' + lines[i].trim()));\n i++;\n } else {\n break;\n }\n }\n blocks.push({ type: 'list', ordered, start, items });\n continue;\n }\n\n // Otherwise, accumulate into the current paragraph.\n para.push(line);\n i++;\n }\n flushPara();\n return blocks;\n}\n","/**\n * Inline SVG icons — no icon-library dependency, so the widget stays light\n * and has zero external asset requests. Each takes standard SVG props.\n */\nimport type { SVGProps } from 'react';\n\nexport function SendIcon(props: SVGProps<SVGSVGElement>) {\n return (\n <svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" aria-hidden {...props}>\n <path\n d=\"M4 12l16-8-6 16-3-6-7-2z\"\n fill=\"currentColor\"\n stroke=\"currentColor\"\n strokeWidth=\"1.2\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n\nexport function CloseIcon(props: SVGProps<SVGSVGElement>) {\n return (\n <svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" aria-hidden {...props}>\n <path d=\"M6 6l12 12M18 6L6 18\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n\nexport function ChatIcon(props: SVGProps<SVGSVGElement>) {\n return (\n <svg viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" fill=\"none\" aria-hidden {...props}>\n <path\n d=\"M21 11.5a8.38 8.38 0 0 1-8.5 8.5 8.5 8.5 0 0 1-3.8-.9L3 21l1.9-5.7A8.5 8.5 0 1 1 21 11.5z\"\n fill=\"currentColor\"\n />\n </svg>\n );\n}\n\nexport function StopIcon(props: SVGProps<SVGSVGElement>) {\n return (\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" aria-hidden {...props}>\n <rect x=\"6\" y=\"6\" width=\"12\" height=\"12\" rx=\"2\" fill=\"currentColor\" />\n </svg>\n );\n}\n"],"mappings":"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","names":["useCallback","useState","useCallback","useEffect","useMemo","useRef","useState","delay","useEffect","Fragment","jsx","jsx","useState","useEffect","useRef","useCallback","useMemo","Fragment","jsx","jsxs","useState","useCallback"]}
@@ -1,2 +1,41 @@
1
- import 'zod';
2
- export { S as SdkMcpServer, a as SdkToolDefinition, b as ToolResult, c as createSdkMcpServer, t as tool } from '../index-DOE19uln.js';
1
+ import { z } from 'zod';
2
+ import { A as AnySdkToolDefinition, S as SdkMcpServer, b as ToolResult, a as SdkToolDefinition } from '../tools-DWFaPtFE.js';
3
+
4
+ /**
5
+ * Helpers for defining custom in-process tools.
6
+ *
7
+ * Available as a sub-path import:
8
+ * import { tool, createSdkMcpServer } from '@openhex-ai/agent-sdk/tools';
9
+ *
10
+ * NOTE: scaffold only — `tool` and `createSdkMcpServer` build the typed
11
+ * definitions today; the executor that runs them inside the agent loop
12
+ * lands in a follow-up MR.
13
+ */
14
+
15
+ /**
16
+ * Define a custom tool with a Zod-typed input schema and an async
17
+ * handler. Bundle the result into a server with {@link createSdkMcpServer}
18
+ * and pass it via `options.mcpServers`.
19
+ *
20
+ * @example
21
+ * const getWeather = tool(
22
+ * 'get_weather',
23
+ * 'Look up the weather for a city',
24
+ * z.object({ city: z.string() }),
25
+ * async ({ city }) => ({ content: [{ type: 'text', text: `Sunny in ${city}` }] }),
26
+ * );
27
+ */
28
+ declare function tool<TSchema extends z.ZodTypeAny>(name: string, description: string, inputSchema: TSchema, handler: (input: z.infer<TSchema>, extra: {
29
+ signal?: AbortSignal;
30
+ }) => Promise<ToolResult> | ToolResult): SdkToolDefinition<TSchema>;
31
+ /**
32
+ * Bundle one or more {@link tool} definitions into an in-process MCP
33
+ * server that the agent loop can call without spawning a subprocess.
34
+ */
35
+ declare function createSdkMcpServer(config: {
36
+ name: string;
37
+ version?: string;
38
+ tools: AnySdkToolDefinition[];
39
+ }): SdkMcpServer;
40
+
41
+ export { SdkMcpServer, SdkToolDefinition, ToolResult, createSdkMcpServer, tool };
@@ -53,41 +53,4 @@ interface SdkMcpServer {
53
53
  tools: AnySdkToolDefinition[];
54
54
  }
55
55
 
56
- /**
57
- * Helpers for defining custom in-process tools.
58
- *
59
- * Available as a sub-path import:
60
- * import { tool, createSdkMcpServer } from '@openhex-ai/agent-sdk/tools';
61
- *
62
- * NOTE: scaffold only — `tool` and `createSdkMcpServer` build the typed
63
- * definitions today; the executor that runs them inside the agent loop
64
- * lands in a follow-up MR.
65
- */
66
-
67
- /**
68
- * Define a custom tool with a Zod-typed input schema and an async
69
- * handler. Bundle the result into a server with {@link createSdkMcpServer}
70
- * and pass it via `options.mcpServers`.
71
- *
72
- * @example
73
- * const getWeather = tool(
74
- * 'get_weather',
75
- * 'Look up the weather for a city',
76
- * z.object({ city: z.string() }),
77
- * async ({ city }) => ({ content: [{ type: 'text', text: `Sunny in ${city}` }] }),
78
- * );
79
- */
80
- declare function tool<TSchema extends z.ZodTypeAny>(name: string, description: string, inputSchema: TSchema, handler: (input: z.infer<TSchema>, extra: {
81
- signal?: AbortSignal;
82
- }) => Promise<ToolResult> | ToolResult): SdkToolDefinition<TSchema>;
83
- /**
84
- * Bundle one or more {@link tool} definitions into an in-process MCP
85
- * server that the agent loop can call without spawning a subprocess.
86
- */
87
- declare function createSdkMcpServer(config: {
88
- name: string;
89
- version?: string;
90
- tools: AnySdkToolDefinition[];
91
- }): SdkMcpServer;
92
-
93
- export { type AnySdkToolDefinition as A, type BuiltinToolName as B, type SdkMcpServer as S, type ToolName as T, type SdkToolDefinition as a, type ToolResult as b, createSdkMcpServer as c, tool as t };
56
+ export type { AnySdkToolDefinition as A, BuiltinToolName as B, SdkMcpServer as S, ToolName as T, SdkToolDefinition as a, ToolResult as b };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@openhex-ai/agent-sdk",
3
- "version": "0.0.1",
4
- "description": "Build AI agents on the Openhex platform. Programmable agent loop, tools, hooks, sessions, and MCP — the same runtime that powers Openhex agents, as a library.",
3
+ "version": "0.1.0",
4
+ "description": "Build AI agents on the Openhex platform. Programmable agent loop, tools, hooks, sessions, MCP, and an embeddable React chat UI — the same runtime that powers Openhex agents, as a library.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
@@ -17,6 +17,11 @@
17
17
  "types": "./dist/tools/index.d.ts",
18
18
  "import": "./dist/tools/index.js",
19
19
  "default": "./dist/tools/index.js"
20
+ },
21
+ "./react": {
22
+ "types": "./dist/react/index.d.ts",
23
+ "import": "./dist/react/index.js",
24
+ "default": "./dist/react/index.js"
20
25
  }
21
26
  },
22
27
  "files": [
@@ -41,15 +46,35 @@
41
46
  "ai",
42
47
  "llm",
43
48
  "mcp",
44
- "tools"
49
+ "tools",
50
+ "react",
51
+ "chat",
52
+ "chatbot",
53
+ "chat-widget"
45
54
  ],
46
55
  "dependencies": {
47
56
  "zod": "^3.24.4"
48
57
  },
58
+ "peerDependencies": {
59
+ "react": ">=18",
60
+ "react-dom": ">=18"
61
+ },
62
+ "peerDependenciesMeta": {
63
+ "react": {
64
+ "optional": true
65
+ },
66
+ "react-dom": {
67
+ "optional": true
68
+ }
69
+ },
49
70
  "devDependencies": {
50
71
  "@types/jest": "^30.0.0",
51
72
  "@types/node": "^25.9.1",
73
+ "@types/react": "^19.0.0",
74
+ "@types/react-dom": "^19.0.0",
52
75
  "jest": "^30.2.0",
76
+ "react": "^19.0.0",
77
+ "react-dom": "^19.0.0",
53
78
  "ts-jest": "^29.4.6",
54
79
  "tsup": "^8.5.1",
55
80
  "typescript": "^5.4.2"