@sentry/junior-dashboard 0.60.1 → 0.61.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/client/format.d.ts +12 -2
- package/dist/client/types.d.ts +1 -0
- package/dist/client.js +23 -11
- package/package.json +2 -2
- package/src/client/code.tsx +1 -1
- package/src/client/components/TranscriptText.tsx +1 -1
- package/src/client/components/TranscriptTurn.tsx +2 -1
- package/src/client/format.ts +35 -9
- package/src/client/types.ts +1 -1
package/dist/client/format.d.ts
CHANGED
|
@@ -52,8 +52,18 @@ export declare function unavailableTranscriptLabel(turn: ConversationTurn): stri
|
|
|
52
52
|
export declare function conversationPath(conversationId: string): string;
|
|
53
53
|
/** Detect the syntax highlighter language for raw transcript blocks. */
|
|
54
54
|
export declare function detectLanguage(text: string): BundledLanguage;
|
|
55
|
-
/**
|
|
56
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Detect the language for LLM text output prose: json if the text is valid
|
|
57
|
+
* JSON or JSONL, markdown otherwise. Never auto-detects XML, HTML, TypeScript,
|
|
58
|
+
* or shell — those heuristics are unreliable for rendered assistant output.
|
|
59
|
+
*/
|
|
60
|
+
export declare function detectOutputLanguage(text: string): BundledLanguage;
|
|
61
|
+
/**
|
|
62
|
+
* Decide whether a fenced block can use the interactive markup renderer.
|
|
63
|
+
* Structured XML/HTML rendering is only enabled for explicitly-fenced blocks;
|
|
64
|
+
* auto-detected prose is never eligible regardless of inferred language.
|
|
65
|
+
*/
|
|
66
|
+
export declare function canRenderStructuredMarkup(block: CodeBlock): boolean;
|
|
57
67
|
/** Parse markdown into renderable code blocks while preserving plain text blocks. */
|
|
58
68
|
export declare function parseMarkdownBlocks(text: string): CodeBlock[];
|
|
59
69
|
/** Parse XML/HTML-ish fragments for the collapsible transcript renderer. */
|
package/dist/client/types.d.ts
CHANGED
|
@@ -140,6 +140,7 @@ export type SessionFilter = "active" | "recent" | "hung" | "failed" | "all";
|
|
|
140
140
|
export type VisualStatus = "active" | "failed" | "hung" | "idle";
|
|
141
141
|
export type CodeBlock = {
|
|
142
142
|
code: string;
|
|
143
|
+
fenced?: boolean;
|
|
143
144
|
language: BundledLanguage;
|
|
144
145
|
};
|
|
145
146
|
export type MarkupNode = {
|
package/dist/client.js
CHANGED
|
@@ -31045,8 +31045,19 @@ function prettyJsonData(text2) {
|
|
|
31045
31045
|
function formatCodeBlock(code, language) {
|
|
31046
31046
|
return language === "json" ? prettyJsonData(code) ?? code : code;
|
|
31047
31047
|
}
|
|
31048
|
-
function
|
|
31049
|
-
|
|
31048
|
+
function detectOutputLanguage(text2) {
|
|
31049
|
+
const trimmed = text2.trim();
|
|
31050
|
+
if (!trimmed) return "markdown";
|
|
31051
|
+
try {
|
|
31052
|
+
JSON.parse(trimmed);
|
|
31053
|
+
return "json";
|
|
31054
|
+
} catch {
|
|
31055
|
+
}
|
|
31056
|
+
if (prettyJsonl(trimmed)) return "json";
|
|
31057
|
+
return "markdown";
|
|
31058
|
+
}
|
|
31059
|
+
function canRenderStructuredMarkup(block) {
|
|
31060
|
+
return block.fenced === true && (block.language === "xml" || block.language === "html");
|
|
31050
31061
|
}
|
|
31051
31062
|
function parseMarkdownBlocks(text2) {
|
|
31052
31063
|
const blocks = [];
|
|
@@ -31056,24 +31067,25 @@ function parseMarkdownBlocks(text2) {
|
|
|
31056
31067
|
while (match = fence.exec(text2)) {
|
|
31057
31068
|
const prose = text2.slice(cursor, match.index).trim();
|
|
31058
31069
|
if (prose) {
|
|
31059
|
-
const language3 =
|
|
31060
|
-
blocks.push({ code: formatCodeBlock(prose, language3), language: language3 });
|
|
31070
|
+
const language3 = detectOutputLanguage(prose);
|
|
31071
|
+
blocks.push({ code: formatCodeBlock(prose, language3), fenced: false, language: language3 });
|
|
31061
31072
|
}
|
|
31062
31073
|
const language2 = normalizeLanguage(match[1]);
|
|
31063
31074
|
blocks.push({
|
|
31064
31075
|
code: formatCodeBlock(match[2] ?? "", language2),
|
|
31076
|
+
fenced: true,
|
|
31065
31077
|
language: language2
|
|
31066
31078
|
});
|
|
31067
31079
|
cursor = match.index + match[0].length;
|
|
31068
31080
|
}
|
|
31069
31081
|
const rest = text2.slice(cursor).trim();
|
|
31070
31082
|
if (rest) {
|
|
31071
|
-
const language2 =
|
|
31072
|
-
blocks.push({ code: formatCodeBlock(rest, language2), language: language2 });
|
|
31083
|
+
const language2 = detectOutputLanguage(rest);
|
|
31084
|
+
blocks.push({ code: formatCodeBlock(rest, language2), fenced: false, language: language2 });
|
|
31073
31085
|
}
|
|
31074
31086
|
if (blocks.length > 0) return blocks;
|
|
31075
|
-
const language =
|
|
31076
|
-
return [{ code: formatCodeBlock(text2, language), language }];
|
|
31087
|
+
const language = detectOutputLanguage(text2);
|
|
31088
|
+
return [{ code: formatCodeBlock(text2, language), fenced: false, language }];
|
|
31077
31089
|
}
|
|
31078
31090
|
function parseMarkupNodes(code, language) {
|
|
31079
31091
|
const parser = new DOMParser();
|
|
@@ -54731,7 +54743,7 @@ var import_react51 = __toESM(require_react(), 1);
|
|
|
54731
54743
|
var import_react50 = __toESM(require_react(), 1);
|
|
54732
54744
|
var import_jsx_runtime17 = __toESM(require_jsx_runtime(), 1);
|
|
54733
54745
|
function countStructuredBlockChildren(block) {
|
|
54734
|
-
if (!canRenderStructuredMarkup(block
|
|
54746
|
+
if (!canRenderStructuredMarkup(block)) return 1;
|
|
54735
54747
|
const rootCount = parseMarkupNodes(block.code, block.language).length;
|
|
54736
54748
|
return rootCount > 0 ? rootCount : 1;
|
|
54737
54749
|
}
|
|
@@ -54888,7 +54900,7 @@ function TranscriptText(props) {
|
|
|
54888
54900
|
const firstChildIndex = seenChildren;
|
|
54889
54901
|
const childCount = countStructuredBlockChildren(block);
|
|
54890
54902
|
seenChildren += childCount;
|
|
54891
|
-
if (!canRenderStructuredMarkup(block
|
|
54903
|
+
if (!canRenderStructuredMarkup(block)) {
|
|
54892
54904
|
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
54893
54905
|
HighlightedCode,
|
|
54894
54906
|
{
|
|
@@ -55531,7 +55543,7 @@ function ThinkingPartView(props) {
|
|
|
55531
55543
|
HighlightedCode,
|
|
55532
55544
|
{
|
|
55533
55545
|
code: rendered || "{}",
|
|
55534
|
-
language:
|
|
55546
|
+
language: detectOutputLanguage(rendered)
|
|
55535
55547
|
}
|
|
55536
55548
|
) })
|
|
55537
55549
|
]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/junior-dashboard",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.61.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"react-router": "^7.16.0",
|
|
40
40
|
"recharts": "^3.8.1",
|
|
41
41
|
"shiki": "4.1.0",
|
|
42
|
-
"@sentry/junior": "0.
|
|
42
|
+
"@sentry/junior": "0.61.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@tailwindcss/cli": "^4.3.0",
|
package/src/client/code.tsx
CHANGED
|
@@ -7,7 +7,7 @@ import type { CodeBlock, MarkupNode } from "./types";
|
|
|
7
7
|
|
|
8
8
|
/** Count rendered children so transcripts can decide which markup node expands. */
|
|
9
9
|
export function countStructuredBlockChildren(block: CodeBlock): number {
|
|
10
|
-
if (!canRenderStructuredMarkup(block
|
|
10
|
+
if (!canRenderStructuredMarkup(block)) return 1;
|
|
11
11
|
const rootCount = parseMarkupNodes(block.code, block.language).length;
|
|
12
12
|
return rootCount > 0 ? rootCount : 1;
|
|
13
13
|
}
|
|
@@ -21,7 +21,7 @@ export function TranscriptText(props: {
|
|
|
21
21
|
const childCount = countStructuredBlockChildren(block);
|
|
22
22
|
seenChildren += childCount;
|
|
23
23
|
|
|
24
|
-
if (!canRenderStructuredMarkup(block
|
|
24
|
+
if (!canRenderStructuredMarkup(block)) {
|
|
25
25
|
return (
|
|
26
26
|
<HighlightedCode
|
|
27
27
|
code={block.code}
|
|
@@ -3,6 +3,7 @@ import { useState, type ClipboardEventHandler, type ReactNode } from "react";
|
|
|
3
3
|
import { HighlightedCode } from "../code";
|
|
4
4
|
import {
|
|
5
5
|
detectLanguage,
|
|
6
|
+
detectOutputLanguage,
|
|
6
7
|
formatBytes,
|
|
7
8
|
formatMessageOffset,
|
|
8
9
|
formatMessageTimestamp,
|
|
@@ -494,7 +495,7 @@ function ThinkingPartView(props: { value: unknown }) {
|
|
|
494
495
|
<div className="border-t border-[#beaaff]/15 px-3 py-3">
|
|
495
496
|
<HighlightedCode
|
|
496
497
|
code={rendered || "{}"}
|
|
497
|
-
language={
|
|
498
|
+
language={detectOutputLanguage(rendered)}
|
|
498
499
|
/>
|
|
499
500
|
</div>
|
|
500
501
|
</details>
|
package/src/client/format.ts
CHANGED
|
@@ -511,9 +511,34 @@ function formatCodeBlock(code: string, language: BundledLanguage): string {
|
|
|
511
511
|
return language === "json" ? (prettyJsonData(code) ?? code) : code;
|
|
512
512
|
}
|
|
513
513
|
|
|
514
|
-
/**
|
|
515
|
-
|
|
516
|
-
|
|
514
|
+
/**
|
|
515
|
+
* Detect the language for LLM text output prose: json if the text is valid
|
|
516
|
+
* JSON or JSONL, markdown otherwise. Never auto-detects XML, HTML, TypeScript,
|
|
517
|
+
* or shell — those heuristics are unreliable for rendered assistant output.
|
|
518
|
+
*/
|
|
519
|
+
export function detectOutputLanguage(text: string): BundledLanguage {
|
|
520
|
+
const trimmed = text.trim();
|
|
521
|
+
if (!trimmed) return "markdown";
|
|
522
|
+
try {
|
|
523
|
+
JSON.parse(trimmed);
|
|
524
|
+
return "json";
|
|
525
|
+
} catch {
|
|
526
|
+
// continue
|
|
527
|
+
}
|
|
528
|
+
if (prettyJsonl(trimmed)) return "json";
|
|
529
|
+
return "markdown";
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Decide whether a fenced block can use the interactive markup renderer.
|
|
534
|
+
* Structured XML/HTML rendering is only enabled for explicitly-fenced blocks;
|
|
535
|
+
* auto-detected prose is never eligible regardless of inferred language.
|
|
536
|
+
*/
|
|
537
|
+
export function canRenderStructuredMarkup(block: CodeBlock): boolean {
|
|
538
|
+
return (
|
|
539
|
+
block.fenced === true &&
|
|
540
|
+
(block.language === "xml" || block.language === "html")
|
|
541
|
+
);
|
|
517
542
|
}
|
|
518
543
|
|
|
519
544
|
/** Parse markdown into renderable code blocks while preserving plain text blocks. */
|
|
@@ -525,24 +550,25 @@ export function parseMarkdownBlocks(text: string): CodeBlock[] {
|
|
|
525
550
|
while ((match = fence.exec(text))) {
|
|
526
551
|
const prose = text.slice(cursor, match.index).trim();
|
|
527
552
|
if (prose) {
|
|
528
|
-
const language =
|
|
529
|
-
blocks.push({ code: formatCodeBlock(prose, language), language });
|
|
553
|
+
const language = detectOutputLanguage(prose);
|
|
554
|
+
blocks.push({ code: formatCodeBlock(prose, language), fenced: false, language });
|
|
530
555
|
}
|
|
531
556
|
const language = normalizeLanguage(match[1]);
|
|
532
557
|
blocks.push({
|
|
533
558
|
code: formatCodeBlock(match[2] ?? "", language),
|
|
559
|
+
fenced: true,
|
|
534
560
|
language,
|
|
535
561
|
});
|
|
536
562
|
cursor = match.index + match[0].length;
|
|
537
563
|
}
|
|
538
564
|
const rest = text.slice(cursor).trim();
|
|
539
565
|
if (rest) {
|
|
540
|
-
const language =
|
|
541
|
-
blocks.push({ code: formatCodeBlock(rest, language), language });
|
|
566
|
+
const language = detectOutputLanguage(rest);
|
|
567
|
+
blocks.push({ code: formatCodeBlock(rest, language), fenced: false, language });
|
|
542
568
|
}
|
|
543
569
|
if (blocks.length > 0) return blocks;
|
|
544
|
-
const language =
|
|
545
|
-
return [{ code: formatCodeBlock(text, language), language }];
|
|
570
|
+
const language = detectOutputLanguage(text);
|
|
571
|
+
return [{ code: formatCodeBlock(text, language), fenced: false, language }];
|
|
546
572
|
}
|
|
547
573
|
|
|
548
574
|
/** Parse XML/HTML-ish fragments for the collapsible transcript renderer. */
|
package/src/client/types.ts
CHANGED
|
@@ -141,7 +141,7 @@ export type SessionFilter = "active" | "recent" | "hung" | "failed" | "all";
|
|
|
141
141
|
|
|
142
142
|
export type VisualStatus = "active" | "failed" | "hung" | "idle";
|
|
143
143
|
|
|
144
|
-
export type CodeBlock = { code: string; language: BundledLanguage };
|
|
144
|
+
export type CodeBlock = { code: string; fenced?: boolean; language: BundledLanguage };
|
|
145
145
|
|
|
146
146
|
export type MarkupNode =
|
|
147
147
|
| {
|