llm-message-react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,746 @@
1
+ 'use strict';
2
+
3
+ var clsx = require('clsx');
4
+ var react = require('react');
5
+ var ReactMarkdown = require('react-markdown');
6
+ var rehypeKatex = require('rehype-katex');
7
+ var remarkGfm = require('remark-gfm');
8
+ var remarkMath = require('remark-math');
9
+ var katex = require('katex');
10
+ var jsxRuntime = require('react/jsx-runtime');
11
+
12
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
13
+
14
+ var ReactMarkdown__default = /*#__PURE__*/_interopDefault(ReactMarkdown);
15
+ var rehypeKatex__default = /*#__PURE__*/_interopDefault(rehypeKatex);
16
+ var remarkGfm__default = /*#__PURE__*/_interopDefault(remarkGfm);
17
+ var remarkMath__default = /*#__PURE__*/_interopDefault(remarkMath);
18
+ var katex__default = /*#__PURE__*/_interopDefault(katex);
19
+
20
+ // src/LLMMessage.tsx
21
+ function completePartialTokens(text, options) {
22
+ if (!text) return text;
23
+ const showUnfinishedLatexBlocks = options?.showUnfinishedLatexBlocks ?? true;
24
+ if (hasUnclosedCodeFence(text)) {
25
+ return text;
26
+ }
27
+ const protectedSpans = [];
28
+ const protect = (value) => `\0llmph${protectedSpans.push(value) - 1}\0`;
29
+ let working = text.replace(/```[\s\S]*?```/g, (match) => protect(match));
30
+ working = working.replace(/``[\s\S]*?``/g, (match) => protect(match));
31
+ working = working.replace(/`[^`\n]+`/g, (match) => protect(match));
32
+ const lastBacktick = working.lastIndexOf("`");
33
+ if (lastBacktick !== -1) {
34
+ const newline = working.indexOf("\n", lastBacktick);
35
+ const end = newline === -1 ? working.length : newline;
36
+ const span = working.slice(lastBacktick, end);
37
+ working = working.slice(0, lastBacktick) + protect(`${span}\``) + working.slice(end);
38
+ }
39
+ working = repairIncompleteMath(working, showUnfinishedLatexBlocks);
40
+ working = hideIncompleteLink(working);
41
+ working = completePartialTable(working);
42
+ working = hideDanglingListMarker(working);
43
+ working = closeUnbalancedEmphasis(working);
44
+ return working.replace(
45
+ /\u0000llmph(\d+)\u0000/g,
46
+ (_match, index) => protectedSpans[Number(index)] ?? ""
47
+ );
48
+ }
49
+ function completePartialTable(text) {
50
+ const lines = text.split("\n");
51
+ if (lines.length < 2) return text;
52
+ const last = lines[lines.length - 1];
53
+ if (!/-/.test(last) || !/^[\s|:-]*$/.test(last)) return text;
54
+ const header = lines[lines.length - 2];
55
+ if (!header.includes("|")) return text;
56
+ for (let i = lines.length - 2; i >= 0; i--) {
57
+ const line = lines[i];
58
+ if (!line.includes("|")) break;
59
+ if (/-/.test(line) && /^[\s|:-]*$/.test(line)) return text;
60
+ }
61
+ const columns = countTableColumns(header);
62
+ lines[lines.length - 1] = buildDelimiterRow(last, columns);
63
+ return lines.join("\n");
64
+ }
65
+ function countTableColumns(row) {
66
+ let inner = row.trim();
67
+ if (inner.startsWith("|")) inner = inner.slice(1);
68
+ if (inner.endsWith("|")) inner = inner.slice(0, -1);
69
+ return inner.split("|").length;
70
+ }
71
+ function buildDelimiterRow(fragment, columns) {
72
+ let inner = fragment.trim();
73
+ if (inner.startsWith("|")) inner = inner.slice(1);
74
+ if (inner.endsWith("|")) inner = inner.slice(0, -1);
75
+ const existing = inner.split("|").map((cell) => cell.trim());
76
+ const cells = Array.from({ length: columns }, (_unused, index) => {
77
+ const spec = existing[index] ?? "";
78
+ const left = spec.startsWith(":");
79
+ const right = spec.endsWith(":");
80
+ if (left && right) return ":---:";
81
+ if (right) return "---:";
82
+ if (left) return ":---";
83
+ return "---";
84
+ });
85
+ return `| ${cells.join(" | ")} |`;
86
+ }
87
+ function hideDanglingListMarker(text) {
88
+ const match = text.match(/\n[ \t]{0,3}-+[ \t]*$/);
89
+ if (match?.index == null) return text;
90
+ const before = text.slice(0, match.index);
91
+ const prevLine = before.slice(before.lastIndexOf("\n") + 1);
92
+ if (prevLine.trim() === "") return text;
93
+ return before;
94
+ }
95
+ function hasUnclosedCodeFence(text) {
96
+ const backticks = (text.match(/^[ \t]{0,3}```/gm) ?? []).length;
97
+ const tildes = (text.match(/^[ \t]{0,3}~~~/gm) ?? []).length;
98
+ return backticks % 2 === 1 || tildes % 2 === 1;
99
+ }
100
+ function hideIncompleteLink(text) {
101
+ let open = -1;
102
+ for (let i = text.length - 1; i >= 0; i--) {
103
+ if (text[i] === "[" && text[i - 1] !== "\\") {
104
+ open = i;
105
+ break;
106
+ }
107
+ }
108
+ if (open === -1) return text;
109
+ const start = open > 0 && text[open - 1] === "!" ? open - 1 : open;
110
+ const rest = text.slice(open);
111
+ if (!rest.includes("]")) {
112
+ return text.slice(0, start);
113
+ }
114
+ if (/^\[[^\]]*\]\([^)]*$/.test(rest)) {
115
+ return text.slice(0, start);
116
+ }
117
+ return text;
118
+ }
119
+ function repairIncompleteMath(text, showUnfinishedLatexBlocks) {
120
+ const countOf = (pattern) => (text.match(pattern) ?? []).length;
121
+ const opens = [];
122
+ if (countOf(/\\\[/g) > countOf(/\\\]/g)) {
123
+ opens.push({
124
+ index: text.lastIndexOf("\\["),
125
+ open: "\\[",
126
+ close: "\\]",
127
+ block: true,
128
+ display: true
129
+ });
130
+ }
131
+ if (countOf(/\\\(/g) > countOf(/\\\)/g)) {
132
+ opens.push({
133
+ index: text.lastIndexOf("\\("),
134
+ open: "\\(",
135
+ close: "",
136
+ block: false,
137
+ display: false
138
+ });
139
+ }
140
+ if (countOf(/\$\$/g) % 2 === 1) {
141
+ opens.push({
142
+ index: text.lastIndexOf("$$"),
143
+ open: "$$",
144
+ close: "$$",
145
+ block: true,
146
+ display: true
147
+ });
148
+ } else {
149
+ const masked = text.replace(/\$\$/g, " ");
150
+ let lastDollar = -1;
151
+ for (const match of masked.matchAll(/(?<!\\)\$(?!\d)/g)) {
152
+ lastDollar = match.index;
153
+ }
154
+ const singles = masked.match(/(?<!\\)\$(?!\d)/g) ?? [];
155
+ if (singles.length % 2 === 1 && lastDollar !== -1) {
156
+ opens.push({
157
+ index: lastDollar,
158
+ open: "$",
159
+ close: "",
160
+ block: false,
161
+ display: false
162
+ });
163
+ }
164
+ }
165
+ const valid = opens.filter((entry) => entry.index >= 0);
166
+ if (valid.length === 0) return text;
167
+ const open = valid.reduce((a, b) => b.index < a.index ? b : a);
168
+ const before = text.slice(0, open.index);
169
+ if (!open.block) {
170
+ return before;
171
+ }
172
+ if (!showUnfinishedLatexBlocks) {
173
+ return before;
174
+ }
175
+ const inner = text.slice(open.index + open.open.length);
176
+ const body = bestRenderableMathBody(inner, open.display);
177
+ if (body == null) return before;
178
+ const blockLayout = /^[ \t]*\r?\n/.test(inner);
179
+ if (!blockLayout) {
180
+ return before + open.open + body + open.close;
181
+ }
182
+ const opener = before === "" || before.endsWith("\n") ? open.open : `
183
+ ${open.open}`;
184
+ return `${before}${opener}${body.replace(/\s+$/, "")}
185
+ ${open.close}`;
186
+ }
187
+ function bestRenderableMathBody(inner, display) {
188
+ const candidates = unclosedEnvironments(inner).length > 0 ? [closeOpenMathConstructs(truncateToLastRow(inner)), closeOpenMathConstructs(trimIncompleteMathTail(inner))] : [closeOpenMathConstructs(trimIncompleteMathTail(inner))];
189
+ for (const candidate of candidates) {
190
+ if (!hasRenderableMathContent(candidate)) continue;
191
+ if (isRenderableMath(candidate, display)) return candidate;
192
+ }
193
+ return null;
194
+ }
195
+ function hasRenderableMathContent(body) {
196
+ const stripped = body.replace(/\\(?:begin|end)\s*\{[^}]*\}/g, "").replace(/[\s{}]/g, "");
197
+ return stripped.length > 0;
198
+ }
199
+ function isRenderableMath(body, display) {
200
+ try {
201
+ katex__default.default.renderToString(body, {
202
+ displayMode: display,
203
+ throwOnError: true,
204
+ strict: false
205
+ });
206
+ return true;
207
+ } catch {
208
+ return false;
209
+ }
210
+ }
211
+ function truncateToLastRow(inner) {
212
+ const lastRow = inner.lastIndexOf("\\\\");
213
+ if (lastRow === -1) return "";
214
+ return inner.slice(0, lastRow + 2);
215
+ }
216
+ function trimIncompleteMathTail(inner) {
217
+ let result = inner;
218
+ let previous;
219
+ do {
220
+ previous = result;
221
+ result = result.replace(/\s+$/, "");
222
+ const backslashes = result.match(/\\+$/);
223
+ if (backslashes != null && backslashes[0].length % 2 === 1) {
224
+ result = result.slice(0, -1);
225
+ }
226
+ result = result.replace(/\\[a-zA-Z]+\*?$/, "");
227
+ result = result.replace(/[_^]$/, "");
228
+ } while (result !== previous);
229
+ return result;
230
+ }
231
+ function closeOpenMathConstructs(inner) {
232
+ let result = inner;
233
+ const lefts = (result.match(/\\left(?![a-zA-Z])/g) ?? []).length;
234
+ const rights = (result.match(/\\right(?![a-zA-Z])/g) ?? []).length;
235
+ result += "\\right.".repeat(Math.max(0, lefts - rights));
236
+ result += "}".repeat(openBraceDepth(result));
237
+ const environments = unclosedEnvironments(result);
238
+ for (let i = environments.length - 1; i >= 0; i--) {
239
+ result += `\\end{${environments[i]}}`;
240
+ }
241
+ return result;
242
+ }
243
+ function openBraceDepth(text) {
244
+ let depth = 0;
245
+ for (let i = 0; i < text.length; i++) {
246
+ const char = text[i];
247
+ if (char === "\\") {
248
+ i++;
249
+ continue;
250
+ }
251
+ if (char === "{") depth++;
252
+ else if (char === "}" && depth > 0) depth--;
253
+ }
254
+ return depth;
255
+ }
256
+ function unclosedEnvironments(text) {
257
+ const stack = [];
258
+ const pattern = /\\(begin|end)\s*\{([^}]*)\}/g;
259
+ let match;
260
+ while ((match = pattern.exec(text)) != null) {
261
+ const name = match[2];
262
+ if (match[1] === "begin") {
263
+ stack.push(name);
264
+ } else {
265
+ const index = stack.lastIndexOf(name);
266
+ if (index !== -1) stack.splice(index, 1);
267
+ else stack.pop();
268
+ }
269
+ }
270
+ return stack;
271
+ }
272
+ function closeUnbalancedEmphasis(text) {
273
+ let result = text;
274
+ result = closeRunMarker(result, "~~");
275
+ result = closeSingleAsterisk(result);
276
+ result = closeRunMarker(result, "**");
277
+ result = closeSingleUnderscore(result);
278
+ result = closeDoubleUnderscore(result);
279
+ return result;
280
+ }
281
+ function opensAtWordBoundary(text, index) {
282
+ if (index <= 0) return true;
283
+ return !/[\p{L}\p{N}_]/u.test(text[index - 1]);
284
+ }
285
+ function closeSingleUnderscore(text) {
286
+ const masked = text.replace(/__/g, "");
287
+ const count = (masked.match(/_/g) ?? []).length;
288
+ if (count % 2 === 0) return text;
289
+ const lastIndex = text.lastIndexOf("_");
290
+ const after = text.slice(lastIndex + 1);
291
+ if (after.length === 0 || /^[\s_]/.test(after)) return text;
292
+ if (!opensAtWordBoundary(text, lastIndex)) return text;
293
+ return insertBeforeTrailingWhitespace(text, "_");
294
+ }
295
+ function closeDoubleUnderscore(text) {
296
+ const count = (text.match(/__/g) ?? []).length;
297
+ if (count % 2 === 0) return text;
298
+ const lastIndex = text.lastIndexOf("__");
299
+ const after = text.slice(lastIndex + 2);
300
+ if (after.length === 0 || /^\s/.test(after)) return text;
301
+ if (!opensAtWordBoundary(text, lastIndex)) return text;
302
+ return insertBeforeTrailingWhitespace(text, "__");
303
+ }
304
+ function closeRunMarker(text, marker) {
305
+ const escaped = marker.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
306
+ const count = (text.match(new RegExp(escaped, "g")) ?? []).length;
307
+ if (count % 2 === 0) return text;
308
+ const lastIndex = text.lastIndexOf(marker);
309
+ const after = text.slice(lastIndex + marker.length);
310
+ if (after.length === 0 || /^\s/.test(after)) return text;
311
+ return insertBeforeTrailingWhitespace(text, marker);
312
+ }
313
+ function closeSingleAsterisk(text) {
314
+ const masked = text.replace(/\*\*/g, "");
315
+ const count = (masked.match(/\*/g) ?? []).length;
316
+ if (count % 2 === 0) return text;
317
+ const lastIndex = text.lastIndexOf("*");
318
+ const after = text.slice(lastIndex + 1);
319
+ if (after.length === 0 || /^[\s*]/.test(after)) return text;
320
+ return insertBeforeTrailingWhitespace(text, "*");
321
+ }
322
+ function insertBeforeTrailingWhitespace(text, marker) {
323
+ const trailing = text.match(/\s+$/)?.[0] ?? "";
324
+ const core = text.slice(0, text.length - trailing.length);
325
+ return core + marker + trailing;
326
+ }
327
+ function CopyIcon() {
328
+ return /* @__PURE__ */ jsxRuntime.jsxs(
329
+ "svg",
330
+ {
331
+ viewBox: "0 0 24 24",
332
+ width: "1em",
333
+ height: "1em",
334
+ fill: "none",
335
+ stroke: "currentColor",
336
+ strokeWidth: "2",
337
+ strokeLinecap: "round",
338
+ strokeLinejoin: "round",
339
+ "aria-hidden": "true",
340
+ children: [
341
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
342
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
343
+ ]
344
+ }
345
+ );
346
+ }
347
+ function CheckIcon() {
348
+ return /* @__PURE__ */ jsxRuntime.jsx(
349
+ "svg",
350
+ {
351
+ viewBox: "0 0 24 24",
352
+ width: "1em",
353
+ height: "1em",
354
+ fill: "none",
355
+ stroke: "currentColor",
356
+ strokeWidth: "2",
357
+ strokeLinecap: "round",
358
+ strokeLinejoin: "round",
359
+ "aria-hidden": "true",
360
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 6 9 17l-5-5" })
361
+ }
362
+ );
363
+ }
364
+ function CopyButton({ text, className }) {
365
+ const [copied, setCopied] = react.useState(false);
366
+ const timeoutRef = react.useRef(null);
367
+ react.useEffect(() => {
368
+ return () => {
369
+ if (timeoutRef.current != null) clearTimeout(timeoutRef.current);
370
+ };
371
+ }, []);
372
+ const copy = () => {
373
+ const clipboard = navigator.clipboard;
374
+ if (!clipboard) return;
375
+ void clipboard.writeText(text).then(() => {
376
+ setCopied(true);
377
+ if (timeoutRef.current != null) clearTimeout(timeoutRef.current);
378
+ timeoutRef.current = setTimeout(() => setCopied(false), 2e3);
379
+ }).catch(() => {
380
+ });
381
+ };
382
+ return /* @__PURE__ */ jsxRuntime.jsx(
383
+ "button",
384
+ {
385
+ type: "button",
386
+ onClick: copy,
387
+ className,
388
+ "aria-label": copied ? "Copied" : "Copy code",
389
+ "data-copied": copied ? "" : void 0,
390
+ children: copied ? /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, {}) : /* @__PURE__ */ jsxRuntime.jsx(CopyIcon, {})
391
+ }
392
+ );
393
+ }
394
+
395
+ // src/preprocess.ts
396
+ var CODE_SPAN = /```[\s\S]*?```|`[^`\n]+`/;
397
+ function preprocessLaTeX(content) {
398
+ const codeBlocks = [];
399
+ content = content.replace(
400
+ new RegExp(`(${CODE_SPAN.source})`, "g"),
401
+ (_match, code) => {
402
+ codeBlocks.push(code);
403
+ return `<<CODE_BLOCK_${codeBlocks.length - 1}>>`;
404
+ }
405
+ );
406
+ const latexExpressions = [];
407
+ content = content.replace(
408
+ /(\$\$[\s\S]*?\$\$|\\\[[\s\S]*?\\\]|\\\(.*?\\\))/g,
409
+ (match) => {
410
+ latexExpressions.push(match);
411
+ return `<<LATEX_${latexExpressions.length - 1}>>`;
412
+ }
413
+ );
414
+ content = content.replace(/\$(?=\d)/g, "\\$");
415
+ content = content.replace(
416
+ /<<LATEX_(\d+)>>/g,
417
+ (_, index) => latexExpressions[parseInt(index, 10)]
418
+ );
419
+ content = content.replace(
420
+ /<<CODE_BLOCK_(\d+)>>/g,
421
+ (_, index) => codeBlocks[parseInt(index, 10)]
422
+ );
423
+ content = escapeBrackets(content);
424
+ content = escapeMhchem(content);
425
+ return content;
426
+ }
427
+ function escapeBrackets(text) {
428
+ const pattern = new RegExp(
429
+ `(${CODE_SPAN.source})|` + /\\\[((?:[\s\S]*?[^\\])?)\\]|\\\((.*?)\\\)/.source,
430
+ "g"
431
+ );
432
+ return text.replace(
433
+ pattern,
434
+ (match, codeBlock, squareBracket, roundBracket) => {
435
+ if (codeBlock != null) {
436
+ return codeBlock;
437
+ } else if (squareBracket != null) {
438
+ return `$$${squareBracket}$$`;
439
+ } else if (roundBracket != null) {
440
+ return `$${roundBracket}$`;
441
+ }
442
+ return match;
443
+ }
444
+ );
445
+ }
446
+ function escapeMhchem(text) {
447
+ return text.replaceAll("$\\ce{", "$\\\\ce{").replaceAll("$\\pu{", "$\\\\pu{");
448
+ }
449
+ var remarkPlugins = [remarkGfm__default.default, remarkMath__default.default];
450
+ var rehypePlugins = [rehypeKatex__default.default];
451
+ function cx(...inputs) {
452
+ const result = clsx.clsx(inputs);
453
+ return result === "" ? void 0 : result;
454
+ }
455
+ function buildComponents(classNames, overrides, highlighter) {
456
+ const cn = classNames ?? {};
457
+ const o = overrides ?? {};
458
+ const Highlighter = highlighter;
459
+ return {
460
+ code({ node: _node, className, children, ...props }) {
461
+ const match = /language-(\w+)/.exec(className || "");
462
+ const codeText = String(children).replace(/\n$/, "");
463
+ const isBlock = match != null || String(children).includes("\n");
464
+ if (isBlock) {
465
+ const language = match?.[1] ?? "";
466
+ if (o.codeBlock) {
467
+ const CodeBlock = o.codeBlock;
468
+ return /* @__PURE__ */ jsxRuntime.jsx(
469
+ CodeBlock,
470
+ {
471
+ code: codeText,
472
+ language,
473
+ className: cn.codeBlock
474
+ }
475
+ );
476
+ }
477
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx("llm-code-block", cn.codeBlock), children: [
478
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cx("llm-code-header", cn.codeHeader), children: [
479
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: cx("llm-code-language", cn.codeLanguage), children: language }),
480
+ o.copyButton ? /* @__PURE__ */ jsxRuntime.jsx(o.copyButton, { text: codeText, className: cn.copyButton }) : /* @__PURE__ */ jsxRuntime.jsx(
481
+ CopyButton,
482
+ {
483
+ text: codeText,
484
+ className: cx("llm-copy-button", cn.copyButton)
485
+ }
486
+ )
487
+ ] }),
488
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "llm-code-body", children: Highlighter ? /* @__PURE__ */ jsxRuntime.jsx(Highlighter, { code: codeText, language }) : /* @__PURE__ */ jsxRuntime.jsx("code", { className: "llm-code-plain", children: codeText }) })
489
+ ] });
490
+ }
491
+ if (o.code) {
492
+ const InlineCode = o.code;
493
+ return /* @__PURE__ */ jsxRuntime.jsx(InlineCode, { className: cx("llm-code", cn.code, className), children });
494
+ }
495
+ return /* @__PURE__ */ jsxRuntime.jsx("code", { className: cx("llm-code", cn.code, className), ...props, children });
496
+ },
497
+ pre({ children }) {
498
+ if (o.pre) {
499
+ return /* @__PURE__ */ jsxRuntime.jsx(o.pre, { children });
500
+ }
501
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
502
+ },
503
+ table({ children }) {
504
+ if (o.table) {
505
+ return /* @__PURE__ */ jsxRuntime.jsx(o.table, { className: cn.table, children });
506
+ }
507
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cx("llm-table-wrapper", cn.tableWrapper), children: /* @__PURE__ */ jsxRuntime.jsx("table", { className: cx("llm-table", cn.table), children }) });
508
+ },
509
+ th({ children }) {
510
+ if (o.th) {
511
+ return /* @__PURE__ */ jsxRuntime.jsx(o.th, { className: cn.th, children });
512
+ }
513
+ return /* @__PURE__ */ jsxRuntime.jsx("th", { className: cx("llm-th", cn.th), children });
514
+ },
515
+ td({ children }) {
516
+ if (o.td) {
517
+ return /* @__PURE__ */ jsxRuntime.jsx(o.td, { className: cn.td, children });
518
+ }
519
+ return /* @__PURE__ */ jsxRuntime.jsx("td", { className: cx("llm-td", cn.td), children });
520
+ },
521
+ blockquote({ children }) {
522
+ if (o.blockquote) {
523
+ return /* @__PURE__ */ jsxRuntime.jsx(o.blockquote, { className: cn.blockquote, children });
524
+ }
525
+ return /* @__PURE__ */ jsxRuntime.jsx("blockquote", { className: cx("llm-blockquote", cn.blockquote), children });
526
+ },
527
+ ul({ children }) {
528
+ if (o.ul) {
529
+ return /* @__PURE__ */ jsxRuntime.jsx(o.ul, { className: cn.ul, children });
530
+ }
531
+ return /* @__PURE__ */ jsxRuntime.jsx("ul", { className: cx("llm-ul", cn.ul), children });
532
+ },
533
+ ol({ children }) {
534
+ if (o.ol) {
535
+ return /* @__PURE__ */ jsxRuntime.jsx(o.ol, { className: cn.ol, children });
536
+ }
537
+ return /* @__PURE__ */ jsxRuntime.jsx("ol", { className: cx("llm-ol", cn.ol), children });
538
+ },
539
+ li({ children }) {
540
+ if (o.li) {
541
+ return /* @__PURE__ */ jsxRuntime.jsx(o.li, { className: cn.li, children });
542
+ }
543
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { className: cx("llm-li", cn.li), children });
544
+ },
545
+ p({ children }) {
546
+ if (o.p) {
547
+ return /* @__PURE__ */ jsxRuntime.jsx(o.p, { className: cn.p, children });
548
+ }
549
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { className: cx("llm-p", cn.p), children });
550
+ },
551
+ h1({ children }) {
552
+ if (o.h1) {
553
+ return /* @__PURE__ */ jsxRuntime.jsx(o.h1, { className: cn.h1, children });
554
+ }
555
+ return /* @__PURE__ */ jsxRuntime.jsx("h1", { className: cx("llm-h1", cn.h1), children });
556
+ },
557
+ h2({ children }) {
558
+ if (o.h2) {
559
+ return /* @__PURE__ */ jsxRuntime.jsx(o.h2, { className: cn.h2, children });
560
+ }
561
+ return /* @__PURE__ */ jsxRuntime.jsx("h2", { className: cx("llm-h2", cn.h2), children });
562
+ },
563
+ h3({ children }) {
564
+ if (o.h3) {
565
+ return /* @__PURE__ */ jsxRuntime.jsx(o.h3, { className: cn.h3, children });
566
+ }
567
+ return /* @__PURE__ */ jsxRuntime.jsx("h3", { className: cx("llm-h3", cn.h3), children });
568
+ },
569
+ h4({ children }) {
570
+ if (o.h4) {
571
+ return /* @__PURE__ */ jsxRuntime.jsx(o.h4, { className: cn.h4, children });
572
+ }
573
+ return /* @__PURE__ */ jsxRuntime.jsx("h4", { className: cx("llm-h4", cn.h4), children });
574
+ },
575
+ h5({ children }) {
576
+ if (o.h5) {
577
+ return /* @__PURE__ */ jsxRuntime.jsx(o.h5, { className: cn.h5, children });
578
+ }
579
+ return /* @__PURE__ */ jsxRuntime.jsx("h5", { className: cx("llm-h5", cn.h5), children });
580
+ },
581
+ h6({ children }) {
582
+ if (o.h6) {
583
+ return /* @__PURE__ */ jsxRuntime.jsx(o.h6, { className: cn.h6, children });
584
+ }
585
+ return /* @__PURE__ */ jsxRuntime.jsx("h6", { className: cx("llm-h6", cn.h6), children });
586
+ },
587
+ input({ node: _node, type, checked, disabled, ...props }) {
588
+ if (type === "checkbox") {
589
+ if (o.checkbox) {
590
+ return /* @__PURE__ */ jsxRuntime.jsx(o.checkbox, { checked: Boolean(checked), className: cn.checkbox });
591
+ }
592
+ return /* @__PURE__ */ jsxRuntime.jsx(
593
+ "input",
594
+ {
595
+ type: "checkbox",
596
+ checked: Boolean(checked),
597
+ disabled: true,
598
+ "aria-label": checked ? "Completed task" : "Incomplete task",
599
+ className: cx("llm-checkbox", cn.checkbox),
600
+ readOnly: true
601
+ }
602
+ );
603
+ }
604
+ return /* @__PURE__ */ jsxRuntime.jsx(
605
+ "input",
606
+ {
607
+ type,
608
+ checked,
609
+ disabled,
610
+ readOnly: true,
611
+ ...props
612
+ }
613
+ );
614
+ },
615
+ a({ href, children }) {
616
+ if (o.a) {
617
+ return /* @__PURE__ */ jsxRuntime.jsx(o.a, { href, className: cn.a, children });
618
+ }
619
+ return /* @__PURE__ */ jsxRuntime.jsx(
620
+ "a",
621
+ {
622
+ href,
623
+ target: "_blank",
624
+ rel: "noopener noreferrer",
625
+ className: cx("llm-a", cn.a),
626
+ children
627
+ }
628
+ );
629
+ },
630
+ img({ node: _node, src, alt, title, className: _className, ...props }) {
631
+ if (o.img) {
632
+ const Image = o.img;
633
+ return /* @__PURE__ */ jsxRuntime.jsx(
634
+ Image,
635
+ {
636
+ src: typeof src === "string" ? src : void 0,
637
+ alt,
638
+ title,
639
+ className: cn.img
640
+ }
641
+ );
642
+ }
643
+ return /* @__PURE__ */ jsxRuntime.jsx(
644
+ "img",
645
+ {
646
+ src: typeof src === "string" ? src : void 0,
647
+ alt,
648
+ title,
649
+ className: cx("llm-img", cn.img),
650
+ ...props
651
+ }
652
+ );
653
+ },
654
+ hr() {
655
+ if (o.hr) {
656
+ return /* @__PURE__ */ jsxRuntime.jsx(o.hr, { className: cn.hr });
657
+ }
658
+ return /* @__PURE__ */ jsxRuntime.jsx("hr", { className: cx("llm-hr", cn.hr) });
659
+ },
660
+ strong({ children }) {
661
+ if (o.strong) {
662
+ return /* @__PURE__ */ jsxRuntime.jsx(o.strong, { className: cn.strong, children });
663
+ }
664
+ return /* @__PURE__ */ jsxRuntime.jsx("strong", { className: cx("llm-strong", cn.strong), children });
665
+ },
666
+ em({ children }) {
667
+ if (o.em) {
668
+ return /* @__PURE__ */ jsxRuntime.jsx(o.em, { className: cn.em, children });
669
+ }
670
+ return /* @__PURE__ */ jsxRuntime.jsx("em", { className: cx("llm-em", cn.em), children });
671
+ },
672
+ del({ children }) {
673
+ if (o.del) {
674
+ return /* @__PURE__ */ jsxRuntime.jsx(o.del, { className: cn.del, children });
675
+ }
676
+ return /* @__PURE__ */ jsxRuntime.jsx("del", { className: cx("llm-del", cn.del), children });
677
+ }
678
+ };
679
+ }
680
+ function LLMMessage({
681
+ children,
682
+ content,
683
+ className,
684
+ classNames,
685
+ components,
686
+ completePartialTokens: repairPartialTokens = true,
687
+ showUnfinishedLatexBlocks = true,
688
+ highlighter,
689
+ ...rest
690
+ }) {
691
+ const source = content ?? children ?? "";
692
+ const markdownComponents = react.useMemo(
693
+ () => buildComponents(classNames, components, highlighter),
694
+ [classNames, components, highlighter]
695
+ );
696
+ const processed = react.useMemo(() => {
697
+ const repaired = repairPartialTokens ? completePartialTokens(source, { showUnfinishedLatexBlocks }) : source;
698
+ return preprocessLaTeX(repaired);
699
+ }, [source, repairPartialTokens, showUnfinishedLatexBlocks]);
700
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cx("llm-message", classNames?.root, className), ...rest, children: /* @__PURE__ */ jsxRuntime.jsx(
701
+ ReactMarkdown__default.default,
702
+ {
703
+ remarkPlugins,
704
+ rehypePlugins,
705
+ components: markdownComponents,
706
+ children: processed
707
+ }
708
+ ) });
709
+ }
710
+ var DEFAULT_THEMES = { light: "github-light", dark: "github-dark" };
711
+ function createShikiHighlighter(codeToHtml, options) {
712
+ const themes = options?.themes ?? DEFAULT_THEMES;
713
+ return function ShikiHighlighter({ code, language, className }) {
714
+ const [html, setHtml] = react.useState(null);
715
+ react.useEffect(() => {
716
+ let cancelled = false;
717
+ Promise.resolve(codeToHtml(code, { lang: language, themes })).then((result) => {
718
+ if (!cancelled) setHtml(result);
719
+ }).catch(() => {
720
+ if (!cancelled) setHtml(null);
721
+ });
722
+ return () => {
723
+ cancelled = true;
724
+ };
725
+ }, [code, language]);
726
+ if (html) {
727
+ return /* @__PURE__ */ jsxRuntime.jsx(
728
+ "div",
729
+ {
730
+ className: className ?? "llm-shiki",
731
+ dangerouslySetInnerHTML: { __html: html }
732
+ }
733
+ );
734
+ }
735
+ return /* @__PURE__ */ jsxRuntime.jsx("code", { className: "llm-code-plain", children: code });
736
+ };
737
+ }
738
+
739
+ exports.LLMMessage = LLMMessage;
740
+ exports.completePartialTokens = completePartialTokens;
741
+ exports.createShikiHighlighter = createShikiHighlighter;
742
+ exports.escapeBrackets = escapeBrackets;
743
+ exports.escapeMhchem = escapeMhchem;
744
+ exports.preprocessLaTeX = preprocessLaTeX;
745
+ //# sourceMappingURL=index.cjs.map
746
+ //# sourceMappingURL=index.cjs.map