@lvce-editor/chat-view 2.9.0 → 2.10.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/chatViewWorkerMain.js +664 -60
- package/package.json +1 -1
|
@@ -1121,6 +1121,9 @@ const sendMessagePortToExtensionHostWorker$1 = async (port, rpcId = 0) => {
|
|
|
1121
1121
|
const activateByEvent$1 = (event, assetDir, platform) => {
|
|
1122
1122
|
return invoke('ExtensionHostManagement.activateByEvent', event, assetDir, platform);
|
|
1123
1123
|
};
|
|
1124
|
+
const getWorkspacePath = () => {
|
|
1125
|
+
return invoke('Workspace.getPath');
|
|
1126
|
+
};
|
|
1124
1127
|
const getPreference = async key => {
|
|
1125
1128
|
return await invoke('Preferences.get', key);
|
|
1126
1129
|
};
|
|
@@ -1543,8 +1546,56 @@ const create = (uid, x, y, width, height, platform, assetDir) => {
|
|
|
1543
1546
|
set(uid, state, state);
|
|
1544
1547
|
};
|
|
1545
1548
|
|
|
1549
|
+
const parseRenderHtmlArguments = rawArguments => {
|
|
1550
|
+
try {
|
|
1551
|
+
const parsed = JSON.parse(rawArguments);
|
|
1552
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
1553
|
+
return undefined;
|
|
1554
|
+
}
|
|
1555
|
+
const html = typeof Reflect.get(parsed, 'html') === 'string' ? String(Reflect.get(parsed, 'html')) : '';
|
|
1556
|
+
if (!html) {
|
|
1557
|
+
return undefined;
|
|
1558
|
+
}
|
|
1559
|
+
const css = typeof Reflect.get(parsed, 'css') === 'string' ? String(Reflect.get(parsed, 'css')) : '';
|
|
1560
|
+
const title = typeof Reflect.get(parsed, 'title') === 'string' ? String(Reflect.get(parsed, 'title')) : 'visual preview';
|
|
1561
|
+
return {
|
|
1562
|
+
css,
|
|
1563
|
+
html,
|
|
1564
|
+
title
|
|
1565
|
+
};
|
|
1566
|
+
} catch {
|
|
1567
|
+
return undefined;
|
|
1568
|
+
}
|
|
1569
|
+
};
|
|
1570
|
+
|
|
1571
|
+
const getRenderHtmlCss = (sessions, selectedSessionId) => {
|
|
1572
|
+
const selectedSession = sessions.find(session => session.id === selectedSessionId);
|
|
1573
|
+
if (!selectedSession) {
|
|
1574
|
+
return '';
|
|
1575
|
+
}
|
|
1576
|
+
const cssRules = new Set();
|
|
1577
|
+
for (const message of selectedSession.messages) {
|
|
1578
|
+
if (message.role !== 'assistant' || !message.toolCalls) {
|
|
1579
|
+
continue;
|
|
1580
|
+
}
|
|
1581
|
+
for (const toolCall of message.toolCalls) {
|
|
1582
|
+
if (toolCall.name !== 'render_html') {
|
|
1583
|
+
continue;
|
|
1584
|
+
}
|
|
1585
|
+
const parsed = parseRenderHtmlArguments(toolCall.arguments);
|
|
1586
|
+
if (!parsed || !parsed.css.trim()) {
|
|
1587
|
+
continue;
|
|
1588
|
+
}
|
|
1589
|
+
cssRules.add(parsed.css);
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
return [...cssRules].join('\n\n');
|
|
1593
|
+
};
|
|
1594
|
+
|
|
1546
1595
|
const isEqual$1 = (oldState, newState) => {
|
|
1547
|
-
|
|
1596
|
+
const oldRenderHtmlCss = getRenderHtmlCss(oldState.sessions, oldState.selectedSessionId);
|
|
1597
|
+
const newRenderHtmlCss = getRenderHtmlCss(newState.sessions, newState.selectedSessionId);
|
|
1598
|
+
return oldState.initial === newState.initial && oldState.chatMessageFontFamily === newState.chatMessageFontFamily && oldState.chatMessageFontSize === newState.chatMessageFontSize && oldState.chatMessageLineHeight === newState.chatMessageLineHeight && oldState.composerHeight === newState.composerHeight && oldState.composerLineHeight === newState.composerLineHeight && oldState.composerFontFamily === newState.composerFontFamily && oldState.composerFontSize === newState.composerFontSize && oldState.listItemHeight === newState.listItemHeight && oldRenderHtmlCss === newRenderHtmlCss;
|
|
1548
1599
|
};
|
|
1549
1600
|
|
|
1550
1601
|
const diffFocus = (oldState, newState) => {
|
|
@@ -1602,17 +1653,57 @@ const diff2 = uid => {
|
|
|
1602
1653
|
|
|
1603
1654
|
const Button$2 = 'button';
|
|
1604
1655
|
|
|
1656
|
+
const Audio = 0;
|
|
1605
1657
|
const Button$1 = 1;
|
|
1658
|
+
const Col = 2;
|
|
1659
|
+
const ColGroup = 3;
|
|
1606
1660
|
const Div = 4;
|
|
1661
|
+
const H1 = 5;
|
|
1607
1662
|
const Input = 6;
|
|
1608
1663
|
const Span = 8;
|
|
1664
|
+
const Table = 9;
|
|
1665
|
+
const TBody = 10;
|
|
1666
|
+
const Td = 11;
|
|
1609
1667
|
const Text = 12;
|
|
1668
|
+
const Th = 13;
|
|
1669
|
+
const THead = 14;
|
|
1670
|
+
const Tr = 15;
|
|
1671
|
+
const I = 16;
|
|
1672
|
+
const Img = 17;
|
|
1673
|
+
const H2 = 22;
|
|
1674
|
+
const H3 = 23;
|
|
1675
|
+
const H4 = 24;
|
|
1676
|
+
const H5 = 25;
|
|
1677
|
+
const H6 = 26;
|
|
1678
|
+
const Article = 27;
|
|
1679
|
+
const Aside = 28;
|
|
1680
|
+
const Footer = 29;
|
|
1681
|
+
const Header = 30;
|
|
1682
|
+
const Nav = 40;
|
|
1683
|
+
const Section = 41;
|
|
1684
|
+
const Dd = 43;
|
|
1685
|
+
const Dl = 44;
|
|
1686
|
+
const Figcaption = 45;
|
|
1687
|
+
const Figure = 46;
|
|
1688
|
+
const Hr = 47;
|
|
1610
1689
|
const Li = 48;
|
|
1611
1690
|
const Ol = 49;
|
|
1612
1691
|
const P = 50;
|
|
1692
|
+
const Pre = 51;
|
|
1693
|
+
const A = 53;
|
|
1694
|
+
const Abbr = 54;
|
|
1695
|
+
const Br = 55;
|
|
1696
|
+
const Tfoot = 59;
|
|
1697
|
+
const Ul = 60;
|
|
1613
1698
|
const TextArea = 62;
|
|
1614
1699
|
const Select$1 = 63;
|
|
1615
1700
|
const Option$1 = 64;
|
|
1701
|
+
const Code = 65;
|
|
1702
|
+
const Label$1 = 66;
|
|
1703
|
+
const Dt = 67;
|
|
1704
|
+
const Main = 69;
|
|
1705
|
+
const Strong = 70;
|
|
1706
|
+
const Em = 71;
|
|
1616
1707
|
const Reference = 100;
|
|
1617
1708
|
|
|
1618
1709
|
const Enter = 3;
|
|
@@ -3054,6 +3145,43 @@ const getMockOpenRouterAssistantText = async (messages, modelId, openRouterApiBa
|
|
|
3054
3145
|
}
|
|
3055
3146
|
};
|
|
3056
3147
|
|
|
3148
|
+
const executeGetWorkspaceUriTool = async (_args, _options) => {
|
|
3149
|
+
try {
|
|
3150
|
+
const workspaceUri = await getWorkspacePath();
|
|
3151
|
+
return JSON.stringify({
|
|
3152
|
+
workspaceUri
|
|
3153
|
+
});
|
|
3154
|
+
} catch (error) {
|
|
3155
|
+
return JSON.stringify({
|
|
3156
|
+
error: String(error)
|
|
3157
|
+
});
|
|
3158
|
+
}
|
|
3159
|
+
};
|
|
3160
|
+
|
|
3161
|
+
const isAbsoluteUri$1 = value => {
|
|
3162
|
+
return /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(value);
|
|
3163
|
+
};
|
|
3164
|
+
const executeListFilesTool = async (args, _options) => {
|
|
3165
|
+
const uri = typeof args.uri === 'string' ? args.uri : '';
|
|
3166
|
+
if (!uri || !isAbsoluteUri$1(uri)) {
|
|
3167
|
+
return JSON.stringify({
|
|
3168
|
+
error: 'Invalid argument: uri must be an absolute URI.'
|
|
3169
|
+
});
|
|
3170
|
+
}
|
|
3171
|
+
try {
|
|
3172
|
+
const entries = await invoke('FileSystem.readDirWithFileTypes', uri);
|
|
3173
|
+
return JSON.stringify({
|
|
3174
|
+
entries,
|
|
3175
|
+
uri
|
|
3176
|
+
});
|
|
3177
|
+
} catch (error) {
|
|
3178
|
+
return JSON.stringify({
|
|
3179
|
+
error: String(error),
|
|
3180
|
+
uri
|
|
3181
|
+
});
|
|
3182
|
+
}
|
|
3183
|
+
};
|
|
3184
|
+
|
|
3057
3185
|
const isPathTraversalAttempt = path => {
|
|
3058
3186
|
if (!path) {
|
|
3059
3187
|
return false;
|
|
@@ -3079,18 +3207,41 @@ const normalizeRelativePath = path => {
|
|
|
3079
3207
|
return segments.join('/');
|
|
3080
3208
|
};
|
|
3081
3209
|
|
|
3082
|
-
const
|
|
3083
|
-
|
|
3084
|
-
|
|
3210
|
+
const isAbsoluteUri = value => {
|
|
3211
|
+
return /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(value);
|
|
3212
|
+
};
|
|
3213
|
+
const executeReadFileTool = async (args, _options) => {
|
|
3214
|
+
const uri = typeof args.uri === 'string' ? args.uri : '';
|
|
3215
|
+
if (uri) {
|
|
3216
|
+
if (!isAbsoluteUri(uri)) {
|
|
3217
|
+
return JSON.stringify({
|
|
3218
|
+
error: 'Invalid argument: uri must be an absolute URI.'
|
|
3219
|
+
});
|
|
3220
|
+
}
|
|
3221
|
+
try {
|
|
3222
|
+
const content = await readFile(uri);
|
|
3223
|
+
return JSON.stringify({
|
|
3224
|
+
content,
|
|
3225
|
+
uri
|
|
3226
|
+
});
|
|
3227
|
+
} catch (error) {
|
|
3228
|
+
return JSON.stringify({
|
|
3229
|
+
error: String(error),
|
|
3230
|
+
uri
|
|
3231
|
+
});
|
|
3232
|
+
}
|
|
3233
|
+
}
|
|
3234
|
+
const filePath = typeof args.path === 'string' ? args.path : '';
|
|
3235
|
+
if (!filePath || isPathTraversalAttempt(filePath)) {
|
|
3085
3236
|
return JSON.stringify({
|
|
3086
3237
|
error: 'Access denied: path must be relative and stay within the open workspace folder.'
|
|
3087
3238
|
});
|
|
3088
3239
|
}
|
|
3089
|
-
const normalizedPath = normalizeRelativePath(
|
|
3240
|
+
const normalizedPath = normalizeRelativePath(filePath);
|
|
3090
3241
|
try {
|
|
3091
|
-
const
|
|
3242
|
+
const content = await readFile(normalizedPath);
|
|
3092
3243
|
return JSON.stringify({
|
|
3093
|
-
|
|
3244
|
+
content,
|
|
3094
3245
|
path: normalizedPath
|
|
3095
3246
|
});
|
|
3096
3247
|
} catch (error) {
|
|
@@ -3101,26 +3252,27 @@ const executeListFilesTool = async (args, _options) => {
|
|
|
3101
3252
|
}
|
|
3102
3253
|
};
|
|
3103
3254
|
|
|
3104
|
-
const
|
|
3105
|
-
|
|
3106
|
-
|
|
3255
|
+
const maxPayloadLength = 40_000;
|
|
3256
|
+
const executeRenderHtmlTool = async (args, _options) => {
|
|
3257
|
+
const html = typeof args.html === 'string' ? args.html : '';
|
|
3258
|
+
const css = typeof args.css === 'string' ? args.css : '';
|
|
3259
|
+
const title = typeof args.title === 'string' ? args.title : '';
|
|
3260
|
+
if (!html) {
|
|
3107
3261
|
return JSON.stringify({
|
|
3108
|
-
error: '
|
|
3262
|
+
error: 'Missing required argument: html'
|
|
3109
3263
|
});
|
|
3110
3264
|
}
|
|
3111
|
-
|
|
3112
|
-
try {
|
|
3113
|
-
const content = await readFile(normalizedPath);
|
|
3114
|
-
return JSON.stringify({
|
|
3115
|
-
content,
|
|
3116
|
-
path: normalizedPath
|
|
3117
|
-
});
|
|
3118
|
-
} catch (error) {
|
|
3265
|
+
if (html.length > maxPayloadLength || css.length > maxPayloadLength) {
|
|
3119
3266
|
return JSON.stringify({
|
|
3120
|
-
error:
|
|
3121
|
-
path: normalizedPath
|
|
3267
|
+
error: 'Payload too large: keep html/css under 40,000 characters each.'
|
|
3122
3268
|
});
|
|
3123
3269
|
}
|
|
3270
|
+
return JSON.stringify({
|
|
3271
|
+
css,
|
|
3272
|
+
html,
|
|
3273
|
+
ok: true,
|
|
3274
|
+
title
|
|
3275
|
+
});
|
|
3124
3276
|
};
|
|
3125
3277
|
|
|
3126
3278
|
const OnFileSystem = 'onFileSystem';
|
|
@@ -3185,30 +3337,39 @@ const executeChatTool = async (name, rawArguments, options) => {
|
|
|
3185
3337
|
if (name === 'list_files') {
|
|
3186
3338
|
return executeListFilesTool(args);
|
|
3187
3339
|
}
|
|
3340
|
+
if (name === 'getWorkspaceUri') {
|
|
3341
|
+
return executeGetWorkspaceUriTool();
|
|
3342
|
+
}
|
|
3343
|
+
if (name === 'render_html') {
|
|
3344
|
+
return executeRenderHtmlTool(args);
|
|
3345
|
+
}
|
|
3188
3346
|
return JSON.stringify({
|
|
3189
3347
|
error: `Unknown tool: ${name}`
|
|
3190
3348
|
});
|
|
3191
3349
|
};
|
|
3192
3350
|
|
|
3193
|
-
const
|
|
3194
|
-
return
|
|
3351
|
+
const getReadFileTool = () => {
|
|
3352
|
+
return {
|
|
3195
3353
|
function: {
|
|
3196
|
-
description: 'Read UTF-8 text content from a file inside the currently open workspace folder.',
|
|
3354
|
+
description: 'Read UTF-8 text content from a file inside the currently open workspace folder. Only pass an absolute URI.',
|
|
3197
3355
|
name: 'read_file',
|
|
3198
3356
|
parameters: {
|
|
3199
3357
|
additionalProperties: false,
|
|
3200
3358
|
properties: {
|
|
3201
|
-
|
|
3202
|
-
description: '
|
|
3359
|
+
uri: {
|
|
3360
|
+
description: 'Absolute file URI within the workspace (for example: file:///workspace/src/index.ts).',
|
|
3203
3361
|
type: 'string'
|
|
3204
3362
|
}
|
|
3205
3363
|
},
|
|
3206
|
-
required: ['
|
|
3364
|
+
required: ['uri'],
|
|
3207
3365
|
type: 'object'
|
|
3208
3366
|
}
|
|
3209
3367
|
},
|
|
3210
3368
|
type: 'function'
|
|
3211
|
-
}
|
|
3369
|
+
};
|
|
3370
|
+
};
|
|
3371
|
+
const getWriteFileTool = () => {
|
|
3372
|
+
return {
|
|
3212
3373
|
function: {
|
|
3213
3374
|
description: 'Write UTF-8 text content to a file inside the currently open workspace folder.',
|
|
3214
3375
|
name: 'write_file',
|
|
@@ -3229,23 +3390,72 @@ const getBasicChatTools = () => {
|
|
|
3229
3390
|
}
|
|
3230
3391
|
},
|
|
3231
3392
|
type: 'function'
|
|
3232
|
-
}
|
|
3393
|
+
};
|
|
3394
|
+
};
|
|
3395
|
+
const getListFilesTool = () => {
|
|
3396
|
+
return {
|
|
3233
3397
|
function: {
|
|
3234
|
-
description: 'List direct children (files and folders) for a folder inside the currently open workspace folder.',
|
|
3398
|
+
description: 'List direct children (files and folders) for a folder URI inside the currently open workspace folder. Only pass an absolute URI.',
|
|
3235
3399
|
name: 'list_files',
|
|
3236
3400
|
parameters: {
|
|
3237
3401
|
additionalProperties: false,
|
|
3238
3402
|
properties: {
|
|
3239
|
-
|
|
3240
|
-
description: '
|
|
3403
|
+
uri: {
|
|
3404
|
+
description: 'Absolute folder URI within the workspace (for example: file:///workspace/src).',
|
|
3241
3405
|
type: 'string'
|
|
3242
3406
|
}
|
|
3243
3407
|
},
|
|
3408
|
+
required: ['uri'],
|
|
3244
3409
|
type: 'object'
|
|
3245
3410
|
}
|
|
3246
3411
|
},
|
|
3247
3412
|
type: 'function'
|
|
3248
|
-
}
|
|
3413
|
+
};
|
|
3414
|
+
};
|
|
3415
|
+
const getGetWorkspaceUriTool = () => {
|
|
3416
|
+
return {
|
|
3417
|
+
function: {
|
|
3418
|
+
description: 'Get the URI of the currently open workspace folder.',
|
|
3419
|
+
name: 'getWorkspaceUri',
|
|
3420
|
+
parameters: {
|
|
3421
|
+
additionalProperties: false,
|
|
3422
|
+
properties: {},
|
|
3423
|
+
type: 'object'
|
|
3424
|
+
}
|
|
3425
|
+
},
|
|
3426
|
+
type: 'function'
|
|
3427
|
+
};
|
|
3428
|
+
};
|
|
3429
|
+
const getRenderHtmlTool = () => {
|
|
3430
|
+
return {
|
|
3431
|
+
function: {
|
|
3432
|
+
description: 'Render custom HTML and optional CSS directly in the chat tool call list using native chat UI rendering. Use this for structured cards, tables, and small dashboards. After calling this tool, do not repeat the same HTML, data table, or long content again as plain text unless the user explicitly asks for a text-only version.',
|
|
3433
|
+
name: 'render_html',
|
|
3434
|
+
parameters: {
|
|
3435
|
+
additionalProperties: false,
|
|
3436
|
+
properties: {
|
|
3437
|
+
css: {
|
|
3438
|
+
description: 'Optional CSS string applied inside the preview document.',
|
|
3439
|
+
type: 'string'
|
|
3440
|
+
},
|
|
3441
|
+
html: {
|
|
3442
|
+
description: 'HTML string to render in the preview document.',
|
|
3443
|
+
type: 'string'
|
|
3444
|
+
},
|
|
3445
|
+
title: {
|
|
3446
|
+
description: 'Optional short title for the preview.',
|
|
3447
|
+
type: 'string'
|
|
3448
|
+
}
|
|
3449
|
+
},
|
|
3450
|
+
required: ['html'],
|
|
3451
|
+
type: 'object'
|
|
3452
|
+
}
|
|
3453
|
+
},
|
|
3454
|
+
type: 'function'
|
|
3455
|
+
};
|
|
3456
|
+
};
|
|
3457
|
+
const getBasicChatTools = () => {
|
|
3458
|
+
return [getReadFileTool(), getWriteFileTool(), getListFilesTool(), getGetWorkspaceUriTool(), getRenderHtmlTool()];
|
|
3249
3459
|
};
|
|
3250
3460
|
|
|
3251
3461
|
const getClientRequestIdHeader = () => {
|
|
@@ -5665,8 +5875,8 @@ const openMockSession = async (state, mockSessionId, mockChatMessages) => {
|
|
|
5665
5875
|
};
|
|
5666
5876
|
};
|
|
5667
5877
|
|
|
5668
|
-
const getCss = (composerHeight, listItemHeight, chatMessageFontSize, chatMessageLineHeight, chatMessageFontFamily) => {
|
|
5669
|
-
|
|
5878
|
+
const getCss = (composerHeight, listItemHeight, chatMessageFontSize, chatMessageLineHeight, chatMessageFontFamily, renderHtmlCss) => {
|
|
5879
|
+
const baseCss = `:root {
|
|
5670
5880
|
--ChatInputBoxHeight: ${composerHeight}px;
|
|
5671
5881
|
--ChatListItemHeight: ${listItemHeight}px;
|
|
5672
5882
|
--ChatMessageFontSize: ${chatMessageFontSize}px;
|
|
@@ -5700,7 +5910,42 @@ const getCss = (composerHeight, listItemHeight, chatMessageFontSize, chatMessage
|
|
|
5700
5910
|
.ChatToolCallReadFileLink {
|
|
5701
5911
|
color: var(--vscode-textLink-foreground);
|
|
5702
5912
|
text-decoration: underline;
|
|
5913
|
+
}
|
|
5914
|
+
|
|
5915
|
+
.ChatToolCallRenderHtmlLabel {
|
|
5916
|
+
margin-bottom: 6px;
|
|
5917
|
+
color: var(--vscode-descriptionForeground);
|
|
5918
|
+
font-size: 12px;
|
|
5919
|
+
}
|
|
5920
|
+
|
|
5921
|
+
.ChatToolCallRenderHtmlContent {
|
|
5922
|
+
border: 1px solid var(--vscode-editorWidget-border);
|
|
5923
|
+
border-radius: 6px;
|
|
5924
|
+
background: var(--vscode-editor-background);
|
|
5925
|
+
overflow: hidden;
|
|
5926
|
+
}
|
|
5927
|
+
|
|
5928
|
+
.ChatToolCallRenderHtmlBody {
|
|
5929
|
+
min-height: 180px;
|
|
5930
|
+
padding: 12px;
|
|
5931
|
+
}
|
|
5932
|
+
|
|
5933
|
+
.ChatToolCallRenderHtmlBody * {
|
|
5934
|
+
box-sizing: border-box;
|
|
5935
|
+
}
|
|
5936
|
+
|
|
5937
|
+
.ChatMessageLink {
|
|
5938
|
+
color: #4d94ff;
|
|
5939
|
+
text-decoration: underline;
|
|
5940
|
+
cursor: pointer;
|
|
5703
5941
|
}`;
|
|
5942
|
+
if (!renderHtmlCss.trim()) {
|
|
5943
|
+
return baseCss;
|
|
5944
|
+
}
|
|
5945
|
+
return `${baseCss}
|
|
5946
|
+
|
|
5947
|
+
/* render_html tool css */
|
|
5948
|
+
${renderHtmlCss}`;
|
|
5704
5949
|
};
|
|
5705
5950
|
|
|
5706
5951
|
// TODO render things like scrollbar height,scrollbar offset, textarea height,
|
|
@@ -5713,9 +5958,12 @@ const renderCss = (oldState, newState) => {
|
|
|
5713
5958
|
chatMessageLineHeight,
|
|
5714
5959
|
composerHeight,
|
|
5715
5960
|
listItemHeight,
|
|
5961
|
+
selectedSessionId,
|
|
5962
|
+
sessions,
|
|
5716
5963
|
uid
|
|
5717
5964
|
} = newState;
|
|
5718
|
-
const
|
|
5965
|
+
const renderHtmlCss = getRenderHtmlCss(sessions, selectedSessionId);
|
|
5966
|
+
const css = getCss(composerHeight, listItemHeight, chatMessageFontSize, chatMessageLineHeight, chatMessageFontFamily, renderHtmlCss);
|
|
5719
5967
|
return [SetCss, uid, css];
|
|
5720
5968
|
};
|
|
5721
5969
|
|
|
@@ -5770,6 +6018,10 @@ const ChatMessageContent = 'ChatMessageContent';
|
|
|
5770
6018
|
const ChatToolCalls = 'ChatToolCalls';
|
|
5771
6019
|
const ChatToolCallsLabel = 'ChatToolCallsLabel';
|
|
5772
6020
|
const ChatToolCallReadFileLink = 'ChatToolCallReadFileLink';
|
|
6021
|
+
const ChatToolCallRenderHtmlLabel = 'ChatToolCallRenderHtmlLabel';
|
|
6022
|
+
const ChatToolCallRenderHtmlContent = 'ChatToolCallRenderHtmlContent';
|
|
6023
|
+
const ChatToolCallRenderHtmlBody = 'ChatToolCallRenderHtmlBody';
|
|
6024
|
+
const ChatMessageLink = 'ChatMessageLink';
|
|
5773
6025
|
const ChatOrderedList = 'ChatOrderedList';
|
|
5774
6026
|
const ChatOrderedListItem = 'ChatOrderedListItem';
|
|
5775
6027
|
const MessageUser = 'MessageUser';
|
|
@@ -5994,25 +6246,41 @@ const getChatHeaderDomDetailMode = selectedSessionTitle => {
|
|
|
5994
6246
|
}, text(selectedSessionTitle), ...getChatHeaderActionsDom()];
|
|
5995
6247
|
};
|
|
5996
6248
|
|
|
6249
|
+
const getInlineNodeDom = inlineNode => {
|
|
6250
|
+
if (inlineNode.type === 'text') {
|
|
6251
|
+
return [text(inlineNode.text)];
|
|
6252
|
+
}
|
|
6253
|
+
return [{
|
|
6254
|
+
childCount: 1,
|
|
6255
|
+
className: ChatMessageLink,
|
|
6256
|
+
href: inlineNode.href,
|
|
6257
|
+
rel: 'noopener noreferrer',
|
|
6258
|
+
target: '_blank',
|
|
6259
|
+
title: inlineNode.href,
|
|
6260
|
+
type: A
|
|
6261
|
+
}, text(inlineNode.text)];
|
|
6262
|
+
};
|
|
6263
|
+
|
|
6264
|
+
const getOrderedListItemDom = item => {
|
|
6265
|
+
return [{
|
|
6266
|
+
childCount: item.children.length,
|
|
6267
|
+
className: ChatOrderedListItem,
|
|
6268
|
+
type: Li
|
|
6269
|
+
}, ...item.children.flatMap(getInlineNodeDom)];
|
|
6270
|
+
};
|
|
5997
6271
|
const getMessageNodeDom = node => {
|
|
5998
6272
|
if (node.type === 'text') {
|
|
5999
6273
|
return [{
|
|
6000
|
-
childCount:
|
|
6274
|
+
childCount: node.children.length,
|
|
6001
6275
|
className: Markdown,
|
|
6002
6276
|
type: P
|
|
6003
|
-
},
|
|
6277
|
+
}, ...node.children.flatMap(getInlineNodeDom)];
|
|
6004
6278
|
}
|
|
6005
6279
|
return [{
|
|
6006
6280
|
childCount: node.items.length,
|
|
6007
6281
|
className: ChatOrderedList,
|
|
6008
6282
|
type: Ol
|
|
6009
|
-
}, ...node.items.flatMap(
|
|
6010
|
-
return [{
|
|
6011
|
-
childCount: 1,
|
|
6012
|
-
className: ChatOrderedListItem,
|
|
6013
|
-
type: Li
|
|
6014
|
-
}, text(item.text)];
|
|
6015
|
-
})];
|
|
6283
|
+
}, ...node.items.flatMap(getOrderedListItemDom)];
|
|
6016
6284
|
};
|
|
6017
6285
|
|
|
6018
6286
|
const getMessageContentDom = nodes => {
|
|
@@ -6167,7 +6435,7 @@ const getReadFileTarget = rawArguments => {
|
|
|
6167
6435
|
if (!title) {
|
|
6168
6436
|
return undefined;
|
|
6169
6437
|
}
|
|
6170
|
-
// `read_file` tool calls
|
|
6438
|
+
// `read_file` tool calls now use absolute `uri`; keep `path` as a legacy fallback for old transcripts.
|
|
6171
6439
|
const clickableUri = uriValue || pathValue;
|
|
6172
6440
|
return {
|
|
6173
6441
|
clickableUri,
|
|
@@ -6175,7 +6443,7 @@ const getReadFileTarget = rawArguments => {
|
|
|
6175
6443
|
};
|
|
6176
6444
|
};
|
|
6177
6445
|
|
|
6178
|
-
const getToolCallStatusLabel
|
|
6446
|
+
const getToolCallStatusLabel = toolCall => {
|
|
6179
6447
|
if (toolCall.status === 'not-found') {
|
|
6180
6448
|
return ' (not-found)';
|
|
6181
6449
|
}
|
|
@@ -6195,7 +6463,7 @@ const getToolCallReadFileVirtualDom = toolCall => {
|
|
|
6195
6463
|
}
|
|
6196
6464
|
const fileName = getFileNameFromUri(target.title);
|
|
6197
6465
|
const toolNameLabel = `${toolCall.name} `;
|
|
6198
|
-
const statusLabel = getToolCallStatusLabel
|
|
6466
|
+
const statusLabel = getToolCallStatusLabel(toolCall);
|
|
6199
6467
|
const fileNameClickableProps = target.clickableUri ? {
|
|
6200
6468
|
'data-uri': target.clickableUri,
|
|
6201
6469
|
onClick: HandleClickReadFile
|
|
@@ -6217,18 +6485,305 @@ const getToolCallReadFileVirtualDom = toolCall => {
|
|
|
6217
6485
|
}, text(fileName), ...(statusLabel ? [text(statusLabel)] : [])];
|
|
6218
6486
|
};
|
|
6219
6487
|
|
|
6220
|
-
const
|
|
6221
|
-
|
|
6222
|
-
|
|
6488
|
+
const maxHtmlLength = 40_000;
|
|
6489
|
+
const tokenRegex = /<!--[\s\S]*?-->|<\/?[a-zA-Z][\w:-]*(?:\s[^<>]*?)?>|[^<]+/g;
|
|
6490
|
+
const attributeRegex = /([^\s=/>]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g;
|
|
6491
|
+
const inlineTags = new Set(['a', 'abbr', 'b', 'code', 'em', 'i', 'label', 'small', 'span', 'strong', 'sub', 'sup', 'u']);
|
|
6492
|
+
const voidElements = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr']);
|
|
6493
|
+
const sanitizeHtml = value => {
|
|
6494
|
+
return value.slice(0, maxHtmlLength).replaceAll(/<script\b[\s\S]*?<\/script>/gi, '').replaceAll(/<style\b[\s\S]*?<\/style>/gi, '').replaceAll(/<head\b[\s\S]*?<\/head>/gi, '').replaceAll(/<meta\b[^>]*>/gi, '').replaceAll(/<link\b[^>]*>/gi, '');
|
|
6495
|
+
};
|
|
6496
|
+
const decodeEntities = value => {
|
|
6497
|
+
return value.replaceAll(' ', ' ').replaceAll('"', '"').replaceAll(''', "'").replaceAll('<', '<').replaceAll('>', '>').replaceAll('&', '&');
|
|
6498
|
+
};
|
|
6499
|
+
const parseAttributes = token => {
|
|
6500
|
+
const withoutTag = token.replace(/^<\/?\s*[a-zA-Z][\w:-]*/, '').replace(/\/?\s*>$/, '').trim();
|
|
6501
|
+
if (!withoutTag) {
|
|
6502
|
+
return Object.create(null);
|
|
6223
6503
|
}
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
|
|
6504
|
+
const attributes = Object.create(null);
|
|
6505
|
+
const matches = withoutTag.matchAll(attributeRegex);
|
|
6506
|
+
for (const match of matches) {
|
|
6507
|
+
const name = String(match[1] || '').toLowerCase();
|
|
6508
|
+
if (!name || name.startsWith('on')) {
|
|
6509
|
+
continue;
|
|
6227
6510
|
}
|
|
6228
|
-
|
|
6511
|
+
const value = String(match[2] ?? match[3] ?? match[4] ?? '');
|
|
6512
|
+
attributes[name] = decodeEntities(value);
|
|
6229
6513
|
}
|
|
6230
|
-
return
|
|
6514
|
+
return attributes;
|
|
6515
|
+
};
|
|
6516
|
+
const parseHtml = value => {
|
|
6517
|
+
const root = {
|
|
6518
|
+
attributes: Object.create(null),
|
|
6519
|
+
children: [],
|
|
6520
|
+
tagName: 'root',
|
|
6521
|
+
type: 'element'
|
|
6522
|
+
};
|
|
6523
|
+
const stack = [root];
|
|
6524
|
+
const matches = sanitizeHtml(value).match(tokenRegex);
|
|
6525
|
+
if (!matches) {
|
|
6526
|
+
return [];
|
|
6527
|
+
}
|
|
6528
|
+
for (const token of matches) {
|
|
6529
|
+
if (token.startsWith('<!--')) {
|
|
6530
|
+
continue;
|
|
6531
|
+
}
|
|
6532
|
+
if (token.startsWith('</')) {
|
|
6533
|
+
const closingTagName = token.slice(2, -1).trim().toLowerCase();
|
|
6534
|
+
while (stack.length > 1) {
|
|
6535
|
+
const top = stack.at(-1);
|
|
6536
|
+
if (!top) {
|
|
6537
|
+
break;
|
|
6538
|
+
}
|
|
6539
|
+
stack.pop();
|
|
6540
|
+
if (top.tagName === closingTagName) {
|
|
6541
|
+
break;
|
|
6542
|
+
}
|
|
6543
|
+
}
|
|
6544
|
+
continue;
|
|
6545
|
+
}
|
|
6546
|
+
if (token.startsWith('<')) {
|
|
6547
|
+
const openTagNameMatch = /^<\s*([a-zA-Z][\w:-]*)/.exec(token);
|
|
6548
|
+
if (!openTagNameMatch) {
|
|
6549
|
+
continue;
|
|
6550
|
+
}
|
|
6551
|
+
const tagName = openTagNameMatch[1].toLowerCase();
|
|
6552
|
+
const elementNode = {
|
|
6553
|
+
attributes: parseAttributes(token),
|
|
6554
|
+
children: [],
|
|
6555
|
+
tagName,
|
|
6556
|
+
type: 'element'
|
|
6557
|
+
};
|
|
6558
|
+
const parent = stack.at(-1);
|
|
6559
|
+
if (!parent) {
|
|
6560
|
+
continue;
|
|
6561
|
+
}
|
|
6562
|
+
parent.children.push(elementNode);
|
|
6563
|
+
const selfClosing = token.endsWith('/>') || voidElements.has(tagName);
|
|
6564
|
+
if (!selfClosing) {
|
|
6565
|
+
stack.push(elementNode);
|
|
6566
|
+
}
|
|
6567
|
+
continue;
|
|
6568
|
+
}
|
|
6569
|
+
const decoded = decodeEntities(token);
|
|
6570
|
+
if (!decoded) {
|
|
6571
|
+
continue;
|
|
6572
|
+
}
|
|
6573
|
+
const parent = stack.at(-1);
|
|
6574
|
+
if (!parent) {
|
|
6575
|
+
continue;
|
|
6576
|
+
}
|
|
6577
|
+
parent.children.push({
|
|
6578
|
+
type: 'text',
|
|
6579
|
+
value: decoded
|
|
6580
|
+
});
|
|
6581
|
+
}
|
|
6582
|
+
return root.children;
|
|
6583
|
+
};
|
|
6584
|
+
const getElementType = tagName => {
|
|
6585
|
+
switch (tagName) {
|
|
6586
|
+
case 'a':
|
|
6587
|
+
return A;
|
|
6588
|
+
case 'abbr':
|
|
6589
|
+
return Abbr;
|
|
6590
|
+
case 'article':
|
|
6591
|
+
return Article;
|
|
6592
|
+
case 'aside':
|
|
6593
|
+
return Aside;
|
|
6594
|
+
case 'audio':
|
|
6595
|
+
return Audio;
|
|
6596
|
+
case 'br':
|
|
6597
|
+
return Br;
|
|
6598
|
+
case 'button':
|
|
6599
|
+
return Button$1;
|
|
6600
|
+
case 'code':
|
|
6601
|
+
return Code;
|
|
6602
|
+
case 'col':
|
|
6603
|
+
return Col;
|
|
6604
|
+
case 'colgroup':
|
|
6605
|
+
return ColGroup;
|
|
6606
|
+
case 'dd':
|
|
6607
|
+
return Dd;
|
|
6608
|
+
case 'dl':
|
|
6609
|
+
return Dl;
|
|
6610
|
+
case 'dt':
|
|
6611
|
+
return Dt;
|
|
6612
|
+
case 'em':
|
|
6613
|
+
return Em;
|
|
6614
|
+
case 'figcaption':
|
|
6615
|
+
return Figcaption;
|
|
6616
|
+
case 'figure':
|
|
6617
|
+
return Figure;
|
|
6618
|
+
case 'footer':
|
|
6619
|
+
return Footer;
|
|
6620
|
+
case 'h1':
|
|
6621
|
+
return H1;
|
|
6622
|
+
case 'h2':
|
|
6623
|
+
return H2;
|
|
6624
|
+
case 'h3':
|
|
6625
|
+
return H3;
|
|
6626
|
+
case 'h4':
|
|
6627
|
+
return H4;
|
|
6628
|
+
case 'h5':
|
|
6629
|
+
return H5;
|
|
6630
|
+
case 'h6':
|
|
6631
|
+
return H6;
|
|
6632
|
+
case 'header':
|
|
6633
|
+
return Header;
|
|
6634
|
+
case 'hr':
|
|
6635
|
+
return Hr;
|
|
6636
|
+
case 'i':
|
|
6637
|
+
return I;
|
|
6638
|
+
case 'img':
|
|
6639
|
+
return Img;
|
|
6640
|
+
case 'input':
|
|
6641
|
+
return Input;
|
|
6642
|
+
case 'label':
|
|
6643
|
+
return Label$1;
|
|
6644
|
+
case 'li':
|
|
6645
|
+
return Li;
|
|
6646
|
+
case 'main':
|
|
6647
|
+
return Main;
|
|
6648
|
+
case 'nav':
|
|
6649
|
+
return Nav;
|
|
6650
|
+
case 'ol':
|
|
6651
|
+
return Ol;
|
|
6652
|
+
case 'option':
|
|
6653
|
+
return Option$1;
|
|
6654
|
+
case 'p':
|
|
6655
|
+
return P;
|
|
6656
|
+
case 'pre':
|
|
6657
|
+
return Pre;
|
|
6658
|
+
case 'section':
|
|
6659
|
+
return Section;
|
|
6660
|
+
case 'select':
|
|
6661
|
+
return Select$1;
|
|
6662
|
+
case 'span':
|
|
6663
|
+
return Span;
|
|
6664
|
+
case 'strong':
|
|
6665
|
+
return Strong;
|
|
6666
|
+
case 'table':
|
|
6667
|
+
return Table;
|
|
6668
|
+
case 'tbody':
|
|
6669
|
+
return TBody;
|
|
6670
|
+
case 'td':
|
|
6671
|
+
return Td;
|
|
6672
|
+
case 'textarea':
|
|
6673
|
+
return TextArea;
|
|
6674
|
+
case 'tfoot':
|
|
6675
|
+
return Tfoot;
|
|
6676
|
+
case 'th':
|
|
6677
|
+
return Th;
|
|
6678
|
+
case 'thead':
|
|
6679
|
+
return THead;
|
|
6680
|
+
case 'tr':
|
|
6681
|
+
return Tr;
|
|
6682
|
+
case 'ul':
|
|
6683
|
+
return Ul;
|
|
6684
|
+
default:
|
|
6685
|
+
return inlineTags.has(tagName) ? Span : Div;
|
|
6686
|
+
}
|
|
6687
|
+
};
|
|
6688
|
+
const normalizeUrl = url => {
|
|
6689
|
+
return url.toLowerCase().startsWith('javascript:') ? '#' : url;
|
|
6690
|
+
};
|
|
6691
|
+
const getElementAttributes = node => {
|
|
6692
|
+
const attributes = {};
|
|
6693
|
+
const className = node.attributes.class || node.attributes.classname;
|
|
6694
|
+
if (className) {
|
|
6695
|
+
attributes.className = className;
|
|
6696
|
+
}
|
|
6697
|
+
if (node.attributes.style) {
|
|
6698
|
+
attributes.style = node.attributes.style;
|
|
6699
|
+
}
|
|
6700
|
+
if (node.attributes.id) {
|
|
6701
|
+
attributes.id = node.attributes.id;
|
|
6702
|
+
}
|
|
6703
|
+
if (node.attributes.name) {
|
|
6704
|
+
attributes.name = node.attributes.name;
|
|
6705
|
+
}
|
|
6706
|
+
if (node.attributes.placeholder) {
|
|
6707
|
+
attributes.placeholder = node.attributes.placeholder;
|
|
6708
|
+
}
|
|
6709
|
+
if (node.attributes.title) {
|
|
6710
|
+
attributes.title = node.attributes.title;
|
|
6711
|
+
}
|
|
6712
|
+
if (node.attributes.value) {
|
|
6713
|
+
attributes.value = node.attributes.value;
|
|
6714
|
+
}
|
|
6715
|
+
if (node.attributes.href) {
|
|
6716
|
+
attributes.href = normalizeUrl(node.attributes.href);
|
|
6717
|
+
}
|
|
6718
|
+
if (node.attributes.src) {
|
|
6719
|
+
attributes.src = normalizeUrl(node.attributes.src);
|
|
6720
|
+
}
|
|
6721
|
+
if (node.attributes.target) {
|
|
6722
|
+
attributes.target = node.attributes.target;
|
|
6723
|
+
}
|
|
6724
|
+
if (node.attributes.rel) {
|
|
6725
|
+
attributes.rel = node.attributes.rel;
|
|
6726
|
+
}
|
|
6727
|
+
if ('checked' in node.attributes) {
|
|
6728
|
+
attributes.checked = node.attributes.checked !== 'false';
|
|
6729
|
+
}
|
|
6730
|
+
if ('disabled' in node.attributes) {
|
|
6731
|
+
attributes.disabled = node.attributes.disabled !== 'false';
|
|
6732
|
+
}
|
|
6733
|
+
if ('readonly' in node.attributes) {
|
|
6734
|
+
attributes.readOnly = node.attributes.readonly !== 'false';
|
|
6735
|
+
}
|
|
6736
|
+
return attributes;
|
|
6231
6737
|
};
|
|
6738
|
+
const toVirtualDom = node => {
|
|
6739
|
+
if (node.type === 'text') {
|
|
6740
|
+
return [text(node.value)];
|
|
6741
|
+
}
|
|
6742
|
+
const children = node.children.flatMap(toVirtualDom);
|
|
6743
|
+
return [{
|
|
6744
|
+
childCount: node.children.length,
|
|
6745
|
+
...getElementAttributes(node),
|
|
6746
|
+
type: getElementType(node.tagName)
|
|
6747
|
+
}, ...children];
|
|
6748
|
+
};
|
|
6749
|
+
const parseHtmlToVirtualDomWithRootCount = value => {
|
|
6750
|
+
const rootNodes = parseHtml(value);
|
|
6751
|
+
return {
|
|
6752
|
+
rootChildCount: rootNodes.length,
|
|
6753
|
+
virtualDom: rootNodes.flatMap(toVirtualDom)
|
|
6754
|
+
};
|
|
6755
|
+
};
|
|
6756
|
+
|
|
6757
|
+
const getToolCallRenderHtmlVirtualDom = toolCall => {
|
|
6758
|
+
const parsed = parseRenderHtmlArguments(toolCall.arguments);
|
|
6759
|
+
if (!parsed) {
|
|
6760
|
+
return [];
|
|
6761
|
+
}
|
|
6762
|
+
const statusLabel = getToolCallStatusLabel(toolCall);
|
|
6763
|
+
const label = `${toolCall.name}: ${parsed.title}${statusLabel}`;
|
|
6764
|
+
const parsedHtml = parseHtmlToVirtualDomWithRootCount(parsed.html);
|
|
6765
|
+
const {
|
|
6766
|
+
rootChildCount
|
|
6767
|
+
} = parsedHtml;
|
|
6768
|
+
return [{
|
|
6769
|
+
childCount: 2,
|
|
6770
|
+
className: ChatOrderedListItem,
|
|
6771
|
+
type: Li
|
|
6772
|
+
}, {
|
|
6773
|
+
childCount: 1,
|
|
6774
|
+
className: ChatToolCallRenderHtmlLabel,
|
|
6775
|
+
type: Div
|
|
6776
|
+
}, text(label), {
|
|
6777
|
+
childCount: 1,
|
|
6778
|
+
className: ChatToolCallRenderHtmlContent,
|
|
6779
|
+
type: Div
|
|
6780
|
+
}, {
|
|
6781
|
+
childCount: rootChildCount,
|
|
6782
|
+
className: ChatToolCallRenderHtmlBody,
|
|
6783
|
+
type: Div
|
|
6784
|
+
}, ...parsedHtml.virtualDom];
|
|
6785
|
+
};
|
|
6786
|
+
|
|
6232
6787
|
const getToolCallDom = toolCall => {
|
|
6233
6788
|
if (toolCall.name === 'read_file') {
|
|
6234
6789
|
const virtualDom = getToolCallReadFileVirtualDom(toolCall);
|
|
@@ -6236,6 +6791,12 @@ const getToolCallDom = toolCall => {
|
|
|
6236
6791
|
return virtualDom;
|
|
6237
6792
|
}
|
|
6238
6793
|
}
|
|
6794
|
+
if (toolCall.name === 'render_html') {
|
|
6795
|
+
const virtualDom = getToolCallRenderHtmlVirtualDom(toolCall);
|
|
6796
|
+
if (virtualDom.length > 0) {
|
|
6797
|
+
return virtualDom;
|
|
6798
|
+
}
|
|
6799
|
+
}
|
|
6239
6800
|
const argumentPreview = getToolCallArgumentPreview(toolCall.arguments);
|
|
6240
6801
|
const label = `${toolCall.name} ${argumentPreview}${getToolCallStatusLabel(toolCall)}`;
|
|
6241
6802
|
return [{
|
|
@@ -6265,10 +6826,50 @@ const getToolCallsDom = message => {
|
|
|
6265
6826
|
};
|
|
6266
6827
|
|
|
6267
6828
|
const orderedListItemRegex = /^\s*\d+\.\s+(.*)$/;
|
|
6829
|
+
const markdownLinkRegex = /\[([^\]]+)\]\(([^)]+)\)/g;
|
|
6830
|
+
const parseInlineNodes = value => {
|
|
6831
|
+
const matches = value.matchAll(markdownLinkRegex);
|
|
6832
|
+
const nodes = [];
|
|
6833
|
+
let lastIndex = 0;
|
|
6834
|
+
for (const match of matches) {
|
|
6835
|
+
const fullMatch = match[0];
|
|
6836
|
+
const linkText = match[1];
|
|
6837
|
+
const href = match[2];
|
|
6838
|
+
const index = match.index ?? 0;
|
|
6839
|
+
if (index > lastIndex) {
|
|
6840
|
+
nodes.push({
|
|
6841
|
+
text: value.slice(lastIndex, index),
|
|
6842
|
+
type: 'text'
|
|
6843
|
+
});
|
|
6844
|
+
}
|
|
6845
|
+
nodes.push({
|
|
6846
|
+
href,
|
|
6847
|
+
text: linkText,
|
|
6848
|
+
type: 'link'
|
|
6849
|
+
});
|
|
6850
|
+
lastIndex = index + fullMatch.length;
|
|
6851
|
+
}
|
|
6852
|
+
if (lastIndex < value.length) {
|
|
6853
|
+
nodes.push({
|
|
6854
|
+
text: value.slice(lastIndex),
|
|
6855
|
+
type: 'text'
|
|
6856
|
+
});
|
|
6857
|
+
}
|
|
6858
|
+
if (nodes.length === 0) {
|
|
6859
|
+
return [{
|
|
6860
|
+
text: value,
|
|
6861
|
+
type: 'text'
|
|
6862
|
+
}];
|
|
6863
|
+
}
|
|
6864
|
+
return nodes;
|
|
6865
|
+
};
|
|
6268
6866
|
const parseMessageContent = rawMessage => {
|
|
6269
6867
|
if (rawMessage === '') {
|
|
6270
6868
|
return [{
|
|
6271
|
-
|
|
6869
|
+
children: [{
|
|
6870
|
+
text: '',
|
|
6871
|
+
type: 'text'
|
|
6872
|
+
}],
|
|
6272
6873
|
type: 'text'
|
|
6273
6874
|
}];
|
|
6274
6875
|
}
|
|
@@ -6281,7 +6882,7 @@ const parseMessageContent = rawMessage => {
|
|
|
6281
6882
|
return;
|
|
6282
6883
|
}
|
|
6283
6884
|
nodes.push({
|
|
6284
|
-
|
|
6885
|
+
children: parseInlineNodes(paragraphLines.join('\n')),
|
|
6285
6886
|
type: 'text'
|
|
6286
6887
|
});
|
|
6287
6888
|
paragraphLines = [];
|
|
@@ -6306,7 +6907,7 @@ const parseMessageContent = rawMessage => {
|
|
|
6306
6907
|
if (match) {
|
|
6307
6908
|
flushParagraph();
|
|
6308
6909
|
listItems.push({
|
|
6309
|
-
|
|
6910
|
+
children: parseInlineNodes(match[1]),
|
|
6310
6911
|
type: 'list-item'
|
|
6311
6912
|
});
|
|
6312
6913
|
continue;
|
|
@@ -6317,7 +6918,10 @@ const parseMessageContent = rawMessage => {
|
|
|
6317
6918
|
flushList();
|
|
6318
6919
|
flushParagraph();
|
|
6319
6920
|
return nodes.length === 0 ? [{
|
|
6320
|
-
|
|
6921
|
+
children: [{
|
|
6922
|
+
text: '',
|
|
6923
|
+
type: 'text'
|
|
6924
|
+
}],
|
|
6321
6925
|
type: 'text'
|
|
6322
6926
|
}] : nodes;
|
|
6323
6927
|
};
|