@lvce-editor/chat-view 3.0.0 → 3.2.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 +212 -16
- package/package.json +1 -1
|
@@ -1508,7 +1508,7 @@ const createDefaultState = () => {
|
|
|
1508
1508
|
messages: [],
|
|
1509
1509
|
title: defaultSessionTitle()
|
|
1510
1510
|
}],
|
|
1511
|
-
streamingEnabled:
|
|
1511
|
+
streamingEnabled: true,
|
|
1512
1512
|
tokensMax: 0,
|
|
1513
1513
|
tokensUsed: 0,
|
|
1514
1514
|
uid: 0,
|
|
@@ -2740,18 +2740,28 @@ const deleteSession = async (state, id) => {
|
|
|
2740
2740
|
};
|
|
2741
2741
|
|
|
2742
2742
|
const handleClickOpenApiApiKeySettings = async state => {
|
|
2743
|
-
// Open the built-in settings editor so the user can inspect or edit their OpenAI API key.
|
|
2744
2743
|
await invoke('Main.openUri', 'app://settings.json');
|
|
2745
2744
|
return state;
|
|
2746
2745
|
};
|
|
2747
2746
|
|
|
2747
|
+
const handleClickOpenApiApiKeyWebsite = async state => {
|
|
2748
|
+
await openExternal(state.openApiApiKeysSettingsUrl);
|
|
2749
|
+
return state;
|
|
2750
|
+
};
|
|
2751
|
+
|
|
2748
2752
|
const handleClickOpenRouterApiKeySettings = async state => {
|
|
2753
|
+
await invoke('Main.openUri', 'app://settings.json');
|
|
2754
|
+
return state;
|
|
2755
|
+
};
|
|
2756
|
+
|
|
2757
|
+
const handleClickOpenRouterApiKeyWebsite = async state => {
|
|
2749
2758
|
await openExternal(state.openRouterApiKeysSettingsUrl);
|
|
2750
2759
|
return state;
|
|
2751
2760
|
};
|
|
2752
2761
|
|
|
2753
2762
|
const openApiApiKeyRequiredMessage = 'OpenAI API key is not configured. Enter your OpenAI API key below and click Save.';
|
|
2754
2763
|
const openApiRequestFailedMessage = 'OpenAI request failed.';
|
|
2764
|
+
const openApiRequestFailedOfflineMessage = 'OpenAI request failed because you are offline. Please check your internet connection.';
|
|
2755
2765
|
const openRouterApiKeyRequiredMessage = 'OpenRouter API key is not configured. Enter your OpenRouter API key below and click Save.';
|
|
2756
2766
|
const openRouterRequestFailedMessage = 'OpenRouter request failed. Possible reasons:';
|
|
2757
2767
|
const openRouterTooManyRequestsMessage = 'OpenRouter rate limit reached (429). Please try again soon. Helpful tips:';
|
|
@@ -4270,6 +4280,12 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
|
|
|
4270
4280
|
};
|
|
4271
4281
|
};
|
|
4272
4282
|
|
|
4283
|
+
const isOffline = () => {
|
|
4284
|
+
if (!globalThis.navigator) {
|
|
4285
|
+
return false;
|
|
4286
|
+
}
|
|
4287
|
+
return globalThis.navigator.onLine === false;
|
|
4288
|
+
};
|
|
4273
4289
|
const getOpenApiErrorMessage = errorResult => {
|
|
4274
4290
|
switch (errorResult.details) {
|
|
4275
4291
|
case 'http-error':
|
|
@@ -4281,7 +4297,7 @@ const getOpenApiErrorMessage = errorResult => {
|
|
|
4281
4297
|
// Provide a concise, user-friendly message when OpenAI reports an invalid API key.
|
|
4282
4298
|
if (errorResult.errorCode === 'invalid_api_key') {
|
|
4283
4299
|
const status = typeof errorResult.statusCode === 'number' ? errorResult.statusCode : 401;
|
|
4284
|
-
return `OpenAI request failed (
|
|
4300
|
+
return `OpenAI request failed (Status ${status}): Invalid API key. Please verify your OpenAI API key in Chat Settings.`;
|
|
4285
4301
|
}
|
|
4286
4302
|
if (errorResult.statusCode === 429) {
|
|
4287
4303
|
let prefix = 'OpenAI rate limit exceeded (429)';
|
|
@@ -4317,6 +4333,9 @@ const getOpenApiErrorMessage = errorResult => {
|
|
|
4317
4333
|
return openApiRequestFailedMessage;
|
|
4318
4334
|
}
|
|
4319
4335
|
case 'request-failed':
|
|
4336
|
+
if (isOffline()) {
|
|
4337
|
+
return openApiRequestFailedOfflineMessage;
|
|
4338
|
+
}
|
|
4320
4339
|
return openApiRequestFailedMessage;
|
|
4321
4340
|
}
|
|
4322
4341
|
};
|
|
@@ -4644,7 +4663,7 @@ const getAiResponse = async ({
|
|
|
4644
4663
|
passIncludeObfuscation = false,
|
|
4645
4664
|
platform,
|
|
4646
4665
|
selectedModelId,
|
|
4647
|
-
streamingEnabled =
|
|
4666
|
+
streamingEnabled = true,
|
|
4648
4667
|
useMockApi,
|
|
4649
4668
|
userText,
|
|
4650
4669
|
webSearchEnabled = false
|
|
@@ -4788,6 +4807,7 @@ const handleClickSaveOpenApiApiKey = async state => {
|
|
|
4788
4807
|
openRouterApiKey: updatedState.openRouterApiKey,
|
|
4789
4808
|
platform: updatedState.platform,
|
|
4790
4809
|
selectedModelId: updatedState.selectedModelId,
|
|
4810
|
+
streamingEnabled: updatedState.streamingEnabled,
|
|
4791
4811
|
useMockApi: updatedState.useMockApi,
|
|
4792
4812
|
userText: previousUserMessage.text
|
|
4793
4813
|
});
|
|
@@ -5275,11 +5295,13 @@ const getRenameIdFromInputName = name => {
|
|
|
5275
5295
|
const OpenApiApiKeyInput = 'open-api-api-key';
|
|
5276
5296
|
const SaveOpenApiApiKey = 'save-openapi-api-key';
|
|
5277
5297
|
const OpenOpenApiApiKeySettings = 'open-openapi-api-key-settings';
|
|
5298
|
+
const OpenOpenApiApiKeyWebsite = 'open-openapi-api-key-website';
|
|
5278
5299
|
|
|
5279
5300
|
// cspell:ignore openrouter
|
|
5280
5301
|
const OpenRouterApiKeyInput = 'open-router-api-key';
|
|
5281
5302
|
const SaveOpenRouterApiKey = 'save-openrouter-api-key';
|
|
5282
5303
|
const OpenOpenRouterApiKeySettings = 'open-openrouter-api-key-settings';
|
|
5304
|
+
const OpenOpenRouterApiKeyWebsite = 'open-openrouter-api-key-website';
|
|
5283
5305
|
|
|
5284
5306
|
const selectSession = async (state, id) => {
|
|
5285
5307
|
const exists = state.sessions.some(session => session.id === id);
|
|
@@ -5368,9 +5390,15 @@ const handleClick = async (state, name, id = '') => {
|
|
|
5368
5390
|
if (name === OpenOpenRouterApiKeySettings) {
|
|
5369
5391
|
return handleClickOpenRouterApiKeySettings(state);
|
|
5370
5392
|
}
|
|
5393
|
+
if (name === OpenOpenRouterApiKeyWebsite) {
|
|
5394
|
+
return handleClickOpenRouterApiKeyWebsite(state);
|
|
5395
|
+
}
|
|
5371
5396
|
if (name === OpenOpenApiApiKeySettings) {
|
|
5372
5397
|
return handleClickOpenApiApiKeySettings(state);
|
|
5373
5398
|
}
|
|
5399
|
+
if (name === OpenOpenApiApiKeyWebsite) {
|
|
5400
|
+
return handleClickOpenApiApiKeyWebsite(state);
|
|
5401
|
+
}
|
|
5374
5402
|
return state;
|
|
5375
5403
|
};
|
|
5376
5404
|
|
|
@@ -5724,9 +5752,9 @@ const loadPassIncludeObfuscation = async () => {
|
|
|
5724
5752
|
const loadStreamingEnabled = async () => {
|
|
5725
5753
|
try {
|
|
5726
5754
|
const savedStreamingEnabled = await get('chatView.streamingEnabled');
|
|
5727
|
-
return typeof savedStreamingEnabled === 'boolean' ? savedStreamingEnabled :
|
|
5755
|
+
return typeof savedStreamingEnabled === 'boolean' ? savedStreamingEnabled : true;
|
|
5728
5756
|
} catch {
|
|
5729
|
-
return
|
|
5757
|
+
return true;
|
|
5730
5758
|
}
|
|
5731
5759
|
};
|
|
5732
5760
|
|
|
@@ -5938,6 +5966,25 @@ const getCss = (composerHeight, listItemHeight, chatMessageFontSize, chatMessage
|
|
|
5938
5966
|
color: #4d94ff;
|
|
5939
5967
|
text-decoration: underline;
|
|
5940
5968
|
cursor: pointer;
|
|
5969
|
+
}
|
|
5970
|
+
|
|
5971
|
+
.MarkdownTable {
|
|
5972
|
+
width: 100%;
|
|
5973
|
+
margin: 6px 0;
|
|
5974
|
+
border-collapse: collapse;
|
|
5975
|
+
border: 1px solid var(--vscode-editorWidget-border);
|
|
5976
|
+
}
|
|
5977
|
+
|
|
5978
|
+
.MarkdownTable th,
|
|
5979
|
+
.MarkdownTable td {
|
|
5980
|
+
border: 1px solid var(--vscode-editorWidget-border);
|
|
5981
|
+
padding: 4px 8px;
|
|
5982
|
+
text-align: left;
|
|
5983
|
+
}
|
|
5984
|
+
|
|
5985
|
+
.MarkdownTable th {
|
|
5986
|
+
background: var(--vscode-editorWidget-background);
|
|
5987
|
+
}
|
|
5941
5988
|
}`;
|
|
5942
5989
|
if (!renderHtmlCss.trim()) {
|
|
5943
5990
|
return baseCss;
|
|
@@ -6013,6 +6060,7 @@ const ChatListEmpty = 'ChatListEmpty';
|
|
|
6013
6060
|
const ChatListItem = 'ChatListItem';
|
|
6014
6061
|
const ChatListItemLabel = 'ChatListItemLabel';
|
|
6015
6062
|
const Markdown = 'Markdown';
|
|
6063
|
+
const MarkdownTable = 'MarkdownTable';
|
|
6016
6064
|
const Message = 'Message';
|
|
6017
6065
|
const ChatMessageContent = 'ChatMessageContent';
|
|
6018
6066
|
const ChatToolCalls = 'ChatToolCalls';
|
|
@@ -6250,6 +6298,12 @@ const getInlineNodeDom = inlineNode => {
|
|
|
6250
6298
|
if (inlineNode.type === 'text') {
|
|
6251
6299
|
return [text(inlineNode.text)];
|
|
6252
6300
|
}
|
|
6301
|
+
if (inlineNode.type === 'bold') {
|
|
6302
|
+
return [{
|
|
6303
|
+
childCount: 1,
|
|
6304
|
+
type: Strong
|
|
6305
|
+
}, text(inlineNode.text)];
|
|
6306
|
+
}
|
|
6253
6307
|
return [{
|
|
6254
6308
|
childCount: 1,
|
|
6255
6309
|
className: ChatMessageLink,
|
|
@@ -6261,6 +6315,15 @@ const getInlineNodeDom = inlineNode => {
|
|
|
6261
6315
|
}, text(inlineNode.text)];
|
|
6262
6316
|
};
|
|
6263
6317
|
|
|
6318
|
+
const getCodeBlockDom = node => {
|
|
6319
|
+
return [{
|
|
6320
|
+
childCount: 1,
|
|
6321
|
+
type: Pre
|
|
6322
|
+
}, {
|
|
6323
|
+
childCount: 1,
|
|
6324
|
+
type: Code
|
|
6325
|
+
}, text(node.text)];
|
|
6326
|
+
};
|
|
6264
6327
|
const getOrderedListItemDom = item => {
|
|
6265
6328
|
return [{
|
|
6266
6329
|
childCount: item.children.length,
|
|
@@ -6268,6 +6331,40 @@ const getOrderedListItemDom = item => {
|
|
|
6268
6331
|
type: Li
|
|
6269
6332
|
}, ...item.children.flatMap(getInlineNodeDom)];
|
|
6270
6333
|
};
|
|
6334
|
+
const getTableHeadCellDom = cell => {
|
|
6335
|
+
return [{
|
|
6336
|
+
childCount: cell.children.length,
|
|
6337
|
+
type: Th
|
|
6338
|
+
}, ...cell.children.flatMap(getInlineNodeDom)];
|
|
6339
|
+
};
|
|
6340
|
+
const getTableBodyCellDom = cell => {
|
|
6341
|
+
return [{
|
|
6342
|
+
childCount: cell.children.length,
|
|
6343
|
+
type: Td
|
|
6344
|
+
}, ...cell.children.flatMap(getInlineNodeDom)];
|
|
6345
|
+
};
|
|
6346
|
+
const getTableRowDom = row => {
|
|
6347
|
+
return [{
|
|
6348
|
+
childCount: row.cells.length,
|
|
6349
|
+
type: Tr
|
|
6350
|
+
}, ...row.cells.flatMap(getTableBodyCellDom)];
|
|
6351
|
+
};
|
|
6352
|
+
const getTableDom = node => {
|
|
6353
|
+
return [{
|
|
6354
|
+
childCount: 2,
|
|
6355
|
+
className: MarkdownTable,
|
|
6356
|
+
type: Table
|
|
6357
|
+
}, {
|
|
6358
|
+
childCount: 1,
|
|
6359
|
+
type: THead
|
|
6360
|
+
}, {
|
|
6361
|
+
childCount: node.headers.length,
|
|
6362
|
+
type: Tr
|
|
6363
|
+
}, ...node.headers.flatMap(getTableHeadCellDom), {
|
|
6364
|
+
childCount: node.rows.length,
|
|
6365
|
+
type: TBody
|
|
6366
|
+
}, ...node.rows.flatMap(getTableRowDom)];
|
|
6367
|
+
};
|
|
6271
6368
|
const getMessageNodeDom = node => {
|
|
6272
6369
|
if (node.type === 'text') {
|
|
6273
6370
|
return [{
|
|
@@ -6276,6 +6373,12 @@ const getMessageNodeDom = node => {
|
|
|
6276
6373
|
type: P
|
|
6277
6374
|
}, ...node.children.flatMap(getInlineNodeDom)];
|
|
6278
6375
|
}
|
|
6376
|
+
if (node.type === 'table') {
|
|
6377
|
+
return getTableDom(node);
|
|
6378
|
+
}
|
|
6379
|
+
if (node.type === 'code-block') {
|
|
6380
|
+
return getCodeBlockDom(node);
|
|
6381
|
+
}
|
|
6279
6382
|
return [{
|
|
6280
6383
|
childCount: node.items.length,
|
|
6281
6384
|
className: ChatOrderedList,
|
|
@@ -6785,7 +6888,7 @@ const getToolCallRenderHtmlVirtualDom = toolCall => {
|
|
|
6785
6888
|
};
|
|
6786
6889
|
|
|
6787
6890
|
const getToolCallDom = toolCall => {
|
|
6788
|
-
if (toolCall.name === 'read_file') {
|
|
6891
|
+
if (toolCall.name === 'read_file' || toolCall.name === 'list_files' || toolCall.name === 'list_file') {
|
|
6789
6892
|
const virtualDom = getToolCallReadFileVirtualDom(toolCall);
|
|
6790
6893
|
if (virtualDom.length > 0) {
|
|
6791
6894
|
return virtualDom;
|
|
@@ -6826,15 +6929,62 @@ const getToolCallsDom = message => {
|
|
|
6826
6929
|
};
|
|
6827
6930
|
|
|
6828
6931
|
const orderedListItemRegex = /^\s*\d+\.\s+(.*)$/;
|
|
6829
|
-
const
|
|
6932
|
+
const markdownInlineRegex = /\[([^\]]+)\]\(([^)]+)\)|\*\*([^*]+)\*\*/g;
|
|
6933
|
+
const markdownTableSeparatorCellRegex = /^:?-{3,}:?$/;
|
|
6934
|
+
const fencedCodeBlockRegex = /^```/;
|
|
6935
|
+
const normalizeInlineTables = value => {
|
|
6936
|
+
return value.split(/\r?\n/).map(line => {
|
|
6937
|
+
if (!line.includes('|')) {
|
|
6938
|
+
return line;
|
|
6939
|
+
}
|
|
6940
|
+
if (!/\|\s*[-:]{3,}/.test(line)) {
|
|
6941
|
+
return line;
|
|
6942
|
+
}
|
|
6943
|
+
return line.replaceAll(/\|\s+\|/g, '|\n|');
|
|
6944
|
+
}).join('\n');
|
|
6945
|
+
};
|
|
6946
|
+
const isTableRow = line => {
|
|
6947
|
+
const trimmed = line.trim();
|
|
6948
|
+
if (!trimmed.startsWith('|') || !trimmed.endsWith('|')) {
|
|
6949
|
+
return false;
|
|
6950
|
+
}
|
|
6951
|
+
return trimmed.length > 2 && trimmed.slice(1, -1).includes('|');
|
|
6952
|
+
};
|
|
6953
|
+
const getTableCells = line => {
|
|
6954
|
+
const trimmed = line.trim();
|
|
6955
|
+
return trimmed.slice(1, -1).split('|').map(part => part.trim());
|
|
6956
|
+
};
|
|
6957
|
+
const isTableSeparatorRow = (line, expectedColumns) => {
|
|
6958
|
+
if (!isTableRow(line)) {
|
|
6959
|
+
return false;
|
|
6960
|
+
}
|
|
6961
|
+
const cells = getTableCells(line);
|
|
6962
|
+
if (cells.length !== expectedColumns) {
|
|
6963
|
+
return false;
|
|
6964
|
+
}
|
|
6965
|
+
return cells.every(cell => markdownTableSeparatorCellRegex.test(cell));
|
|
6966
|
+
};
|
|
6967
|
+
const toTableCell = value => {
|
|
6968
|
+
return {
|
|
6969
|
+
children: parseInlineNodes(value),
|
|
6970
|
+
type: 'table-cell'
|
|
6971
|
+
};
|
|
6972
|
+
};
|
|
6973
|
+
const toTableRow = line => {
|
|
6974
|
+
return {
|
|
6975
|
+
cells: getTableCells(line).map(toTableCell),
|
|
6976
|
+
type: 'table-row'
|
|
6977
|
+
};
|
|
6978
|
+
};
|
|
6830
6979
|
const parseInlineNodes = value => {
|
|
6831
|
-
const matches = value.matchAll(
|
|
6980
|
+
const matches = value.matchAll(markdownInlineRegex);
|
|
6832
6981
|
const nodes = [];
|
|
6833
6982
|
let lastIndex = 0;
|
|
6834
6983
|
for (const match of matches) {
|
|
6835
6984
|
const fullMatch = match[0];
|
|
6836
6985
|
const linkText = match[1];
|
|
6837
6986
|
const href = match[2];
|
|
6987
|
+
const boldText = match[3];
|
|
6838
6988
|
const index = match.index ?? 0;
|
|
6839
6989
|
if (index > lastIndex) {
|
|
6840
6990
|
nodes.push({
|
|
@@ -6842,11 +6992,18 @@ const parseInlineNodes = value => {
|
|
|
6842
6992
|
type: 'text'
|
|
6843
6993
|
});
|
|
6844
6994
|
}
|
|
6845
|
-
|
|
6846
|
-
|
|
6847
|
-
|
|
6848
|
-
|
|
6849
|
-
|
|
6995
|
+
if (linkText && href) {
|
|
6996
|
+
nodes.push({
|
|
6997
|
+
href,
|
|
6998
|
+
text: linkText,
|
|
6999
|
+
type: 'link'
|
|
7000
|
+
});
|
|
7001
|
+
} else if (boldText) {
|
|
7002
|
+
nodes.push({
|
|
7003
|
+
text: boldText,
|
|
7004
|
+
type: 'bold'
|
|
7005
|
+
});
|
|
7006
|
+
}
|
|
6850
7007
|
lastIndex = index + fullMatch.length;
|
|
6851
7008
|
}
|
|
6852
7009
|
if (lastIndex < value.length) {
|
|
@@ -6873,7 +7030,7 @@ const parseMessageContent = rawMessage => {
|
|
|
6873
7030
|
type: 'text'
|
|
6874
7031
|
}];
|
|
6875
7032
|
}
|
|
6876
|
-
const lines = rawMessage.split(/\r?\n/);
|
|
7033
|
+
const lines = normalizeInlineTables(rawMessage).split(/\r?\n/);
|
|
6877
7034
|
const nodes = [];
|
|
6878
7035
|
let paragraphLines = [];
|
|
6879
7036
|
let listItems = [];
|
|
@@ -6897,12 +7054,51 @@ const parseMessageContent = rawMessage => {
|
|
|
6897
7054
|
});
|
|
6898
7055
|
listItems = [];
|
|
6899
7056
|
};
|
|
6900
|
-
for (
|
|
7057
|
+
for (let i = 0; i < lines.length; i++) {
|
|
7058
|
+
const line = lines[i];
|
|
6901
7059
|
if (!line.trim()) {
|
|
6902
7060
|
flushList();
|
|
6903
7061
|
flushParagraph();
|
|
6904
7062
|
continue;
|
|
6905
7063
|
}
|
|
7064
|
+
if (fencedCodeBlockRegex.test(line.trim())) {
|
|
7065
|
+
flushList();
|
|
7066
|
+
flushParagraph();
|
|
7067
|
+
const codeLines = [];
|
|
7068
|
+
i++;
|
|
7069
|
+
while (i < lines.length && !fencedCodeBlockRegex.test(lines[i].trim())) {
|
|
7070
|
+
codeLines.push(lines[i]);
|
|
7071
|
+
i++;
|
|
7072
|
+
}
|
|
7073
|
+
nodes.push({
|
|
7074
|
+
text: codeLines.join('\n'),
|
|
7075
|
+
type: 'code-block'
|
|
7076
|
+
});
|
|
7077
|
+
continue;
|
|
7078
|
+
}
|
|
7079
|
+
if (isTableRow(line) && i + 1 < lines.length) {
|
|
7080
|
+
const headerCells = getTableCells(line);
|
|
7081
|
+
if (isTableSeparatorRow(lines[i + 1], headerCells.length)) {
|
|
7082
|
+
flushList();
|
|
7083
|
+
flushParagraph();
|
|
7084
|
+
const rows = [];
|
|
7085
|
+
i += 2;
|
|
7086
|
+
while (i < lines.length && isTableRow(lines[i])) {
|
|
7087
|
+
const row = toTableRow(lines[i]);
|
|
7088
|
+
if (row.cells.length === headerCells.length) {
|
|
7089
|
+
rows.push(row);
|
|
7090
|
+
}
|
|
7091
|
+
i++;
|
|
7092
|
+
}
|
|
7093
|
+
i--;
|
|
7094
|
+
nodes.push({
|
|
7095
|
+
headers: headerCells.map(toTableCell),
|
|
7096
|
+
rows,
|
|
7097
|
+
type: 'table'
|
|
7098
|
+
});
|
|
7099
|
+
continue;
|
|
7100
|
+
}
|
|
7101
|
+
}
|
|
6906
7102
|
const match = line.match(orderedListItemRegex);
|
|
6907
7103
|
if (match) {
|
|
6908
7104
|
flushParagraph();
|