Skip to content

Commit f5b0ebc

Browse files
commit
1 parent 74d2157 commit f5b0ebc

1 file changed

Lines changed: 55 additions & 6 deletions

File tree

src/App/src/components/content/streaming/StreamingBufferMessage.tsx

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,59 @@ interface StreamingBufferMessageProps {
1313
}
1414

1515
/**
16-
* Wrap any raw JSON object/array blocks in markdown fenced code blocks so the
17-
* Details section renders them as formatted code rather than plain text.
18-
* Lines that already sit inside an existing fenced block are left alone.
16+
* Format a key from snake_case / camelCase / kebab-case into a readable label.
17+
*/
18+
const humanizeKey = (key: string): string => {
19+
if (!key) return key;
20+
const spaced = key
21+
.replace(/[_-]+/g, ' ')
22+
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
23+
.trim();
24+
return spaced.replace(/\b\w/g, (c) => c.toUpperCase());
25+
};
26+
27+
/**
28+
* Render a parsed JSON value as readable Markdown (bullet list of
29+
* "**Key**: value" entries, recursing into nested objects/arrays).
30+
*/
31+
const jsonToMarkdown = (value: any, depth = 0): string => {
32+
const indent = ' '.repeat(depth);
33+
34+
if (value === null || value === undefined) return `${indent}_n/a_`;
35+
36+
if (Array.isArray(value)) {
37+
if (value.length === 0) return `${indent}_(none)_`;
38+
return value
39+
.map((item) => {
40+
if (item !== null && typeof item === 'object') {
41+
return `${indent}- \n${jsonToMarkdown(item, depth + 1)}`;
42+
}
43+
return `${indent}- ${String(item)}`;
44+
})
45+
.join('\n');
46+
}
47+
48+
if (typeof value === 'object') {
49+
const entries = Object.entries(value);
50+
if (entries.length === 0) return `${indent}_(empty)_`;
51+
return entries
52+
.map(([k, v]) => {
53+
const label = humanizeKey(k);
54+
if (v !== null && typeof v === 'object') {
55+
return `${indent}- **${label}:**\n${jsonToMarkdown(v, depth + 1)}`;
56+
}
57+
return `${indent}- **${label}:** ${v === null || v === undefined ? '' : String(v)}`;
58+
})
59+
.join('\n');
60+
}
61+
62+
return `${indent}${String(value)}`;
63+
};
64+
65+
/**
66+
* Detect raw JSON blocks in the streaming buffer and replace them with a
67+
* readable Markdown rendering so the Details section doesn't expose raw JSON.
68+
* Lines that already sit inside an existing fenced code block are left alone.
1969
*/
2070
const formatBufferContent = (content: string): string => {
2171
if (!content) return content;
@@ -55,9 +105,8 @@ const formatBufferContent = (content: string): string => {
55105
const block = lines.slice(i, endIdx + 1).join('\n');
56106
try {
57107
const parsed = JSON.parse(block);
58-
out.push('```json');
59-
out.push(JSON.stringify(parsed, null, 2));
60-
out.push('```');
108+
out.push(jsonToMarkdown(parsed));
109+
out.push('');
61110
i = endIdx + 1;
62111
continue;
63112
} catch {

0 commit comments

Comments
 (0)