@lvce-editor/chat-view 2.10.0 → 3.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/chatViewWorkerMain.js +179 -12
- package/package.json +1 -1
|
@@ -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
|
};
|
|
@@ -5275,11 +5294,13 @@ const getRenameIdFromInputName = name => {
|
|
|
5275
5294
|
const OpenApiApiKeyInput = 'open-api-api-key';
|
|
5276
5295
|
const SaveOpenApiApiKey = 'save-openapi-api-key';
|
|
5277
5296
|
const OpenOpenApiApiKeySettings = 'open-openapi-api-key-settings';
|
|
5297
|
+
const OpenOpenApiApiKeyWebsite = 'open-openapi-api-key-website';
|
|
5278
5298
|
|
|
5279
5299
|
// cspell:ignore openrouter
|
|
5280
5300
|
const OpenRouterApiKeyInput = 'open-router-api-key';
|
|
5281
5301
|
const SaveOpenRouterApiKey = 'save-openrouter-api-key';
|
|
5282
5302
|
const OpenOpenRouterApiKeySettings = 'open-openrouter-api-key-settings';
|
|
5303
|
+
const OpenOpenRouterApiKeyWebsite = 'open-openrouter-api-key-website';
|
|
5283
5304
|
|
|
5284
5305
|
const selectSession = async (state, id) => {
|
|
5285
5306
|
const exists = state.sessions.some(session => session.id === id);
|
|
@@ -5368,9 +5389,15 @@ const handleClick = async (state, name, id = '') => {
|
|
|
5368
5389
|
if (name === OpenOpenRouterApiKeySettings) {
|
|
5369
5390
|
return handleClickOpenRouterApiKeySettings(state);
|
|
5370
5391
|
}
|
|
5392
|
+
if (name === OpenOpenRouterApiKeyWebsite) {
|
|
5393
|
+
return handleClickOpenRouterApiKeyWebsite(state);
|
|
5394
|
+
}
|
|
5371
5395
|
if (name === OpenOpenApiApiKeySettings) {
|
|
5372
5396
|
return handleClickOpenApiApiKeySettings(state);
|
|
5373
5397
|
}
|
|
5398
|
+
if (name === OpenOpenApiApiKeyWebsite) {
|
|
5399
|
+
return handleClickOpenApiApiKeyWebsite(state);
|
|
5400
|
+
}
|
|
5374
5401
|
return state;
|
|
5375
5402
|
};
|
|
5376
5403
|
|
|
@@ -5938,6 +5965,25 @@ const getCss = (composerHeight, listItemHeight, chatMessageFontSize, chatMessage
|
|
|
5938
5965
|
color: #4d94ff;
|
|
5939
5966
|
text-decoration: underline;
|
|
5940
5967
|
cursor: pointer;
|
|
5968
|
+
}
|
|
5969
|
+
|
|
5970
|
+
.MarkdownTable {
|
|
5971
|
+
width: 100%;
|
|
5972
|
+
margin: 6px 0;
|
|
5973
|
+
border-collapse: collapse;
|
|
5974
|
+
border: 1px solid var(--vscode-editorWidget-border);
|
|
5975
|
+
}
|
|
5976
|
+
|
|
5977
|
+
.MarkdownTable th,
|
|
5978
|
+
.MarkdownTable td {
|
|
5979
|
+
border: 1px solid var(--vscode-editorWidget-border);
|
|
5980
|
+
padding: 4px 8px;
|
|
5981
|
+
text-align: left;
|
|
5982
|
+
}
|
|
5983
|
+
|
|
5984
|
+
.MarkdownTable th {
|
|
5985
|
+
background: var(--vscode-editorWidget-background);
|
|
5986
|
+
}
|
|
5941
5987
|
}`;
|
|
5942
5988
|
if (!renderHtmlCss.trim()) {
|
|
5943
5989
|
return baseCss;
|
|
@@ -6013,6 +6059,7 @@ const ChatListEmpty = 'ChatListEmpty';
|
|
|
6013
6059
|
const ChatListItem = 'ChatListItem';
|
|
6014
6060
|
const ChatListItemLabel = 'ChatListItemLabel';
|
|
6015
6061
|
const Markdown = 'Markdown';
|
|
6062
|
+
const MarkdownTable = 'MarkdownTable';
|
|
6016
6063
|
const Message = 'Message';
|
|
6017
6064
|
const ChatMessageContent = 'ChatMessageContent';
|
|
6018
6065
|
const ChatToolCalls = 'ChatToolCalls';
|
|
@@ -6250,6 +6297,12 @@ const getInlineNodeDom = inlineNode => {
|
|
|
6250
6297
|
if (inlineNode.type === 'text') {
|
|
6251
6298
|
return [text(inlineNode.text)];
|
|
6252
6299
|
}
|
|
6300
|
+
if (inlineNode.type === 'bold') {
|
|
6301
|
+
return [{
|
|
6302
|
+
childCount: 1,
|
|
6303
|
+
type: Strong
|
|
6304
|
+
}, text(inlineNode.text)];
|
|
6305
|
+
}
|
|
6253
6306
|
return [{
|
|
6254
6307
|
childCount: 1,
|
|
6255
6308
|
className: ChatMessageLink,
|
|
@@ -6268,6 +6321,40 @@ const getOrderedListItemDom = item => {
|
|
|
6268
6321
|
type: Li
|
|
6269
6322
|
}, ...item.children.flatMap(getInlineNodeDom)];
|
|
6270
6323
|
};
|
|
6324
|
+
const getTableHeadCellDom = cell => {
|
|
6325
|
+
return [{
|
|
6326
|
+
childCount: cell.children.length,
|
|
6327
|
+
type: Th
|
|
6328
|
+
}, ...cell.children.flatMap(getInlineNodeDom)];
|
|
6329
|
+
};
|
|
6330
|
+
const getTableBodyCellDom = cell => {
|
|
6331
|
+
return [{
|
|
6332
|
+
childCount: cell.children.length,
|
|
6333
|
+
type: Td
|
|
6334
|
+
}, ...cell.children.flatMap(getInlineNodeDom)];
|
|
6335
|
+
};
|
|
6336
|
+
const getTableRowDom = row => {
|
|
6337
|
+
return [{
|
|
6338
|
+
childCount: row.cells.length,
|
|
6339
|
+
type: Tr
|
|
6340
|
+
}, ...row.cells.flatMap(getTableBodyCellDom)];
|
|
6341
|
+
};
|
|
6342
|
+
const getTableDom = node => {
|
|
6343
|
+
return [{
|
|
6344
|
+
childCount: 2,
|
|
6345
|
+
className: MarkdownTable,
|
|
6346
|
+
type: Table
|
|
6347
|
+
}, {
|
|
6348
|
+
childCount: 1,
|
|
6349
|
+
type: THead
|
|
6350
|
+
}, {
|
|
6351
|
+
childCount: node.headers.length,
|
|
6352
|
+
type: Tr
|
|
6353
|
+
}, ...node.headers.flatMap(getTableHeadCellDom), {
|
|
6354
|
+
childCount: node.rows.length,
|
|
6355
|
+
type: TBody
|
|
6356
|
+
}, ...node.rows.flatMap(getTableRowDom)];
|
|
6357
|
+
};
|
|
6271
6358
|
const getMessageNodeDom = node => {
|
|
6272
6359
|
if (node.type === 'text') {
|
|
6273
6360
|
return [{
|
|
@@ -6276,6 +6363,9 @@ const getMessageNodeDom = node => {
|
|
|
6276
6363
|
type: P
|
|
6277
6364
|
}, ...node.children.flatMap(getInlineNodeDom)];
|
|
6278
6365
|
}
|
|
6366
|
+
if (node.type === 'table') {
|
|
6367
|
+
return getTableDom(node);
|
|
6368
|
+
}
|
|
6279
6369
|
return [{
|
|
6280
6370
|
childCount: node.items.length,
|
|
6281
6371
|
className: ChatOrderedList,
|
|
@@ -6785,7 +6875,7 @@ const getToolCallRenderHtmlVirtualDom = toolCall => {
|
|
|
6785
6875
|
};
|
|
6786
6876
|
|
|
6787
6877
|
const getToolCallDom = toolCall => {
|
|
6788
|
-
if (toolCall.name === 'read_file') {
|
|
6878
|
+
if (toolCall.name === 'read_file' || toolCall.name === 'list_files' || toolCall.name === 'list_file') {
|
|
6789
6879
|
const virtualDom = getToolCallReadFileVirtualDom(toolCall);
|
|
6790
6880
|
if (virtualDom.length > 0) {
|
|
6791
6881
|
return virtualDom;
|
|
@@ -6826,15 +6916,61 @@ const getToolCallsDom = message => {
|
|
|
6826
6916
|
};
|
|
6827
6917
|
|
|
6828
6918
|
const orderedListItemRegex = /^\s*\d+\.\s+(.*)$/;
|
|
6829
|
-
const
|
|
6919
|
+
const markdownInlineRegex = /\[([^\]]+)\]\(([^)]+)\)|\*\*([^*]+)\*\*/g;
|
|
6920
|
+
const markdownTableSeparatorCellRegex = /^:?-{3,}:?$/;
|
|
6921
|
+
const normalizeInlineTables = value => {
|
|
6922
|
+
return value.split(/\r?\n/).map(line => {
|
|
6923
|
+
if (!line.includes('|')) {
|
|
6924
|
+
return line;
|
|
6925
|
+
}
|
|
6926
|
+
if (!/\|\s*[-:]{3,}/.test(line)) {
|
|
6927
|
+
return line;
|
|
6928
|
+
}
|
|
6929
|
+
return line.replaceAll(/\|\s+\|/g, '|\n|');
|
|
6930
|
+
}).join('\n');
|
|
6931
|
+
};
|
|
6932
|
+
const isTableRow = line => {
|
|
6933
|
+
const trimmed = line.trim();
|
|
6934
|
+
if (!trimmed.startsWith('|') || !trimmed.endsWith('|')) {
|
|
6935
|
+
return false;
|
|
6936
|
+
}
|
|
6937
|
+
return trimmed.length > 2 && trimmed.slice(1, -1).includes('|');
|
|
6938
|
+
};
|
|
6939
|
+
const getTableCells = line => {
|
|
6940
|
+
const trimmed = line.trim();
|
|
6941
|
+
return trimmed.slice(1, -1).split('|').map(part => part.trim());
|
|
6942
|
+
};
|
|
6943
|
+
const isTableSeparatorRow = (line, expectedColumns) => {
|
|
6944
|
+
if (!isTableRow(line)) {
|
|
6945
|
+
return false;
|
|
6946
|
+
}
|
|
6947
|
+
const cells = getTableCells(line);
|
|
6948
|
+
if (cells.length !== expectedColumns) {
|
|
6949
|
+
return false;
|
|
6950
|
+
}
|
|
6951
|
+
return cells.every(cell => markdownTableSeparatorCellRegex.test(cell));
|
|
6952
|
+
};
|
|
6953
|
+
const toTableCell = value => {
|
|
6954
|
+
return {
|
|
6955
|
+
children: parseInlineNodes(value),
|
|
6956
|
+
type: 'table-cell'
|
|
6957
|
+
};
|
|
6958
|
+
};
|
|
6959
|
+
const toTableRow = line => {
|
|
6960
|
+
return {
|
|
6961
|
+
cells: getTableCells(line).map(toTableCell),
|
|
6962
|
+
type: 'table-row'
|
|
6963
|
+
};
|
|
6964
|
+
};
|
|
6830
6965
|
const parseInlineNodes = value => {
|
|
6831
|
-
const matches = value.matchAll(
|
|
6966
|
+
const matches = value.matchAll(markdownInlineRegex);
|
|
6832
6967
|
const nodes = [];
|
|
6833
6968
|
let lastIndex = 0;
|
|
6834
6969
|
for (const match of matches) {
|
|
6835
6970
|
const fullMatch = match[0];
|
|
6836
6971
|
const linkText = match[1];
|
|
6837
6972
|
const href = match[2];
|
|
6973
|
+
const boldText = match[3];
|
|
6838
6974
|
const index = match.index ?? 0;
|
|
6839
6975
|
if (index > lastIndex) {
|
|
6840
6976
|
nodes.push({
|
|
@@ -6842,11 +6978,18 @@ const parseInlineNodes = value => {
|
|
|
6842
6978
|
type: 'text'
|
|
6843
6979
|
});
|
|
6844
6980
|
}
|
|
6845
|
-
|
|
6846
|
-
|
|
6847
|
-
|
|
6848
|
-
|
|
6849
|
-
|
|
6981
|
+
if (linkText && href) {
|
|
6982
|
+
nodes.push({
|
|
6983
|
+
href,
|
|
6984
|
+
text: linkText,
|
|
6985
|
+
type: 'link'
|
|
6986
|
+
});
|
|
6987
|
+
} else if (boldText) {
|
|
6988
|
+
nodes.push({
|
|
6989
|
+
text: boldText,
|
|
6990
|
+
type: 'bold'
|
|
6991
|
+
});
|
|
6992
|
+
}
|
|
6850
6993
|
lastIndex = index + fullMatch.length;
|
|
6851
6994
|
}
|
|
6852
6995
|
if (lastIndex < value.length) {
|
|
@@ -6873,7 +7016,7 @@ const parseMessageContent = rawMessage => {
|
|
|
6873
7016
|
type: 'text'
|
|
6874
7017
|
}];
|
|
6875
7018
|
}
|
|
6876
|
-
const lines = rawMessage.split(/\r?\n/);
|
|
7019
|
+
const lines = normalizeInlineTables(rawMessage).split(/\r?\n/);
|
|
6877
7020
|
const nodes = [];
|
|
6878
7021
|
let paragraphLines = [];
|
|
6879
7022
|
let listItems = [];
|
|
@@ -6897,12 +7040,36 @@ const parseMessageContent = rawMessage => {
|
|
|
6897
7040
|
});
|
|
6898
7041
|
listItems = [];
|
|
6899
7042
|
};
|
|
6900
|
-
for (
|
|
7043
|
+
for (let i = 0; i < lines.length; i++) {
|
|
7044
|
+
const line = lines[i];
|
|
6901
7045
|
if (!line.trim()) {
|
|
6902
7046
|
flushList();
|
|
6903
7047
|
flushParagraph();
|
|
6904
7048
|
continue;
|
|
6905
7049
|
}
|
|
7050
|
+
if (isTableRow(line) && i + 1 < lines.length) {
|
|
7051
|
+
const headerCells = getTableCells(line);
|
|
7052
|
+
if (isTableSeparatorRow(lines[i + 1], headerCells.length)) {
|
|
7053
|
+
flushList();
|
|
7054
|
+
flushParagraph();
|
|
7055
|
+
const rows = [];
|
|
7056
|
+
i += 2;
|
|
7057
|
+
while (i < lines.length && isTableRow(lines[i])) {
|
|
7058
|
+
const row = toTableRow(lines[i]);
|
|
7059
|
+
if (row.cells.length === headerCells.length) {
|
|
7060
|
+
rows.push(row);
|
|
7061
|
+
}
|
|
7062
|
+
i++;
|
|
7063
|
+
}
|
|
7064
|
+
i--;
|
|
7065
|
+
nodes.push({
|
|
7066
|
+
headers: headerCells.map(toTableCell),
|
|
7067
|
+
rows,
|
|
7068
|
+
type: 'table'
|
|
7069
|
+
});
|
|
7070
|
+
continue;
|
|
7071
|
+
}
|
|
7072
|
+
}
|
|
6906
7073
|
const match = line.match(orderedListItemRegex);
|
|
6907
7074
|
if (match) {
|
|
6908
7075
|
flushParagraph();
|