@tangle-network/agent-app 0.10.0 → 0.11.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.
- package/README.md +10 -0
- package/dist/agent-activity-C8ZG0F0M.d.ts +43 -0
- package/dist/chunk-5RT6KY4G.js +190 -0
- package/dist/chunk-5RT6KY4G.js.map +1 -0
- package/dist/chunk-AFDROJ64.js +218 -0
- package/dist/chunk-AFDROJ64.js.map +1 -0
- package/dist/{chunk-UIWB2F6N.js → chunk-UDXMR3AD.js} +80 -24
- package/dist/chunk-UDXMR3AD.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +31 -1
- package/dist/missions/index.d.ts +38 -5
- package/dist/missions/index.js +3 -1
- package/dist/trace/index.d.ts +137 -1
- package/dist/trace/index.js +24 -138
- package/dist/trace/index.js.map +1 -1
- package/dist/web-react/index.d.ts +79 -1
- package/dist/web-react/index.js +417 -116
- package/dist/web-react/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-UIWB2F6N.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/web-react/index.tsx","../../src/web-react/provider-logo.tsx","../../src/web-react/smooth-text.ts","../../src/web-react/chat-stream.ts"],"sourcesContent":["/**\n * `@tangle-network/agent-app/web-react` — the shared chat-shell components\n * every agent app's web UI hand-rolls: a model picker over the runtime's\n * model catalogue, a reasoning-effort selector, and a message thread with\n * User/Agent identity, per-message model + cost + tokens/sec metrics, tool\n * chips, and a collapsible thinking section.\n *\n * Works for BOTH chat shapes: router-backed copilots (LoopEvents from\n * `runtime/openai-stream`) and sandbox-backed chats — the thread renders\n * `ChatUiMessage`s; how they're produced is the app's business.\n *\n * Styling contract: Tailwind classes against the shared design tokens\n * (`bg-card`, `border-border`, `text-muted-foreground`, `bg-primary`, …) that\n * Tangle app shells define. No icon library — the few glyphs are inline SVGs.\n * Markdown and provider logos are injected (`renderMarkdown`,\n * `renderProviderBadge`) so this package stays dependency-free beyond React.\n */\n\nimport { useEffect, useMemo, useRef, useState, type ReactNode } from 'react'\nimport { ProviderLogo } from './provider-logo'\nimport { useSmoothText } from './smooth-text'\n\nexport * from './chat-stream'\nexport * from './provider-logo'\nexport * from './smooth-text'\nimport type { CatalogModel } from '../runtime/model-catalog'\n\n// ── shared glyphs (no icon-library dependency) ────────────────────────────\n\nfunction ChevronDown({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n )\n}\n\nfunction SearchGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.3-4.3\" />\n </svg>\n )\n}\n\nfunction SparkleGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M12 3v3m0 12v3M3 12h3m12 0h3M5.6 5.6l2.1 2.1m8.6 8.6 2.1 2.1m0-12.8-2.1 2.1M7.7 16.3l-2.1 2.1\" />\n </svg>\n )\n}\n\n/** Close an absolutely-positioned popover on outside mousedown. */\nfunction useClickOutside(onOutside: () => void) {\n const ref = useRef<HTMLDivElement>(null)\n useEffect(() => {\n function handler(e: MouseEvent) {\n if (ref.current && !ref.current.contains(e.target as Node)) onOutside()\n }\n document.addEventListener('mousedown', handler)\n return () => document.removeEventListener('mousedown', handler)\n })\n return ref\n}\n\n// ── metrics helpers ───────────────────────────────────────────────────────\n\nexport interface ChatMessageMetrics {\n modelUsed?: string\n promptTokens?: number\n completionTokens?: number\n durationMs?: number\n}\n\n/** \"$0.0042\" from token counts × catalogue per-token pricing; null when unknown. */\nexport function formatModelCost(msg: ChatMessageMetrics, models: CatalogModel[]): string | null {\n if (msg.promptTokens == null && msg.completionTokens == null) return null\n const pricing = models.find((m) => m.id === msg.modelUsed)?.pricing\n if (!pricing) return null\n const cost =\n (msg.promptTokens ?? 0) * Number(pricing.prompt ?? 0) +\n (msg.completionTokens ?? 0) * Number(pricing.completion ?? 0)\n if (!isFinite(cost) || cost <= 0) return null\n return cost < 0.01 ? `$${cost.toFixed(4)}` : `$${cost.toFixed(2)}`\n}\n\n/** \"38 tok/s\" from completion tokens over first-token→end duration; null when unknown. */\nexport function formatTokensPerSecond(msg: ChatMessageMetrics): string | null {\n if (msg.completionTokens == null || !msg.durationMs) return null\n return `${Math.round(msg.completionTokens / (msg.durationMs / 1000))} tok/s`\n}\n\n// ── ModelPicker ───────────────────────────────────────────────────────────\n\nexport interface ModelPickerProps {\n value: string\n onChange: (id: string) => void\n /** Catalogue models — from `GET`ing the app's catalogue route (see\n * `runtime/model-catalog`), plus any product-specific entries appended. */\n models: CatalogModel[]\n loading?: boolean\n /** Render a provider logo/badge; default is a generic sparkle. */\n renderProviderBadge?: (provider: string) => ReactNode\n /** Section label for `featured` models. */\n recommendedLabel?: string\n}\n\nfunction formatPrice(p?: string): string | undefined {\n if (!p) return undefined\n const n = Number(p)\n if (isNaN(n) || n === 0) return undefined\n const perM = n * 1_000_000\n return perM >= 1 ? `$${perM.toFixed(0)}/M` : `$${perM.toFixed(2)}/M`\n}\n\nfunction formatContext(len?: number): string | undefined {\n if (!len) return undefined\n if (len >= 1_000_000) return `${(len / 1_000_000).toFixed(1)}M ctx`\n if (len >= 1_000) return `${Math.round(len / 1_000)}K ctx`\n return `${len} ctx`\n}\n\nfunction SectionHeader({ children }: { children: ReactNode }) {\n return (\n <div className=\"px-3 pb-1 pt-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground/70\">\n {children}\n </div>\n )\n}\n\nfunction ModelRow({\n model,\n selected,\n onSelect,\n renderProviderBadge,\n}: {\n model: CatalogModel\n selected: boolean\n onSelect: () => void\n renderProviderBadge?: (provider: string) => ReactNode\n}) {\n const price = formatPrice(model.pricing?.prompt)\n const ctx = formatContext(model.contextLength)\n return (\n <button\n type=\"button\"\n onClick={onSelect}\n className={`flex w-full items-center gap-2.5 rounded-md px-3 py-2.5 text-left text-sm transition ${\n selected ? 'bg-primary/10 font-medium' : 'hover:bg-accent/30'\n }`}\n >\n {renderProviderBadge ? renderProviderBadge(model.provider) : <ProviderLogo provider={model.provider} size={16} />}\n <span className=\"truncate\">{model.name}</span>\n {!model.supportsTools && (\n <span className=\"shrink-0 rounded bg-muted/60 px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground\">\n no tools\n </span>\n )}\n <span className=\"ml-auto flex shrink-0 items-center gap-2 text-xs text-muted-foreground\">\n {ctx && <span>{ctx}</span>}\n {price && <span>{price}</span>}\n </span>\n </button>\n )\n}\n\n/**\n * Searchable model picker pill + popover: a featured/recommended section\n * first, then per-provider groups in catalogue order (the server already\n * sorts providers by tier).\n */\nexport function ModelPicker({ value, onChange, models, loading, renderProviderBadge, recommendedLabel = 'Recommended' }: ModelPickerProps) {\n const [open, setOpen] = useState(false)\n const [query, setQuery] = useState('')\n const containerRef = useClickOutside(() => setOpen(false))\n const inputRef = useRef<HTMLInputElement>(null)\n\n useEffect(() => {\n if (open) inputRef.current?.focus()\n }, [open])\n\n const selected = models.find((m) => m.id === value)\n\n const filtered = useMemo(() => {\n const q = query.trim().toLowerCase()\n if (!q) return null\n return models.filter(\n (m) =>\n m.id.toLowerCase().includes(q) ||\n m.name.toLowerCase().includes(q) ||\n (m.description?.toLowerCase() ?? '').includes(q) ||\n m.provider.toLowerCase().includes(q),\n )\n }, [models, query])\n\n const sections = useMemo(() => {\n const recommended = models.filter((m) => m.featured)\n const byProvider: Array<{ provider: string; items: CatalogModel[] }> = []\n for (const m of models) {\n if (m.featured) continue\n const last = byProvider[byProvider.length - 1]\n if (last && last.provider === m.provider) last.items.push(m)\n else byProvider.push({ provider: m.provider, items: [m] })\n }\n return { recommended, byProvider }\n }, [models])\n\n const select = (id: string) => {\n onChange(id)\n setOpen(false)\n setQuery('')\n }\n\n return (\n <div ref={containerRef} className=\"relative inline-flex\">\n <button\n type=\"button\"\n onClick={() => setOpen((v) => !v)}\n className=\"inline-flex items-center gap-1.5 rounded-full border border-border bg-card px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-accent/30\"\n >\n {selected ? (renderProviderBadge ? renderProviderBadge(selected.provider) : <ProviderLogo provider={selected.provider} size={16} />) : <SparkleGlyph className=\"h-3.5 w-3.5 text-muted-foreground\" />}\n <span className=\"max-w-[160px] truncate\">{selected?.name ?? value}</span>\n <ChevronDown className=\"h-3.5 w-3.5 text-muted-foreground\" />\n </button>\n\n {open && (\n <div className=\"absolute bottom-full left-0 z-50 mb-2 w-[420px] overflow-hidden rounded-xl border border-border bg-card shadow-lg\">\n <div className=\"border-b border-border px-3 py-2\">\n <div className=\"flex items-center gap-2 rounded-lg border border-border bg-background px-3 py-2\">\n <SearchGlyph className=\"h-3.5 w-3.5 text-muted-foreground\" />\n <input\n ref={inputRef}\n type=\"text\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Search models...\"\n className=\"flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground\"\n />\n </div>\n </div>\n <div className=\"max-h-[400px] overflow-y-auto p-1 pb-2\">\n {loading && <div className=\"px-3 py-4 text-center text-sm text-muted-foreground\">Loading models...</div>}\n {!loading && filtered && (\n <>\n {filtered.length === 0 && (\n <div className=\"px-3 py-4 text-center text-sm text-muted-foreground\">No models match your search</div>\n )}\n {filtered.map((m) => (\n <ModelRow key={m.id} model={m} selected={m.id === value} onSelect={() => select(m.id)} renderProviderBadge={renderProviderBadge} />\n ))}\n </>\n )}\n {!loading && !filtered && (\n <>\n {sections.recommended.length > 0 && (\n <>\n <SectionHeader>{recommendedLabel}</SectionHeader>\n {sections.recommended.map((m) => (\n <ModelRow key={m.id} model={m} selected={m.id === value} onSelect={() => select(m.id)} renderProviderBadge={renderProviderBadge} />\n ))}\n </>\n )}\n {sections.byProvider.map((g) => (\n <div key={g.provider}>\n <SectionHeader>{g.provider}</SectionHeader>\n {g.items.map((m) => (\n <ModelRow key={m.id} model={m} selected={m.id === value} onSelect={() => select(m.id)} renderProviderBadge={renderProviderBadge} />\n ))}\n </div>\n ))}\n </>\n )}\n </div>\n </div>\n )}\n </div>\n )\n}\n\n// ── EffortPicker ──────────────────────────────────────────────────────────\n\nconst EFFORT_LEVELS = [\n { id: 'off', label: 'Off' },\n { id: 'low', label: 'Low' },\n { id: 'medium', label: 'Medium' },\n { id: 'high', label: 'High' },\n] as const\n\nexport interface EffortPickerProps {\n value: string\n onChange: (id: string) => void\n}\n\n/** Reasoning-effort selector pill, styled to match {@link ModelPicker}. Show\n * it only when the selected model `supportsReasoning`. */\nexport function EffortPicker({ value, onChange }: EffortPickerProps) {\n const [open, setOpen] = useState(false)\n const containerRef = useClickOutside(() => setOpen(false))\n const selected = EFFORT_LEVELS.find((l) => l.id === value) ?? EFFORT_LEVELS[2]\n\n return (\n <div ref={containerRef} className=\"relative inline-flex\">\n <button\n type=\"button\"\n onClick={() => setOpen((v) => !v)}\n title=\"Reasoning effort\"\n className=\"inline-flex items-center gap-1.5 rounded-full border border-border bg-card px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-accent/30\"\n >\n <SparkleGlyph className=\"h-3.5 w-3.5 text-muted-foreground\" />\n <span>{selected.label}</span>\n <ChevronDown className=\"h-3.5 w-3.5 text-muted-foreground\" />\n </button>\n {open && (\n <div className=\"absolute bottom-full left-0 z-50 mb-2 w-36 overflow-hidden rounded-xl border border-border bg-card p-1 shadow-lg\">\n {EFFORT_LEVELS.map((l) => (\n <button\n key={l.id}\n type=\"button\"\n onClick={() => {\n onChange(l.id)\n setOpen(false)\n }}\n className={`flex w-full items-center rounded-md px-3 py-2 text-left text-sm transition ${\n l.id === value ? 'bg-primary/10 font-medium' : 'hover:bg-accent/30'\n }`}\n >\n {l.label}\n </button>\n ))}\n </div>\n )}\n </div>\n )\n}\n\n// ── Tool run drill-in (retained runs) ─────────────────────────────────────\n\n/** One step of a retained tool run (e.g. a sandbox command + its output). */\nexport interface ToolRunStep {\n at: string\n label: string\n detail?: string\n status?: 'ok' | 'error'\n}\n\n/** A retained tool run keyed by the parent message's toolCallId. The product\n * persists these server-side (fail-closed: only ids its own loop created)\n * and serves them to the drill-in panel. */\nexport interface ToolRunRecord {\n toolCallId: string\n toolName: string\n title: string\n status: 'running' | 'complete' | 'error'\n steps: ToolRunStep[]\n}\n\nexport interface RunDrillInProps {\n run: ToolRunRecord\n onClose: () => void\n}\n\n/**\n * Readonly side panel showing a retained tool run's transcript — the\n * \"drill into what the sandbox actually did\" view. Follow-ups happen in the\n * main chat, never here.\n */\nexport function RunDrillIn({ run, onClose }: RunDrillInProps) {\n return (\n <div className=\"fixed inset-y-0 right-0 z-50 flex w-[480px] max-w-full flex-col border-l border-border bg-card shadow-xl\">\n <div className=\"flex items-center gap-2 border-b border-border px-4 py-3\">\n <span\n className={`h-2 w-2 shrink-0 rounded-full ${\n run.status === 'running' ? 'bg-yellow-500' : run.status === 'error' ? 'bg-red-500' : 'bg-green-500'\n }`}\n />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-semibold\">{run.title}</p>\n <p className=\"truncate font-mono text-[11px] text-muted-foreground\">{run.toolName}</p>\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close\"\n className=\"rounded-md p-1.5 text-muted-foreground transition hover:bg-accent/30 hover:text-foreground\"\n >\n <svg className=\"h-4 w-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n </button>\n </div>\n <div className=\"flex-1 space-y-3 overflow-y-auto p-4\">\n {run.steps.length === 0 && (\n <p className=\"text-sm text-muted-foreground\">No steps recorded yet.</p>\n )}\n {run.steps.map((step, i) => (\n <div key={i} className=\"rounded-lg border border-border/60 bg-background\">\n <div className=\"flex items-baseline gap-2 border-b border-border/40 px-3 py-1.5\">\n <span className={`font-mono text-[11px] ${step.status === 'error' ? 'text-red-600' : 'text-muted-foreground'}`}>\n {step.status === 'error' ? '✗' : '$'}\n </span>\n <code className=\"min-w-0 flex-1 truncate font-mono text-xs\">{step.label}</code>\n <span className=\"shrink-0 text-[10px] text-muted-foreground/60\">\n {new Date(step.at).toLocaleTimeString()}\n </span>\n </div>\n {step.detail && (\n <pre className=\"max-h-48 overflow-auto whitespace-pre-wrap px-3 py-2 font-mono text-[11px] leading-relaxed text-muted-foreground\">\n {step.detail}\n </pre>\n )}\n </div>\n ))}\n </div>\n <p className=\"border-t border-border px-4 py-2 text-[11px] text-muted-foreground/60\">\n Readonly drill-in. Follow up in the main chat.\n </p>\n </div>\n )\n}\n\n// ── ChatMessages ──────────────────────────────────────────────────────────\n\nexport interface ChatToolCallInfo {\n id: string\n name: string\n status: 'running' | 'done' | 'error'\n /** The call arguments, captured from the tool_call event — shown in the\n * expanded card so users see exactly what the agent invoked. */\n args?: Record<string, unknown>\n /** The tool outcome (`{ok, result}` shape). When `result.status` is\n * 'queued_for_approval' the card renders the approval state. */\n result?: unknown\n}\n\n/** Extract `{proposalId, status}` from a tool outcome when it is a proposal\n * awaiting human approval; null otherwise. */\nexport function pendingApprovalOf(call: ChatToolCallInfo): { proposalId: string } | null {\n const outcome = call.result as { ok?: boolean; result?: { status?: string; proposalId?: string } } | undefined\n if (!outcome?.ok || outcome.result?.status !== 'queued_for_approval' || !outcome.result.proposalId) return null\n return { proposalId: outcome.result.proposalId }\n}\n\nexport interface ChatUiMessage extends ChatMessageMetrics {\n id: string\n role: 'user' | 'assistant' | 'system'\n content: string\n reasoning?: string\n toolCalls?: ChatToolCallInfo[]\n}\n\nexport interface ChatMessagesProps {\n messages: ChatUiMessage[]\n /** Catalogue models, for per-message cost from pricing. Pass [] to skip cost. */\n models?: CatalogModel[]\n /** Markdown renderer for assistant content; default renders pre-wrapped text. */\n renderMarkdown?: (content: string) => ReactNode\n /** Extra per-message content (artifacts, custom panels) appended after the body. */\n renderExtras?: (message: ChatUiMessage) => ReactNode\n userLabel?: string\n agentLabel?: string\n /** Render the trailing \"agent is thinking\" row. */\n loading?: boolean\n /** Approve/Reject handlers for proposals awaiting approval. When omitted the\n * chip still shows \"awaiting approval\" but without action buttons. */\n approval?: ProposalApprovalHandlers\n /** Open a full-transcript view (e.g. {@link RunDrillIn}) from a tool card. */\n onToolCallClick?: (call: ChatToolCallInfo, message: ChatUiMessage) => void\n /** Per-tool custom detail renderers for expanded tool cards. */\n toolRenderers?: ToolDetailRenderers\n}\n\nexport interface ProposalApprovalHandlers {\n onApprove: (proposalId: string, toolCallId: string) => void | Promise<void>\n onReject: (proposalId: string, toolCallId: string) => void | Promise<void>\n}\n\n/** Per-tool custom detail renderers for the expanded card body — keyed by\n * tool name. Return null to fall back to the generic detail view. */\nexport type ToolDetailRenderers = Record<\n string,\n (call: ChatToolCallInfo, message: ChatUiMessage) => ReactNode\n>\n\nfunction toolOutcomeOf(call: ChatToolCallInfo): { ok?: boolean; result?: Record<string, unknown>; message?: string } | undefined {\n return call.result as { ok?: boolean; result?: Record<string, unknown>; message?: string } | undefined\n}\n\n/** Human title for a call, derived from its real arguments. */\nfunction friendlyToolTitle(call: ChatToolCallInfo): string {\n const a = call.args ?? {}\n switch (call.name) {\n case 'submit_proposal':\n return `Proposal · ${String(a.type ?? '')}${a.title ? `: ${String(a.title)}` : ''}`\n case 'sandbox_create':\n return `Create sandbox (${String(a.environment ?? 'universal')})`\n case 'sandbox_run_command':\n return `$ ${String(a.command ?? '')}`\n case 'sandbox_destroy':\n return `Destroy sandbox ${String(a.sandbox_id ?? '')}`\n case 'schedule_followup':\n return `Follow-up · ${String(a.title ?? '')}`\n case 'render_ui':\n return `Render view · ${String(a.title ?? '')}`\n case 'add_citation':\n return `Citation · ${String(a.path ?? '')}`\n default:\n return call.name\n }\n}\n\nfunction truncate(v: unknown, max = 240): string {\n const s = typeof v === 'string' ? v : JSON.stringify(v)\n return s.length > max ? `${s.slice(0, max)}…` : s\n}\n\nfunction KvRows({ data }: { data: Record<string, unknown> }) {\n const entries = Object.entries(data).filter(([, v]) => v !== undefined && v !== null && v !== '')\n if (!entries.length) return null\n return (\n <dl className=\"grid grid-cols-[auto_1fr] gap-x-3 gap-y-1\">\n {entries.map(([k, v]) => (\n <div key={k} className=\"contents\">\n <dt className=\"font-mono text-[11px] text-muted-foreground/70\">{k}</dt>\n <dd className=\"min-w-0 whitespace-pre-wrap break-words font-mono text-[11px] text-muted-foreground\">\n {truncate(v)}\n </dd>\n </div>\n ))}\n </dl>\n )\n}\n\n/** Generic expanded detail: what was called, and what actually happened. */\nfunction DefaultToolDetail({ call }: { call: ChatToolCallInfo }) {\n const outcome = toolOutcomeOf(call)\n return (\n <div className=\"space-y-2\">\n {call.args && Object.keys(call.args).length > 0 && (\n <div>\n <p className=\"mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground/50\">Called with</p>\n <KvRows data={call.args} />\n </div>\n )}\n {outcome && (\n <div>\n <p className=\"mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground/50\">\n {outcome.ok === false ? 'Failed' : 'Result'}\n </p>\n {outcome.ok === false ? (\n <p className=\"text-xs text-red-600\">{outcome.message ?? 'Tool failed'}</p>\n ) : outcome.result && typeof outcome.result === 'object' ? (\n <KvRows data={outcome.result} />\n ) : (\n <p className=\"font-mono text-[11px] text-muted-foreground\">{truncate(outcome.result)}</p>\n )}\n </div>\n )}\n </div>\n )\n}\n\nfunction ToolCallCard({\n call,\n message,\n approval,\n onOpenRun,\n renderers,\n}: {\n call: ChatToolCallInfo\n message: ChatUiMessage\n approval?: ProposalApprovalHandlers\n onOpenRun?: (call: ChatToolCallInfo, message: ChatUiMessage) => void\n renderers?: ToolDetailRenderers\n}) {\n const [expanded, setExpanded] = useState(false)\n const pending = call.status === 'done' ? pendingApprovalOf(call) : null\n const failed = call.status === 'error' || toolOutcomeOf(call)?.ok === false\n const custom = renderers?.[call.name]?.(call, message)\n\n return (\n <div\n className={`w-fit min-w-[280px] max-w-full rounded-lg border text-xs transition ${\n pending\n ? 'border-amber-300/60 bg-amber-500/5'\n : failed\n ? 'border-red-300/60 bg-red-500/5'\n : 'border-border/60 bg-muted/20'\n }`}\n >\n <button\n type=\"button\"\n onClick={() => setExpanded((v) => !v)}\n className=\"flex w-full items-center gap-2 px-3 py-2 text-left\"\n >\n <span\n className={`h-2 w-2 shrink-0 rounded-full ${\n call.status === 'running'\n ? 'animate-pulse bg-yellow-500'\n : pending\n ? 'bg-amber-500'\n : failed\n ? 'bg-red-500'\n : 'bg-green-500'\n }`}\n />\n <span className=\"min-w-0 flex-1 truncate font-medium\">{friendlyToolTitle(call)}</span>\n {pending && approval && (\n <span className=\"flex shrink-0 items-center gap-1\" onClick={(e) => e.stopPropagation()}>\n <button\n type=\"button\"\n onClick={() => approval.onApprove(pending.proposalId, call.id)}\n className=\"rounded bg-green-600/90 px-2 py-0.5 text-[11px] font-semibold text-white transition hover:bg-green-600\"\n >\n Approve\n </button>\n <button\n type=\"button\"\n onClick={() => approval.onReject(pending.proposalId, call.id)}\n className=\"rounded border border-border bg-card px-2 py-0.5 text-[11px] font-medium text-foreground transition hover:bg-accent/30\"\n >\n Reject\n </button>\n </span>\n )}\n <span className=\"shrink-0 text-[11px] text-muted-foreground/70\">\n {call.status === 'running' ? 'running…' : pending ? 'awaiting approval' : failed ? 'failed' : 'done'}\n </span>\n <ChevronDown className={`h-3 w-3 shrink-0 text-muted-foreground transition-transform ${expanded ? 'rotate-180' : ''}`} />\n </button>\n {expanded && (\n <div className=\"border-t border-border/40 px-3 py-2.5\">\n {custom ?? <DefaultToolDetail call={call} />}\n {onOpenRun && call.name.startsWith('sandbox_') && (\n <button\n type=\"button\"\n onClick={() => onOpenRun(call, message)}\n className=\"mt-2 rounded border border-border bg-card px-2 py-1 text-[11px] font-medium transition hover:bg-accent/30\"\n >\n Open full transcript →\n </button>\n )}\n </div>\n )}\n </div>\n )\n}\n\nfunction AssistantMessage({\n msg,\n streaming,\n models,\n agentLabel,\n renderBody,\n approval,\n onToolCallClick,\n toolRenderers,\n renderExtras,\n}: {\n msg: ChatUiMessage\n streaming: boolean\n models: CatalogModel[]\n agentLabel: string\n renderBody: (content: string) => ReactNode\n approval?: ProposalApprovalHandlers\n onToolCallClick?: (call: ChatToolCallInfo, message: ChatUiMessage) => void\n toolRenderers?: ToolDetailRenderers\n renderExtras?: (message: ChatUiMessage) => ReactNode\n}) {\n // Smooth reveal: chunky network slabs (model bursts, flush windows, replay\n // polls) paint as a continuous typewriter. Reasoning often arrives as one\n // burst right before the answer — smoothing makes it visibly type out in\n // the open thinking box instead of popping in and collapsing.\n const content = useSmoothText(msg.content, streaming)\n const reasoning = useSmoothText(msg.reasoning ?? '', streaming)\n const reasoningScrollRef = useRef<HTMLDivElement>(null)\n useEffect(() => {\n const el = reasoningScrollRef.current\n if (el && streaming && !content) el.scrollTop = el.scrollHeight\n }, [reasoning, streaming, content])\n\n return (\n <div className=\"mx-auto w-full max-w-3xl px-6 py-3\">\n <div className=\"mb-1 flex items-baseline gap-2 text-[11px] tracking-wide text-muted-foreground/60\">\n <span className=\"font-semibold uppercase\">{agentLabel}</span>\n {msg.modelUsed && <span className=\"font-mono normal-case\">{msg.modelUsed}</span>}\n {formatTokensPerSecond(msg) && <span>{formatTokensPerSecond(msg)}</span>}\n {formatModelCost(msg, models) && <span>{formatModelCost(msg, models)}</span>}\n </div>\n {reasoning && (\n <details className=\"mb-2 rounded-md border border-border/40 bg-muted/30 px-3 py-2\" open={!content}>\n <summary className=\"cursor-pointer select-none text-xs font-medium text-muted-foreground\">\n {content ? 'Thinking…' : 'Thinking'}\n {!content && <span className=\"ml-1 inline-block animate-pulse\">●</span>}\n </summary>\n <div ref={reasoningScrollRef} className=\"mt-2 max-h-48 overflow-y-auto whitespace-pre-wrap text-sm text-muted-foreground/80\">\n {reasoning}\n </div>\n </details>\n )}\n <div className=\"text-base leading-[1.75]\">{renderBody(content)}</div>\n {msg.toolCalls && msg.toolCalls.length > 0 && (\n <div className=\"mt-2 flex flex-col gap-1.5\">\n {msg.toolCalls.map((tc) => (\n <ToolCallCard\n key={tc.id}\n call={tc}\n message={msg}\n approval={approval}\n onOpenRun={onToolCallClick}\n renderers={toolRenderers}\n />\n ))}\n </div>\n )}\n {renderExtras?.(msg)}\n </div>\n )\n}\n\nfunction ThinkingRow({ agentLabel }: { agentLabel: string }) {\n const [seconds, setSeconds] = useState(0)\n useEffect(() => {\n const id = setInterval(() => setSeconds((s) => s + 1), 1000)\n return () => clearInterval(id)\n }, [])\n return (\n <div className=\"mx-auto w-full max-w-3xl px-6 py-3\">\n <p className=\"mb-1 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground/60\">{agentLabel}</p>\n <div className=\"flex items-center gap-2 text-base text-muted-foreground\">\n <svg className=\"h-4 w-4 animate-spin\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" aria-hidden>\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" strokeLinecap=\"round\" />\n </svg>\n Thinking{seconds >= 3 ? ` · ${seconds}s` : '...'}\n </div>\n </div>\n )\n}\n\n/**\n * The message thread: one centered column; user messages are right-aligned\n * bubbles with a User label; agent messages carry an Agent meta line with\n * model id, tokens/sec, and cost, plus a collapsible thinking section and\n * tool-call chips.\n */\nexport function ChatMessages({\n messages,\n models = [],\n renderMarkdown,\n renderExtras,\n userLabel = 'User',\n agentLabel = 'Agent',\n loading,\n approval,\n onToolCallClick,\n toolRenderers,\n}: ChatMessagesProps) {\n const renderBody = renderMarkdown ?? ((content: string) => <p className=\"whitespace-pre-wrap\">{content}</p>)\n const lastIsUser = messages[messages.length - 1]?.role === 'user'\n return (\n <>\n {messages.map((msg) =>\n msg.role === 'user' ? (\n <div key={msg.id} className=\"mx-auto w-full max-w-3xl px-6 py-3\">\n <div className=\"ml-auto w-fit max-w-[85%]\">\n <p className=\"mb-1 text-right text-[11px] font-semibold uppercase tracking-wide text-muted-foreground/60\">\n {userLabel}\n </p>\n <div className=\"rounded-2xl rounded-tr-md bg-primary/10 px-4 py-2.5 text-base leading-relaxed\">\n <p className=\"whitespace-pre-wrap\">{msg.content}</p>\n </div>\n </div>\n </div>\n ) : (\n <AssistantMessage\n key={msg.id}\n msg={msg}\n streaming={!!loading && msg.id === messages[messages.length - 1]?.id}\n models={models}\n agentLabel={agentLabel}\n renderBody={renderBody}\n approval={approval}\n onToolCallClick={onToolCallClick}\n toolRenderers={toolRenderers}\n renderExtras={renderExtras}\n />\n ),\n )}\n {loading && lastIsUser && <ThinkingRow agentLabel={agentLabel} />}\n </>\n )\n}\n","/**\n * Provider brand marks — real logo path data (simple-icons / SVG Logos, both\n * CC0) inlined so the picker shows actual provider identity instead of\n * colored-initial monograms. Providers without a usable mark fall back to a\n * tinted monogram chip. Aliases (z-ai/zai, moonshot/moonshotai, deepseek_ai)\n * normalize to one entry.\n */\n\nimport type { ReactNode } from 'react'\n\ninterface LogoDef {\n viewBox: string\n fill: string\n paths: string[]\n}\n\nconst LOGOS: Record<string, LogoDef> = {\n anthropic: { viewBox: '0 0 24 24', fill: '#D97757', paths: [\"M17.3041 3.541h-3.6718l6.696 16.918H24Zm-10.6082 0L0 20.459h3.7442l1.3693-3.5527h7.0052l1.3693 3.5528h3.7442L10.5363 3.5409Zm-.3712 10.2232 2.2914-5.9456 2.2914 5.9456Z\"] },\n google: { viewBox: '0 0 24 24', fill: '#8E75B2', paths: [\"M11.04 19.32Q12 21.51 12 24q0-2.49.93-4.68.96-2.19 2.58-3.81t3.81-2.55Q21.51 12 24 12q-2.49 0-4.68-.93a12.3 12.3 0 0 1-3.81-2.58 12.3 12.3 0 0 1-2.58-3.81Q12 2.49 12 0q0 2.49-.96 4.68-.93 2.19-2.55 3.81a12.3 12.3 0 0 1-3.81 2.58Q2.49 12 0 12q2.49 0 4.68.96 2.19.93 3.81 2.55t2.55 3.81\"] },\n deepseek: { viewBox: '0 0 24 24', fill: '#4D6BFE', paths: [\"M23.748 4.651c-.254-.124-.364.113-.512.233-.051.04-.094.09-.137.137-.372.397-.806.657-1.373.626-.829-.046-1.537.214-2.163.848-.133-.782-.575-1.248-1.247-1.548-.352-.155-.708-.311-.955-.65-.172-.24-.219-.509-.305-.774-.055-.16-.11-.323-.293-.35-.2-.031-.278.136-.356.276-.313.572-.434 1.202-.422 1.84.027 1.436.633 2.58 1.838 3.393.137.094.172.187.129.323-.082.28-.18.553-.266.833-.055.179-.137.218-.328.14a5.5 5.5 0 0 1-1.737-1.179c-.857-.828-1.631-1.743-2.597-2.46a12 12 0 0 0-.689-.47c-.985-.957.13-1.743.387-1.836.27-.098.094-.433-.778-.428-.872.003-1.67.295-2.687.685a3 3 0 0 1-.465.136 9.6 9.6 0 0 0-2.883-.101c-1.885.21-3.39 1.1-4.497 2.622C.082 8.776-.231 10.854.152 13.02c.403 2.284 1.568 4.175 3.36 5.653 1.857 1.533 3.997 2.284 6.438 2.14 1.482-.085 3.132-.284 4.994-1.86.47.234.962.328 1.78.398.629.058 1.235-.031 1.705-.129.735-.155.684-.836.418-.961-2.155-1.004-1.682-.595-2.112-.926 1.095-1.295 2.768-3.598 3.284-6.733.05-.346.115-.834.108-1.114-.004-.171.035-.238.23-.257a4.2 4.2 0 0 0 1.545-.475c1.397-.763 1.96-2.016 2.093-3.517.02-.23-.004-.467-.247-.588M11.58 18.168c-2.088-1.642-3.101-2.183-3.52-2.16-.39.024-.32.472-.234.763.09.288.207.487.371.74.114.167.192.416-.113.603-.673.416-1.842-.14-1.897-.168-1.361-.801-2.5-1.86-3.301-3.306-.775-1.393-1.225-2.888-1.299-4.482-.02-.385.094-.522.477-.592a4.7 4.7 0 0 1 1.53-.038c2.131.311 3.946 1.264 5.467 2.774.868.86 1.525 1.887 2.202 2.89.72 1.066 1.494 2.082 2.48 2.915.348.291.626.513.892.677-.802.09-2.14.109-3.055-.615zm1.001-6.44a.306.306 0 0 1 .415-.287.3.3 0 0 1 .113.074.3.3 0 0 1 .086.214c0 .17-.136.307-.308.307a.303.303 0 0 1-.306-.307m3.11 1.596c-.2.081-.4.151-.591.16a1.25 1.25 0 0 1-.798-.254c-.274-.23-.47-.358-.551-.758a1.7 1.7 0 0 1 .015-.588c.07-.327-.007-.537-.238-.727-.188-.156-.426-.199-.689-.199a.6.6 0 0 1-.254-.078.253.253 0 0 1-.114-.358 1 1 0 0 1 .192-.21c.356-.202.767-.136 1.146.016.352.144.618.408 1.001.782.392.451.462.576.685.915.176.264.336.536.446.848.066.194-.02.353-.25.45\"] },\n mistral: { viewBox: '0 0 24 24', fill: '#FA520F', paths: [\"M17.143 3.429v3.428h-3.429v3.429h-3.428V6.857H6.857V3.43H3.43v13.714H0v3.428h10.286v-3.428H6.857v-3.429h3.429v3.429h3.429v-3.429h3.428v3.429h-3.428v3.428H24v-3.428h-3.43V3.429z\"] },\n xai: { viewBox: '0 0 24 24', fill: '#000000', paths: [\"M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z\"] },\n nvidia: { viewBox: '0 0 24 24', fill: '#76B900', paths: [\"M8.948 8.798v-1.43a6.7 6.7 0 0 1 .424-.018c3.922-.124 6.493 3.374 6.493 3.374s-2.774 3.851-5.75 3.851c-.398 0-.787-.062-1.158-.185v-4.346c1.528.185 1.837.857 2.747 2.385l2.04-1.714s-1.492-1.952-4-1.952a6.016 6.016 0 0 0-.796.035m0-4.735v2.138l.424-.027c5.45-.185 9.01 4.47 9.01 4.47s-4.08 4.964-8.33 4.964c-.37 0-.733-.035-1.095-.097v1.325c.3.035.61.062.91.062 3.957 0 6.82-2.023 9.593-4.408.459.371 2.34 1.263 2.73 1.652-2.633 2.208-8.772 3.984-12.253 3.984-.335 0-.653-.018-.971-.053v1.864H24V4.063zm0 10.326v1.131c-3.657-.654-4.673-4.46-4.673-4.46s1.758-1.944 4.673-2.262v1.237H8.94c-1.528-.186-2.73 1.245-2.73 1.245s.68 2.412 2.739 3.11M2.456 10.9s2.164-3.197 6.5-3.533V6.201C4.153 6.59 0 10.653 0 10.653s2.35 6.802 8.948 7.42v-1.237c-4.84-.6-6.492-5.936-6.492-5.936z\"] },\n meta: { viewBox: '0 0 24 24', fill: '#0467DF', paths: [\"M6.915 4.03c-1.968 0-3.683 1.28-4.871 3.113C.704 9.208 0 11.883 0 14.449c0 .706.07 1.369.21 1.973a6.624 6.624 0 0 0 .265.86 5.297 5.297 0 0 0 .371.761c.696 1.159 1.818 1.927 3.593 1.927 1.497 0 2.633-.671 3.965-2.444.76-1.012 1.144-1.626 2.663-4.32l.756-1.339.186-.325c.061.1.121.196.183.3l2.152 3.595c.724 1.21 1.665 2.556 2.47 3.314 1.046.987 1.992 1.22 3.06 1.22 1.075 0 1.876-.355 2.455-.843a3.743 3.743 0 0 0 .81-.973c.542-.939.861-2.127.861-3.745 0-2.72-.681-5.357-2.084-7.45-1.282-1.912-2.957-2.93-4.716-2.93-1.047 0-2.088.467-3.053 1.308-.652.57-1.257 1.29-1.82 2.05-.69-.875-1.335-1.547-1.958-2.056-1.182-.966-2.315-1.303-3.454-1.303zm10.16 2.053c1.147 0 2.188.758 2.992 1.999 1.132 1.748 1.647 4.195 1.647 6.4 0 1.548-.368 2.9-1.839 2.9-.58 0-1.027-.23-1.664-1.004-.496-.601-1.343-1.878-2.832-4.358l-.617-1.028a44.908 44.908 0 0 0-1.255-1.98c.07-.109.141-.224.211-.327 1.12-1.667 2.118-2.602 3.358-2.602zm-10.201.553c1.265 0 2.058.791 2.675 1.446.307.327.737.871 1.234 1.579l-1.02 1.566c-.757 1.163-1.882 3.017-2.837 4.338-1.191 1.649-1.81 1.817-2.486 1.817-.524 0-1.038-.237-1.383-.794-.263-.426-.464-1.13-.464-2.046 0-2.221.63-4.535 1.66-6.088.454-.687.964-1.226 1.533-1.533a2.264 2.264 0 0 1 1.088-.285z\"] },\n moonshotai: { viewBox: '0 0 24 24', fill: '#16191E', paths: [\"m1.053 16.91 9.538 2.55a21 20.981 0 0 0 .06 2.031l5.956 1.592a12 11.99 0 0 1-15.554-6.172m-1.02-5.79 11.352 3.035a21 20.981 0 0 0-.469 2.01l10.817 2.89a12 11.99 0 0 1-1.845 2.004L.658 15.918a12 11.99 0 0 1-.625-4.796m1.593-5.146L13.573 9.17a21 20.981 0 0 0-1.01 1.874l11.297 3.02a21 20.981 0 0 1-.67 2.362l-11.55-3.087L.125 10.26a12 11.99 0 0 1 1.499-4.285ZM6.067 1.58l11.285 3.016a21 20.981 0 0 0-1.688 1.719l7.824 2.091a21 20.981 0 0 1 .513 2.664L2.107 5.218a12 11.99 0 0 1 3.96-3.638M21.68 4.866 7.222 1.003A12 11.99 0 0 1 21.68 4.866\"] },\n openai: { viewBox: '0 0 256 260', fill: '#10A37F', paths: [\"M239.184 106.203a64.72 64.72 0 0 0-5.576-53.103C219.452 28.459 191 15.784 163.213 21.74A65.586 65.586 0 0 0 52.096 45.22a64.72 64.72 0 0 0-43.23 31.36c-14.31 24.602-11.061 55.634 8.033 76.74a64.67 64.67 0 0 0 5.525 53.102c14.174 24.65 42.644 37.324 70.446 31.36a64.72 64.72 0 0 0 48.754 21.744c28.481.025 53.714-18.361 62.414-45.481a64.77 64.77 0 0 0 43.229-31.36c14.137-24.558 10.875-55.423-8.083-76.483m-97.56 136.338a48.4 48.4 0 0 1-31.105-11.255l1.535-.87l51.67-29.825a8.6 8.6 0 0 0 4.247-7.367v-72.85l21.845 12.636c.218.111.37.32.409.563v60.367c-.056 26.818-21.783 48.545-48.601 48.601M37.158 197.93a48.35 48.35 0 0 1-5.781-32.589l1.534.921l51.722 29.826a8.34 8.34 0 0 0 8.441 0l63.181-36.425v25.221a.87.87 0 0 1-.358.665l-52.335 30.184c-23.257 13.398-52.97 5.431-66.404-17.803M23.549 85.38a48.5 48.5 0 0 1 25.58-21.333v61.39a8.29 8.29 0 0 0 4.195 7.316l62.874 36.272l-21.845 12.636a.82.82 0 0 1-.767 0L41.353 151.53c-23.211-13.454-31.171-43.144-17.804-66.405zm179.466 41.695l-63.08-36.63L161.73 77.86a.82.82 0 0 1 .768 0l52.233 30.184a48.6 48.6 0 0 1-7.316 87.635v-61.391a8.54 8.54 0 0 0-4.4-7.213m21.742-32.69l-1.535-.922l-51.619-30.081a8.39 8.39 0 0 0-8.492 0L99.98 99.808V74.587a.72.72 0 0 1 .307-.665l52.233-30.133a48.652 48.652 0 0 1 72.236 50.391zM88.061 139.097l-21.845-12.585a.87.87 0 0 1-.41-.614V65.685a48.652 48.652 0 0 1 79.757-37.346l-1.535.87l-51.67 29.825a8.6 8.6 0 0 0-4.246 7.367zm11.868-25.58L128.067 97.3l28.188 16.218v32.434l-28.086 16.218l-28.188-16.218z\"] },\n}\n\nconst ALIASES: Record<string, string> = {\n moonshot: 'moonshotai',\n deepseek_ai: 'deepseek',\n 'x-ai': 'xai',\n 'meta-llama': 'meta',\n}\n\nconst MONOGRAM: Record<string, { bg: string; fg: string }> = {\n cohere: { bg: '#fae8ff', fg: '#c026d3' },\n groq: { bg: '#fce7f3', fg: '#db2777' },\n cerebras: { bg: '#ccfbf1', fg: '#0d9488' },\n zai: { bg: '#ede9fe', fg: '#7c3aed' },\n 'z-ai': { bg: '#ede9fe', fg: '#7c3aed' },\n tuner: { bg: '#dbeafe', fg: '#2563eb' },\n}\n\nexport interface ProviderLogoProps {\n provider?: string\n size?: number\n}\n\n/** Real brand mark when we have one; tinted monogram otherwise. */\nexport function ProviderLogo({ provider, size = 16 }: ProviderLogoProps): ReactNode {\n const key = ALIASES[provider ?? ''] ?? provider ?? ''\n const logo = LOGOS[key]\n if (logo) {\n return (\n <svg width={size} height={size} viewBox={logo.viewBox} role=\"img\" aria-label={key}>\n {logo.paths.map((d, i) => (\n <path key={i} d={d} fill={logo.fill} />\n ))}\n </svg>\n )\n }\n const mono = MONOGRAM[key] ?? { bg: '#f3f4f6', fg: '#6b7280' }\n return (\n <svg width={size} height={size} viewBox=\"0 0 16 16\" role=\"img\" aria-label={key || 'model'}>\n <rect width=\"16\" height=\"16\" rx=\"4\" fill={mono.bg} />\n <text x=\"8\" y=\"11.6\" textAnchor=\"middle\" fill={mono.fg} fontSize=\"9\" fontWeight=\"700\" fontFamily=\"system-ui, sans-serif\">\n {(key || '?').charAt(0).toUpperCase()}\n </text>\n </svg>\n )\n}\n","/**\n * Smooth text reveal — turns chunky network deltas into a continuous\n * typewriter paint. Streamed turns arrive in 100-500ms slabs (model burst,\n * flush windows, replay polls); revealing characters at an adaptive rate\n * makes the same bytes read as top-tier streaming. The rate scales with the\n * backlog so the reveal never falls behind the stream — it crawls when caught\n * up and sprints when a burst lands (e.g. a reasoning summary arriving all at\n * once still *types out* instead of popping in).\n */\n\nimport { useEffect, useRef, useState } from 'react'\n\nexport interface SmoothRevealOptions {\n /** Baseline reveal rate when nearly caught up. Default 90 chars/s. */\n baseCharsPerSecond?: number\n /** Extra chars/s per backlog character — the catch-up pressure. Default 5. */\n catchUpPerChar?: number\n /** Hard ceiling so giant bursts still animate. Default 2400 chars/s. */\n maxCharsPerSecond?: number\n}\n\n/** Pure reveal step: how many characters should be visible after `dtMs`.\n * Exposed for tests; the hook is a thin rAF wrapper around it. */\nexport function nextRevealCount(\n shown: number,\n targetLength: number,\n dtMs: number,\n opts: SmoothRevealOptions = {},\n): number {\n if (shown >= targetLength) return targetLength\n const base = opts.baseCharsPerSecond ?? 90\n const catchUp = opts.catchUpPerChar ?? 5\n const max = opts.maxCharsPerSecond ?? 2400\n const backlog = targetLength - shown\n const rate = Math.min(max, base + backlog * catchUp)\n return Math.min(targetLength, shown + (rate * dtMs) / 1000)\n}\n\n/**\n * Animate `target` text into view. While `enabled`, the returned string grows\n * smoothly toward `target` (which may itself keep growing); when `enabled` is\n * false the full text returns immediately (history, completed turns). A\n * target that is not an extension of the revealed prefix (new message) resets\n * the reveal.\n */\nexport function useSmoothText(target: string, enabled: boolean, opts?: SmoothRevealOptions): string {\n const [, force] = useState(0)\n const shownRef = useRef(0)\n const lastTargetRef = useRef('')\n\n // New message / rewritten prefix → restart the reveal from zero.\n if (!target.startsWith(lastTargetRef.current.slice(0, Math.floor(shownRef.current)))) {\n shownRef.current = 0\n }\n lastTargetRef.current = target\n if (!enabled) shownRef.current = target.length\n\n useEffect(() => {\n if (!enabled) return\n let raf = 0\n let last: number | null = null\n const tick = (t: number) => {\n const dt = last == null ? 16 : Math.min(t - last, 100)\n last = t\n const targetLen = lastTargetRef.current.length\n if (shownRef.current < targetLen) {\n shownRef.current = nextRevealCount(shownRef.current, targetLen, dt, opts)\n force((n) => n + 1)\n }\n raf = requestAnimationFrame(tick)\n }\n raf = requestAnimationFrame(tick)\n return () => cancelAnimationFrame(raf)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [enabled])\n\n return target.slice(0, Math.floor(shownRef.current))\n}\n","/**\n * Client-side chat-stream consumption — the NDJSON parse loop every agent\n * app's chat UI hand-rolls (and breaks). Normalizes the three line shapes the\n * agent-app chat routes emit:\n *\n * {kind:'event', event:{type:'text'|'reasoning'|'tool_call'|'usage', ...}}\n * {kind:'tool_result', toolCallId, toolName, label, outcome}\n * {type:'turn'|'metadata'|'error'|'turn_status', ...} (route-level)\n *\n * Replayed lines carry an extra `seq` — transparently ignored. Works for\n * router-backed and sandbox-backed chats alike: anything producing these\n * lines (live pump, queued follow, resume replay) feeds the same callbacks.\n */\n\nexport interface ChatStreamToolCall {\n toolCallId?: string\n toolName: string\n args: Record<string, unknown>\n}\n\nexport interface ChatStreamToolResult {\n toolCallId?: string\n toolName?: string\n label?: string\n outcome: { ok: boolean; result?: unknown; code?: string; message?: string }\n}\n\nexport interface ChatStreamCallbacks {\n onTurnId?: (turnId: string) => void\n onText?: (delta: string) => void\n onReasoning?: (delta: string) => void\n onToolCall?: (call: ChatStreamToolCall) => void\n onToolResult?: (result: ChatStreamToolResult) => void\n onUsage?: (usage: { promptTokens: number; completionTokens: number }) => void\n onMetadata?: (data: Record<string, unknown>) => void\n /** A loop-level error event (the turn failed server-side). */\n onErrorEvent?: (message: string) => void\n}\n\nexport interface ConsumeChatStreamResult {\n turnId: string | null\n /** True when any text/reasoning/tool activity was received. */\n receivedContent: boolean\n}\n\n/** Parse one NDJSON line into the callbacks. Exposed for tests. */\nexport function dispatchChatStreamLine(line: string, cb: ChatStreamCallbacks): {\n turnId?: string\n receivedContent: boolean\n} {\n let receivedContent = false\n let turnId: string | undefined\n if (!line.trim()) return { receivedContent }\n let parsed: Record<string, unknown>\n try {\n parsed = JSON.parse(line) as Record<string, unknown>\n } catch {\n return { receivedContent } // tolerate a torn line\n }\n\n if (parsed.kind === 'tool_result') {\n cb.onToolResult?.({\n toolCallId: parsed.toolCallId as string | undefined,\n toolName: parsed.toolName as string | undefined,\n label: parsed.label as string | undefined,\n outcome: (parsed.outcome ?? parsed.result) as ChatStreamToolResult['outcome'],\n })\n return { receivedContent: true }\n }\n\n const evt = (parsed.kind === 'event' ? parsed.event : parsed) as Record<string, unknown>\n if (!evt || typeof evt !== 'object') return { receivedContent }\n\n switch (evt.type) {\n case 'turn':\n if (typeof evt.turnId === 'string') turnId = evt.turnId\n break\n case 'text':\n if (typeof evt.text === 'string') {\n cb.onText?.(evt.text)\n receivedContent = true\n }\n break\n case 'reasoning':\n if (typeof evt.text === 'string') {\n cb.onReasoning?.(evt.text)\n receivedContent = true\n }\n break\n case 'tool_call': {\n const call = (evt.call ?? evt) as Record<string, unknown>\n cb.onToolCall?.({\n toolCallId: (call.toolCallId ?? call.id) as string | undefined,\n toolName: String(call.toolName ?? call.name ?? 'unknown'),\n args: (call.args ?? {}) as Record<string, unknown>,\n })\n receivedContent = true\n break\n }\n case 'tool_result':\n cb.onToolResult?.({\n toolCallId: evt.toolCallId as string | undefined,\n toolName: evt.toolName as string | undefined,\n label: evt.label as string | undefined,\n outcome: (evt.outcome ?? evt.result) as ChatStreamToolResult['outcome'],\n })\n receivedContent = true\n break\n case 'usage': {\n const u = evt.usage as { promptTokens?: number; completionTokens?: number } | undefined\n if (u) cb.onUsage?.({ promptTokens: u.promptTokens ?? 0, completionTokens: u.completionTokens ?? 0 })\n break\n }\n case 'metadata':\n cb.onMetadata?.((evt.data ?? {}) as Record<string, unknown>)\n break\n case 'error':\n cb.onErrorEvent?.(String(evt.details ?? evt.error ?? 'Unknown stream error'))\n break\n default:\n break // turn_status and unknown line types are non-content\n }\n return { turnId, receivedContent }\n}\n\n/** Drain one NDJSON body into the callbacks. Throws on transport failure\n * (caller decides whether to resume). */\nexport async function consumeChatStream(\n body: ReadableStream<Uint8Array>,\n cb: ChatStreamCallbacks,\n): Promise<ConsumeChatStreamResult> {\n const reader = body.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n let turnId: string | null = null\n let receivedContent = false\n\n const handle = (line: string) => {\n const r = dispatchChatStreamLine(line, cb)\n if (r.turnId) {\n turnId = r.turnId\n cb.onTurnId?.(r.turnId)\n }\n if (r.receivedContent) receivedContent = true\n }\n\n for (;;) {\n const { done, value } = await reader.read()\n if (done) {\n if (buffer.trim()) handle(buffer)\n break\n }\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split('\\n')\n buffer = lines.pop() ?? ''\n for (const line of lines) handle(line)\n }\n return { turnId, receivedContent }\n}\n\nexport interface StreamChatOptions {\n /** Start the turn (POST the chat request); must return a streaming Response. */\n start: () => Promise<Response>\n /** Re-attach to a turn after a transport drop (GET the resume route). */\n resume?: (turnId: string, fromSeq: number) => Promise<Response>\n callbacks: ChatStreamCallbacks\n /** Called before a resume replays from 0 so the UI can reset accumulated\n * turn state (text, reasoning, tool chips). */\n onResetForResume?: () => void\n}\n\n/**\n * Run one chat turn with automatic single-shot resume: if the transport drops\n * mid-turn and the server announced a turnId, reset and replay the buffered\n * turn. Server-side the turn keeps running either way (queued runner).\n */\nexport async function streamChatTurn(opts: StreamChatOptions): Promise<ConsumeChatStreamResult> {\n const res = await opts.start()\n if (!res.ok || !res.body) {\n const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` })) as { error?: string }\n throw new Error(err.error ?? `HTTP ${res.status}`)\n }\n let turnId: string | null = null\n const cb: ChatStreamCallbacks = {\n ...opts.callbacks,\n onTurnId: (id) => {\n turnId = id\n opts.callbacks.onTurnId?.(id)\n },\n }\n try {\n return await consumeChatStream(res.body, cb)\n } catch (transportErr) {\n if (!turnId || !opts.resume) throw transportErr\n opts.onResetForResume?.()\n const resumed = await opts.resume(turnId, 0)\n if (!resumed.ok || !resumed.body) throw transportErr\n return await consumeChatStream(resumed.body, cb)\n }\n}\n"],"mappings":";AAkBA,SAAS,aAAAA,YAAW,SAAS,UAAAC,SAAQ,YAAAC,iBAAgC;;;ACuC3D,cAON,YAPM;AAzCV,IAAM,QAAiC;AAAA,EACrC,WAAW,EAAE,SAAS,aAAa,MAAM,WAAW,OAAO,CAAC,0KAA0K,EAAE;AAAA,EACxO,QAAQ,EAAE,SAAS,aAAa,MAAM,WAAW,OAAO,CAAC,8RAA8R,EAAE;AAAA,EACzV,UAAU,EAAE,SAAS,aAAa,MAAM,WAAW,OAAO,CAAC,w7DAAw7D,EAAE;AAAA,EACr/D,SAAS,EAAE,SAAS,aAAa,MAAM,WAAW,OAAO,CAAC,kLAAkL,EAAE;AAAA,EAC9O,KAAK,EAAE,SAAS,aAAa,MAAM,WAAW,OAAO,CAAC,oMAAoM,EAAE;AAAA,EAC5P,QAAQ,EAAE,SAAS,aAAa,MAAM,WAAW,OAAO,CAAC,qwBAAqwB,EAAE;AAAA,EACh0B,MAAM,EAAE,SAAS,aAAa,MAAM,WAAW,OAAO,CAAC,ksCAAksC,EAAE;AAAA,EAC3vC,YAAY,EAAE,SAAS,aAAa,MAAM,WAAW,OAAO,CAAC,2hBAA2hB,EAAE;AAAA,EAC1lB,QAAQ,EAAE,SAAS,eAAe,MAAM,WAAW,OAAO,CAAC,28CAA28C,EAAE;AAC1gD;AAEA,IAAM,UAAkC;AAAA,EACtC,UAAU;AAAA,EACV,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,cAAc;AAChB;AAEA,IAAM,WAAuD;AAAA,EAC3D,QAAQ,EAAE,IAAI,WAAW,IAAI,UAAU;AAAA,EACvC,MAAM,EAAE,IAAI,WAAW,IAAI,UAAU;AAAA,EACrC,UAAU,EAAE,IAAI,WAAW,IAAI,UAAU;AAAA,EACzC,KAAK,EAAE,IAAI,WAAW,IAAI,UAAU;AAAA,EACpC,QAAQ,EAAE,IAAI,WAAW,IAAI,UAAU;AAAA,EACvC,OAAO,EAAE,IAAI,WAAW,IAAI,UAAU;AACxC;AAQO,SAAS,aAAa,EAAE,UAAU,OAAO,GAAG,GAAiC;AAClF,QAAM,MAAM,QAAQ,YAAY,EAAE,KAAK,YAAY;AACnD,QAAM,OAAO,MAAM,GAAG;AACtB,MAAI,MAAM;AACR,WACE,oBAAC,SAAI,OAAO,MAAM,QAAQ,MAAM,SAAS,KAAK,SAAS,MAAK,OAAM,cAAY,KAC3E,eAAK,MAAM,IAAI,CAAC,GAAG,MAClB,oBAAC,UAAa,GAAM,MAAM,KAAK,QAApB,CAA0B,CACtC,GACH;AAAA,EAEJ;AACA,QAAM,OAAO,SAAS,GAAG,KAAK,EAAE,IAAI,WAAW,IAAI,UAAU;AAC7D,SACE,qBAAC,SAAI,OAAO,MAAM,QAAQ,MAAM,SAAQ,aAAY,MAAK,OAAM,cAAY,OAAO,SAChF;AAAA,wBAAC,UAAK,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI,MAAM,KAAK,IAAI;AAAA,IACnD,oBAAC,UAAK,GAAE,KAAI,GAAE,QAAO,YAAW,UAAS,MAAM,KAAK,IAAI,UAAS,KAAI,YAAW,OAAM,YAAW,yBAC7F,kBAAO,KAAK,OAAO,CAAC,EAAE,YAAY,GACtC;AAAA,KACF;AAEJ;;;AC7DA,SAAS,WAAW,QAAQ,gBAAgB;AAarC,SAAS,gBACd,OACA,cACA,MACA,OAA4B,CAAC,GACrB;AACR,MAAI,SAAS,aAAc,QAAO;AAClC,QAAM,OAAO,KAAK,sBAAsB;AACxC,QAAM,UAAU,KAAK,kBAAkB;AACvC,QAAM,MAAM,KAAK,qBAAqB;AACtC,QAAM,UAAU,eAAe;AAC/B,QAAM,OAAO,KAAK,IAAI,KAAK,OAAO,UAAU,OAAO;AACnD,SAAO,KAAK,IAAI,cAAc,QAAS,OAAO,OAAQ,GAAI;AAC5D;AASO,SAAS,cAAc,QAAgB,SAAkB,MAAoC;AAClG,QAAM,CAAC,EAAE,KAAK,IAAI,SAAS,CAAC;AAC5B,QAAM,WAAW,OAAO,CAAC;AACzB,QAAM,gBAAgB,OAAO,EAAE;AAG/B,MAAI,CAAC,OAAO,WAAW,cAAc,QAAQ,MAAM,GAAG,KAAK,MAAM,SAAS,OAAO,CAAC,CAAC,GAAG;AACpF,aAAS,UAAU;AAAA,EACrB;AACA,gBAAc,UAAU;AACxB,MAAI,CAAC,QAAS,UAAS,UAAU,OAAO;AAExC,YAAU,MAAM;AACd,QAAI,CAAC,QAAS;AACd,QAAI,MAAM;AACV,QAAI,OAAsB;AAC1B,UAAM,OAAO,CAAC,MAAc;AAC1B,YAAM,KAAK,QAAQ,OAAO,KAAK,KAAK,IAAI,IAAI,MAAM,GAAG;AACrD,aAAO;AACP,YAAM,YAAY,cAAc,QAAQ;AACxC,UAAI,SAAS,UAAU,WAAW;AAChC,iBAAS,UAAU,gBAAgB,SAAS,SAAS,WAAW,IAAI,IAAI;AACxE,cAAM,CAAC,MAAM,IAAI,CAAC;AAAA,MACpB;AACA,YAAM,sBAAsB,IAAI;AAAA,IAClC;AACA,UAAM,sBAAsB,IAAI;AAChC,WAAO,MAAM,qBAAqB,GAAG;AAAA,EAEvC,GAAG,CAAC,OAAO,CAAC;AAEZ,SAAO,OAAO,MAAM,GAAG,KAAK,MAAM,SAAS,OAAO,CAAC;AACrD;;;AC/BO,SAAS,uBAAuB,MAAc,IAGnD;AACA,MAAI,kBAAkB;AACtB,MAAI;AACJ,MAAI,CAAC,KAAK,KAAK,EAAG,QAAO,EAAE,gBAAgB;AAC3C,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,IAAI;AAAA,EAC1B,QAAQ;AACN,WAAO,EAAE,gBAAgB;AAAA,EAC3B;AAEA,MAAI,OAAO,SAAS,eAAe;AACjC,OAAG,eAAe;AAAA,MAChB,YAAY,OAAO;AAAA,MACnB,UAAU,OAAO;AAAA,MACjB,OAAO,OAAO;AAAA,MACd,SAAU,OAAO,WAAW,OAAO;AAAA,IACrC,CAAC;AACD,WAAO,EAAE,iBAAiB,KAAK;AAAA,EACjC;AAEA,QAAM,MAAO,OAAO,SAAS,UAAU,OAAO,QAAQ;AACtD,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO,EAAE,gBAAgB;AAE9D,UAAQ,IAAI,MAAM;AAAA,IAChB,KAAK;AACH,UAAI,OAAO,IAAI,WAAW,SAAU,UAAS,IAAI;AACjD;AAAA,IACF,KAAK;AACH,UAAI,OAAO,IAAI,SAAS,UAAU;AAChC,WAAG,SAAS,IAAI,IAAI;AACpB,0BAAkB;AAAA,MACpB;AACA;AAAA,IACF,KAAK;AACH,UAAI,OAAO,IAAI,SAAS,UAAU;AAChC,WAAG,cAAc,IAAI,IAAI;AACzB,0BAAkB;AAAA,MACpB;AACA;AAAA,IACF,KAAK,aAAa;AAChB,YAAM,OAAQ,IAAI,QAAQ;AAC1B,SAAG,aAAa;AAAA,QACd,YAAa,KAAK,cAAc,KAAK;AAAA,QACrC,UAAU,OAAO,KAAK,YAAY,KAAK,QAAQ,SAAS;AAAA,QACxD,MAAO,KAAK,QAAQ,CAAC;AAAA,MACvB,CAAC;AACD,wBAAkB;AAClB;AAAA,IACF;AAAA,IACA,KAAK;AACH,SAAG,eAAe;AAAA,QAChB,YAAY,IAAI;AAAA,QAChB,UAAU,IAAI;AAAA,QACd,OAAO,IAAI;AAAA,QACX,SAAU,IAAI,WAAW,IAAI;AAAA,MAC/B,CAAC;AACD,wBAAkB;AAClB;AAAA,IACF,KAAK,SAAS;AACZ,YAAM,IAAI,IAAI;AACd,UAAI,EAAG,IAAG,UAAU,EAAE,cAAc,EAAE,gBAAgB,GAAG,kBAAkB,EAAE,oBAAoB,EAAE,CAAC;AACpG;AAAA,IACF;AAAA,IACA,KAAK;AACH,SAAG,aAAc,IAAI,QAAQ,CAAC,CAA6B;AAC3D;AAAA,IACF,KAAK;AACH,SAAG,eAAe,OAAO,IAAI,WAAW,IAAI,SAAS,sBAAsB,CAAC;AAC5E;AAAA,IACF;AACE;AAAA,EACJ;AACA,SAAO,EAAE,QAAQ,gBAAgB;AACnC;AAIA,eAAsB,kBACpB,MACA,IACkC;AAClC,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,UAAU,IAAI,YAAY;AAChC,MAAI,SAAS;AACb,MAAI,SAAwB;AAC5B,MAAI,kBAAkB;AAEtB,QAAM,SAAS,CAAC,SAAiB;AAC/B,UAAM,IAAI,uBAAuB,MAAM,EAAE;AACzC,QAAI,EAAE,QAAQ;AACZ,eAAS,EAAE;AACX,SAAG,WAAW,EAAE,MAAM;AAAA,IACxB;AACA,QAAI,EAAE,gBAAiB,mBAAkB;AAAA,EAC3C;AAEA,aAAS;AACP,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,QAAI,MAAM;AACR,UAAI,OAAO,KAAK,EAAG,QAAO,MAAM;AAChC;AAAA,IACF;AACA,cAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAChD,UAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,aAAS,MAAM,IAAI,KAAK;AACxB,eAAW,QAAQ,MAAO,QAAO,IAAI;AAAA,EACvC;AACA,SAAO,EAAE,QAAQ,gBAAgB;AACnC;AAkBA,eAAsB,eAAe,MAA2D;AAC9F,QAAM,MAAM,MAAM,KAAK,MAAM;AAC7B,MAAI,CAAC,IAAI,MAAM,CAAC,IAAI,MAAM;AACxB,UAAM,MAAM,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,EAAE,OAAO,QAAQ,IAAI,MAAM,GAAG,EAAE;AAC1E,UAAM,IAAI,MAAM,IAAI,SAAS,QAAQ,IAAI,MAAM,EAAE;AAAA,EACnD;AACA,MAAI,SAAwB;AAC5B,QAAM,KAA0B;AAAA,IAC9B,GAAG,KAAK;AAAA,IACR,UAAU,CAAC,OAAO;AAChB,eAAS;AACT,WAAK,UAAU,WAAW,EAAE;AAAA,IAC9B;AAAA,EACF;AACA,MAAI;AACF,WAAO,MAAM,kBAAkB,IAAI,MAAM,EAAE;AAAA,EAC7C,SAAS,cAAc;AACrB,QAAI,CAAC,UAAU,CAAC,KAAK,OAAQ,OAAM;AACnC,SAAK,mBAAmB;AACxB,UAAM,UAAU,MAAM,KAAK,OAAO,QAAQ,CAAC;AAC3C,QAAI,CAAC,QAAQ,MAAM,CAAC,QAAQ,KAAM,OAAM;AACxC,WAAO,MAAM,kBAAkB,QAAQ,MAAM,EAAE;AAAA,EACjD;AACF;;;AHvKM,SAqNQ,UArNR,OAAAC,MAOF,QAAAC,aAPE;AAHN,SAAS,YAAY,EAAE,UAAU,GAA2B;AAC1D,SACE,gBAAAD,KAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACvJ,0BAAAA,KAAC,UAAK,GAAE,gBAAe,GACzB;AAEJ;AAEA,SAAS,YAAY,EAAE,UAAU,GAA2B;AAC1D,SACE,gBAAAC,MAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACvJ;AAAA,oBAAAD,KAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,IAC9B,gBAAAA,KAAC,UAAK,GAAE,kBAAiB;AAAA,KAC3B;AAEJ;AAEA,SAAS,aAAa,EAAE,UAAU,GAA2B;AAC3D,SACE,gBAAAA,KAAC,SAAI,WAAsB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SAAQ,eAAW,MACvJ,0BAAAA,KAAC,UAAK,GAAE,iGAAgG,GAC1G;AAEJ;AAGA,SAAS,gBAAgB,WAAuB;AAC9C,QAAM,MAAME,QAAuB,IAAI;AACvC,EAAAC,WAAU,MAAM;AACd,aAAS,QAAQ,GAAe;AAC9B,UAAI,IAAI,WAAW,CAAC,IAAI,QAAQ,SAAS,EAAE,MAAc,EAAG,WAAU;AAAA,IACxE;AACA,aAAS,iBAAiB,aAAa,OAAO;AAC9C,WAAO,MAAM,SAAS,oBAAoB,aAAa,OAAO;AAAA,EAChE,CAAC;AACD,SAAO;AACT;AAYO,SAAS,gBAAgB,KAAyB,QAAuC;AAC9F,MAAI,IAAI,gBAAgB,QAAQ,IAAI,oBAAoB,KAAM,QAAO;AACrE,QAAM,UAAU,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,IAAI,SAAS,GAAG;AAC5D,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,QACH,IAAI,gBAAgB,KAAK,OAAO,QAAQ,UAAU,CAAC,KACnD,IAAI,oBAAoB,KAAK,OAAO,QAAQ,cAAc,CAAC;AAC9D,MAAI,CAAC,SAAS,IAAI,KAAK,QAAQ,EAAG,QAAO;AACzC,SAAO,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,KAAK,IAAI,KAAK,QAAQ,CAAC,CAAC;AAClE;AAGO,SAAS,sBAAsB,KAAwC;AAC5E,MAAI,IAAI,oBAAoB,QAAQ,CAAC,IAAI,WAAY,QAAO;AAC5D,SAAO,GAAG,KAAK,MAAM,IAAI,oBAAoB,IAAI,aAAa,IAAK,CAAC;AACtE;AAiBA,SAAS,YAAY,GAAgC;AACnD,MAAI,CAAC,EAAG,QAAO;AACf,QAAM,IAAI,OAAO,CAAC;AAClB,MAAI,MAAM,CAAC,KAAK,MAAM,EAAG,QAAO;AAChC,QAAM,OAAO,IAAI;AACjB,SAAO,QAAQ,IAAI,IAAI,KAAK,QAAQ,CAAC,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC;AAClE;AAEA,SAAS,cAAc,KAAkC;AACvD,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,OAAO,IAAW,QAAO,IAAI,MAAM,KAAW,QAAQ,CAAC,CAAC;AAC5D,MAAI,OAAO,IAAO,QAAO,GAAG,KAAK,MAAM,MAAM,GAAK,CAAC;AACnD,SAAO,GAAG,GAAG;AACf;AAEA,SAAS,cAAc,EAAE,SAAS,GAA4B;AAC5D,SACE,gBAAAH,KAAC,SAAI,WAAU,yFACZ,UACH;AAEJ;AAEA,SAAS,SAAS;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,QAAQ,YAAY,MAAM,SAAS,MAAM;AAC/C,QAAM,MAAM,cAAc,MAAM,aAAa;AAC7C,SACE,gBAAAC;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAS;AAAA,MACT,WAAW,wFACT,WAAW,8BAA8B,oBAC3C;AAAA,MAEC;AAAA,8BAAsB,oBAAoB,MAAM,QAAQ,IAAI,gBAAAD,KAAC,gBAAa,UAAU,MAAM,UAAU,MAAM,IAAI;AAAA,QAC/G,gBAAAA,KAAC,UAAK,WAAU,YAAY,gBAAM,MAAK;AAAA,QACtC,CAAC,MAAM,iBACN,gBAAAA,KAAC,UAAK,WAAU,4FAA2F,sBAE3G;AAAA,QAEF,gBAAAC,MAAC,UAAK,WAAU,0EACb;AAAA,iBAAO,gBAAAD,KAAC,UAAM,eAAI;AAAA,UAClB,SAAS,gBAAAA,KAAC,UAAM,iBAAM;AAAA,WACzB;AAAA;AAAA;AAAA,EACF;AAEJ;AAOO,SAAS,YAAY,EAAE,OAAO,UAAU,QAAQ,SAAS,qBAAqB,mBAAmB,cAAc,GAAqB;AACzI,QAAM,CAAC,MAAM,OAAO,IAAII,UAAS,KAAK;AACtC,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAS,EAAE;AACrC,QAAM,eAAe,gBAAgB,MAAM,QAAQ,KAAK,CAAC;AACzD,QAAM,WAAWF,QAAyB,IAAI;AAE9C,EAAAC,WAAU,MAAM;AACd,QAAI,KAAM,UAAS,SAAS,MAAM;AAAA,EACpC,GAAG,CAAC,IAAI,CAAC;AAET,QAAM,WAAW,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK;AAElD,QAAM,WAAW,QAAQ,MAAM;AAC7B,UAAM,IAAI,MAAM,KAAK,EAAE,YAAY;AACnC,QAAI,CAAC,EAAG,QAAO;AACf,WAAO,OAAO;AAAA,MACZ,CAAC,MACC,EAAE,GAAG,YAAY,EAAE,SAAS,CAAC,KAC7B,EAAE,KAAK,YAAY,EAAE,SAAS,CAAC,MAC9B,EAAE,aAAa,YAAY,KAAK,IAAI,SAAS,CAAC,KAC/C,EAAE,SAAS,YAAY,EAAE,SAAS,CAAC;AAAA,IACvC;AAAA,EACF,GAAG,CAAC,QAAQ,KAAK,CAAC;AAElB,QAAM,WAAW,QAAQ,MAAM;AAC7B,UAAM,cAAc,OAAO,OAAO,CAAC,MAAM,EAAE,QAAQ;AACnD,UAAM,aAAiE,CAAC;AACxE,eAAW,KAAK,QAAQ;AACtB,UAAI,EAAE,SAAU;AAChB,YAAM,OAAO,WAAW,WAAW,SAAS,CAAC;AAC7C,UAAI,QAAQ,KAAK,aAAa,EAAE,SAAU,MAAK,MAAM,KAAK,CAAC;AAAA,UACtD,YAAW,KAAK,EAAE,UAAU,EAAE,UAAU,OAAO,CAAC,CAAC,EAAE,CAAC;AAAA,IAC3D;AACA,WAAO,EAAE,aAAa,WAAW;AAAA,EACnC,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,SAAS,CAAC,OAAe;AAC7B,aAAS,EAAE;AACX,YAAQ,KAAK;AACb,aAAS,EAAE;AAAA,EACb;AAEA,SACE,gBAAAF,MAAC,SAAI,KAAK,cAAc,WAAU,wBAChC;AAAA,oBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;AAAA,QAChC,WAAU;AAAA,QAET;AAAA,qBAAY,sBAAsB,oBAAoB,SAAS,QAAQ,IAAI,gBAAAD,KAAC,gBAAa,UAAU,SAAS,UAAU,MAAM,IAAI,IAAM,gBAAAA,KAAC,gBAAa,WAAU,qCAAoC;AAAA,UACnM,gBAAAA,KAAC,UAAK,WAAU,0BAA0B,oBAAU,QAAQ,OAAM;AAAA,UAClE,gBAAAA,KAAC,eAAY,WAAU,qCAAoC;AAAA;AAAA;AAAA,IAC7D;AAAA,IAEC,QACC,gBAAAC,MAAC,SAAI,WAAU,qHACb;AAAA,sBAAAD,KAAC,SAAI,WAAU,oCACb,0BAAAC,MAAC,SAAI,WAAU,mFACb;AAAA,wBAAAD,KAAC,eAAY,WAAU,qCAAoC;AAAA,QAC3D,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,MAAK;AAAA,YACL,OAAO;AAAA,YACP,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,YACxC,aAAY;AAAA,YACZ,WAAU;AAAA;AAAA,QACZ;AAAA,SACF,GACF;AAAA,MACA,gBAAAC,MAAC,SAAI,WAAU,0CACZ;AAAA,mBAAW,gBAAAD,KAAC,SAAI,WAAU,uDAAsD,+BAAiB;AAAA,QACjG,CAAC,WAAW,YACX,gBAAAC,MAAA,YACG;AAAA,mBAAS,WAAW,KACnB,gBAAAD,KAAC,SAAI,WAAU,uDAAsD,yCAA2B;AAAA,UAEjG,SAAS,IAAI,CAAC,MACb,gBAAAA,KAAC,YAAoB,OAAO,GAAG,UAAU,EAAE,OAAO,OAAO,UAAU,MAAM,OAAO,EAAE,EAAE,GAAG,uBAAxE,EAAE,EAAgH,CAClI;AAAA,WACH;AAAA,QAED,CAAC,WAAW,CAAC,YACZ,gBAAAC,MAAA,YACG;AAAA,mBAAS,YAAY,SAAS,KAC7B,gBAAAA,MAAA,YACE;AAAA,4BAAAD,KAAC,iBAAe,4BAAiB;AAAA,YAChC,SAAS,YAAY,IAAI,CAAC,MACzB,gBAAAA,KAAC,YAAoB,OAAO,GAAG,UAAU,EAAE,OAAO,OAAO,UAAU,MAAM,OAAO,EAAE,EAAE,GAAG,uBAAxE,EAAE,EAAgH,CAClI;AAAA,aACH;AAAA,UAED,SAAS,WAAW,IAAI,CAAC,MACxB,gBAAAC,MAAC,SACC;AAAA,4BAAAD,KAAC,iBAAe,YAAE,UAAS;AAAA,YAC1B,EAAE,MAAM,IAAI,CAAC,MACZ,gBAAAA,KAAC,YAAoB,OAAO,GAAG,UAAU,EAAE,OAAO,OAAO,UAAU,MAAM,OAAO,EAAE,EAAE,GAAG,uBAAxE,EAAE,EAAgH,CAClI;AAAA,eAJO,EAAE,QAKZ,CACD;AAAA,WACH;AAAA,SAEJ;AAAA,OACF;AAAA,KAEJ;AAEJ;AAIA,IAAM,gBAAgB;AAAA,EACpB,EAAE,IAAI,OAAO,OAAO,MAAM;AAAA,EAC1B,EAAE,IAAI,OAAO,OAAO,MAAM;AAAA,EAC1B,EAAE,IAAI,UAAU,OAAO,SAAS;AAAA,EAChC,EAAE,IAAI,QAAQ,OAAO,OAAO;AAC9B;AASO,SAAS,aAAa,EAAE,OAAO,SAAS,GAAsB;AACnE,QAAM,CAAC,MAAM,OAAO,IAAII,UAAS,KAAK;AACtC,QAAM,eAAe,gBAAgB,MAAM,QAAQ,KAAK,CAAC;AACzD,QAAM,WAAW,cAAc,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,KAAK,cAAc,CAAC;AAE7E,SACE,gBAAAH,MAAC,SAAI,KAAK,cAAc,WAAU,wBAChC;AAAA,oBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAM,QAAQ,CAAC,MAAM,CAAC,CAAC;AAAA,QAChC,OAAM;AAAA,QACN,WAAU;AAAA,QAEV;AAAA,0BAAAD,KAAC,gBAAa,WAAU,qCAAoC;AAAA,UAC5D,gBAAAA,KAAC,UAAM,mBAAS,OAAM;AAAA,UACtB,gBAAAA,KAAC,eAAY,WAAU,qCAAoC;AAAA;AAAA;AAAA,IAC7D;AAAA,IACC,QACC,gBAAAA,KAAC,SAAI,WAAU,oHACZ,wBAAc,IAAI,CAAC,MAClB,gBAAAA;AAAA,MAAC;AAAA;AAAA,QAEC,MAAK;AAAA,QACL,SAAS,MAAM;AACb,mBAAS,EAAE,EAAE;AACb,kBAAQ,KAAK;AAAA,QACf;AAAA,QACA,WAAW,8EACT,EAAE,OAAO,QAAQ,8BAA8B,oBACjD;AAAA,QAEC,YAAE;AAAA;AAAA,MAVE,EAAE;AAAA,IAWT,CACD,GACH;AAAA,KAEJ;AAEJ;AAiCO,SAAS,WAAW,EAAE,KAAK,QAAQ,GAAoB;AAC5D,SACE,gBAAAC,MAAC,SAAI,WAAU,4GACb;AAAA,oBAAAA,MAAC,SAAI,WAAU,4DACb;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,iCACT,IAAI,WAAW,YAAY,kBAAkB,IAAI,WAAW,UAAU,eAAe,cACvF;AAAA;AAAA,MACF;AAAA,MACA,gBAAAC,MAAC,SAAI,WAAU,kBACb;AAAA,wBAAAD,KAAC,OAAE,WAAU,kCAAkC,cAAI,OAAM;AAAA,QACzD,gBAAAA,KAAC,OAAE,WAAU,wDAAwD,cAAI,UAAS;AAAA,SACpF;AAAA,MACA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS;AAAA,UACT,cAAW;AAAA,UACX,WAAU;AAAA,UAEV,0BAAAA,KAAC,SAAI,WAAU,WAAU,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,eAAW,MAC9H,0BAAAA,KAAC,UAAK,GAAE,wBAAuB,GACjC;AAAA;AAAA,MACF;AAAA,OACF;AAAA,IACA,gBAAAC,MAAC,SAAI,WAAU,wCACZ;AAAA,UAAI,MAAM,WAAW,KACpB,gBAAAD,KAAC,OAAE,WAAU,iCAAgC,oCAAsB;AAAA,MAEpE,IAAI,MAAM,IAAI,CAAC,MAAM,MACpB,gBAAAC,MAAC,SAAY,WAAU,oDACrB;AAAA,wBAAAA,MAAC,SAAI,WAAU,mEACb;AAAA,0BAAAD,KAAC,UAAK,WAAW,yBAAyB,KAAK,WAAW,UAAU,iBAAiB,uBAAuB,IACzG,eAAK,WAAW,UAAU,WAAM,KACnC;AAAA,UACA,gBAAAA,KAAC,UAAK,WAAU,6CAA6C,eAAK,OAAM;AAAA,UACxE,gBAAAA,KAAC,UAAK,WAAU,iDACb,cAAI,KAAK,KAAK,EAAE,EAAE,mBAAmB,GACxC;AAAA,WACF;AAAA,QACC,KAAK,UACJ,gBAAAA,KAAC,SAAI,WAAU,oHACZ,eAAK,QACR;AAAA,WAbM,CAeV,CACD;AAAA,OACH;AAAA,IACA,gBAAAA,KAAC,OAAE,WAAU,yEAAwE,4DAErF;AAAA,KACF;AAEJ;AAkBO,SAAS,kBAAkB,MAAuD;AACvF,QAAM,UAAU,KAAK;AACrB,MAAI,CAAC,SAAS,MAAM,QAAQ,QAAQ,WAAW,yBAAyB,CAAC,QAAQ,OAAO,WAAY,QAAO;AAC3G,SAAO,EAAE,YAAY,QAAQ,OAAO,WAAW;AACjD;AA2CA,SAAS,cAAc,MAA0G;AAC/H,SAAO,KAAK;AACd;AAGA,SAAS,kBAAkB,MAAgC;AACzD,QAAM,IAAI,KAAK,QAAQ,CAAC;AACxB,UAAQ,KAAK,MAAM;AAAA,IACjB,KAAK;AACH,aAAO,iBAAc,OAAO,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,OAAO,EAAE,KAAK,CAAC,KAAK,EAAE;AAAA,IACnF,KAAK;AACH,aAAO,mBAAmB,OAAO,EAAE,eAAe,WAAW,CAAC;AAAA,IAChE,KAAK;AACH,aAAO,KAAK,OAAO,EAAE,WAAW,EAAE,CAAC;AAAA,IACrC,KAAK;AACH,aAAO,mBAAmB,OAAO,EAAE,cAAc,EAAE,CAAC;AAAA,IACtD,KAAK;AACH,aAAO,kBAAe,OAAO,EAAE,SAAS,EAAE,CAAC;AAAA,IAC7C,KAAK;AACH,aAAO,oBAAiB,OAAO,EAAE,SAAS,EAAE,CAAC;AAAA,IAC/C,KAAK;AACH,aAAO,iBAAc,OAAO,EAAE,QAAQ,EAAE,CAAC;AAAA,IAC3C;AACE,aAAO,KAAK;AAAA,EAChB;AACF;AAEA,SAAS,SAAS,GAAY,MAAM,KAAa;AAC/C,QAAM,IAAI,OAAO,MAAM,WAAW,IAAI,KAAK,UAAU,CAAC;AACtD,SAAO,EAAE,SAAS,MAAM,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC,WAAM;AAClD;AAEA,SAAS,OAAO,EAAE,KAAK,GAAsC;AAC3D,QAAM,UAAU,OAAO,QAAQ,IAAI,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,MAAM,UAAa,MAAM,QAAQ,MAAM,EAAE;AAChG,MAAI,CAAC,QAAQ,OAAQ,QAAO;AAC5B,SACE,gBAAAA,KAAC,QAAG,WAAU,6CACX,kBAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,MACjB,gBAAAC,MAAC,SAAY,WAAU,YACrB;AAAA,oBAAAD,KAAC,QAAG,WAAU,kDAAkD,aAAE;AAAA,IAClE,gBAAAA,KAAC,QAAG,WAAU,uFACX,mBAAS,CAAC,GACb;AAAA,OAJQ,CAKV,CACD,GACH;AAEJ;AAGA,SAAS,kBAAkB,EAAE,KAAK,GAA+B;AAC/D,QAAM,UAAU,cAAc,IAAI;AAClC,SACE,gBAAAC,MAAC,SAAI,WAAU,aACZ;AAAA,SAAK,QAAQ,OAAO,KAAK,KAAK,IAAI,EAAE,SAAS,KAC5C,gBAAAA,MAAC,SACC;AAAA,sBAAAD,KAAC,OAAE,WAAU,mFAAkF,yBAAW;AAAA,MAC1G,gBAAAA,KAAC,UAAO,MAAM,KAAK,MAAM;AAAA,OAC3B;AAAA,IAED,WACC,gBAAAC,MAAC,SACC;AAAA,sBAAAD,KAAC,OAAE,WAAU,mFACV,kBAAQ,OAAO,QAAQ,WAAW,UACrC;AAAA,MACC,QAAQ,OAAO,QACd,gBAAAA,KAAC,OAAE,WAAU,wBAAwB,kBAAQ,WAAW,eAAc,IACpE,QAAQ,UAAU,OAAO,QAAQ,WAAW,WAC9C,gBAAAA,KAAC,UAAO,MAAM,QAAQ,QAAQ,IAE9B,gBAAAA,KAAC,OAAE,WAAU,+CAA+C,mBAAS,QAAQ,MAAM,GAAE;AAAA,OAEzF;AAAA,KAEJ;AAEJ;AAEA,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,QAAM,CAAC,UAAU,WAAW,IAAII,UAAS,KAAK;AAC9C,QAAM,UAAU,KAAK,WAAW,SAAS,kBAAkB,IAAI,IAAI;AACnE,QAAM,SAAS,KAAK,WAAW,WAAW,cAAc,IAAI,GAAG,OAAO;AACtE,QAAM,SAAS,YAAY,KAAK,IAAI,IAAI,MAAM,OAAO;AAErD,SACE,gBAAAH;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,uEACT,UACI,uCACA,SACE,mCACA,8BACR;AAAA,MAEA;AAAA,wBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAS,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;AAAA,YACpC,WAAU;AAAA,YAEV;AAAA,8BAAAD;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAW,iCACT,KAAK,WAAW,YACZ,gCACA,UACE,iBACA,SACE,eACA,cACV;AAAA;AAAA,cACF;AAAA,cACA,gBAAAA,KAAC,UAAK,WAAU,uCAAuC,4BAAkB,IAAI,GAAE;AAAA,cAC9E,WAAW,YACV,gBAAAC,MAAC,UAAK,WAAU,oCAAmC,SAAS,CAAC,MAAM,EAAE,gBAAgB,GACnF;AAAA,gCAAAD;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,SAAS,MAAM,SAAS,UAAU,QAAQ,YAAY,KAAK,EAAE;AAAA,oBAC7D,WAAU;AAAA,oBACX;AAAA;AAAA,gBAED;AAAA,gBACA,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,SAAS,MAAM,SAAS,SAAS,QAAQ,YAAY,KAAK,EAAE;AAAA,oBAC5D,WAAU;AAAA,oBACX;AAAA;AAAA,gBAED;AAAA,iBACF;AAAA,cAEF,gBAAAA,KAAC,UAAK,WAAU,iDACb,eAAK,WAAW,YAAY,kBAAa,UAAU,sBAAsB,SAAS,WAAW,QAChG;AAAA,cACA,gBAAAA,KAAC,eAAY,WAAW,+DAA+D,WAAW,eAAe,EAAE,IAAI;AAAA;AAAA;AAAA,QACzH;AAAA,QACC,YACC,gBAAAC,MAAC,SAAI,WAAU,yCACZ;AAAA,oBAAU,gBAAAD,KAAC,qBAAkB,MAAY;AAAA,UACzC,aAAa,KAAK,KAAK,WAAW,UAAU,KAC3C,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAM,UAAU,MAAM,OAAO;AAAA,cACtC,WAAU;AAAA,cACX;AAAA;AAAA,UAED;AAAA,WAEJ;AAAA;AAAA;AAAA,EAEJ;AAEJ;AAEA,SAAS,iBAAiB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAUG;AAKD,QAAM,UAAU,cAAc,IAAI,SAAS,SAAS;AACpD,QAAM,YAAY,cAAc,IAAI,aAAa,IAAI,SAAS;AAC9D,QAAM,qBAAqBE,QAAuB,IAAI;AACtD,EAAAC,WAAU,MAAM;AACd,UAAM,KAAK,mBAAmB;AAC9B,QAAI,MAAM,aAAa,CAAC,QAAS,IAAG,YAAY,GAAG;AAAA,EACrD,GAAG,CAAC,WAAW,WAAW,OAAO,CAAC;AAElC,SACE,gBAAAF,MAAC,SAAI,WAAU,sCACb;AAAA,oBAAAA,MAAC,SAAI,WAAU,qFACb;AAAA,sBAAAD,KAAC,UAAK,WAAU,2BAA2B,sBAAW;AAAA,MACrD,IAAI,aAAa,gBAAAA,KAAC,UAAK,WAAU,yBAAyB,cAAI,WAAU;AAAA,MACxE,sBAAsB,GAAG,KAAK,gBAAAA,KAAC,UAAM,gCAAsB,GAAG,GAAE;AAAA,MAChE,gBAAgB,KAAK,MAAM,KAAK,gBAAAA,KAAC,UAAM,0BAAgB,KAAK,MAAM,GAAE;AAAA,OACvE;AAAA,IACC,aACC,gBAAAC,MAAC,aAAQ,WAAU,iEAAgE,MAAM,CAAC,SACxF;AAAA,sBAAAA,MAAC,aAAQ,WAAU,wEAChB;AAAA,kBAAU,mBAAc;AAAA,QACxB,CAAC,WAAW,gBAAAD,KAAC,UAAK,WAAU,mCAAkC,oBAAC;AAAA,SAClE;AAAA,MACA,gBAAAA,KAAC,SAAI,KAAK,oBAAoB,WAAU,sFACrC,qBACH;AAAA,OACF;AAAA,IAEF,gBAAAA,KAAC,SAAI,WAAU,4BAA4B,qBAAW,OAAO,GAAE;AAAA,IAC9D,IAAI,aAAa,IAAI,UAAU,SAAS,KACvC,gBAAAA,KAAC,SAAI,WAAU,8BACZ,cAAI,UAAU,IAAI,CAAC,OAClB,gBAAAA;AAAA,MAAC;AAAA;AAAA,QAEC,MAAM;AAAA,QACN,SAAS;AAAA,QACT;AAAA,QACA,WAAW;AAAA,QACX,WAAW;AAAA;AAAA,MALN,GAAG;AAAA,IAMV,CACD,GACH;AAAA,IAED,eAAe,GAAG;AAAA,KACrB;AAEJ;AAEA,SAAS,YAAY,EAAE,WAAW,GAA2B;AAC3D,QAAM,CAAC,SAAS,UAAU,IAAII,UAAS,CAAC;AACxC,EAAAD,WAAU,MAAM;AACd,UAAM,KAAK,YAAY,MAAM,WAAW,CAAC,MAAM,IAAI,CAAC,GAAG,GAAI;AAC3D,WAAO,MAAM,cAAc,EAAE;AAAA,EAC/B,GAAG,CAAC,CAAC;AACL,SACE,gBAAAF,MAAC,SAAI,WAAU,sCACb;AAAA,oBAAAD,KAAC,OAAE,WAAU,mFAAmF,sBAAW;AAAA,IAC3G,gBAAAC,MAAC,SAAI,WAAU,2DACb;AAAA,sBAAAD,KAAC,SAAI,WAAU,wBAAuB,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAW,MACrH,0BAAAA,KAAC,UAAK,GAAE,+BAA8B,eAAc,SAAQ,GAC9D;AAAA,MAAM;AAAA,MACG,WAAW,IAAI,SAAM,OAAO,MAAM;AAAA,OAC7C;AAAA,KACF;AAEJ;AAQO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA,SAAS,CAAC;AAAA,EACV;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAsB;AACpB,QAAM,aAAa,mBAAmB,CAAC,YAAoB,gBAAAA,KAAC,OAAE,WAAU,uBAAuB,mBAAQ;AACvG,QAAM,aAAa,SAAS,SAAS,SAAS,CAAC,GAAG,SAAS;AAC3D,SACE,gBAAAC,MAAA,YACG;AAAA,aAAS;AAAA,MAAI,CAAC,QACb,IAAI,SAAS,SACX,gBAAAD,KAAC,SAAiB,WAAU,sCAC1B,0BAAAC,MAAC,SAAI,WAAU,6BACb;AAAA,wBAAAD,KAAC,OAAE,WAAU,8FACV,qBACH;AAAA,QACA,gBAAAA,KAAC,SAAI,WAAU,iFACb,0BAAAA,KAAC,OAAE,WAAU,uBAAuB,cAAI,SAAQ,GAClD;AAAA,SACF,KARQ,IAAI,EASd,IAEA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UAEC;AAAA,UACA,WAAW,CAAC,CAAC,WAAW,IAAI,OAAO,SAAS,SAAS,SAAS,CAAC,GAAG;AAAA,UAClE;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA;AAAA,QATK,IAAI;AAAA,MAUX;AAAA,IAEJ;AAAA,IACC,WAAW,cAAc,gBAAAA,KAAC,eAAY,YAAwB;AAAA,KACjE;AAEJ;","names":["useEffect","useRef","useState","jsx","jsxs","useRef","useEffect","useState"]}
|
|
1
|
+
{"version":3,"sources":["../../src/web-react/index.tsx","../../src/web-react/provider-logo.tsx","../../src/web-react/smooth-text.ts","../../src/web-react/chat-stream.ts","../../src/web-react/mission-activity.tsx"],"sourcesContent":["/**\n * `@tangle-network/agent-app/web-react` — the shared chat-shell components\n * every agent app's web UI hand-rolls: a model picker over the runtime's\n * model catalogue, a reasoning-effort selector, and a message thread with\n * User/Agent identity, per-message model + cost + tokens/sec metrics, tool\n * chips, and a collapsible thinking section.\n *\n * Works for BOTH chat shapes: router-backed copilots (LoopEvents from\n * `runtime/openai-stream`) and sandbox-backed chats — the thread renders\n * `ChatUiMessage`s; how they're produced is the app's business.\n *\n * Styling contract: Tailwind classes against the shared design tokens\n * (`bg-card`, `border-border`, `text-muted-foreground`, `bg-primary`, …) that\n * Tangle app shells define. No icon library — the few glyphs are inline SVGs.\n * Markdown and provider logos are injected (`renderMarkdown`,\n * `renderProviderBadge`) so this package stays dependency-free beyond React.\n */\n\nimport { useEffect, useMemo, useRef, useState, type ReactNode } from 'react'\nimport { ProviderLogo } from './provider-logo'\nimport { useSmoothText } from './smooth-text'\n\nexport * from './chat-stream'\nexport * from './provider-logo'\nexport * from './smooth-text'\nexport * from './mission-activity'\nimport type { CatalogModel } from '../runtime/model-catalog'\n\n// ── shared glyphs (no icon-library dependency) ────────────────────────────\n\nfunction ChevronDown({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n )\n}\n\nfunction SearchGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.3-4.3\" />\n </svg>\n )\n}\n\nfunction SparkleGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M12 3v3m0 12v3M3 12h3m12 0h3M5.6 5.6l2.1 2.1m8.6 8.6 2.1 2.1m0-12.8-2.1 2.1M7.7 16.3l-2.1 2.1\" />\n </svg>\n )\n}\n\n/** Close an absolutely-positioned popover on outside mousedown. */\nfunction useClickOutside(onOutside: () => void) {\n const ref = useRef<HTMLDivElement>(null)\n useEffect(() => {\n function handler(e: MouseEvent) {\n if (ref.current && !ref.current.contains(e.target as Node)) onOutside()\n }\n document.addEventListener('mousedown', handler)\n return () => document.removeEventListener('mousedown', handler)\n })\n return ref\n}\n\n// ── metrics helpers ───────────────────────────────────────────────────────\n\nexport interface ChatMessageMetrics {\n modelUsed?: string\n promptTokens?: number\n completionTokens?: number\n durationMs?: number\n}\n\n/** \"$0.0042\" from token counts × catalogue per-token pricing; null when unknown. */\nexport function formatModelCost(msg: ChatMessageMetrics, models: CatalogModel[]): string | null {\n if (msg.promptTokens == null && msg.completionTokens == null) return null\n const pricing = models.find((m) => m.id === msg.modelUsed)?.pricing\n if (!pricing) return null\n const cost =\n (msg.promptTokens ?? 0) * Number(pricing.prompt ?? 0) +\n (msg.completionTokens ?? 0) * Number(pricing.completion ?? 0)\n if (!isFinite(cost) || cost <= 0) return null\n return cost < 0.01 ? `$${cost.toFixed(4)}` : `$${cost.toFixed(2)}`\n}\n\n/** \"38 tok/s\" from completion tokens over first-token→end duration; null when unknown. */\nexport function formatTokensPerSecond(msg: ChatMessageMetrics): string | null {\n if (msg.completionTokens == null || !msg.durationMs) return null\n return `${Math.round(msg.completionTokens / (msg.durationMs / 1000))} tok/s`\n}\n\n// ── ModelPicker ───────────────────────────────────────────────────────────\n\nexport interface ModelPickerProps {\n value: string\n onChange: (id: string) => void\n /** Catalogue models — from `GET`ing the app's catalogue route (see\n * `runtime/model-catalog`), plus any product-specific entries appended. */\n models: CatalogModel[]\n loading?: boolean\n /** Render a provider logo/badge; default is a generic sparkle. */\n renderProviderBadge?: (provider: string) => ReactNode\n /** Section label for `featured` models. */\n recommendedLabel?: string\n}\n\nfunction formatPrice(p?: string): string | undefined {\n if (!p) return undefined\n const n = Number(p)\n if (isNaN(n) || n === 0) return undefined\n const perM = n * 1_000_000\n return perM >= 1 ? `$${perM.toFixed(0)}/M` : `$${perM.toFixed(2)}/M`\n}\n\nfunction formatContext(len?: number): string | undefined {\n if (!len) return undefined\n if (len >= 1_000_000) return `${(len / 1_000_000).toFixed(1)}M ctx`\n if (len >= 1_000) return `${Math.round(len / 1_000)}K ctx`\n return `${len} ctx`\n}\n\nfunction SectionHeader({ children }: { children: ReactNode }) {\n return (\n <div className=\"px-3 pb-1 pt-3 text-xs font-semibold uppercase tracking-wide text-muted-foreground/70\">\n {children}\n </div>\n )\n}\n\nfunction ModelRow({\n model,\n selected,\n onSelect,\n renderProviderBadge,\n}: {\n model: CatalogModel\n selected: boolean\n onSelect: () => void\n renderProviderBadge?: (provider: string) => ReactNode\n}) {\n const price = formatPrice(model.pricing?.prompt)\n const ctx = formatContext(model.contextLength)\n return (\n <button\n type=\"button\"\n onClick={onSelect}\n className={`flex w-full items-center gap-2.5 rounded-md px-3 py-2.5 text-left text-sm transition ${\n selected ? 'bg-primary/10 font-medium' : 'hover:bg-accent/30'\n }`}\n >\n {renderProviderBadge ? renderProviderBadge(model.provider) : <ProviderLogo provider={model.provider} size={16} />}\n <span className=\"truncate\">{model.name}</span>\n {!model.supportsTools && (\n <span className=\"shrink-0 rounded bg-muted/60 px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground\">\n no tools\n </span>\n )}\n <span className=\"ml-auto flex shrink-0 items-center gap-2 text-xs text-muted-foreground\">\n {ctx && <span>{ctx}</span>}\n {price && <span>{price}</span>}\n </span>\n </button>\n )\n}\n\n/**\n * Searchable model picker pill + popover: a featured/recommended section\n * first, then per-provider groups in catalogue order (the server already\n * sorts providers by tier).\n */\nexport function ModelPicker({ value, onChange, models, loading, renderProviderBadge, recommendedLabel = 'Recommended' }: ModelPickerProps) {\n const [open, setOpen] = useState(false)\n const [query, setQuery] = useState('')\n const containerRef = useClickOutside(() => setOpen(false))\n const inputRef = useRef<HTMLInputElement>(null)\n\n useEffect(() => {\n if (open) inputRef.current?.focus()\n }, [open])\n\n const selected = models.find((m) => m.id === value)\n\n const filtered = useMemo(() => {\n const q = query.trim().toLowerCase()\n if (!q) return null\n return models.filter(\n (m) =>\n m.id.toLowerCase().includes(q) ||\n m.name.toLowerCase().includes(q) ||\n (m.description?.toLowerCase() ?? '').includes(q) ||\n m.provider.toLowerCase().includes(q),\n )\n }, [models, query])\n\n const sections = useMemo(() => {\n const recommended = models.filter((m) => m.featured)\n const byProvider: Array<{ provider: string; items: CatalogModel[] }> = []\n for (const m of models) {\n if (m.featured) continue\n const last = byProvider[byProvider.length - 1]\n if (last && last.provider === m.provider) last.items.push(m)\n else byProvider.push({ provider: m.provider, items: [m] })\n }\n return { recommended, byProvider }\n }, [models])\n\n const select = (id: string) => {\n onChange(id)\n setOpen(false)\n setQuery('')\n }\n\n return (\n <div ref={containerRef} className=\"relative inline-flex\">\n <button\n type=\"button\"\n onClick={() => setOpen((v) => !v)}\n className=\"inline-flex items-center gap-1.5 rounded-full border border-border bg-card px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-accent/30\"\n >\n {selected ? (renderProviderBadge ? renderProviderBadge(selected.provider) : <ProviderLogo provider={selected.provider} size={16} />) : <SparkleGlyph className=\"h-3.5 w-3.5 text-muted-foreground\" />}\n <span className=\"max-w-[160px] truncate\">{selected?.name ?? value}</span>\n <ChevronDown className=\"h-3.5 w-3.5 text-muted-foreground\" />\n </button>\n\n {open && (\n <div className=\"absolute bottom-full left-0 z-50 mb-2 w-[420px] overflow-hidden rounded-xl border border-border bg-card shadow-lg\">\n <div className=\"border-b border-border px-3 py-2\">\n <div className=\"flex items-center gap-2 rounded-lg border border-border bg-background px-3 py-2\">\n <SearchGlyph className=\"h-3.5 w-3.5 text-muted-foreground\" />\n <input\n ref={inputRef}\n type=\"text\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Search models...\"\n className=\"flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground\"\n />\n </div>\n </div>\n <div className=\"max-h-[400px] overflow-y-auto p-1 pb-2\">\n {loading && <div className=\"px-3 py-4 text-center text-sm text-muted-foreground\">Loading models...</div>}\n {!loading && filtered && (\n <>\n {filtered.length === 0 && (\n <div className=\"px-3 py-4 text-center text-sm text-muted-foreground\">No models match your search</div>\n )}\n {filtered.map((m) => (\n <ModelRow key={m.id} model={m} selected={m.id === value} onSelect={() => select(m.id)} renderProviderBadge={renderProviderBadge} />\n ))}\n </>\n )}\n {!loading && !filtered && (\n <>\n {sections.recommended.length > 0 && (\n <>\n <SectionHeader>{recommendedLabel}</SectionHeader>\n {sections.recommended.map((m) => (\n <ModelRow key={m.id} model={m} selected={m.id === value} onSelect={() => select(m.id)} renderProviderBadge={renderProviderBadge} />\n ))}\n </>\n )}\n {sections.byProvider.map((g) => (\n <div key={g.provider}>\n <SectionHeader>{g.provider}</SectionHeader>\n {g.items.map((m) => (\n <ModelRow key={m.id} model={m} selected={m.id === value} onSelect={() => select(m.id)} renderProviderBadge={renderProviderBadge} />\n ))}\n </div>\n ))}\n </>\n )}\n </div>\n </div>\n )}\n </div>\n )\n}\n\n// ── EffortPicker ──────────────────────────────────────────────────────────\n\nconst EFFORT_LEVELS = [\n { id: 'off', label: 'Off' },\n { id: 'low', label: 'Low' },\n { id: 'medium', label: 'Medium' },\n { id: 'high', label: 'High' },\n] as const\n\nexport interface EffortPickerProps {\n value: string\n onChange: (id: string) => void\n}\n\n/** Reasoning-effort selector pill, styled to match {@link ModelPicker}. Show\n * it only when the selected model `supportsReasoning`. */\nexport function EffortPicker({ value, onChange }: EffortPickerProps) {\n const [open, setOpen] = useState(false)\n const containerRef = useClickOutside(() => setOpen(false))\n const selected = EFFORT_LEVELS.find((l) => l.id === value) ?? EFFORT_LEVELS[2]\n\n return (\n <div ref={containerRef} className=\"relative inline-flex\">\n <button\n type=\"button\"\n onClick={() => setOpen((v) => !v)}\n title=\"Reasoning effort\"\n className=\"inline-flex items-center gap-1.5 rounded-full border border-border bg-card px-3 py-1.5 text-sm font-medium text-foreground transition hover:bg-accent/30\"\n >\n <SparkleGlyph className=\"h-3.5 w-3.5 text-muted-foreground\" />\n <span>{selected.label}</span>\n <ChevronDown className=\"h-3.5 w-3.5 text-muted-foreground\" />\n </button>\n {open && (\n <div className=\"absolute bottom-full left-0 z-50 mb-2 w-36 overflow-hidden rounded-xl border border-border bg-card p-1 shadow-lg\">\n {EFFORT_LEVELS.map((l) => (\n <button\n key={l.id}\n type=\"button\"\n onClick={() => {\n onChange(l.id)\n setOpen(false)\n }}\n className={`flex w-full items-center rounded-md px-3 py-2 text-left text-sm transition ${\n l.id === value ? 'bg-primary/10 font-medium' : 'hover:bg-accent/30'\n }`}\n >\n {l.label}\n </button>\n ))}\n </div>\n )}\n </div>\n )\n}\n\n// ── Tool run drill-in (retained runs) ─────────────────────────────────────\n\n/** One step of a retained tool run (e.g. a sandbox command + its output). */\nexport interface ToolRunStep {\n at: string\n label: string\n detail?: string\n status?: 'ok' | 'error'\n}\n\n/** A retained tool run keyed by the parent message's toolCallId. The product\n * persists these server-side (fail-closed: only ids its own loop created)\n * and serves them to the drill-in panel. */\nexport interface ToolRunRecord {\n toolCallId: string\n toolName: string\n title: string\n status: 'running' | 'complete' | 'error'\n steps: ToolRunStep[]\n}\n\nexport interface RunDrillInProps {\n run: ToolRunRecord\n onClose: () => void\n}\n\n/**\n * Readonly side panel showing a retained tool run's transcript — the\n * \"drill into what the sandbox actually did\" view. Follow-ups happen in the\n * main chat, never here.\n */\nexport function RunDrillIn({ run, onClose }: RunDrillInProps) {\n return (\n <div className=\"fixed inset-y-0 right-0 z-50 flex w-[480px] max-w-full flex-col border-l border-border bg-card shadow-xl\">\n <div className=\"flex items-center gap-2 border-b border-border px-4 py-3\">\n <span\n className={`h-2 w-2 shrink-0 rounded-full ${\n run.status === 'running' ? 'bg-yellow-500' : run.status === 'error' ? 'bg-red-500' : 'bg-green-500'\n }`}\n />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-semibold\">{run.title}</p>\n <p className=\"truncate font-mono text-[11px] text-muted-foreground\">{run.toolName}</p>\n </div>\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close\"\n className=\"rounded-md p-1.5 text-muted-foreground transition hover:bg-accent/30 hover:text-foreground\"\n >\n <svg className=\"h-4 w-4\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <path d=\"M18 6 6 18M6 6l12 12\" />\n </svg>\n </button>\n </div>\n <div className=\"flex-1 space-y-3 overflow-y-auto p-4\">\n {run.steps.length === 0 && (\n <p className=\"text-sm text-muted-foreground\">No steps recorded yet.</p>\n )}\n {run.steps.map((step, i) => (\n <div key={i} className=\"rounded-lg border border-border/60 bg-background\">\n <div className=\"flex items-baseline gap-2 border-b border-border/40 px-3 py-1.5\">\n <span className={`font-mono text-[11px] ${step.status === 'error' ? 'text-red-600' : 'text-muted-foreground'}`}>\n {step.status === 'error' ? '✗' : '$'}\n </span>\n <code className=\"min-w-0 flex-1 truncate font-mono text-xs\">{step.label}</code>\n <span className=\"shrink-0 text-[10px] text-muted-foreground/60\">\n {new Date(step.at).toLocaleTimeString()}\n </span>\n </div>\n {step.detail && (\n <pre className=\"max-h-48 overflow-auto whitespace-pre-wrap px-3 py-2 font-mono text-[11px] leading-relaxed text-muted-foreground\">\n {step.detail}\n </pre>\n )}\n </div>\n ))}\n </div>\n <p className=\"border-t border-border px-4 py-2 text-[11px] text-muted-foreground/60\">\n Readonly drill-in. Follow up in the main chat.\n </p>\n </div>\n )\n}\n\n// ── ChatMessages ──────────────────────────────────────────────────────────\n\nexport interface ChatToolCallInfo {\n id: string\n name: string\n status: 'running' | 'done' | 'error'\n /** The call arguments, captured from the tool_call event — shown in the\n * expanded card so users see exactly what the agent invoked. */\n args?: Record<string, unknown>\n /** The tool outcome (`{ok, result}` shape). When `result.status` is\n * 'queued_for_approval' the card renders the approval state. */\n result?: unknown\n}\n\n/** Extract `{proposalId, status}` from a tool outcome when it is a proposal\n * awaiting human approval; null otherwise. */\nexport function pendingApprovalOf(call: ChatToolCallInfo): { proposalId: string } | null {\n const outcome = call.result as { ok?: boolean; result?: { status?: string; proposalId?: string } } | undefined\n if (!outcome?.ok || outcome.result?.status !== 'queued_for_approval' || !outcome.result.proposalId) return null\n return { proposalId: outcome.result.proposalId }\n}\n\nexport interface ChatUiMessage extends ChatMessageMetrics {\n id: string\n role: 'user' | 'assistant' | 'system'\n content: string\n reasoning?: string\n toolCalls?: ChatToolCallInfo[]\n}\n\nexport interface ChatMessagesProps {\n messages: ChatUiMessage[]\n /** Catalogue models, for per-message cost from pricing. Pass [] to skip cost. */\n models?: CatalogModel[]\n /** Markdown renderer for assistant content; default renders pre-wrapped text. */\n renderMarkdown?: (content: string) => ReactNode\n /** Extra per-message content (artifacts, custom panels) appended after the body. */\n renderExtras?: (message: ChatUiMessage) => ReactNode\n userLabel?: string\n agentLabel?: string\n /** Render the trailing \"agent is thinking\" row. */\n loading?: boolean\n /** Approve/Reject handlers for proposals awaiting approval. When omitted the\n * chip still shows \"awaiting approval\" but without action buttons. */\n approval?: ProposalApprovalHandlers\n /** Open a full-transcript view (e.g. {@link RunDrillIn}) from a tool card. */\n onToolCallClick?: (call: ChatToolCallInfo, message: ChatUiMessage) => void\n /** Per-tool custom detail renderers for expanded tool cards. */\n toolRenderers?: ToolDetailRenderers\n}\n\nexport interface ProposalApprovalHandlers {\n onApprove: (proposalId: string, toolCallId: string) => void | Promise<void>\n onReject: (proposalId: string, toolCallId: string) => void | Promise<void>\n}\n\n/** Per-tool custom detail renderers for the expanded card body — keyed by\n * tool name. Return null to fall back to the generic detail view. */\nexport type ToolDetailRenderers = Record<\n string,\n (call: ChatToolCallInfo, message: ChatUiMessage) => ReactNode\n>\n\nfunction ToolGlyph({ name, className }: { name: string; className?: string }) {\n if (name.startsWith('sandbox_')) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <polyline points=\"4 17 10 11 4 5\" />\n <line x1=\"12\" y1=\"19\" x2=\"20\" y2=\"19\" />\n </svg>\n )\n }\n if (name === 'submit_proposal') {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\" />\n <path d=\"M14 2v6h6M9 15l2 2 4-4\" />\n </svg>\n )\n }\n if (name === 'schedule_followup') {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <circle cx=\"12\" cy=\"12\" r=\"9\" />\n <path d=\"M12 7v5l3 3\" />\n </svg>\n )\n }\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M12 3v3m0 12v3M3 12h3m12 0h3\" />\n <circle cx=\"12\" cy=\"12\" r=\"4\" />\n </svg>\n )\n}\n\nfunction toolOutcomeOf(call: ChatToolCallInfo): { ok?: boolean; result?: Record<string, unknown>; message?: string } | undefined {\n return call.result as { ok?: boolean; result?: Record<string, unknown>; message?: string } | undefined\n}\n\n/** Human title for a call, derived from its real arguments. */\nfunction friendlyToolTitle(call: ChatToolCallInfo): string {\n const a = call.args ?? {}\n switch (call.name) {\n case 'submit_proposal':\n return `Proposal · ${String(a.type ?? '')}${a.title ? `: ${String(a.title)}` : ''}`\n case 'sandbox_create':\n return `Create sandbox (${String(a.environment ?? 'universal')})`\n case 'sandbox_run_command':\n return `$ ${String(a.command ?? '')}`\n case 'sandbox_destroy':\n return `Destroy sandbox ${String(a.sandbox_id ?? '')}`\n case 'schedule_followup':\n return `Follow-up · ${String(a.title ?? '')}`\n case 'render_ui':\n return `Render view · ${String(a.title ?? '')}`\n case 'add_citation':\n return `Citation · ${String(a.path ?? '')}`\n default:\n return call.name\n }\n}\n\nfunction truncate(v: unknown, max = 240): string {\n const s = typeof v === 'string' ? v : JSON.stringify(v)\n return s.length > max ? `${s.slice(0, max)}…` : s\n}\n\nfunction KvRows({ data }: { data: Record<string, unknown> }) {\n const entries = Object.entries(data).filter(([, v]) => v !== undefined && v !== null && v !== '')\n if (!entries.length) return null\n return (\n <dl className=\"grid grid-cols-[auto_1fr] gap-x-3 gap-y-1\">\n {entries.map(([k, v]) => (\n <div key={k} className=\"contents\">\n <dt className=\"font-mono text-[11px] text-muted-foreground/70\">{k}</dt>\n <dd className=\"min-w-0 whitespace-pre-wrap break-words font-mono text-[11px] text-muted-foreground\">\n {truncate(v)}\n </dd>\n </div>\n ))}\n </dl>\n )\n}\n\n/** Terminal-styled rendering for shell executions. */\nfunction ShellDetail({ call }: { call: ChatToolCallInfo }) {\n const outcome = toolOutcomeOf(call)\n const r = (outcome?.result ?? {}) as { stdout?: string; stderr?: string; exitCode?: number }\n return (\n <div className=\"overflow-hidden rounded-md bg-zinc-900 font-mono text-[11px] leading-relaxed\">\n <div className=\"flex items-center gap-2 px-3 pt-2 text-zinc-400\">\n <span className=\"select-none text-zinc-500\">$</span>\n <span className=\"min-w-0 flex-1 truncate text-zinc-200\">{String(call.args?.command ?? '')}</span>\n {r.exitCode != null && (\n <span className={r.exitCode === 0 ? 'text-emerald-400' : 'text-red-400'}>exit {r.exitCode}</span>\n )}\n </div>\n <pre className=\"max-h-56 overflow-auto whitespace-pre-wrap px-3 pb-2.5 pt-1.5 text-zinc-300\">\n {outcome?.ok === false ? (outcome.message ?? 'failed') : [r.stdout, r.stderr].filter(Boolean).join('\\n') || '(no output)'}\n </pre>\n </div>\n )\n}\n\n/** Generic expanded detail: what was called, and what actually happened. */\nfunction DefaultToolDetail({ call }: { call: ChatToolCallInfo }) {\n const outcome = toolOutcomeOf(call)\n return (\n <div className=\"space-y-2\">\n {call.args && Object.keys(call.args).length > 0 && (\n <div>\n <p className=\"mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground/50\">Called with</p>\n <KvRows data={call.args} />\n </div>\n )}\n {outcome && (\n <div>\n <p className=\"mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground/50\">\n {outcome.ok === false ? 'Failed' : 'Result'}\n </p>\n {outcome.ok === false ? (\n <p className=\"text-xs text-red-600\">{outcome.message ?? 'Tool failed'}</p>\n ) : outcome.result && typeof outcome.result === 'object' ? (\n <KvRows data={outcome.result} />\n ) : (\n <p className=\"font-mono text-[11px] text-muted-foreground\">{truncate(outcome.result)}</p>\n )}\n </div>\n )}\n </div>\n )\n}\n\nfunction ToolCallCard({\n call,\n message,\n approval,\n onOpenRun,\n renderers,\n}: {\n call: ChatToolCallInfo\n message: ChatUiMessage\n approval?: ProposalApprovalHandlers\n onOpenRun?: (call: ChatToolCallInfo, message: ChatUiMessage) => void\n renderers?: ToolDetailRenderers\n}) {\n const [expanded, setExpanded] = useState(false)\n const pending = call.status === 'done' ? pendingApprovalOf(call) : null\n const failed = call.status === 'error' || toolOutcomeOf(call)?.ok === false\n const custom = renderers?.[call.name]?.(call, message)\n\n return (\n <div\n className={`w-fit min-w-[280px] max-w-full rounded-lg border text-xs transition ${\n pending\n ? 'border-amber-300/60 bg-amber-500/5'\n : failed\n ? 'border-red-300/60 bg-red-500/5'\n : 'border-border/60 bg-muted/20'\n }`}\n >\n <button\n type=\"button\"\n onClick={() => setExpanded((v) => !v)}\n className=\"flex w-full items-center gap-2 px-3 py-2 text-left\"\n >\n <span\n className={`h-2 w-2 shrink-0 rounded-full ${\n call.status === 'running'\n ? 'animate-pulse bg-yellow-500'\n : pending\n ? 'bg-amber-500'\n : failed\n ? 'bg-red-500'\n : 'bg-green-500'\n }`}\n />\n <ToolGlyph name={call.name} className=\"h-3.5 w-3.5 shrink-0 text-muted-foreground\" />\n <span className=\"min-w-0 flex-1 truncate font-medium\">{friendlyToolTitle(call)}</span>\n {pending && approval && (\n <span className=\"flex shrink-0 items-center gap-1\" onClick={(e) => e.stopPropagation()}>\n <button\n type=\"button\"\n onClick={() => approval.onApprove(pending.proposalId, call.id)}\n className=\"rounded bg-green-600/90 px-2 py-0.5 text-[11px] font-semibold text-white transition hover:bg-green-600\"\n >\n Approve\n </button>\n <button\n type=\"button\"\n onClick={() => approval.onReject(pending.proposalId, call.id)}\n className=\"rounded border border-border bg-card px-2 py-0.5 text-[11px] font-medium text-foreground transition hover:bg-accent/30\"\n >\n Reject\n </button>\n </span>\n )}\n <span className=\"shrink-0 text-[11px] text-muted-foreground/70\">\n {call.status === 'running' ? 'running…' : pending ? 'awaiting approval' : failed ? 'failed' : 'done'}\n </span>\n <ChevronDown className={`h-3 w-3 shrink-0 text-muted-foreground transition-transform ${expanded ? 'rotate-180' : ''}`} />\n </button>\n {expanded && (\n <div className=\"border-t border-border/40 px-3 py-2.5\">\n {custom ?? (call.name === 'sandbox_run_command' ? <ShellDetail call={call} /> : <DefaultToolDetail call={call} />)}\n {onOpenRun && call.name.startsWith('sandbox_') && (\n <button\n type=\"button\"\n onClick={() => onOpenRun(call, message)}\n className=\"mt-2 rounded border border-border bg-card px-2 py-1 text-[11px] font-medium transition hover:bg-accent/30\"\n >\n Open full transcript →\n </button>\n )}\n </div>\n )}\n </div>\n )\n}\n\nfunction AssistantMessage({\n msg,\n streaming,\n models,\n agentLabel,\n renderBody,\n approval,\n onToolCallClick,\n toolRenderers,\n renderExtras,\n}: {\n msg: ChatUiMessage\n streaming: boolean\n models: CatalogModel[]\n agentLabel: string\n renderBody: (content: string) => ReactNode\n approval?: ProposalApprovalHandlers\n onToolCallClick?: (call: ChatToolCallInfo, message: ChatUiMessage) => void\n toolRenderers?: ToolDetailRenderers\n renderExtras?: (message: ChatUiMessage) => ReactNode\n}) {\n // Smooth reveal: chunky network slabs (model bursts, flush windows, replay\n // polls) paint as a continuous typewriter. Reasoning often arrives as one\n // burst right before the answer — smoothing makes it visibly type out in\n // the open thinking box instead of popping in and collapsing.\n const content = useSmoothText(msg.content, streaming)\n const reasoning = useSmoothText(msg.reasoning ?? '', streaming)\n const reasoningScrollRef = useRef<HTMLDivElement>(null)\n // Measure visible thinking time: first reasoning reveal → first answer text.\n const thinkStartRef = useRef<number | null>(null)\n const thinkMsRef = useRef<number | null>(null)\n if (streaming && reasoning && !content && thinkStartRef.current === null) {\n thinkStartRef.current = performance.now()\n }\n if (content && thinkStartRef.current !== null && thinkMsRef.current === null) {\n thinkMsRef.current = performance.now() - thinkStartRef.current\n }\n useEffect(() => {\n const el = reasoningScrollRef.current\n if (el && streaming && !content) el.scrollTop = el.scrollHeight\n }, [reasoning, streaming, content])\n\n return (\n <div className=\"mx-auto w-full max-w-3xl px-6 py-3\">\n <div className=\"mb-1 flex items-baseline gap-2 text-[11px] tracking-wide text-muted-foreground/60\">\n <span className=\"font-semibold uppercase\">{agentLabel}</span>\n {msg.modelUsed && <span className=\"font-mono normal-case\">{msg.modelUsed}</span>}\n {formatTokensPerSecond(msg) && <span>{formatTokensPerSecond(msg)}</span>}\n {formatModelCost(msg, models) && <span>{formatModelCost(msg, models)}</span>}\n </div>\n {reasoning && (\n <details className=\"mb-2 rounded-lg border-l-2 border-border/70 bg-muted/20 px-3 py-2\" open={!content}>\n <summary className=\"cursor-pointer select-none text-xs font-medium text-muted-foreground\">\n {!content ? (\n <span className=\"animate-pulse\">Thinking…</span>\n ) : thinkMsRef.current != null ? (\n `Thought for ${Math.max(1, Math.round(thinkMsRef.current / 1000))}s`\n ) : (\n 'Thought process'\n )}\n </summary>\n <div ref={reasoningScrollRef} className=\"mt-2 max-h-48 overflow-y-auto whitespace-pre-wrap text-[13px] leading-relaxed text-muted-foreground/70\">\n {reasoning}\n </div>\n </details>\n )}\n <div className=\"text-base leading-[1.75]\">\n {renderBody(content)}\n {streaming && content && !msg.toolCalls?.length && (\n <span className=\"ml-0.5 inline-block h-[1.1em] w-[3px] translate-y-[2px] animate-pulse rounded-sm bg-foreground/70\" aria-hidden />\n )}\n </div>\n {msg.toolCalls && msg.toolCalls.length > 0 && (\n <div className=\"mt-2 flex flex-col gap-1.5\">\n {msg.toolCalls.map((tc) => (\n <ToolCallCard\n key={tc.id}\n call={tc}\n message={msg}\n approval={approval}\n onOpenRun={onToolCallClick}\n renderers={toolRenderers}\n />\n ))}\n </div>\n )}\n {renderExtras?.(msg)}\n </div>\n )\n}\n\nfunction ThinkingRow({ agentLabel }: { agentLabel: string }) {\n const [seconds, setSeconds] = useState(0)\n useEffect(() => {\n const id = setInterval(() => setSeconds((s) => s + 1), 1000)\n return () => clearInterval(id)\n }, [])\n return (\n <div className=\"mx-auto w-full max-w-3xl px-6 py-3\">\n <p className=\"mb-1 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground/60\">{agentLabel}</p>\n <div className=\"flex items-center gap-2 text-base text-muted-foreground\">\n <svg className=\"h-4 w-4 animate-spin\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" aria-hidden>\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" strokeLinecap=\"round\" />\n </svg>\n Thinking{seconds >= 3 ? ` · ${seconds}s` : '...'}\n </div>\n </div>\n )\n}\n\n/**\n * The message thread: one centered column; user messages are right-aligned\n * bubbles with a User label; agent messages carry an Agent meta line with\n * model id, tokens/sec, and cost, plus a collapsible thinking section and\n * tool-call chips.\n */\nexport function ChatMessages({\n messages,\n models = [],\n renderMarkdown,\n renderExtras,\n userLabel = 'User',\n agentLabel = 'Agent',\n loading,\n approval,\n onToolCallClick,\n toolRenderers,\n}: ChatMessagesProps) {\n const renderBody = renderMarkdown ?? ((content: string) => <p className=\"whitespace-pre-wrap\">{content}</p>)\n const lastIsUser = messages[messages.length - 1]?.role === 'user'\n return (\n <>\n {messages.map((msg) =>\n msg.role === 'user' ? (\n <div key={msg.id} className=\"mx-auto w-full max-w-3xl px-6 py-3\">\n <div className=\"ml-auto w-fit max-w-[85%]\">\n <p className=\"mb-1 text-right text-[11px] font-semibold uppercase tracking-wide text-muted-foreground/60\">\n {userLabel}\n </p>\n <div className=\"rounded-2xl rounded-tr-md bg-primary/10 px-4 py-2.5 text-base leading-relaxed\">\n <p className=\"whitespace-pre-wrap\">{msg.content}</p>\n </div>\n </div>\n </div>\n ) : (\n <AssistantMessage\n key={msg.id}\n msg={msg}\n streaming={!!loading && msg.id === messages[messages.length - 1]?.id}\n models={models}\n agentLabel={agentLabel}\n renderBody={renderBody}\n approval={approval}\n onToolCallClick={onToolCallClick}\n toolRenderers={toolRenderers}\n renderExtras={renderExtras}\n />\n ),\n )}\n {loading && lastIsUser && <ThinkingRow agentLabel={agentLabel} />}\n </>\n )\n}\n","/**\n * Provider brand marks — real logo path data (simple-icons / SVG Logos, both\n * CC0) inlined so the picker shows actual provider identity instead of\n * colored-initial monograms. Providers without a usable mark fall back to a\n * tinted monogram chip. Aliases (z-ai/zai, moonshot/moonshotai, deepseek_ai)\n * normalize to one entry.\n */\n\nimport type { ReactNode } from 'react'\n\ninterface LogoDef {\n viewBox: string\n fill: string\n paths: string[]\n}\n\nconst LOGOS: Record<string, LogoDef> = {\n anthropic: { viewBox: '0 0 24 24', fill: '#D97757', paths: [\"M17.3041 3.541h-3.6718l6.696 16.918H24Zm-10.6082 0L0 20.459h3.7442l1.3693-3.5527h7.0052l1.3693 3.5528h3.7442L10.5363 3.5409Zm-.3712 10.2232 2.2914-5.9456 2.2914 5.9456Z\"] },\n google: { viewBox: '0 0 24 24', fill: '#8E75B2', paths: [\"M11.04 19.32Q12 21.51 12 24q0-2.49.93-4.68.96-2.19 2.58-3.81t3.81-2.55Q21.51 12 24 12q-2.49 0-4.68-.93a12.3 12.3 0 0 1-3.81-2.58 12.3 12.3 0 0 1-2.58-3.81Q12 2.49 12 0q0 2.49-.96 4.68-.93 2.19-2.55 3.81a12.3 12.3 0 0 1-3.81 2.58Q2.49 12 0 12q2.49 0 4.68.96 2.19.93 3.81 2.55t2.55 3.81\"] },\n deepseek: { viewBox: '0 0 24 24', fill: '#4D6BFE', paths: [\"M23.748 4.651c-.254-.124-.364.113-.512.233-.051.04-.094.09-.137.137-.372.397-.806.657-1.373.626-.829-.046-1.537.214-2.163.848-.133-.782-.575-1.248-1.247-1.548-.352-.155-.708-.311-.955-.65-.172-.24-.219-.509-.305-.774-.055-.16-.11-.323-.293-.35-.2-.031-.278.136-.356.276-.313.572-.434 1.202-.422 1.84.027 1.436.633 2.58 1.838 3.393.137.094.172.187.129.323-.082.28-.18.553-.266.833-.055.179-.137.218-.328.14a5.5 5.5 0 0 1-1.737-1.179c-.857-.828-1.631-1.743-2.597-2.46a12 12 0 0 0-.689-.47c-.985-.957.13-1.743.387-1.836.27-.098.094-.433-.778-.428-.872.003-1.67.295-2.687.685a3 3 0 0 1-.465.136 9.6 9.6 0 0 0-2.883-.101c-1.885.21-3.39 1.1-4.497 2.622C.082 8.776-.231 10.854.152 13.02c.403 2.284 1.568 4.175 3.36 5.653 1.857 1.533 3.997 2.284 6.438 2.14 1.482-.085 3.132-.284 4.994-1.86.47.234.962.328 1.78.398.629.058 1.235-.031 1.705-.129.735-.155.684-.836.418-.961-2.155-1.004-1.682-.595-2.112-.926 1.095-1.295 2.768-3.598 3.284-6.733.05-.346.115-.834.108-1.114-.004-.171.035-.238.23-.257a4.2 4.2 0 0 0 1.545-.475c1.397-.763 1.96-2.016 2.093-3.517.02-.23-.004-.467-.247-.588M11.58 18.168c-2.088-1.642-3.101-2.183-3.52-2.16-.39.024-.32.472-.234.763.09.288.207.487.371.74.114.167.192.416-.113.603-.673.416-1.842-.14-1.897-.168-1.361-.801-2.5-1.86-3.301-3.306-.775-1.393-1.225-2.888-1.299-4.482-.02-.385.094-.522.477-.592a4.7 4.7 0 0 1 1.53-.038c2.131.311 3.946 1.264 5.467 2.774.868.86 1.525 1.887 2.202 2.89.72 1.066 1.494 2.082 2.48 2.915.348.291.626.513.892.677-.802.09-2.14.109-3.055-.615zm1.001-6.44a.306.306 0 0 1 .415-.287.3.3 0 0 1 .113.074.3.3 0 0 1 .086.214c0 .17-.136.307-.308.307a.303.303 0 0 1-.306-.307m3.11 1.596c-.2.081-.4.151-.591.16a1.25 1.25 0 0 1-.798-.254c-.274-.23-.47-.358-.551-.758a1.7 1.7 0 0 1 .015-.588c.07-.327-.007-.537-.238-.727-.188-.156-.426-.199-.689-.199a.6.6 0 0 1-.254-.078.253.253 0 0 1-.114-.358 1 1 0 0 1 .192-.21c.356-.202.767-.136 1.146.016.352.144.618.408 1.001.782.392.451.462.576.685.915.176.264.336.536.446.848.066.194-.02.353-.25.45\"] },\n mistral: { viewBox: '0 0 24 24', fill: '#FA520F', paths: [\"M17.143 3.429v3.428h-3.429v3.429h-3.428V6.857H6.857V3.43H3.43v13.714H0v3.428h10.286v-3.428H6.857v-3.429h3.429v3.429h3.429v-3.429h3.428v3.429h-3.428v3.428H24v-3.428h-3.43V3.429z\"] },\n xai: { viewBox: '0 0 24 24', fill: '#000000', paths: [\"M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z\"] },\n nvidia: { viewBox: '0 0 24 24', fill: '#76B900', paths: [\"M8.948 8.798v-1.43a6.7 6.7 0 0 1 .424-.018c3.922-.124 6.493 3.374 6.493 3.374s-2.774 3.851-5.75 3.851c-.398 0-.787-.062-1.158-.185v-4.346c1.528.185 1.837.857 2.747 2.385l2.04-1.714s-1.492-1.952-4-1.952a6.016 6.016 0 0 0-.796.035m0-4.735v2.138l.424-.027c5.45-.185 9.01 4.47 9.01 4.47s-4.08 4.964-8.33 4.964c-.37 0-.733-.035-1.095-.097v1.325c.3.035.61.062.91.062 3.957 0 6.82-2.023 9.593-4.408.459.371 2.34 1.263 2.73 1.652-2.633 2.208-8.772 3.984-12.253 3.984-.335 0-.653-.018-.971-.053v1.864H24V4.063zm0 10.326v1.131c-3.657-.654-4.673-4.46-4.673-4.46s1.758-1.944 4.673-2.262v1.237H8.94c-1.528-.186-2.73 1.245-2.73 1.245s.68 2.412 2.739 3.11M2.456 10.9s2.164-3.197 6.5-3.533V6.201C4.153 6.59 0 10.653 0 10.653s2.35 6.802 8.948 7.42v-1.237c-4.84-.6-6.492-5.936-6.492-5.936z\"] },\n meta: { viewBox: '0 0 24 24', fill: '#0467DF', paths: [\"M6.915 4.03c-1.968 0-3.683 1.28-4.871 3.113C.704 9.208 0 11.883 0 14.449c0 .706.07 1.369.21 1.973a6.624 6.624 0 0 0 .265.86 5.297 5.297 0 0 0 .371.761c.696 1.159 1.818 1.927 3.593 1.927 1.497 0 2.633-.671 3.965-2.444.76-1.012 1.144-1.626 2.663-4.32l.756-1.339.186-.325c.061.1.121.196.183.3l2.152 3.595c.724 1.21 1.665 2.556 2.47 3.314 1.046.987 1.992 1.22 3.06 1.22 1.075 0 1.876-.355 2.455-.843a3.743 3.743 0 0 0 .81-.973c.542-.939.861-2.127.861-3.745 0-2.72-.681-5.357-2.084-7.45-1.282-1.912-2.957-2.93-4.716-2.93-1.047 0-2.088.467-3.053 1.308-.652.57-1.257 1.29-1.82 2.05-.69-.875-1.335-1.547-1.958-2.056-1.182-.966-2.315-1.303-3.454-1.303zm10.16 2.053c1.147 0 2.188.758 2.992 1.999 1.132 1.748 1.647 4.195 1.647 6.4 0 1.548-.368 2.9-1.839 2.9-.58 0-1.027-.23-1.664-1.004-.496-.601-1.343-1.878-2.832-4.358l-.617-1.028a44.908 44.908 0 0 0-1.255-1.98c.07-.109.141-.224.211-.327 1.12-1.667 2.118-2.602 3.358-2.602zm-10.201.553c1.265 0 2.058.791 2.675 1.446.307.327.737.871 1.234 1.579l-1.02 1.566c-.757 1.163-1.882 3.017-2.837 4.338-1.191 1.649-1.81 1.817-2.486 1.817-.524 0-1.038-.237-1.383-.794-.263-.426-.464-1.13-.464-2.046 0-2.221.63-4.535 1.66-6.088.454-.687.964-1.226 1.533-1.533a2.264 2.264 0 0 1 1.088-.285z\"] },\n moonshotai: { viewBox: '0 0 24 24', fill: '#16191E', paths: [\"m1.053 16.91 9.538 2.55a21 20.981 0 0 0 .06 2.031l5.956 1.592a12 11.99 0 0 1-15.554-6.172m-1.02-5.79 11.352 3.035a21 20.981 0 0 0-.469 2.01l10.817 2.89a12 11.99 0 0 1-1.845 2.004L.658 15.918a12 11.99 0 0 1-.625-4.796m1.593-5.146L13.573 9.17a21 20.981 0 0 0-1.01 1.874l11.297 3.02a21 20.981 0 0 1-.67 2.362l-11.55-3.087L.125 10.26a12 11.99 0 0 1 1.499-4.285ZM6.067 1.58l11.285 3.016a21 20.981 0 0 0-1.688 1.719l7.824 2.091a21 20.981 0 0 1 .513 2.664L2.107 5.218a12 11.99 0 0 1 3.96-3.638M21.68 4.866 7.222 1.003A12 11.99 0 0 1 21.68 4.866\"] },\n openai: { viewBox: '0 0 256 260', fill: '#10A37F', paths: [\"M239.184 106.203a64.72 64.72 0 0 0-5.576-53.103C219.452 28.459 191 15.784 163.213 21.74A65.586 65.586 0 0 0 52.096 45.22a64.72 64.72 0 0 0-43.23 31.36c-14.31 24.602-11.061 55.634 8.033 76.74a64.67 64.67 0 0 0 5.525 53.102c14.174 24.65 42.644 37.324 70.446 31.36a64.72 64.72 0 0 0 48.754 21.744c28.481.025 53.714-18.361 62.414-45.481a64.77 64.77 0 0 0 43.229-31.36c14.137-24.558 10.875-55.423-8.083-76.483m-97.56 136.338a48.4 48.4 0 0 1-31.105-11.255l1.535-.87l51.67-29.825a8.6 8.6 0 0 0 4.247-7.367v-72.85l21.845 12.636c.218.111.37.32.409.563v60.367c-.056 26.818-21.783 48.545-48.601 48.601M37.158 197.93a48.35 48.35 0 0 1-5.781-32.589l1.534.921l51.722 29.826a8.34 8.34 0 0 0 8.441 0l63.181-36.425v25.221a.87.87 0 0 1-.358.665l-52.335 30.184c-23.257 13.398-52.97 5.431-66.404-17.803M23.549 85.38a48.5 48.5 0 0 1 25.58-21.333v61.39a8.29 8.29 0 0 0 4.195 7.316l62.874 36.272l-21.845 12.636a.82.82 0 0 1-.767 0L41.353 151.53c-23.211-13.454-31.171-43.144-17.804-66.405zm179.466 41.695l-63.08-36.63L161.73 77.86a.82.82 0 0 1 .768 0l52.233 30.184a48.6 48.6 0 0 1-7.316 87.635v-61.391a8.54 8.54 0 0 0-4.4-7.213m21.742-32.69l-1.535-.922l-51.619-30.081a8.39 8.39 0 0 0-8.492 0L99.98 99.808V74.587a.72.72 0 0 1 .307-.665l52.233-30.133a48.652 48.652 0 0 1 72.236 50.391zM88.061 139.097l-21.845-12.585a.87.87 0 0 1-.41-.614V65.685a48.652 48.652 0 0 1 79.757-37.346l-1.535.87l-51.67 29.825a8.6 8.6 0 0 0-4.246 7.367zm11.868-25.58L128.067 97.3l28.188 16.218v32.434l-28.086 16.218l-28.188-16.218z\"] },\n}\n\nconst ALIASES: Record<string, string> = {\n moonshot: 'moonshotai',\n deepseek_ai: 'deepseek',\n 'x-ai': 'xai',\n 'meta-llama': 'meta',\n}\n\nconst MONOGRAM: Record<string, { bg: string; fg: string }> = {\n cohere: { bg: '#fae8ff', fg: '#c026d3' },\n groq: { bg: '#fce7f3', fg: '#db2777' },\n cerebras: { bg: '#ccfbf1', fg: '#0d9488' },\n zai: { bg: '#ede9fe', fg: '#7c3aed' },\n 'z-ai': { bg: '#ede9fe', fg: '#7c3aed' },\n tuner: { bg: '#dbeafe', fg: '#2563eb' },\n}\n\nexport interface ProviderLogoProps {\n provider?: string\n size?: number\n}\n\n/** Real brand mark when we have one; tinted monogram otherwise. */\nexport function ProviderLogo({ provider, size = 16 }: ProviderLogoProps): ReactNode {\n const key = ALIASES[provider ?? ''] ?? provider ?? ''\n const logo = LOGOS[key]\n if (logo) {\n return (\n <svg width={size} height={size} viewBox={logo.viewBox} role=\"img\" aria-label={key}>\n {logo.paths.map((d, i) => (\n <path key={i} d={d} fill={logo.fill} />\n ))}\n </svg>\n )\n }\n const mono = MONOGRAM[key] ?? { bg: '#f3f4f6', fg: '#6b7280' }\n return (\n <svg width={size} height={size} viewBox=\"0 0 16 16\" role=\"img\" aria-label={key || 'model'}>\n <rect width=\"16\" height=\"16\" rx=\"4\" fill={mono.bg} />\n <text x=\"8\" y=\"11.6\" textAnchor=\"middle\" fill={mono.fg} fontSize=\"9\" fontWeight=\"700\" fontFamily=\"system-ui, sans-serif\">\n {(key || '?').charAt(0).toUpperCase()}\n </text>\n </svg>\n )\n}\n","/**\n * Smooth text reveal — turns chunky network deltas into a continuous\n * typewriter paint. Streamed turns arrive in 100-500ms slabs (model burst,\n * flush windows, replay polls); revealing characters at an adaptive rate\n * makes the same bytes read as top-tier streaming. The rate scales with the\n * backlog so the reveal never falls behind the stream — it crawls when caught\n * up and sprints when a burst lands (e.g. a reasoning summary arriving all at\n * once still *types out* instead of popping in).\n */\n\nimport { useEffect, useRef, useState } from 'react'\n\nexport interface SmoothRevealOptions {\n /** Baseline reveal rate when nearly caught up. Default 90 chars/s. */\n baseCharsPerSecond?: number\n /** Extra chars/s per backlog character — the catch-up pressure. Default 5. */\n catchUpPerChar?: number\n /** Hard ceiling so giant bursts still animate. Default 2400 chars/s. */\n maxCharsPerSecond?: number\n}\n\n/** Pure reveal step: how many characters should be visible after `dtMs`.\n * Exposed for tests; the hook is a thin rAF wrapper around it. */\nexport function nextRevealCount(\n shown: number,\n targetLength: number,\n dtMs: number,\n opts: SmoothRevealOptions = {},\n): number {\n if (shown >= targetLength) return targetLength\n const base = opts.baseCharsPerSecond ?? 90\n const catchUp = opts.catchUpPerChar ?? 5\n const max = opts.maxCharsPerSecond ?? 2400\n const backlog = targetLength - shown\n const rate = Math.min(max, base + backlog * catchUp)\n return Math.min(targetLength, shown + (rate * dtMs) / 1000)\n}\n\n/**\n * Animate `target` text into view. While `enabled`, the returned string grows\n * smoothly toward `target` (which may itself keep growing); when `enabled` is\n * false the full text returns immediately (history, completed turns). A\n * target that is not an extension of the revealed prefix (new message) resets\n * the reveal.\n */\nexport function useSmoothText(target: string, enabled: boolean, opts?: SmoothRevealOptions): string {\n const [, force] = useState(0)\n const shownRef = useRef(0)\n const lastTargetRef = useRef('')\n\n // New message / rewritten prefix → restart the reveal from zero.\n if (!target.startsWith(lastTargetRef.current.slice(0, Math.floor(shownRef.current)))) {\n shownRef.current = 0\n }\n lastTargetRef.current = target\n if (!enabled) shownRef.current = target.length\n\n useEffect(() => {\n if (!enabled) return\n let raf = 0\n let last: number | null = null\n const tick = (t: number) => {\n const dt = last == null ? 16 : Math.min(t - last, 100)\n last = t\n const targetLen = lastTargetRef.current.length\n if (shownRef.current < targetLen) {\n shownRef.current = nextRevealCount(shownRef.current, targetLen, dt, opts)\n force((n) => n + 1)\n }\n raf = requestAnimationFrame(tick)\n }\n raf = requestAnimationFrame(tick)\n return () => cancelAnimationFrame(raf)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [enabled])\n\n return target.slice(0, Math.floor(shownRef.current))\n}\n","/**\n * Client-side chat-stream consumption — the NDJSON parse loop every agent\n * app's chat UI hand-rolls (and breaks). Normalizes the three line shapes the\n * agent-app chat routes emit:\n *\n * {kind:'event', event:{type:'text'|'reasoning'|'tool_call'|'usage', ...}}\n * {kind:'tool_result', toolCallId, toolName, label, outcome}\n * {type:'turn'|'metadata'|'error'|'turn_status', ...} (route-level)\n *\n * Replayed lines carry an extra `seq` — transparently ignored. Works for\n * router-backed and sandbox-backed chats alike: anything producing these\n * lines (live pump, queued follow, resume replay) feeds the same callbacks.\n */\n\nexport interface ChatStreamToolCall {\n toolCallId?: string\n toolName: string\n args: Record<string, unknown>\n}\n\nexport interface ChatStreamToolResult {\n toolCallId?: string\n toolName?: string\n label?: string\n outcome: { ok: boolean; result?: unknown; code?: string; message?: string }\n}\n\nexport interface ChatStreamCallbacks {\n onTurnId?: (turnId: string) => void\n onText?: (delta: string) => void\n onReasoning?: (delta: string) => void\n onToolCall?: (call: ChatStreamToolCall) => void\n onToolResult?: (result: ChatStreamToolResult) => void\n onUsage?: (usage: { promptTokens: number; completionTokens: number }) => void\n onMetadata?: (data: Record<string, unknown>) => void\n /** A loop-level error event (the turn failed server-side). */\n onErrorEvent?: (message: string) => void\n}\n\nexport interface ConsumeChatStreamResult {\n turnId: string | null\n /** True when any text/reasoning/tool activity was received. */\n receivedContent: boolean\n}\n\n/** Parse one NDJSON line into the callbacks. Exposed for tests. */\nexport function dispatchChatStreamLine(line: string, cb: ChatStreamCallbacks): {\n turnId?: string\n receivedContent: boolean\n} {\n let receivedContent = false\n let turnId: string | undefined\n if (!line.trim()) return { receivedContent }\n let parsed: Record<string, unknown>\n try {\n parsed = JSON.parse(line) as Record<string, unknown>\n } catch {\n return { receivedContent } // tolerate a torn line\n }\n\n if (parsed.kind === 'tool_result') {\n cb.onToolResult?.({\n toolCallId: parsed.toolCallId as string | undefined,\n toolName: parsed.toolName as string | undefined,\n label: parsed.label as string | undefined,\n outcome: (parsed.outcome ?? parsed.result) as ChatStreamToolResult['outcome'],\n })\n return { receivedContent: true }\n }\n\n const evt = (parsed.kind === 'event' ? parsed.event : parsed) as Record<string, unknown>\n if (!evt || typeof evt !== 'object') return { receivedContent }\n\n switch (evt.type) {\n case 'turn':\n if (typeof evt.turnId === 'string') turnId = evt.turnId\n break\n case 'text':\n if (typeof evt.text === 'string') {\n cb.onText?.(evt.text)\n receivedContent = true\n }\n break\n case 'reasoning':\n if (typeof evt.text === 'string') {\n cb.onReasoning?.(evt.text)\n receivedContent = true\n }\n break\n case 'tool_call': {\n const call = (evt.call ?? evt) as Record<string, unknown>\n cb.onToolCall?.({\n toolCallId: (call.toolCallId ?? call.id) as string | undefined,\n toolName: String(call.toolName ?? call.name ?? 'unknown'),\n args: (call.args ?? {}) as Record<string, unknown>,\n })\n receivedContent = true\n break\n }\n case 'tool_result':\n cb.onToolResult?.({\n toolCallId: evt.toolCallId as string | undefined,\n toolName: evt.toolName as string | undefined,\n label: evt.label as string | undefined,\n outcome: (evt.outcome ?? evt.result) as ChatStreamToolResult['outcome'],\n })\n receivedContent = true\n break\n case 'usage': {\n const u = evt.usage as { promptTokens?: number; completionTokens?: number } | undefined\n if (u) cb.onUsage?.({ promptTokens: u.promptTokens ?? 0, completionTokens: u.completionTokens ?? 0 })\n break\n }\n case 'metadata':\n cb.onMetadata?.((evt.data ?? {}) as Record<string, unknown>)\n break\n case 'error':\n cb.onErrorEvent?.(String(evt.details ?? evt.error ?? 'Unknown stream error'))\n break\n default:\n break // turn_status and unknown line types are non-content\n }\n return { turnId, receivedContent }\n}\n\n/** Drain one NDJSON body into the callbacks. Throws on transport failure\n * (caller decides whether to resume). */\nexport async function consumeChatStream(\n body: ReadableStream<Uint8Array>,\n cb: ChatStreamCallbacks,\n): Promise<ConsumeChatStreamResult> {\n const reader = body.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n let turnId: string | null = null\n let receivedContent = false\n\n const handle = (line: string) => {\n const r = dispatchChatStreamLine(line, cb)\n if (r.turnId) {\n turnId = r.turnId\n cb.onTurnId?.(r.turnId)\n }\n if (r.receivedContent) receivedContent = true\n }\n\n for (;;) {\n const { done, value } = await reader.read()\n if (done) {\n if (buffer.trim()) handle(buffer)\n break\n }\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split('\\n')\n buffer = lines.pop() ?? ''\n for (const line of lines) handle(line)\n }\n return { turnId, receivedContent }\n}\n\nexport interface StreamChatOptions {\n /** Start the turn (POST the chat request); must return a streaming Response. */\n start: () => Promise<Response>\n /** Re-attach to a turn after a transport drop (GET the resume route). */\n resume?: (turnId: string, fromSeq: number) => Promise<Response>\n callbacks: ChatStreamCallbacks\n /** Called before a resume replays from 0 so the UI can reset accumulated\n * turn state (text, reasoning, tool chips). */\n onResetForResume?: () => void\n}\n\n/**\n * Run one chat turn with automatic single-shot resume: if the transport drops\n * mid-turn and the server announced a turnId, reset and replay the buffered\n * turn. Server-side the turn keeps running either way (queued runner).\n */\nexport async function streamChatTurn(opts: StreamChatOptions): Promise<ConsumeChatStreamResult> {\n const res = await opts.start()\n if (!res.ok || !res.body) {\n const err = await res.json().catch(() => ({ error: `HTTP ${res.status}` })) as { error?: string }\n throw new Error(err.error ?? `HTTP ${res.status}`)\n }\n let turnId: string | null = null\n const cb: ChatStreamCallbacks = {\n ...opts.callbacks,\n onTurnId: (id) => {\n turnId = id\n opts.callbacks.onTurnId?.(id)\n },\n }\n try {\n return await consumeChatStream(res.body, cb)\n } catch (transportErr) {\n if (!turnId || !opts.resume) throw transportErr\n opts.onResetForResume?.()\n const resumed = await opts.resume(turnId, 0)\n if (!resumed.ok || !resumed.body) throw transportErr\n return await consumeChatStream(resumed.body, cb)\n }\n}\n","/**\n * Mission + delegation observability surfaces — different nouns, one trace\n * tree:\n *\n * - {@link MissionActivityLane}: the collapsed sub-rows under a mission step\n * (what the step's agent is actually doing), expanding to a compact web\n * waterfall rendered from the `/trace` converters.\n * - {@link AgentActivityPanel}: the standalone cross-context surface — every\n * delegation a workspace ran, regardless of which mission (if any) spawned\n * it — behind a `fetchActivity` data port with cursor + refresh.\n * - {@link FlowWaterfall}: the web counterpart of `/trace`'s ASCII\n * `renderWaterfall` (which stays CLI) — proportional bars over a FlowTrace.\n *\n * Same styling contract as the rest of `/web-react`: Tailwind classes against\n * the shared design tokens, inline SVG glyphs, no icon library. The pure\n * layout/merge/format helpers are exported for tests and reuse.\n */\n\nimport { useCallback, useEffect, useState, type ReactNode } from 'react'\n\nimport type { StepAgentActivity } from '../missions/agent-activity'\nimport type { FlowTrace } from '../trace/index'\nimport { stepActivityFlowTrace } from '../trace/mission-flow'\n\n// ── pure helpers ──────────────────────────────────────────────────────────\n\nexport type ActivityTone = 'live' | 'ok' | 'error' | 'neutral'\n\nconst LIVE_STATUSES = new Set(['pending', 'running'])\nconst OK_STATUSES = new Set(['completed', 'done', 'succeeded'])\nconst ERROR_STATUSES = new Set(['failed', 'error', 'cancelled', 'aborted'])\n\n/** Map a delegation status (free-form string on the wire) to a render tone. */\nexport function activityTone(status: string): ActivityTone {\n const s = status.toLowerCase()\n if (LIVE_STATUSES.has(s)) return 'live'\n if (OK_STATUSES.has(s)) return 'ok'\n if (ERROR_STATUSES.has(s)) return 'error'\n return 'neutral'\n}\n\n/** \"$0.4000\" under a cent shows 4 decimals; null when unknown/zero. */\nexport function formatActivityCost(costUsd?: number): string | null {\n if (costUsd === undefined || !isFinite(costUsd) || costUsd <= 0) return null\n return costUsd < 0.01 ? `$${costUsd.toFixed(4)}` : `$${costUsd.toFixed(2)}`\n}\n\n/** \"8s\" / \"2m 05s\" / \"1h 12m\"; null when unknown. */\nexport function formatActivityDuration(durationMs?: number): string | null {\n if (durationMs === undefined || !isFinite(durationMs) || durationMs < 0) return null\n const totalSeconds = Math.round(durationMs / 1000)\n if (totalSeconds < 60) return `${totalSeconds}s`\n const minutes = Math.floor(totalSeconds / 60)\n const seconds = totalSeconds % 60\n if (minutes < 60) return `${minutes}m ${String(seconds).padStart(2, '0')}s`\n return `${Math.floor(minutes / 60)}h ${String(minutes % 60).padStart(2, '0')}m`\n}\n\n/** A delegation record on the cross-context surface; `missionRef` links a\n * promoted delegation back to the mission/step that spawned it. */\nexport interface AgentActivityRecord extends StepAgentActivity {\n missionRef?: { missionId: string; stepId?: string; label?: string }\n}\n\nexport interface AgentActivityPage {\n items: AgentActivityRecord[]\n /** Opaque continuation token; absent ⇒ no further pages. */\n nextCursor?: string\n}\n\n/**\n * Fold a fetched page into the held rows: dedupe by `taskId` with the\n * incoming row winning (a refresh re-fetches the head page, so newer\n * snapshots of in-flight runs replace stale ones), newest `startedAt` first.\n */\nexport function mergeActivityPages(\n existing: AgentActivityRecord[],\n incoming: AgentActivityRecord[],\n): AgentActivityRecord[] {\n const byTask = new Map<string, AgentActivityRecord>()\n for (const row of existing) byTask.set(row.taskId, row)\n for (const row of incoming) byTask.set(row.taskId, row)\n return [...byTask.values()].sort((a, b) => Date.parse(b.startedAt) - Date.parse(a.startedAt))\n}\n\nexport interface WaterfallRow {\n name: string\n kind: 'pipeline' | 'model' | 'tool'\n /** Bar geometry as percentages of the trace's total span. */\n offsetPct: number\n widthPct: number\n durationLabel: string\n approx: boolean\n /** False only when the span's meta carries an explicit failure. */\n ok: boolean\n}\n\n/** Project a FlowTrace into proportional bar geometry for {@link FlowWaterfall}. */\nexport function waterfallLayout(trace: FlowTrace): WaterfallRow[] {\n const total = trace.totalMs > 0 ? trace.totalMs : 1\n return [...trace.spans]\n .sort((a, b) => a.startMs - b.startMs)\n .map((span) => {\n const meta = span.meta ?? {}\n const failed =\n meta.ok === false || (typeof meta.status === 'string' && activityTone(meta.status) === 'error')\n return {\n name: span.name,\n kind: span.kind,\n offsetPct: Math.max(0, Math.min(100, (span.startMs / total) * 100)),\n widthPct: Math.max(0.5, Math.min(100, ((span.endMs - span.startMs) / total) * 100)),\n durationLabel: `${((span.endMs - span.startMs) / 1000).toFixed(1)}s${span.approx ? '~' : ''}`,\n approx: span.approx === true,\n ok: !failed,\n }\n })\n}\n\n// ── glyphs ────────────────────────────────────────────────────────────────\n\nfunction ChevronGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n )\n}\n\nfunction RefreshGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M21 12a9 9 0 1 1-2.64-6.36M21 3v6h-6\" />\n </svg>\n )\n}\n\nfunction StatusDot({ tone }: { tone: ActivityTone }) {\n return (\n <span\n className={`h-2 w-2 shrink-0 rounded-full ${\n tone === 'live' ? 'animate-pulse bg-yellow-500' : tone === 'ok' ? 'bg-green-500' : tone === 'error' ? 'bg-red-500' : 'bg-muted-foreground/40'\n }`}\n />\n )\n}\n\n// ── FlowWaterfall ─────────────────────────────────────────────────────────\n\nconst BAR_CLASS: Record<WaterfallRow['kind'], string> = {\n pipeline: 'bg-muted-foreground/30',\n model: 'bg-primary/60',\n tool: 'bg-primary',\n}\n\nexport interface FlowWaterfallProps {\n trace: FlowTrace\n}\n\n/** Compact proportional waterfall over a FlowTrace — span name, bar, duration\n * per row; total + cost in the footer. */\nexport function FlowWaterfall({ trace }: FlowWaterfallProps) {\n const rows = waterfallLayout(trace)\n if (rows.length === 0) return null\n const cost = formatActivityCost(trace.costUsd)\n return (\n <div className=\"space-y-1\">\n {rows.map((row, i) => (\n <div key={i} className=\"grid grid-cols-[minmax(0,2fr)_minmax(0,3fr)_auto] items-center gap-2\">\n <span className=\"truncate font-mono text-[11px] text-muted-foreground\" title={row.name}>\n {row.name}\n </span>\n <div className=\"relative h-2 rounded-sm bg-muted/40\">\n <div\n className={`absolute inset-y-0 rounded-sm ${row.ok ? BAR_CLASS[row.kind] : 'bg-red-500/80'} ${row.approx ? 'opacity-70' : ''}`}\n style={{ left: `${row.offsetPct}%`, width: `${row.widthPct}%` }}\n />\n </div>\n <span className=\"shrink-0 font-mono text-[10px] tabular-nums text-muted-foreground/70\">{row.durationLabel}</span>\n </div>\n ))}\n <p className=\"pt-0.5 text-right font-mono text-[10px] tabular-nums text-muted-foreground/60\">\n {(trace.totalMs / 1000).toFixed(1)}s{cost ? ` · ${cost}` : ''}\n </p>\n </div>\n )\n}\n\n// ── MissionActivityLane ───────────────────────────────────────────────────\n\nexport interface MissionActivityLaneProps {\n /** The step's delegated-run snapshot (`MissionStepState.agentActivity`). */\n activity: StepAgentActivity[]\n /** Epoch ms origin for the expanded waterfall — usually the step start. */\n startedAt?: number\n /** Wall clock for extending in-flight runs on the waterfall. */\n nowMs?: number\n}\n\n/**\n * Collapsed sub-rows under a mission step — one row per delegated run —\n * expanding to the step's waterfall. Renders nothing for an empty lane.\n */\nexport function MissionActivityLane({ activity, startedAt, nowMs }: MissionActivityLaneProps) {\n const [expanded, setExpanded] = useState(false)\n if (activity.length === 0) return null\n\n return (\n <div className=\"mt-1 border-l border-border/50 pl-3\">\n {activity.map((run) => {\n const tone = activityTone(run.status)\n const cost = formatActivityCost(run.costUsd)\n const duration = formatActivityDuration(run.durationMs)\n return (\n <div key={run.taskId} className=\"flex items-center gap-2 py-1 text-xs\">\n <StatusDot tone={tone} />\n <span className=\"min-w-0 flex-1 truncate\">\n <span className=\"font-medium\">{run.tool}</span>\n <span className=\"text-muted-foreground\"> — {run.detail}</span>\n </span>\n {tone === 'live' && (run.iteration !== undefined || run.phase !== undefined) && (\n <span className=\"shrink-0 rounded-full bg-yellow-500/10 px-1.5 py-0.5 font-mono text-[10px] text-yellow-700 dark:text-yellow-400\">\n {[run.iteration !== undefined ? `iter ${run.iteration}` : null, run.phase ?? null]\n .filter(Boolean)\n .join(' · ')}\n </span>\n )}\n <span className=\"flex shrink-0 items-center gap-1.5 font-mono text-[10px] tabular-nums text-muted-foreground/70\">\n {tone !== 'live' && tone !== 'ok' && <span>{run.status}</span>}\n {cost && <span>{cost}</span>}\n {duration && <span>{duration}</span>}\n </span>\n </div>\n )\n })}\n <button\n type=\"button\"\n onClick={() => setExpanded((v) => !v)}\n className=\"flex items-center gap-1 py-0.5 text-[10px] font-medium text-muted-foreground/70 transition hover:text-foreground\"\n >\n <ChevronGlyph className={`h-3 w-3 transition-transform ${expanded ? 'rotate-180' : ''}`} />\n timeline\n </button>\n {expanded && (\n <div className=\"rounded-md border border-border/50 bg-muted/10 p-2\">\n <FlowWaterfall\n trace={stepActivityFlowTrace(activity, {\n ...(startedAt !== undefined ? { startedAt } : {}),\n ...(nowMs !== undefined ? { nowMs } : {}),\n })}\n />\n </div>\n )}\n </div>\n )\n}\n\n// ── AgentActivityPanel ────────────────────────────────────────────────────\n\nexport interface AgentActivityPanelProps {\n /** Data port — page through the product's delegation records. Called with\n * no cursor on mount/refresh, with `nextCursor` for older pages. */\n fetchActivity: (cursor?: string) => Promise<AgentActivityPage>\n /** Render the mission link for a promoted delegation (chip, anchor, router\n * Link — the product's routing, not ours). */\n renderMissionRef?: (ref: NonNullable<AgentActivityRecord['missionRef']>, record: AgentActivityRecord) => ReactNode\n title?: string\n emptyLabel?: string\n}\n\nfunction ActivityRow({\n record,\n renderMissionRef,\n}: {\n record: AgentActivityRecord\n renderMissionRef?: AgentActivityPanelProps['renderMissionRef']\n}) {\n const [open, setOpen] = useState(false)\n const tone = activityTone(record.status)\n const cost = formatActivityCost(record.costUsd)\n const duration = formatActivityDuration(record.durationMs)\n\n return (\n <div className=\"rounded-lg border border-border/60 bg-card\">\n <button type=\"button\" onClick={() => setOpen((v) => !v)} className=\"flex w-full items-center gap-2.5 px-3 py-2 text-left text-sm\">\n <StatusDot tone={tone} />\n <span className=\"min-w-0 flex-1 truncate\">\n <span className=\"font-medium\">{record.tool}</span>\n <span className=\"text-muted-foreground\"> — {record.detail}</span>\n </span>\n {tone === 'live' && (record.iteration !== undefined || record.phase !== undefined) && (\n <span className=\"shrink-0 rounded-full bg-yellow-500/10 px-2 py-0.5 font-mono text-[10px] text-yellow-700 dark:text-yellow-400\">\n {[record.iteration !== undefined ? `iter ${record.iteration}` : null, record.phase ?? null]\n .filter(Boolean)\n .join(' · ')}\n </span>\n )}\n <span\n className={`shrink-0 rounded-full px-2 py-0.5 text-[10px] font-medium ${\n tone === 'ok'\n ? 'bg-green-500/10 text-green-700 dark:text-green-400'\n : tone === 'error'\n ? 'bg-red-500/10 text-red-700 dark:text-red-400'\n : tone === 'live'\n ? 'bg-yellow-500/10 text-yellow-700 dark:text-yellow-400'\n : 'bg-muted/60 text-muted-foreground'\n }`}\n >\n {record.status}\n </span>\n {cost && <span className=\"shrink-0 font-mono text-[11px] tabular-nums text-muted-foreground\">{cost}</span>}\n <ChevronGlyph className={`h-3 w-3 shrink-0 text-muted-foreground transition-transform ${open ? 'rotate-180' : ''}`} />\n </button>\n {open && (\n <div className=\"space-y-1.5 border-t border-border/40 px-3 py-2.5\">\n <dl className=\"grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 font-mono text-[11px]\">\n <dt className=\"text-muted-foreground/60\">task</dt>\n <dd className=\"truncate text-muted-foreground\">{record.taskId}</dd>\n <dt className=\"text-muted-foreground/60\">started</dt>\n <dd className=\"text-muted-foreground\">{new Date(record.startedAt).toLocaleString()}</dd>\n {duration && (\n <>\n <dt className=\"text-muted-foreground/60\">duration</dt>\n <dd className=\"text-muted-foreground\">{duration}</dd>\n </>\n )}\n {record.traceId && (\n <>\n <dt className=\"text-muted-foreground/60\">trace</dt>\n <dd className=\"truncate text-muted-foreground\">{record.traceId}</dd>\n </>\n )}\n </dl>\n {record.missionRef && renderMissionRef?.(record.missionRef, record)}\n </div>\n )}\n </div>\n )\n}\n\n/**\n * The standalone cross-context delegation surface: every agent run the\n * product journaled, mission-spawned or not, with status, cost, drill-in, and\n * a mission link slot for promoted delegations.\n */\nexport function AgentActivityPanel({ fetchActivity, renderMissionRef, title = 'Agent activity', emptyLabel = 'No agent runs yet.' }: AgentActivityPanelProps) {\n const [rows, setRows] = useState<AgentActivityRecord[]>([])\n const [cursor, setCursor] = useState<string | undefined>(undefined)\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<string | null>(null)\n\n const load = useCallback(\n async (from?: string) => {\n setLoading(true)\n setError(null)\n try {\n const page = await fetchActivity(from)\n setRows((prev) => mergeActivityPages(from === undefined ? [] : prev, page.items))\n setCursor(page.nextCursor)\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e))\n } finally {\n setLoading(false)\n }\n },\n [fetchActivity],\n )\n\n useEffect(() => {\n void load()\n }, [load])\n\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-2\">\n <h2 className=\"flex-1 text-sm font-semibold\">{title}</h2>\n <button\n type=\"button\"\n onClick={() => void load()}\n disabled={loading}\n aria-label=\"Refresh\"\n className=\"rounded-md p-1.5 text-muted-foreground transition hover:bg-accent/30 hover:text-foreground disabled:opacity-50\"\n >\n <RefreshGlyph className={`h-3.5 w-3.5 ${loading ? 'animate-spin' : ''}`} />\n </button>\n </div>\n {error && <p className=\"rounded-md border border-red-300/60 bg-red-500/5 px-3 py-2 text-xs text-red-600\">{error}</p>}\n {!error && rows.length === 0 && !loading && <p className=\"px-1 text-sm text-muted-foreground\">{emptyLabel}</p>}\n <div className=\"space-y-1.5\">\n {rows.map((record) => (\n <ActivityRow key={record.taskId} record={record} renderMissionRef={renderMissionRef} />\n ))}\n </div>\n {cursor && (\n <button\n type=\"button\"\n onClick={() => void load(cursor)}\n disabled={loading}\n className=\"w-full rounded-md border border-border bg-card px-3 py-1.5 text-xs font-medium text-muted-foreground transition hover:bg-accent/30 disabled:opacity-50\"\n >\n Older runs\n </button>\n )}\n </div>\n )\n}\n"],"mappings":"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","names":["useEffect","useRef","useState","useEffect","useState","jsx","jsxs","useState","useEffect","Fragment","jsx","jsxs","useRef","useEffect","useState"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tangle-network/agent-app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"packageManager": "pnpm@10.33.4",
|
|
5
5
|
"description": "Application-shell framework for Tangle agent products: a bounded tool loop, the structured agent\u2192app tool side channel, integration-hub client, per-workspace billing, and crypto \u2014 composed over the Tangle agent substrate through typed seams.",
|
|
6
6
|
"keywords": [
|