@usetheo/ui 0.5.0-next.0 → 0.6.0-next.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/CHANGELOG.md +176 -0
- package/NOTICE +38 -0
- package/README.md +18 -18
- package/dist/index.d.ts +324 -31
- package/dist/index.js +991 -56
- package/dist/index.js.map +1 -1
- package/dist/preset-v3-legacy.d.ts +35 -0
- package/dist/{preset.js → preset-v3-legacy.js} +5 -5
- package/dist/preset-v3-legacy.js.map +1 -0
- package/dist/preset.css +27 -0
- package/dist/styles-v3-legacy.css +88 -0
- package/dist/styles.css +22 -5
- package/dist/tokens-v4.css +187 -0
- package/package.json +12 -6
- package/registry/index.json +1 -1
- package/registry/r/agent-stream.json +1 -1
- package/registry/r/chat-message.json +112 -4
- package/registry/r/chat-types.json +1 -1
- package/dist/preset.d.ts +0 -31
- package/dist/preset.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { clsx } from 'clsx';
|
|
2
2
|
import { extendTailwindMerge } from 'tailwind-merge';
|
|
3
|
-
import { createContext, forwardRef, useId, Children, isValidElement, cloneElement, useState, useMemo, Fragment as Fragment$1, useRef, useEffect, useContext, useCallback } from 'react';
|
|
3
|
+
import { createContext, forwardRef, useId, Children, isValidElement, cloneElement, useState, useMemo, Fragment as Fragment$1, memo, useRef, useEffect, useContext, createElement, useCallback } from 'react';
|
|
4
4
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
import * as DropdownMenu2 from '@radix-ui/react-dropdown-menu';
|
|
6
|
-
import { X, AlertCircle, ChevronDown, ChevronUp, Check, Minus, Circle, Settings2, Eye, Lock, Plus, Trash2, Users, User, BookOpen, Sparkles, Globe, Pencil, Coins, TrendingUp, TrendingDown, CircleX, CheckCircle2, Loader2, CircleDashed, RotateCcw, Folder, FolderOpen, Brain, Zap, ShieldAlert, Clock, Play, Square, Server, Plug, Wrench, CalendarDays, CornerDownRight, Bot, MessageSquare, ChevronRight, ArrowRight, AlertOctagon, Network, KeyRound, ShieldOff, Database, GitBranch, ChevronsUpDown, FileText, FileCode, FileSpreadsheet, FileImage, File, Hammer, ShieldCheck, Edit3, FilePlus, FileSearch, Terminal, AlertTriangle, CircleDot, FileEdit, Cloud, RefreshCw, Maximize2, ArrowLeft, RotateCw, Search, Paperclip, Mic, Send, GitCommit, Activity, EyeOff, Copy, GitPullRequest, ExternalLink, ShieldX, ArrowDownLeft, TriangleAlert, Info, ShieldQuestion, Rocket, Image, Palette, Moon, Sun, Hash, Slash } from 'lucide-react';
|
|
6
|
+
import { X, AlertCircle, ChevronDown, ChevronUp, Check, Minus, Circle, Settings2, Eye, Lock, Plus, Trash2, Users, User, BookOpen, Sparkles, Globe, Pencil, Coins, TrendingUp, TrendingDown, CircleX, CheckCircle2, Loader2, CircleDashed, RotateCcw, Folder, FolderOpen, Brain, Zap, ShieldAlert, Clock, Play, Square, Server, Plug, Wrench, CalendarDays, CornerDownRight, Bot, MessageSquare, ChevronRight, ArrowRight, AlertOctagon, Network, KeyRound, ShieldOff, Database, GitBranch, ChevronsUpDown, FileText, FileCode, FileSpreadsheet, FileImage, File, Hammer, ShieldCheck, Edit3, FilePlus, FileSearch, Terminal, AlertTriangle, CircleDot, FileEdit, Cloud, RefreshCw, Maximize2, ArrowLeft, RotateCw, Search, Paperclip, Mic, Send, GitCommit, Activity, EyeOff, Copy, GitPullRequest, ExternalLink, ShieldX, ArrowDownLeft, TriangleAlert, Info, ShieldQuestion, BrainCircuitIcon, ImageIcon, FileIcon, ExternalLinkIcon, FileTextIcon, WrenchIcon, CodeIcon, ShieldIcon, AlertCircleIcon, CheckCircleIcon, LoaderIcon, Rocket, Image, Palette, Moon, Sun, ChevronLeftIcon, ChevronRightIcon, Hash, Slash, CheckIcon, CopyIcon } from 'lucide-react';
|
|
7
7
|
import * as ToastPrimitive from '@radix-ui/react-toast';
|
|
8
8
|
import { cva } from 'class-variance-authority';
|
|
9
9
|
import { Slot } from '@radix-ui/react-slot';
|
|
@@ -1411,6 +1411,38 @@ function TheoUIProvider({ children, theme, toaster }) {
|
|
|
1411
1411
|
return /* @__PURE__ */ jsx(ThemeProvider, { themes: themes ?? builtinThemes, ...restTheme, children: /* @__PURE__ */ jsx(Toaster, { ...toaster, children }) });
|
|
1412
1412
|
}
|
|
1413
1413
|
TheoUIProvider.displayName = "TheoUIProvider";
|
|
1414
|
+
|
|
1415
|
+
// src/types/chat.ts
|
|
1416
|
+
function isTextUIPart(part) {
|
|
1417
|
+
return part.type === "text";
|
|
1418
|
+
}
|
|
1419
|
+
function isReasoningUIPart(part) {
|
|
1420
|
+
return part.type === "reasoning";
|
|
1421
|
+
}
|
|
1422
|
+
function isFileUIPart(part) {
|
|
1423
|
+
return part.type === "file";
|
|
1424
|
+
}
|
|
1425
|
+
function isReasoningFileUIPart(part) {
|
|
1426
|
+
return part.type === "reasoning-file";
|
|
1427
|
+
}
|
|
1428
|
+
function isSourceUrlUIPart(part) {
|
|
1429
|
+
return part.type === "source-url";
|
|
1430
|
+
}
|
|
1431
|
+
function isSourceDocumentUIPart(part) {
|
|
1432
|
+
return part.type === "source-document";
|
|
1433
|
+
}
|
|
1434
|
+
function isStepStartUIPart(part) {
|
|
1435
|
+
return part.type === "step-start";
|
|
1436
|
+
}
|
|
1437
|
+
function isCustomContentUIPart(part) {
|
|
1438
|
+
return part.type === "custom";
|
|
1439
|
+
}
|
|
1440
|
+
function isToolUIPart(part) {
|
|
1441
|
+
return part.type === "dynamic-tool" || part.type.startsWith("tool-");
|
|
1442
|
+
}
|
|
1443
|
+
function isDataUIPart(part) {
|
|
1444
|
+
return part.type.startsWith("data-");
|
|
1445
|
+
}
|
|
1414
1446
|
var buttonVariants = cva(
|
|
1415
1447
|
[
|
|
1416
1448
|
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg",
|
|
@@ -5135,83 +5167,986 @@ var SessionListItem = forwardRef(
|
|
|
5135
5167
|
)
|
|
5136
5168
|
);
|
|
5137
5169
|
SessionListItem.displayName = "SessionListItem";
|
|
5138
|
-
|
|
5139
|
-
(
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
}
|
|
5161
|
-
),
|
|
5162
|
-
avatar ? /* @__PURE__ */ jsx("div", { className: "shrink-0", children: avatar }) : null
|
|
5163
|
-
]
|
|
5164
|
-
}
|
|
5165
|
-
);
|
|
5170
|
+
function deriveDataName(part) {
|
|
5171
|
+
return part.type.slice("data-".length);
|
|
5172
|
+
}
|
|
5173
|
+
function DataPart({ part, renderers }) {
|
|
5174
|
+
const name = deriveDataName(part);
|
|
5175
|
+
const renderer = renderers?.[part.type] ?? renderers?.[name];
|
|
5176
|
+
if (renderer) return renderer(part.data, part);
|
|
5177
|
+
return /* @__PURE__ */ jsxs(
|
|
5178
|
+
"details",
|
|
5179
|
+
{
|
|
5180
|
+
className: cn("my-2 rounded-md border border-border bg-muted/20 px-3 py-1.5 text-body-sm"),
|
|
5181
|
+
"data-theo-data": name,
|
|
5182
|
+
children: [
|
|
5183
|
+
/* @__PURE__ */ jsxs("summary", { className: "flex cursor-pointer items-center gap-1.5 font-mono text-label-caps text-muted-foreground uppercase tracking-wider", children: [
|
|
5184
|
+
/* @__PURE__ */ jsx(CodeIcon, { className: "size-3", "aria-hidden": "true" }),
|
|
5185
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
5186
|
+
"data-",
|
|
5187
|
+
name
|
|
5188
|
+
] })
|
|
5189
|
+
] }),
|
|
5190
|
+
/* @__PURE__ */ jsx("pre", { className: "mt-2 overflow-x-auto border-border border-t pt-2 text-code-sm", children: /* @__PURE__ */ jsx("code", { children: safeStringify(part.data) }) })
|
|
5191
|
+
]
|
|
5166
5192
|
}
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
5193
|
+
);
|
|
5194
|
+
}
|
|
5195
|
+
function safeStringify(value) {
|
|
5196
|
+
try {
|
|
5197
|
+
return JSON.stringify(value, null, 2);
|
|
5198
|
+
} catch {
|
|
5199
|
+
return String(value);
|
|
5200
|
+
}
|
|
5201
|
+
}
|
|
5202
|
+
function isImage(mediaType) {
|
|
5203
|
+
return mediaType.startsWith("image/") || mediaType === "image";
|
|
5204
|
+
}
|
|
5205
|
+
function FilePart({ part }) {
|
|
5206
|
+
const safeUrl = safeHref(part.url);
|
|
5207
|
+
const label = part.filename ?? part.url.split("/").pop() ?? "file";
|
|
5208
|
+
if (isImage(part.mediaType)) {
|
|
5209
|
+
if (!safeUrl) {
|
|
5210
|
+
return /* @__PURE__ */ jsxs(
|
|
5211
|
+
"div",
|
|
5170
5212
|
{
|
|
5171
|
-
ref,
|
|
5172
5213
|
className: cn(
|
|
5173
|
-
"rounded-
|
|
5174
|
-
"text-body-sm text-foreground"
|
|
5175
|
-
className
|
|
5214
|
+
"my-2 inline-flex items-center gap-2 rounded-md border border-border bg-muted/30 px-3 py-2",
|
|
5215
|
+
"text-body-sm text-muted-foreground"
|
|
5176
5216
|
),
|
|
5177
|
-
|
|
5178
|
-
|
|
5179
|
-
|
|
5217
|
+
children: [
|
|
5218
|
+
/* @__PURE__ */ jsx(ImageIcon, { className: "size-4", "aria-hidden": "true" }),
|
|
5219
|
+
/* @__PURE__ */ jsx("span", { children: label }),
|
|
5220
|
+
/* @__PURE__ */ jsx("span", { className: "text-destructive", children: "(blocked)" })
|
|
5221
|
+
]
|
|
5180
5222
|
}
|
|
5181
5223
|
);
|
|
5182
5224
|
}
|
|
5183
5225
|
return /* @__PURE__ */ jsxs(
|
|
5184
|
-
"
|
|
5226
|
+
"figure",
|
|
5185
5227
|
{
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
"aria-label": "assistant message",
|
|
5189
|
-
...props,
|
|
5228
|
+
className: "my-3 overflow-hidden rounded-lg border border-border",
|
|
5229
|
+
"data-theo-file": "image",
|
|
5190
5230
|
children: [
|
|
5191
|
-
|
|
5231
|
+
/* @__PURE__ */ jsx("img", { src: safeUrl, alt: label, className: "block max-w-full", loading: "lazy" }),
|
|
5232
|
+
part.filename ? /* @__PURE__ */ jsx("figcaption", { className: "border-border border-t bg-muted/30 px-3 py-1.5 font-mono text-label-caps text-muted-foreground uppercase tracking-wider", children: part.filename }) : null
|
|
5233
|
+
]
|
|
5234
|
+
}
|
|
5235
|
+
);
|
|
5236
|
+
}
|
|
5237
|
+
return /* @__PURE__ */ jsxs(
|
|
5238
|
+
"div",
|
|
5239
|
+
{
|
|
5240
|
+
className: cn(
|
|
5241
|
+
"my-2 inline-flex items-center gap-2 rounded-md border border-border bg-card px-3 py-2",
|
|
5242
|
+
"text-body-sm"
|
|
5243
|
+
),
|
|
5244
|
+
"data-theo-file": "generic",
|
|
5245
|
+
children: [
|
|
5246
|
+
/* @__PURE__ */ jsx(FileIcon, { className: "size-4 text-muted-foreground", "aria-hidden": "true" }),
|
|
5247
|
+
safeUrl ? /* @__PURE__ */ jsx("a", { href: safeUrl, className: "text-primary hover:text-primary-deep hover:underline", children: label }) : /* @__PURE__ */ jsx("span", { children: label }),
|
|
5248
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono text-label-caps text-muted-foreground uppercase tracking-wider", children: part.mediaType })
|
|
5249
|
+
]
|
|
5250
|
+
}
|
|
5251
|
+
);
|
|
5252
|
+
}
|
|
5253
|
+
var DEFAULT_THEMES = { light: "github-light", dark: "github-dark" };
|
|
5254
|
+
var cachedHighlighter = null;
|
|
5255
|
+
var highlighterFailed = false;
|
|
5256
|
+
async function getHighlighter(themes) {
|
|
5257
|
+
if (cachedHighlighter) return cachedHighlighter;
|
|
5258
|
+
if (highlighterFailed) return null;
|
|
5259
|
+
try {
|
|
5260
|
+
const shiki = await import('shiki');
|
|
5261
|
+
cachedHighlighter = await shiki.createHighlighter({
|
|
5262
|
+
themes: [themes.light, themes.dark],
|
|
5263
|
+
langs: [
|
|
5264
|
+
"ts",
|
|
5265
|
+
"tsx",
|
|
5266
|
+
"js",
|
|
5267
|
+
"jsx",
|
|
5268
|
+
"python",
|
|
5269
|
+
"go",
|
|
5270
|
+
"rust",
|
|
5271
|
+
"java",
|
|
5272
|
+
"json",
|
|
5273
|
+
"yaml",
|
|
5274
|
+
"bash",
|
|
5275
|
+
"shell",
|
|
5276
|
+
"html",
|
|
5277
|
+
"css",
|
|
5278
|
+
"sql",
|
|
5279
|
+
"markdown"
|
|
5280
|
+
]
|
|
5281
|
+
});
|
|
5282
|
+
return cachedHighlighter;
|
|
5283
|
+
} catch {
|
|
5284
|
+
highlighterFailed = true;
|
|
5285
|
+
return null;
|
|
5286
|
+
}
|
|
5287
|
+
}
|
|
5288
|
+
function CodeBlock({ code, language, themes, className }) {
|
|
5289
|
+
const [html, setHtml] = useState(null);
|
|
5290
|
+
const [copied, setCopied] = useState(false);
|
|
5291
|
+
const effectiveThemes = themes ?? DEFAULT_THEMES;
|
|
5292
|
+
useEffect(() => {
|
|
5293
|
+
let cancelled = false;
|
|
5294
|
+
if (!language) return;
|
|
5295
|
+
getHighlighter(effectiveThemes).then((hl) => {
|
|
5296
|
+
if (cancelled || !hl) return;
|
|
5297
|
+
try {
|
|
5298
|
+
const out = hl.codeToHtml(code, {
|
|
5299
|
+
lang: language,
|
|
5300
|
+
themes: { light: effectiveThemes.light, dark: effectiveThemes.dark },
|
|
5301
|
+
defaultColor: "light"
|
|
5302
|
+
});
|
|
5303
|
+
setHtml(out);
|
|
5304
|
+
} catch {
|
|
5305
|
+
}
|
|
5306
|
+
}).catch(() => {
|
|
5307
|
+
});
|
|
5308
|
+
return () => {
|
|
5309
|
+
cancelled = true;
|
|
5310
|
+
};
|
|
5311
|
+
}, [code, language, effectiveThemes.light, effectiveThemes.dark, effectiveThemes]);
|
|
5312
|
+
const handleCopy = async () => {
|
|
5313
|
+
try {
|
|
5314
|
+
await navigator.clipboard.writeText(code);
|
|
5315
|
+
setCopied(true);
|
|
5316
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
5317
|
+
} catch {
|
|
5318
|
+
}
|
|
5319
|
+
};
|
|
5320
|
+
return /* @__PURE__ */ jsxs(
|
|
5321
|
+
"div",
|
|
5322
|
+
{
|
|
5323
|
+
className: cn(
|
|
5324
|
+
"group relative my-4 overflow-hidden rounded-lg border border-border bg-muted/30",
|
|
5325
|
+
className
|
|
5326
|
+
),
|
|
5327
|
+
"data-theo-code-block": "",
|
|
5328
|
+
children: [
|
|
5329
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-border border-b bg-muted/50 px-3 py-1.5", children: [
|
|
5330
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono text-label-caps text-muted-foreground uppercase tracking-wider", children: language || "text" }),
|
|
5331
|
+
/* @__PURE__ */ jsx(
|
|
5332
|
+
"button",
|
|
5333
|
+
{
|
|
5334
|
+
type: "button",
|
|
5335
|
+
onClick: handleCopy,
|
|
5336
|
+
className: cn(
|
|
5337
|
+
"inline-flex h-7 items-center gap-1.5 rounded-md px-2 text-label",
|
|
5338
|
+
"text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground",
|
|
5339
|
+
"focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring"
|
|
5340
|
+
),
|
|
5341
|
+
"aria-label": copied ? "Copied" : "Copy code",
|
|
5342
|
+
children: copied ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5343
|
+
/* @__PURE__ */ jsx(CheckIcon, { className: "size-3.5", "aria-hidden": "true" }),
|
|
5344
|
+
/* @__PURE__ */ jsx("span", { children: "Copied" })
|
|
5345
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5346
|
+
/* @__PURE__ */ jsx(CopyIcon, { className: "size-3.5", "aria-hidden": "true" }),
|
|
5347
|
+
/* @__PURE__ */ jsx("span", { children: "Copy" })
|
|
5348
|
+
] })
|
|
5349
|
+
}
|
|
5350
|
+
)
|
|
5351
|
+
] }),
|
|
5352
|
+
html ? /* @__PURE__ */ jsx(
|
|
5353
|
+
"div",
|
|
5354
|
+
{
|
|
5355
|
+
className: "[&_pre]:!bg-transparent [&_pre]:!m-0 [&_pre]:!p-0 overflow-x-auto p-3 text-code-sm",
|
|
5356
|
+
dangerouslySetInnerHTML: { __html: html }
|
|
5357
|
+
}
|
|
5358
|
+
) : /* @__PURE__ */ jsx("pre", { className: "overflow-x-auto p-3 text-code-sm", children: /* @__PURE__ */ jsx("code", { className: language ? `language-${language}` : void 0, children: code }) })
|
|
5359
|
+
]
|
|
5360
|
+
}
|
|
5361
|
+
);
|
|
5362
|
+
}
|
|
5363
|
+
function InlineCode({ className, children, ...props }) {
|
|
5364
|
+
return /* @__PURE__ */ jsx(
|
|
5365
|
+
"code",
|
|
5366
|
+
{
|
|
5367
|
+
className: cn(
|
|
5368
|
+
"rounded bg-muted px-1.5 py-0.5 font-mono text-code-sm text-foreground",
|
|
5369
|
+
className
|
|
5370
|
+
),
|
|
5371
|
+
...props,
|
|
5372
|
+
children
|
|
5373
|
+
}
|
|
5374
|
+
);
|
|
5375
|
+
}
|
|
5376
|
+
|
|
5377
|
+
// src/lib/markdown/streaming-preprocess.ts
|
|
5378
|
+
function preprocessStreaming(markdown, isStreaming = true) {
|
|
5379
|
+
if (!isStreaming) return markdown;
|
|
5380
|
+
let buf = markdown;
|
|
5381
|
+
const fenceCount = countTripleBackticks(buf);
|
|
5382
|
+
if (fenceCount % 2 === 1) {
|
|
5383
|
+
buf = `${buf.endsWith("\n") ? buf : `${buf}
|
|
5384
|
+
`}\`\`\``;
|
|
5385
|
+
return buf;
|
|
5386
|
+
}
|
|
5387
|
+
const blockMathCount = countOccurrences(buf, "$$");
|
|
5388
|
+
if (blockMathCount % 2 === 1) {
|
|
5389
|
+
buf = `${buf}$$`;
|
|
5390
|
+
return buf;
|
|
5391
|
+
}
|
|
5392
|
+
const inlineBackticks = countSingleBackticks(buf);
|
|
5393
|
+
if (inlineBackticks % 2 === 1) {
|
|
5394
|
+
buf = `${buf}\``;
|
|
5395
|
+
}
|
|
5396
|
+
const inlineDollars = countSingleDollars(buf);
|
|
5397
|
+
if (inlineDollars % 2 === 1) {
|
|
5398
|
+
buf = `${buf}$`;
|
|
5399
|
+
}
|
|
5400
|
+
for (const marker of ["**", "__", "*", "_"]) {
|
|
5401
|
+
if (countMarker(buf, marker) % 2 === 1) {
|
|
5402
|
+
buf = `${buf}${marker}`;
|
|
5403
|
+
}
|
|
5404
|
+
}
|
|
5405
|
+
buf = closeUnclosedLink(buf);
|
|
5406
|
+
return buf;
|
|
5407
|
+
}
|
|
5408
|
+
function countTripleBackticks(s) {
|
|
5409
|
+
let count = 0;
|
|
5410
|
+
let i = 0;
|
|
5411
|
+
while (i < s.length) {
|
|
5412
|
+
if (s[i] === "`" && s[i + 1] === "`" && s[i + 2] === "`") {
|
|
5413
|
+
count++;
|
|
5414
|
+
i += 3;
|
|
5415
|
+
} else {
|
|
5416
|
+
i++;
|
|
5417
|
+
}
|
|
5418
|
+
}
|
|
5419
|
+
return count;
|
|
5420
|
+
}
|
|
5421
|
+
function countSingleBackticks(s) {
|
|
5422
|
+
let count = 0;
|
|
5423
|
+
let i = 0;
|
|
5424
|
+
while (i < s.length) {
|
|
5425
|
+
if (s[i] === "`") {
|
|
5426
|
+
if (s[i + 1] === "`" && s[i + 2] === "`") {
|
|
5427
|
+
i += 3;
|
|
5428
|
+
continue;
|
|
5429
|
+
}
|
|
5430
|
+
count++;
|
|
5431
|
+
}
|
|
5432
|
+
i++;
|
|
5433
|
+
}
|
|
5434
|
+
return count;
|
|
5435
|
+
}
|
|
5436
|
+
function countOccurrences(s, needle) {
|
|
5437
|
+
if (needle.length === 0) return 0;
|
|
5438
|
+
let count = 0;
|
|
5439
|
+
let i = s.indexOf(needle);
|
|
5440
|
+
while (i !== -1) {
|
|
5441
|
+
count++;
|
|
5442
|
+
i = s.indexOf(needle, i + needle.length);
|
|
5443
|
+
}
|
|
5444
|
+
return count;
|
|
5445
|
+
}
|
|
5446
|
+
function countSingleDollars(s) {
|
|
5447
|
+
let count = 0;
|
|
5448
|
+
let i = 0;
|
|
5449
|
+
while (i < s.length) {
|
|
5450
|
+
if (s[i] === "$") {
|
|
5451
|
+
if (s[i + 1] === "$") {
|
|
5452
|
+
i += 2;
|
|
5453
|
+
continue;
|
|
5454
|
+
}
|
|
5455
|
+
if (i > 0 && s[i - 1] === "\\") {
|
|
5456
|
+
i++;
|
|
5457
|
+
continue;
|
|
5458
|
+
}
|
|
5459
|
+
count++;
|
|
5460
|
+
}
|
|
5461
|
+
i++;
|
|
5462
|
+
}
|
|
5463
|
+
return count;
|
|
5464
|
+
}
|
|
5465
|
+
function countMarker(s, marker) {
|
|
5466
|
+
if (marker.length === 0) return 0;
|
|
5467
|
+
if (marker.length === 1) {
|
|
5468
|
+
let count2 = 0;
|
|
5469
|
+
let i2 = 0;
|
|
5470
|
+
while (i2 < s.length) {
|
|
5471
|
+
if (s[i2] === marker) {
|
|
5472
|
+
if (s[i2 + 1] === marker) {
|
|
5473
|
+
i2 += 2;
|
|
5474
|
+
continue;
|
|
5475
|
+
}
|
|
5476
|
+
if (i2 > 0 && s[i2 - 1] === "\\") {
|
|
5477
|
+
i2++;
|
|
5478
|
+
continue;
|
|
5479
|
+
}
|
|
5480
|
+
count2++;
|
|
5481
|
+
}
|
|
5482
|
+
i2++;
|
|
5483
|
+
}
|
|
5484
|
+
return count2;
|
|
5485
|
+
}
|
|
5486
|
+
let count = 0;
|
|
5487
|
+
let i = 0;
|
|
5488
|
+
while (i <= s.length - marker.length) {
|
|
5489
|
+
if (s.substring(i, i + marker.length) === marker) {
|
|
5490
|
+
count++;
|
|
5491
|
+
i += marker.length;
|
|
5492
|
+
} else {
|
|
5493
|
+
i++;
|
|
5494
|
+
}
|
|
5495
|
+
}
|
|
5496
|
+
return count;
|
|
5497
|
+
}
|
|
5498
|
+
function closeUnclosedLink(s) {
|
|
5499
|
+
const lastOpenParen = s.lastIndexOf("(");
|
|
5500
|
+
const lastCloseParen = s.lastIndexOf(")");
|
|
5501
|
+
if (lastOpenParen === -1 || lastOpenParen <= lastCloseParen) return s;
|
|
5502
|
+
if (s[lastOpenParen - 1] !== "]") return s;
|
|
5503
|
+
const closingBracket = lastOpenParen - 1;
|
|
5504
|
+
const openingBracket = s.lastIndexOf("[", closingBracket - 1);
|
|
5505
|
+
if (openingBracket === -1) return s;
|
|
5506
|
+
return `${s})`;
|
|
5507
|
+
}
|
|
5508
|
+
|
|
5509
|
+
// src/lib/markdown/parser.ts
|
|
5510
|
+
async function parseBody(body) {
|
|
5511
|
+
const [{ fromMarkdown }, { gfmFromMarkdown }, { gfm }] = await Promise.all([
|
|
5512
|
+
import('mdast-util-from-markdown'),
|
|
5513
|
+
import('mdast-util-gfm'),
|
|
5514
|
+
import('micromark-extension-gfm')
|
|
5515
|
+
]);
|
|
5516
|
+
return fromMarkdown(body, {
|
|
5517
|
+
extensions: [gfm()],
|
|
5518
|
+
mdastExtensions: [gfmFromMarkdown()]
|
|
5519
|
+
});
|
|
5520
|
+
}
|
|
5521
|
+
async function mdastToHast(tree) {
|
|
5522
|
+
const { toHast } = await import('mdast-util-to-hast');
|
|
5523
|
+
const hast = toHast(tree, { allowDangerousHtml: false });
|
|
5524
|
+
if (!hast || hast.type !== "root") {
|
|
5525
|
+
return { type: "root", children: hast ? [hast] : [] };
|
|
5526
|
+
}
|
|
5527
|
+
return hast;
|
|
5528
|
+
}
|
|
5529
|
+
async function sanitizeHast(tree) {
|
|
5530
|
+
const { sanitize, defaultSchema } = await import('hast-util-sanitize');
|
|
5531
|
+
const schema = {
|
|
5532
|
+
...defaultSchema,
|
|
5533
|
+
attributes: {
|
|
5534
|
+
...defaultSchema.attributes ?? {},
|
|
5535
|
+
code: [...defaultSchema.attributes?.code ?? [], ["className", /^language-./]],
|
|
5536
|
+
pre: [...defaultSchema.attributes?.pre ?? [], ["className", /./]],
|
|
5537
|
+
span: [...defaultSchema.attributes?.span ?? [], ["className", /./], ["style"]]
|
|
5538
|
+
}
|
|
5539
|
+
};
|
|
5540
|
+
const safe2 = sanitize(tree, schema);
|
|
5541
|
+
return safe2.type === "root" ? safe2 : { type: "root", children: [safe2] };
|
|
5542
|
+
}
|
|
5543
|
+
async function hastToReact(tree, components) {
|
|
5544
|
+
const { Fragment: Fragment17, jsx: jsx117, jsxs: jsxs95 } = await import('react/jsx-runtime');
|
|
5545
|
+
const { toJsxRuntime } = await import('hast-util-to-jsx-runtime');
|
|
5546
|
+
return toJsxRuntime(tree, {
|
|
5547
|
+
Fragment: Fragment17,
|
|
5548
|
+
jsx: jsx117,
|
|
5549
|
+
jsxs: jsxs95,
|
|
5550
|
+
components
|
|
5551
|
+
});
|
|
5552
|
+
}
|
|
5553
|
+
async function parseMarkdownToReact(markdown, opts = {}) {
|
|
5554
|
+
const preprocessed = preprocessStreaming(markdown, opts.isStreaming ?? false);
|
|
5555
|
+
const mdast = await parseBody(preprocessed);
|
|
5556
|
+
const hast = await mdastToHast(mdast);
|
|
5557
|
+
const safe2 = await sanitizeHast(hast);
|
|
5558
|
+
return hastToReact(safe2, opts.components);
|
|
5559
|
+
}
|
|
5560
|
+
async function parseMarkdownToReactSafe(markdown, opts = {}) {
|
|
5561
|
+
try {
|
|
5562
|
+
return await parseMarkdownToReact(markdown, opts);
|
|
5563
|
+
} catch {
|
|
5564
|
+
return createElement("span", { className: "whitespace-pre-wrap" }, markdown);
|
|
5565
|
+
}
|
|
5566
|
+
}
|
|
5567
|
+
function isFenced(props) {
|
|
5568
|
+
const cls = props.className;
|
|
5569
|
+
if (typeof cls === "string") return cls.startsWith("language-");
|
|
5570
|
+
if (Array.isArray(cls))
|
|
5571
|
+
return cls.some((c) => typeof c === "string" && c.startsWith("language-"));
|
|
5572
|
+
return false;
|
|
5573
|
+
}
|
|
5574
|
+
function extractLanguage(props) {
|
|
5575
|
+
const cls = props.className;
|
|
5576
|
+
const list = typeof cls === "string" ? [cls] : Array.isArray(cls) ? cls : [];
|
|
5577
|
+
for (const c of list) {
|
|
5578
|
+
if (typeof c === "string" && c.startsWith("language-")) {
|
|
5579
|
+
return c.slice("language-".length);
|
|
5580
|
+
}
|
|
5581
|
+
}
|
|
5582
|
+
return void 0;
|
|
5583
|
+
}
|
|
5584
|
+
function extractText(children) {
|
|
5585
|
+
if (typeof children === "string") return children;
|
|
5586
|
+
if (Array.isArray(children)) return children.map(extractText).join("");
|
|
5587
|
+
if (children && typeof children === "object" && "props" in children && children.props) {
|
|
5588
|
+
return extractText(children.props.children);
|
|
5589
|
+
}
|
|
5590
|
+
return "";
|
|
5591
|
+
}
|
|
5592
|
+
var MARKDOWN_COMPONENTS = {
|
|
5593
|
+
code: (props) => {
|
|
5594
|
+
if (isFenced(props)) {
|
|
5595
|
+
const language = extractLanguage(props);
|
|
5596
|
+
const code = extractText(props.children);
|
|
5597
|
+
return /* @__PURE__ */ jsx(CodeBlock, { code, language });
|
|
5598
|
+
}
|
|
5599
|
+
return /* @__PURE__ */ jsx(InlineCode, { ...props, children: props.children });
|
|
5600
|
+
},
|
|
5601
|
+
// Strip the default `<pre>` since `<CodeBlock>` ships its own wrapper.
|
|
5602
|
+
// Inline `<pre>` still works for raw whitespace-preserving text.
|
|
5603
|
+
pre: ({ children }) => {
|
|
5604
|
+
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
5605
|
+
}
|
|
5606
|
+
};
|
|
5607
|
+
function ChatMessageResponseImpl({
|
|
5608
|
+
text,
|
|
5609
|
+
isStreaming = false,
|
|
5610
|
+
className
|
|
5611
|
+
}) {
|
|
5612
|
+
const [tree, setTree] = useState(null);
|
|
5613
|
+
useEffect(() => {
|
|
5614
|
+
let cancelled = false;
|
|
5615
|
+
parseMarkdownToReactSafe(text, {
|
|
5616
|
+
isStreaming,
|
|
5617
|
+
components: MARKDOWN_COMPONENTS
|
|
5618
|
+
}).then((next) => {
|
|
5619
|
+
if (!cancelled) setTree(next);
|
|
5620
|
+
});
|
|
5621
|
+
return () => {
|
|
5622
|
+
cancelled = true;
|
|
5623
|
+
};
|
|
5624
|
+
}, [text, isStreaming]);
|
|
5625
|
+
return /* @__PURE__ */ jsx(
|
|
5626
|
+
"div",
|
|
5627
|
+
{
|
|
5628
|
+
className: cn(
|
|
5629
|
+
"prose-theo max-w-none text-body-md text-foreground leading-relaxed",
|
|
5630
|
+
// First/last child margin reset — fork from vercel/ai-elements
|
|
5631
|
+
"[&>*:first-child]:mt-0 [&>*:last-child]:mb-0",
|
|
5632
|
+
// Heading sizes inside chat use our typescale, not browser defaults
|
|
5633
|
+
"[&_h1]:mt-4 [&_h1]:mb-2 [&_h1]:font-semibold [&_h1]:text-title-lg",
|
|
5634
|
+
"[&_h2]:mt-3 [&_h2]:mb-2 [&_h2]:font-semibold [&_h2]:text-title-md",
|
|
5635
|
+
"[&_h3]:mt-3 [&_h3]:mb-1.5 [&_h3]:font-semibold [&_h3]:text-body-lg",
|
|
5636
|
+
"[&_p]:my-2",
|
|
5637
|
+
"[&_ul]:my-2 [&_ul]:list-disc [&_ul]:pl-5",
|
|
5638
|
+
"[&_ol]:my-2 [&_ol]:list-decimal [&_ol]:pl-5",
|
|
5639
|
+
"[&_li]:my-0.5",
|
|
5640
|
+
"[&_blockquote]:my-2 [&_blockquote]:border-primary/40 [&_blockquote]:border-l-2 [&_blockquote]:pl-3 [&_blockquote]:text-muted-foreground",
|
|
5641
|
+
"[&_a:hover]:text-primary-deep [&_a]:text-primary [&_a]:underline",
|
|
5642
|
+
"[&_table]:my-3 [&_table]:w-full [&_table]:border-collapse",
|
|
5643
|
+
"[&_th]:border [&_th]:border-border [&_th]:bg-muted/40 [&_th]:px-3 [&_th]:py-1.5 [&_th]:text-left",
|
|
5644
|
+
"[&_td]:border [&_td]:border-border [&_td]:px-3 [&_td]:py-1.5",
|
|
5645
|
+
"[&_hr]:my-4 [&_hr]:border-border",
|
|
5646
|
+
className
|
|
5647
|
+
),
|
|
5648
|
+
"data-theo-chat-response": "",
|
|
5649
|
+
children: tree
|
|
5650
|
+
}
|
|
5651
|
+
);
|
|
5652
|
+
}
|
|
5653
|
+
var ChatMessageResponse = memo(ChatMessageResponseImpl, (prev, next) => {
|
|
5654
|
+
return prev.text === next.text && prev.isStreaming === next.isStreaming;
|
|
5655
|
+
});
|
|
5656
|
+
ChatMessageResponse.displayName = "ChatMessageResponse";
|
|
5657
|
+
function ReasoningPart({ part, defaultOpen }) {
|
|
5658
|
+
const isStreaming = part.state === "streaming";
|
|
5659
|
+
const open = defaultOpen ?? isStreaming;
|
|
5660
|
+
return /* @__PURE__ */ jsxs(
|
|
5661
|
+
"details",
|
|
5662
|
+
{
|
|
5663
|
+
className: cn(
|
|
5664
|
+
"my-2 rounded-md border border-border bg-muted/20 px-3 py-2",
|
|
5665
|
+
"[&[open]]:bg-muted/40"
|
|
5666
|
+
),
|
|
5667
|
+
open,
|
|
5668
|
+
"data-theo-reasoning": "",
|
|
5669
|
+
children: [
|
|
5670
|
+
/* @__PURE__ */ jsxs(
|
|
5671
|
+
"summary",
|
|
5672
|
+
{
|
|
5673
|
+
className: cn(
|
|
5674
|
+
"cursor-pointer list-none font-mono text-label-caps text-muted-foreground uppercase tracking-wider",
|
|
5675
|
+
"flex items-center gap-1.5 marker:hidden",
|
|
5676
|
+
"transition-colors hover:text-foreground"
|
|
5677
|
+
),
|
|
5678
|
+
children: [
|
|
5679
|
+
/* @__PURE__ */ jsx(BrainCircuitIcon, { className: "size-3.5", "aria-hidden": "true" }),
|
|
5680
|
+
/* @__PURE__ */ jsx("span", { children: "Reasoning" }),
|
|
5681
|
+
isStreaming ? /* @__PURE__ */ jsx("span", { className: "text-primary/80", children: "\u2026" }) : null
|
|
5682
|
+
]
|
|
5683
|
+
}
|
|
5684
|
+
),
|
|
5685
|
+
/* @__PURE__ */ jsx("div", { className: "mt-2 border-border border-t pt-2", children: /* @__PURE__ */ jsx(ChatMessageResponse, { text: part.text, isStreaming }) })
|
|
5686
|
+
]
|
|
5687
|
+
}
|
|
5688
|
+
);
|
|
5689
|
+
}
|
|
5690
|
+
function SourceUrlPart({ part }) {
|
|
5691
|
+
const safe2 = safeHref(part.url);
|
|
5692
|
+
const label = part.title || part.url;
|
|
5693
|
+
return /* @__PURE__ */ jsxs(
|
|
5694
|
+
"span",
|
|
5695
|
+
{
|
|
5696
|
+
className: cn(
|
|
5697
|
+
"my-1 inline-flex max-w-full items-center gap-1.5 rounded-md border border-border bg-card px-2 py-1",
|
|
5698
|
+
"align-middle font-mono text-label"
|
|
5699
|
+
),
|
|
5700
|
+
"data-theo-source": "url",
|
|
5701
|
+
children: [
|
|
5702
|
+
/* @__PURE__ */ jsx(ExternalLinkIcon, { className: "size-3 text-muted-foreground", "aria-hidden": "true" }),
|
|
5703
|
+
safe2 ? /* @__PURE__ */ jsx(
|
|
5704
|
+
"a",
|
|
5705
|
+
{
|
|
5706
|
+
href: safe2,
|
|
5707
|
+
className: "truncate text-primary hover:text-primary-deep hover:underline",
|
|
5708
|
+
rel: "noopener noreferrer",
|
|
5709
|
+
target: "_blank",
|
|
5710
|
+
children: label
|
|
5711
|
+
}
|
|
5712
|
+
) : /* @__PURE__ */ jsx("span", { className: "truncate text-muted-foreground", children: label })
|
|
5713
|
+
]
|
|
5714
|
+
}
|
|
5715
|
+
);
|
|
5716
|
+
}
|
|
5717
|
+
function SourceDocumentPart({ part }) {
|
|
5718
|
+
return /* @__PURE__ */ jsxs(
|
|
5719
|
+
"span",
|
|
5720
|
+
{
|
|
5721
|
+
className: cn(
|
|
5722
|
+
"my-1 inline-flex max-w-full items-center gap-1.5 rounded-md border border-border bg-card px-2 py-1",
|
|
5723
|
+
"align-middle font-mono text-label"
|
|
5724
|
+
),
|
|
5725
|
+
"data-theo-source": "document",
|
|
5726
|
+
children: [
|
|
5727
|
+
/* @__PURE__ */ jsx(FileTextIcon, { className: "size-3 text-muted-foreground", "aria-hidden": "true" }),
|
|
5728
|
+
/* @__PURE__ */ jsx("span", { className: "truncate text-foreground", children: part.title }),
|
|
5729
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\xB7" }),
|
|
5730
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: part.mediaType })
|
|
5731
|
+
]
|
|
5732
|
+
}
|
|
5733
|
+
);
|
|
5734
|
+
}
|
|
5735
|
+
function TextPart({ part }) {
|
|
5736
|
+
return /* @__PURE__ */ jsx(ChatMessageResponse, { text: part.text, isStreaming: part.state === "streaming" });
|
|
5737
|
+
}
|
|
5738
|
+
function deriveToolName(part) {
|
|
5739
|
+
if (part.toolName) return part.toolName;
|
|
5740
|
+
if (part.type === "dynamic-tool") return "dynamic-tool";
|
|
5741
|
+
return part.type.slice("tool-".length);
|
|
5742
|
+
}
|
|
5743
|
+
function stateBadge(state) {
|
|
5744
|
+
switch (state) {
|
|
5745
|
+
case "input-streaming":
|
|
5746
|
+
return {
|
|
5747
|
+
icon: /* @__PURE__ */ jsx(LoaderIcon, { className: "size-3.5 animate-spin", "aria-hidden": "true" }),
|
|
5748
|
+
label: "Streaming input",
|
|
5749
|
+
tone: "text-muted-foreground"
|
|
5750
|
+
};
|
|
5751
|
+
case "input-available":
|
|
5752
|
+
return {
|
|
5753
|
+
icon: /* @__PURE__ */ jsx(WrenchIcon, { className: "size-3.5", "aria-hidden": "true" }),
|
|
5754
|
+
label: "Ready to call",
|
|
5755
|
+
tone: "text-primary"
|
|
5756
|
+
};
|
|
5757
|
+
case "approval-requested":
|
|
5758
|
+
return {
|
|
5759
|
+
icon: /* @__PURE__ */ jsx(ShieldIcon, { className: "size-3.5", "aria-hidden": "true" }),
|
|
5760
|
+
label: "Awaiting approval",
|
|
5761
|
+
tone: "text-warning"
|
|
5762
|
+
};
|
|
5763
|
+
case "approval-responded":
|
|
5764
|
+
return {
|
|
5765
|
+
icon: /* @__PURE__ */ jsx(ShieldIcon, { className: "size-3.5", "aria-hidden": "true" }),
|
|
5766
|
+
label: "Approval responded",
|
|
5767
|
+
tone: "text-primary"
|
|
5768
|
+
};
|
|
5769
|
+
case "output-available":
|
|
5770
|
+
return {
|
|
5771
|
+
icon: /* @__PURE__ */ jsx(CheckCircleIcon, { className: "size-3.5", "aria-hidden": "true" }),
|
|
5772
|
+
label: "Completed",
|
|
5773
|
+
tone: "text-success"
|
|
5774
|
+
};
|
|
5775
|
+
case "output-error":
|
|
5776
|
+
return {
|
|
5777
|
+
icon: /* @__PURE__ */ jsx(AlertCircleIcon, { className: "size-3.5", "aria-hidden": "true" }),
|
|
5778
|
+
label: "Error",
|
|
5779
|
+
tone: "text-destructive"
|
|
5780
|
+
};
|
|
5781
|
+
case "output-denied":
|
|
5782
|
+
return {
|
|
5783
|
+
icon: /* @__PURE__ */ jsx(ShieldIcon, { className: "size-3.5", "aria-hidden": "true" }),
|
|
5784
|
+
label: "Denied",
|
|
5785
|
+
tone: "text-destructive"
|
|
5786
|
+
};
|
|
5787
|
+
default:
|
|
5788
|
+
return {
|
|
5789
|
+
icon: /* @__PURE__ */ jsx(WrenchIcon, { className: "size-3.5", "aria-hidden": "true" }),
|
|
5790
|
+
label: "Unknown",
|
|
5791
|
+
tone: "text-muted-foreground"
|
|
5792
|
+
};
|
|
5793
|
+
}
|
|
5794
|
+
}
|
|
5795
|
+
function safeStringify2(value) {
|
|
5796
|
+
if (value === void 0) return "";
|
|
5797
|
+
if (typeof value === "string") return value;
|
|
5798
|
+
try {
|
|
5799
|
+
return JSON.stringify(value, null, 2);
|
|
5800
|
+
} catch {
|
|
5801
|
+
return String(value);
|
|
5802
|
+
}
|
|
5803
|
+
}
|
|
5804
|
+
function ToolCallPart({ part }) {
|
|
5805
|
+
const toolName = deriveToolName(part);
|
|
5806
|
+
const badge = stateBadge(part.state);
|
|
5807
|
+
const inputStr = safeStringify2(part.input);
|
|
5808
|
+
const outputStr = part.state === "output-available" ? safeStringify2(part.output) : part.errorText ?? "";
|
|
5809
|
+
return /* @__PURE__ */ jsxs(
|
|
5810
|
+
"div",
|
|
5811
|
+
{
|
|
5812
|
+
className: cn("my-3 overflow-hidden rounded-lg border border-border bg-card", "shadow-sm"),
|
|
5813
|
+
"data-theo-tool-call": part.state,
|
|
5814
|
+
children: [
|
|
5815
|
+
/* @__PURE__ */ jsxs("header", { className: "flex items-center justify-between gap-3 border-border border-b bg-muted/30 px-3 py-1.5", children: [
|
|
5816
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
5817
|
+
/* @__PURE__ */ jsx(WrenchIcon, { className: "size-3.5 shrink-0 text-muted-foreground", "aria-hidden": "true" }),
|
|
5818
|
+
/* @__PURE__ */ jsx("span", { className: "truncate font-mono text-foreground text-label", children: toolName })
|
|
5819
|
+
] }),
|
|
5192
5820
|
/* @__PURE__ */ jsxs(
|
|
5193
|
-
"
|
|
5821
|
+
"span",
|
|
5194
5822
|
{
|
|
5195
5823
|
className: cn(
|
|
5196
|
-
"
|
|
5197
|
-
|
|
5824
|
+
"inline-flex items-center gap-1 text-label-caps uppercase tracking-wider",
|
|
5825
|
+
badge.tone
|
|
5198
5826
|
),
|
|
5199
5827
|
children: [
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
message.timestamp ? /* @__PURE__ */ jsx("span", { className: "font-mono text-label text-muted-foreground", children: message.timestamp }) : null
|
|
5203
|
-
] }),
|
|
5204
|
-
/* @__PURE__ */ jsx("div", { className: "text-body-md text-foreground leading-relaxed", children: message.content }),
|
|
5205
|
-
actions ? /* @__PURE__ */ jsx("div", { className: "mt-3 flex items-center gap-1", children: actions }) : null
|
|
5828
|
+
badge.icon,
|
|
5829
|
+
/* @__PURE__ */ jsx("span", { children: badge.label })
|
|
5206
5830
|
]
|
|
5207
5831
|
}
|
|
5208
5832
|
)
|
|
5833
|
+
] }),
|
|
5834
|
+
inputStr ? /* @__PURE__ */ jsxs("details", { className: "border-border border-b", open: part.state === "input-streaming", children: [
|
|
5835
|
+
/* @__PURE__ */ jsx("summary", { className: "cursor-pointer px-3 py-1.5 font-mono text-label-caps text-muted-foreground uppercase tracking-wider hover:text-foreground", children: "Input" }),
|
|
5836
|
+
/* @__PURE__ */ jsx("pre", { className: "overflow-x-auto bg-muted/20 px-3 py-2 text-code-sm", children: /* @__PURE__ */ jsx("code", { children: inputStr }) })
|
|
5837
|
+
] }) : null,
|
|
5838
|
+
outputStr ? /* @__PURE__ */ jsxs("details", { open: part.state === "output-error" || part.state === "output-available", children: [
|
|
5839
|
+
/* @__PURE__ */ jsx(
|
|
5840
|
+
"summary",
|
|
5841
|
+
{
|
|
5842
|
+
className: cn(
|
|
5843
|
+
"cursor-pointer px-3 py-1.5 font-mono text-label-caps uppercase tracking-wider hover:text-foreground",
|
|
5844
|
+
part.state === "output-error" ? "text-destructive" : "text-muted-foreground"
|
|
5845
|
+
),
|
|
5846
|
+
children: part.state === "output-error" ? "Error" : "Output"
|
|
5847
|
+
}
|
|
5848
|
+
),
|
|
5849
|
+
/* @__PURE__ */ jsx(
|
|
5850
|
+
"pre",
|
|
5851
|
+
{
|
|
5852
|
+
className: cn(
|
|
5853
|
+
"overflow-x-auto px-3 py-2 text-code-sm",
|
|
5854
|
+
part.state === "output-error" ? "bg-destructive/5" : "bg-muted/20"
|
|
5855
|
+
),
|
|
5856
|
+
children: /* @__PURE__ */ jsx("code", { children: outputStr })
|
|
5857
|
+
}
|
|
5858
|
+
)
|
|
5859
|
+
] }) : null
|
|
5860
|
+
]
|
|
5861
|
+
}
|
|
5862
|
+
);
|
|
5863
|
+
}
|
|
5864
|
+
var ChatMessageRoot = forwardRef(
|
|
5865
|
+
({ className, from, children, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
5866
|
+
"div",
|
|
5867
|
+
{
|
|
5868
|
+
ref,
|
|
5869
|
+
className: cn(
|
|
5870
|
+
"group flex w-full max-w-[95%] flex-col gap-2",
|
|
5871
|
+
from === "user" ? "is-user ml-auto justify-end" : from === "assistant" ? "is-assistant" : "is-system",
|
|
5872
|
+
className
|
|
5873
|
+
),
|
|
5874
|
+
"data-theo-chat-message": from,
|
|
5875
|
+
...props,
|
|
5876
|
+
children
|
|
5877
|
+
}
|
|
5878
|
+
)
|
|
5879
|
+
);
|
|
5880
|
+
ChatMessageRoot.displayName = "ChatMessageRoot";
|
|
5881
|
+
var ChatMessageContent = forwardRef(
|
|
5882
|
+
({ className, variant, children, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
5883
|
+
"div",
|
|
5884
|
+
{
|
|
5885
|
+
ref,
|
|
5886
|
+
className: cn(
|
|
5887
|
+
"flex w-fit min-w-0 max-w-full flex-col gap-2 overflow-hidden text-body-md",
|
|
5888
|
+
// User bubble — secondary surface, right-aligned (within the `is-user` group)
|
|
5889
|
+
"group-[.is-user]:ml-auto",
|
|
5890
|
+
variant !== "flat" && "group-[.is-user]:rounded-2xl group-[.is-user]:rounded-tr-md group-[.is-user]:border group-[.is-user]:border-border/40 group-[.is-user]:bg-secondary group-[.is-user]:px-4 group-[.is-user]:py-3",
|
|
5891
|
+
// Assistant card — primary accent border-left
|
|
5892
|
+
variant === "contained" && "group-[.is-assistant]:rounded-2xl group-[.is-assistant]:rounded-tl-md group-[.is-assistant]:border group-[.is-assistant]:border-border/40 group-[.is-assistant]:border-l-2 group-[.is-assistant]:border-l-primary group-[.is-assistant]:bg-card group-[.is-assistant]:px-5 group-[.is-assistant]:py-4 group-[.is-assistant]:shadow-sm",
|
|
5893
|
+
// System callout — accent-deep border
|
|
5894
|
+
"group-[.is-system]:rounded-lg group-[.is-system]:border group-[.is-system]:border-accent-deep/40 group-[.is-system]:border-l-4 group-[.is-system]:bg-accent/10 group-[.is-system]:px-4 group-[.is-system]:py-2 group-[.is-system]:text-body-sm",
|
|
5895
|
+
"group-[.is-assistant]:text-foreground group-[.is-user]:text-secondary-foreground",
|
|
5896
|
+
className
|
|
5897
|
+
),
|
|
5898
|
+
"data-theo-chat-content": "",
|
|
5899
|
+
...props,
|
|
5900
|
+
children
|
|
5901
|
+
}
|
|
5902
|
+
)
|
|
5903
|
+
);
|
|
5904
|
+
ChatMessageContent.displayName = "ChatMessageContent";
|
|
5905
|
+
function renderPart(part, opts = {}) {
|
|
5906
|
+
const overrides = opts.partRenderers ?? {};
|
|
5907
|
+
if (isTextUIPart(part)) {
|
|
5908
|
+
return overrides.text?.(part) ?? /* @__PURE__ */ jsx(TextPart, { part });
|
|
5909
|
+
}
|
|
5910
|
+
if (isReasoningUIPart(part)) {
|
|
5911
|
+
return overrides.reasoning?.(part) ?? /* @__PURE__ */ jsx(ReasoningPart, { part });
|
|
5912
|
+
}
|
|
5913
|
+
if (isReasoningFileUIPart(part)) {
|
|
5914
|
+
return overrides["reasoning-file"]?.(part) ?? null;
|
|
5915
|
+
}
|
|
5916
|
+
if (isFileUIPart(part)) {
|
|
5917
|
+
return overrides.file?.(part) ?? /* @__PURE__ */ jsx(FilePart, { part });
|
|
5918
|
+
}
|
|
5919
|
+
if (isSourceUrlUIPart(part)) {
|
|
5920
|
+
return overrides["source-url"]?.(part) ?? /* @__PURE__ */ jsx(SourceUrlPart, { part });
|
|
5921
|
+
}
|
|
5922
|
+
if (isSourceDocumentUIPart(part)) {
|
|
5923
|
+
return overrides["source-document"]?.(part) ?? /* @__PURE__ */ jsx(SourceDocumentPart, { part });
|
|
5924
|
+
}
|
|
5925
|
+
if (isToolUIPart(part)) {
|
|
5926
|
+
return overrides.tool?.(part) ?? /* @__PURE__ */ jsx(ToolCallPart, { part });
|
|
5927
|
+
}
|
|
5928
|
+
if (isDataUIPart(part)) {
|
|
5929
|
+
return overrides.data?.(part) ?? /* @__PURE__ */ jsx(DataPart, { part, renderers: opts.dataRenderers });
|
|
5930
|
+
}
|
|
5931
|
+
if (isStepStartUIPart(part)) {
|
|
5932
|
+
return overrides["step-start"]?.() ?? /* @__PURE__ */ jsx("hr", { className: "my-3 border-border", "aria-label": "Step boundary" });
|
|
5933
|
+
}
|
|
5934
|
+
return null;
|
|
5935
|
+
}
|
|
5936
|
+
var ChatMessage = forwardRef(
|
|
5937
|
+
({ message, avatar, actions, variant, partRenderers, dataRenderers, className, ...props }, ref) => {
|
|
5938
|
+
const inner = /* @__PURE__ */ jsxs(
|
|
5939
|
+
ChatMessageContent,
|
|
5940
|
+
{
|
|
5941
|
+
variant: variant ?? (message.role === "assistant" ? "contained" : void 0),
|
|
5942
|
+
children: [
|
|
5943
|
+
message.parts.map((part, idx) => /* @__PURE__ */ jsx("div", { children: renderPart(part, { dataRenderers, partRenderers }) }, `${part.type}-${idx}`)),
|
|
5944
|
+
actions
|
|
5209
5945
|
]
|
|
5210
5946
|
}
|
|
5211
5947
|
);
|
|
5948
|
+
if (message.role === "user") {
|
|
5949
|
+
return /* @__PURE__ */ jsxs(ChatMessageRoot, { ref, from: "user", className, ...props, children: [
|
|
5950
|
+
inner,
|
|
5951
|
+
avatar ? /* @__PURE__ */ jsx("div", { className: "shrink-0", children: avatar }) : null
|
|
5952
|
+
] });
|
|
5953
|
+
}
|
|
5954
|
+
return /* @__PURE__ */ jsxs(ChatMessageRoot, { ref, from: message.role, className, ...props, children: [
|
|
5955
|
+
avatar ? /* @__PURE__ */ jsx("div", { className: "shrink-0", children: avatar }) : null,
|
|
5956
|
+
inner
|
|
5957
|
+
] });
|
|
5212
5958
|
}
|
|
5213
5959
|
);
|
|
5214
5960
|
ChatMessage.displayName = "ChatMessage";
|
|
5961
|
+
function ChatMessageActions({
|
|
5962
|
+
className,
|
|
5963
|
+
children,
|
|
5964
|
+
...props
|
|
5965
|
+
}) {
|
|
5966
|
+
return /* @__PURE__ */ jsx("div", { className: cn("flex items-center gap-1", className), "data-theo-chat-actions": "", ...props, children });
|
|
5967
|
+
}
|
|
5968
|
+
function ChatMessageAction({
|
|
5969
|
+
tooltip,
|
|
5970
|
+
label,
|
|
5971
|
+
variant = "ghost",
|
|
5972
|
+
size = "icon",
|
|
5973
|
+
className,
|
|
5974
|
+
children,
|
|
5975
|
+
...props
|
|
5976
|
+
}) {
|
|
5977
|
+
return /* @__PURE__ */ jsxs(
|
|
5978
|
+
Button,
|
|
5979
|
+
{
|
|
5980
|
+
type: "button",
|
|
5981
|
+
variant,
|
|
5982
|
+
size,
|
|
5983
|
+
title: tooltip,
|
|
5984
|
+
className: cn(className),
|
|
5985
|
+
...props,
|
|
5986
|
+
children: [
|
|
5987
|
+
children,
|
|
5988
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: label || tooltip })
|
|
5989
|
+
]
|
|
5990
|
+
}
|
|
5991
|
+
);
|
|
5992
|
+
}
|
|
5993
|
+
function ChatMessageToolbar({
|
|
5994
|
+
className,
|
|
5995
|
+
children,
|
|
5996
|
+
...props
|
|
5997
|
+
}) {
|
|
5998
|
+
return /* @__PURE__ */ jsx(
|
|
5999
|
+
"div",
|
|
6000
|
+
{
|
|
6001
|
+
className: cn("mt-3 flex w-full items-center justify-between gap-3", className),
|
|
6002
|
+
"data-theo-chat-toolbar": "",
|
|
6003
|
+
...props,
|
|
6004
|
+
children
|
|
6005
|
+
}
|
|
6006
|
+
);
|
|
6007
|
+
}
|
|
6008
|
+
var MessageBranchContext = createContext(null);
|
|
6009
|
+
function useMessageBranch() {
|
|
6010
|
+
const ctx = useContext(MessageBranchContext);
|
|
6011
|
+
if (!ctx) {
|
|
6012
|
+
throw new Error("ChatMessageBranch* components must be wrapped in <ChatMessageBranch>.");
|
|
6013
|
+
}
|
|
6014
|
+
return ctx;
|
|
6015
|
+
}
|
|
6016
|
+
function ChatMessageBranch({
|
|
6017
|
+
defaultBranch = 0,
|
|
6018
|
+
onBranchChange,
|
|
6019
|
+
className,
|
|
6020
|
+
...props
|
|
6021
|
+
}) {
|
|
6022
|
+
const [currentBranch, setCurrentBranch] = useState(defaultBranch);
|
|
6023
|
+
const [branches, setBranches] = useState([]);
|
|
6024
|
+
const handleChange = useCallback(
|
|
6025
|
+
(next) => {
|
|
6026
|
+
setCurrentBranch(next);
|
|
6027
|
+
onBranchChange?.(next);
|
|
6028
|
+
},
|
|
6029
|
+
[onBranchChange]
|
|
6030
|
+
);
|
|
6031
|
+
const goToPrevious = useCallback(() => {
|
|
6032
|
+
handleChange(currentBranch > 0 ? currentBranch - 1 : branches.length - 1);
|
|
6033
|
+
}, [currentBranch, branches.length, handleChange]);
|
|
6034
|
+
const goToNext = useCallback(() => {
|
|
6035
|
+
handleChange(currentBranch < branches.length - 1 ? currentBranch + 1 : 0);
|
|
6036
|
+
}, [currentBranch, branches.length, handleChange]);
|
|
6037
|
+
const value = useMemo(
|
|
6038
|
+
() => ({
|
|
6039
|
+
branches,
|
|
6040
|
+
currentBranch,
|
|
6041
|
+
goToNext,
|
|
6042
|
+
goToPrevious,
|
|
6043
|
+
setBranches,
|
|
6044
|
+
totalBranches: branches.length
|
|
6045
|
+
}),
|
|
6046
|
+
[branches, currentBranch, goToNext, goToPrevious]
|
|
6047
|
+
);
|
|
6048
|
+
return /* @__PURE__ */ jsx(MessageBranchContext.Provider, { value, children: /* @__PURE__ */ jsx("div", { className: cn("grid w-full gap-2", className), ...props }) });
|
|
6049
|
+
}
|
|
6050
|
+
function ChatMessageBranchContent({
|
|
6051
|
+
children,
|
|
6052
|
+
...props
|
|
6053
|
+
}) {
|
|
6054
|
+
const { currentBranch, setBranches, branches } = useMessageBranch();
|
|
6055
|
+
const childrenArray = useMemo(
|
|
6056
|
+
() => Array.isArray(children) ? children : [children],
|
|
6057
|
+
[children]
|
|
6058
|
+
);
|
|
6059
|
+
useEffect(() => {
|
|
6060
|
+
if (branches.length !== childrenArray.length) {
|
|
6061
|
+
setBranches(childrenArray);
|
|
6062
|
+
}
|
|
6063
|
+
}, [childrenArray, branches, setBranches]);
|
|
6064
|
+
return /* @__PURE__ */ jsx(Fragment, { children: childrenArray.map((branch, idx) => /* @__PURE__ */ jsx(
|
|
6065
|
+
"div",
|
|
6066
|
+
{
|
|
6067
|
+
className: cn("grid gap-2 overflow-hidden", idx === currentBranch ? "block" : "hidden"),
|
|
6068
|
+
...props,
|
|
6069
|
+
children: branch
|
|
6070
|
+
},
|
|
6071
|
+
// Prefer a stable element key; fall back to index
|
|
6072
|
+
branch?.key ?? `branch-${idx}`
|
|
6073
|
+
)) });
|
|
6074
|
+
}
|
|
6075
|
+
function ChatMessageBranchSelector({
|
|
6076
|
+
className,
|
|
6077
|
+
...props
|
|
6078
|
+
}) {
|
|
6079
|
+
const { totalBranches } = useMessageBranch();
|
|
6080
|
+
if (totalBranches <= 1) return null;
|
|
6081
|
+
return /* @__PURE__ */ jsx(
|
|
6082
|
+
"div",
|
|
6083
|
+
{
|
|
6084
|
+
className: cn("inline-flex items-center gap-0.5 rounded-md border border-border", className),
|
|
6085
|
+
role: "group",
|
|
6086
|
+
"aria-label": "Branch selector",
|
|
6087
|
+
...props
|
|
6088
|
+
}
|
|
6089
|
+
);
|
|
6090
|
+
}
|
|
6091
|
+
function ChatMessageBranchPrevious({
|
|
6092
|
+
children,
|
|
6093
|
+
...props
|
|
6094
|
+
}) {
|
|
6095
|
+
const { goToPrevious, totalBranches } = useMessageBranch();
|
|
6096
|
+
return /* @__PURE__ */ jsx(
|
|
6097
|
+
Button,
|
|
6098
|
+
{
|
|
6099
|
+
type: "button",
|
|
6100
|
+
variant: "ghost",
|
|
6101
|
+
size: "icon",
|
|
6102
|
+
"aria-label": "Previous branch",
|
|
6103
|
+
disabled: totalBranches <= 1,
|
|
6104
|
+
onClick: goToPrevious,
|
|
6105
|
+
...props,
|
|
6106
|
+
children: children ?? /* @__PURE__ */ jsx(ChevronLeftIcon, { className: "size-3.5", "aria-hidden": "true" })
|
|
6107
|
+
}
|
|
6108
|
+
);
|
|
6109
|
+
}
|
|
6110
|
+
function ChatMessageBranchNext({
|
|
6111
|
+
children,
|
|
6112
|
+
...props
|
|
6113
|
+
}) {
|
|
6114
|
+
const { goToNext, totalBranches } = useMessageBranch();
|
|
6115
|
+
return /* @__PURE__ */ jsx(
|
|
6116
|
+
Button,
|
|
6117
|
+
{
|
|
6118
|
+
type: "button",
|
|
6119
|
+
variant: "ghost",
|
|
6120
|
+
size: "icon",
|
|
6121
|
+
"aria-label": "Next branch",
|
|
6122
|
+
disabled: totalBranches <= 1,
|
|
6123
|
+
onClick: goToNext,
|
|
6124
|
+
...props,
|
|
6125
|
+
children: children ?? /* @__PURE__ */ jsx(ChevronRightIcon, { className: "size-3.5", "aria-hidden": "true" })
|
|
6126
|
+
}
|
|
6127
|
+
);
|
|
6128
|
+
}
|
|
6129
|
+
function ChatMessageBranchPage({
|
|
6130
|
+
className,
|
|
6131
|
+
...props
|
|
6132
|
+
}) {
|
|
6133
|
+
const { currentBranch, totalBranches } = useMessageBranch();
|
|
6134
|
+
return /* @__PURE__ */ jsxs(
|
|
6135
|
+
"span",
|
|
6136
|
+
{
|
|
6137
|
+
className: cn(
|
|
6138
|
+
"inline-flex items-center px-2 font-mono text-label-caps text-muted-foreground",
|
|
6139
|
+
className
|
|
6140
|
+
),
|
|
6141
|
+
...props,
|
|
6142
|
+
children: [
|
|
6143
|
+
currentBranch + 1,
|
|
6144
|
+
" of ",
|
|
6145
|
+
totalBranches
|
|
6146
|
+
]
|
|
6147
|
+
}
|
|
6148
|
+
);
|
|
6149
|
+
}
|
|
5215
6150
|
var ChatThread = forwardRef(
|
|
5216
6151
|
({ className, ...props }, ref) => /* @__PURE__ */ jsx(LiveRegionProvider, { value: true, children: /* @__PURE__ */ jsx(
|
|
5217
6152
|
"div",
|
|
@@ -8582,6 +9517,6 @@ function CommandPalette({
|
|
|
8582
9517
|
] }) });
|
|
8583
9518
|
}
|
|
8584
9519
|
|
|
8585
|
-
export { ALL_MODES, AgentComposer, AgentEditor, AgentErrorCard, AgentEvent, AgentHandoff, AgentProfile, AgentStartingState, AgentStream, AgentStreaming, AgentTimeline, ApprovalCard, ArtifactPreview, AttachmentChip, AuditLogEntry, AutoCompactNotice, Avatar, BadgeWithDot as Badge, BrowserControls, BuildLogStream, Button, CapabilityIndicator, Card, ChatComposer, ChatMessage, ChatThread, Checkbox, CommandPalette, ContextCard, ContextWindowBar, CostMeter, CreatedFilesCard, CronJobCard, CronJobsList, DeploymentRow, Dialog, DiffViewer, DomainConfig, EmptyState, EnvVarEditor, FolderContextCard, FolderSelector, FormField, HOOK_EVENTS, HookConfig, HookEventLog, Input, IntentSelector, Label, LaneBoard, LoginSplit, MCPServerCard, MCPServerList, MODE_LABEL, MemoryEditor, MentionMenu, MetricsPanel, ModelCard, ModelSelector, PermissionMatrix, PermissionModal, PreviewEnvCard, PreviewPanel, ProgressChecklist, ProjectCard, ProjectSwitcher, QuickActionChips, RadioGroup, RecentFoldersList, RollbackUI, RuleCard, RuleEditor, RunStats, RunningTasksPanel, ScrollArea, Select, SessionListItem, SessionTimeline, Sheet, Sidebar, Skeleton, SkillCard, SkillEditor, SkillsList, SocialAuthRow, StepsRail, SubAgentDispatch, Switch, SystemPromptEditor, Tabs, TaskHeader, TaskNode, TaskPlan, TerminalPanel, Textarea, ThemeProvider, ThemeScript, ThemeSwitcher, TheoUIProvider, Toast, Toaster, TokenUsageChart, ToolCall, ToolCallCard, ToolResult, ToolsList, TooltipWithStatics as Tooltip, TopNav, anthropicStyle, auroraTerminal, avatarVariants, badgeVariants, builtinThemes, buttonVariants, capabilityPresets, classicPaper, cn, defineTheme, dracula, githubDark, hex, linearGlass, modelCapabilityPresets, oneDark, openaiStyle, rgb, sheetVariants, useDensity, useTheme, useToast, vercelMono, violetForge };
|
|
9520
|
+
export { ALL_MODES, AgentComposer, AgentEditor, AgentErrorCard, AgentEvent, AgentHandoff, AgentProfile, AgentStartingState, AgentStream, AgentStreaming, AgentTimeline, ApprovalCard, ArtifactPreview, AttachmentChip, AuditLogEntry, AutoCompactNotice, Avatar, BadgeWithDot as Badge, BrowserControls, BuildLogStream, Button, CapabilityIndicator, Card, ChatComposer, ChatMessage, ChatMessageAction, ChatMessageActions, ChatMessageBranch, ChatMessageBranchContent, ChatMessageBranchNext, ChatMessageBranchPage, ChatMessageBranchPrevious, ChatMessageBranchSelector, ChatMessageContent, ChatMessageResponse, ChatMessageRoot, ChatMessageToolbar, ChatThread, Checkbox, CommandPalette, ContextCard, ContextWindowBar, CostMeter, CreatedFilesCard, CronJobCard, CronJobsList, DataPart, DeploymentRow, Dialog, DiffViewer, DomainConfig, EmptyState, EnvVarEditor, FilePart, FolderContextCard, FolderSelector, FormField, HOOK_EVENTS, HookConfig, HookEventLog, Input, IntentSelector, Label, LaneBoard, LoginSplit, MCPServerCard, MCPServerList, MODE_LABEL, MemoryEditor, MentionMenu, MetricsPanel, ModelCard, ModelSelector, PermissionMatrix, PermissionModal, PreviewEnvCard, PreviewPanel, ProgressChecklist, ProjectCard, ProjectSwitcher, QuickActionChips, RadioGroup, ReasoningPart, RecentFoldersList, RollbackUI, RuleCard, RuleEditor, RunStats, RunningTasksPanel, ScrollArea, Select, SessionListItem, SessionTimeline, Sheet, Sidebar, Skeleton, SkillCard, SkillEditor, SkillsList, SocialAuthRow, SourceDocumentPart, SourceUrlPart, StepsRail, SubAgentDispatch, Switch, SystemPromptEditor, Tabs, TaskHeader, TaskNode, TaskPlan, TerminalPanel, TextPart, Textarea, ThemeProvider, ThemeScript, ThemeSwitcher, TheoUIProvider, Toast, Toaster, TokenUsageChart, ToolCall, ToolCallCard, ToolCallPart, ToolResult, ToolsList, TooltipWithStatics as Tooltip, TopNav, anthropicStyle, auroraTerminal, avatarVariants, badgeVariants, builtinThemes, buttonVariants, capabilityPresets, classicPaper, cn, defineTheme, dracula, githubDark, hex, isCustomContentUIPart, isDataUIPart, isFileUIPart, isReasoningFileUIPart, isReasoningUIPart, isSourceDocumentUIPart, isSourceUrlUIPart, isStepStartUIPart, isTextUIPart, isToolUIPart, linearGlass, modelCapabilityPresets, oneDark, openaiStyle, renderPart, rgb, sheetVariants, useDensity, useTheme, useToast, vercelMono, violetForge };
|
|
8586
9521
|
//# sourceMappingURL=index.js.map
|
|
8587
9522
|
//# sourceMappingURL=index.js.map
|