@lvce-editor/chat-view 4.2.0 → 4.3.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.
@@ -1079,8 +1079,61 @@ const {
1079
1079
  set: set$3
1080
1080
  } = create$2(6002);
1081
1081
 
1082
- const Div$1 = 4;
1083
- const Ol$1 = 49;
1082
+ const Button$2 = 'button';
1083
+
1084
+ const Audio = 0;
1085
+ const Button$1 = 1;
1086
+ const Col = 2;
1087
+ const ColGroup = 3;
1088
+ const Div = 4;
1089
+ const H1 = 5;
1090
+ const Input = 6;
1091
+ const Span$1 = 8;
1092
+ const Table = 9;
1093
+ const TBody = 10;
1094
+ const Td = 11;
1095
+ const Text = 12;
1096
+ const Th = 13;
1097
+ const THead = 14;
1098
+ const Tr = 15;
1099
+ const I = 16;
1100
+ const Img$1 = 17;
1101
+ const H2 = 22;
1102
+ const H3 = 23;
1103
+ const H4 = 24;
1104
+ const H5 = 25;
1105
+ const H6 = 26;
1106
+ const Article = 27;
1107
+ const Aside = 28;
1108
+ const Footer = 29;
1109
+ const Header = 30;
1110
+ const Nav = 40;
1111
+ const Section = 41;
1112
+ const Dd = 43;
1113
+ const Dl = 44;
1114
+ const Figcaption = 45;
1115
+ const Figure = 46;
1116
+ const Hr = 47;
1117
+ const Li = 48;
1118
+ const Ol = 49;
1119
+ const P = 50;
1120
+ const Pre = 51;
1121
+ const A = 53;
1122
+ const Abbr = 54;
1123
+ const Br = 55;
1124
+ const Tfoot = 59;
1125
+ const Ul = 60;
1126
+ const TextArea = 62;
1127
+ const Select$1 = 63;
1128
+ const Option$1 = 64;
1129
+ const Code = 65;
1130
+ const Label$1 = 66;
1131
+ const Dt = 67;
1132
+ const Main = 69;
1133
+ const Strong = 70;
1134
+ const Em = 71;
1135
+ const Form = 78;
1136
+ const Reference = 100;
1084
1137
 
1085
1138
  const ClientX = 'event.clientX';
1086
1139
  const ClientY = 'event.clientY';
@@ -1089,6 +1142,10 @@ const ShiftKey = 'event.shiftKey';
1089
1142
  const TargetName = 'event.target.name';
1090
1143
  const TargetValue = 'event.target.value';
1091
1144
 
1145
+ const Enter = 3;
1146
+
1147
+ const Shift = 1 << 10 >>> 0;
1148
+
1092
1149
  const ExtensionHostWorker = 44;
1093
1150
  const RendererWorker = 1;
1094
1151
 
@@ -1376,6 +1433,9 @@ const openApiApiKeyPlaceholder = () => {
1376
1433
  const sendMessage = () => {
1377
1434
  return i18nString('Send message');
1378
1435
  };
1436
+ const startVoiceDictation = () => {
1437
+ return i18nString('Start voice dictation');
1438
+ };
1379
1439
  const save = () => {
1380
1440
  return i18nString('Save');
1381
1441
  };
@@ -1566,6 +1626,7 @@ const createDefaultState = () => {
1566
1626
  useChatNetworkWorkerForRequests: false,
1567
1627
  useMockApi: false,
1568
1628
  viewMode: 'list',
1629
+ voiceDictationEnabled: false,
1569
1630
  warningCount: 0,
1570
1631
  webSearchEnabled: true,
1571
1632
  width: 0,
@@ -2369,7 +2430,7 @@ const isEqualProjectExpandedIds = (a, b) => {
2369
2430
  return true;
2370
2431
  };
2371
2432
  const isEqual = (oldState, newState) => {
2372
- return oldState.composerDropActive === newState.composerDropActive && oldState.composerDropEnabled === newState.composerDropEnabled && oldState.composerValue === newState.composerValue && oldState.initial === newState.initial && isEqualProjectExpandedIds(oldState.projectExpandedIds, newState.projectExpandedIds) && oldState.projectListScrollTop === newState.projectListScrollTop && oldState.renamingSessionId === newState.renamingSessionId && oldState.selectedModelId === newState.selectedModelId && oldState.selectedProjectId === newState.selectedProjectId && oldState.selectedSessionId === newState.selectedSessionId && oldState.sessions === newState.sessions && oldState.tokensMax === newState.tokensMax && oldState.tokensUsed === newState.tokensUsed && oldState.usageOverviewEnabled === newState.usageOverviewEnabled && oldState.viewMode === newState.viewMode;
2433
+ return oldState.composerDropActive === newState.composerDropActive && oldState.composerDropEnabled === newState.composerDropEnabled && oldState.composerValue === newState.composerValue && oldState.initial === newState.initial && isEqualProjectExpandedIds(oldState.projectExpandedIds, newState.projectExpandedIds) && oldState.projectListScrollTop === newState.projectListScrollTop && oldState.renamingSessionId === newState.renamingSessionId && oldState.selectedModelId === newState.selectedModelId && oldState.selectedProjectId === newState.selectedProjectId && oldState.selectedSessionId === newState.selectedSessionId && oldState.sessions === newState.sessions && oldState.tokensMax === newState.tokensMax && oldState.tokensUsed === newState.tokensUsed && oldState.usageOverviewEnabled === newState.usageOverviewEnabled && oldState.viewMode === newState.viewMode && oldState.voiceDictationEnabled === newState.voiceDictationEnabled;
2373
2434
  };
2374
2435
 
2375
2436
  const diffScrollTop = (oldState, newState) => {
@@ -2414,65 +2475,6 @@ const diff2 = uid => {
2414
2475
  return result;
2415
2476
  };
2416
2477
 
2417
- const Button$2 = 'button';
2418
-
2419
- const Audio = 0;
2420
- const Button$1 = 1;
2421
- const Col = 2;
2422
- const ColGroup = 3;
2423
- const Div = 4;
2424
- const H1 = 5;
2425
- const Input = 6;
2426
- const Span$1 = 8;
2427
- const Table = 9;
2428
- const TBody = 10;
2429
- const Td = 11;
2430
- const Text = 12;
2431
- const Th = 13;
2432
- const THead = 14;
2433
- const Tr = 15;
2434
- const I = 16;
2435
- const Img$1 = 17;
2436
- const H2 = 22;
2437
- const H3 = 23;
2438
- const H4 = 24;
2439
- const H5 = 25;
2440
- const H6 = 26;
2441
- const Article = 27;
2442
- const Aside = 28;
2443
- const Footer = 29;
2444
- const Header = 30;
2445
- const Nav = 40;
2446
- const Section = 41;
2447
- const Dd = 43;
2448
- const Dl = 44;
2449
- const Figcaption = 45;
2450
- const Figure = 46;
2451
- const Hr = 47;
2452
- const Li = 48;
2453
- const Ol = 49;
2454
- const P = 50;
2455
- const Pre = 51;
2456
- const A = 53;
2457
- const Abbr = 54;
2458
- const Br = 55;
2459
- const Tfoot = 59;
2460
- const Ul = 60;
2461
- const TextArea = 62;
2462
- const Select$1 = 63;
2463
- const Option$1 = 64;
2464
- const Code = 65;
2465
- const Label$1 = 66;
2466
- const Dt = 67;
2467
- const Main = 69;
2468
- const Strong = 70;
2469
- const Em = 71;
2470
- const Reference = 100;
2471
-
2472
- const Enter = 3;
2473
-
2474
- const Shift = 1 << 10 >>> 0;
2475
-
2476
2478
  const mergeClassNames = (...classNames) => {
2477
2479
  return classNames.filter(Boolean).join(' ');
2478
2480
  };
@@ -3036,6 +3038,9 @@ const executeReadFileTool = async (args, _options) => {
3036
3038
  } catch (error) {
3037
3039
  return JSON.stringify({
3038
3040
  error: String(error),
3041
+ ...(error instanceof Error && typeof error.stack === 'string' ? {
3042
+ stack: error.stack
3043
+ } : {}),
3039
3044
  uri
3040
3045
  });
3041
3046
  }
@@ -3056,6 +3061,9 @@ const executeReadFileTool = async (args, _options) => {
3056
3061
  } catch (error) {
3057
3062
  return JSON.stringify({
3058
3063
  error: String(error),
3064
+ ...(error instanceof Error && typeof error.stack === 'string' ? {
3065
+ stack: error.stack
3066
+ } : {}),
3059
3067
  path: normalizedPath
3060
3068
  });
3061
3069
  }
@@ -3774,6 +3782,7 @@ const getToolCallExecutionStatus = content => {
3774
3782
  status: 'success'
3775
3783
  };
3776
3784
  }
3785
+ const rawErrorStack = Reflect.get(parsed, 'stack');
3777
3786
  const errorMessage = getShortToolErrorMessage(rawError);
3778
3787
  if (/not[\s_-]?found|enoent/i.test(errorMessage)) {
3779
3788
  return {
@@ -3782,6 +3791,9 @@ const getToolCallExecutionStatus = content => {
3782
3791
  }
3783
3792
  return {
3784
3793
  errorMessage,
3794
+ ...(typeof rawErrorStack === 'string' && rawErrorStack.trim() ? {
3795
+ errorStack: rawErrorStack
3796
+ } : {}),
3785
3797
  status: 'error'
3786
3798
  };
3787
3799
  };
@@ -4388,6 +4400,9 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
4388
4400
  ...(executionStatus.errorMessage ? {
4389
4401
  errorMessage: executionStatus.errorMessage
4390
4402
  } : {}),
4403
+ ...(executionStatus.errorStack ? {
4404
+ errorStack: executionStatus.errorStack
4405
+ } : {}),
4391
4406
  id: toolCall.callId,
4392
4407
  name: toolCall.name,
4393
4408
  ...(executionStatus.status ? {
@@ -4523,6 +4538,9 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
4523
4538
  ...(executionStatus.errorMessage ? {
4524
4539
  errorMessage: executionStatus.errorMessage
4525
4540
  } : {}),
4541
+ ...(executionStatus.errorStack ? {
4542
+ errorStack: executionStatus.errorStack
4543
+ } : {}),
4526
4544
  id: toolCall.callId,
4527
4545
  name: toolCall.name,
4528
4546
  ...(executionStatus.status ? {
@@ -4586,6 +4604,9 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
4586
4604
  ...(executionStatus.errorMessage ? {
4587
4605
  errorMessage: executionStatus.errorMessage
4588
4606
  } : {}),
4607
+ ...(executionStatus.errorStack ? {
4608
+ errorStack: executionStatus.errorStack
4609
+ } : {}),
4589
4610
  id,
4590
4611
  name,
4591
4612
  ...(executionStatus.status ? {
@@ -5960,6 +5981,7 @@ const handleClickSend = async state => {
5960
5981
 
5961
5982
  const Composer = 'composer';
5962
5983
  const ComposerDropTarget = 'composer-drop-target';
5984
+ const Dictate = 'dictate';
5963
5985
  const Send = 'send';
5964
5986
  const Back = 'back';
5965
5987
  const Model = 'model';
@@ -6201,6 +6223,10 @@ const handleClickDelete = async (state, sessionId = '') => {
6201
6223
  return deleteSession(state, sessionId);
6202
6224
  };
6203
6225
 
6226
+ const handleClickDictationButton = async state => {
6227
+ return state;
6228
+ };
6229
+
6204
6230
  const handleClickNew = async state => {
6205
6231
  return createSession(state);
6206
6232
  };
@@ -6666,8 +6692,17 @@ const loadUseChatNetworkWorkerForRequests = async () => {
6666
6692
  }
6667
6693
  };
6668
6694
 
6695
+ const loadVoiceDictationEnabled = async () => {
6696
+ try {
6697
+ const savedVoiceDictationEnabled = await get('chatView.voiceDictationEnabled');
6698
+ return typeof savedVoiceDictationEnabled === 'boolean' ? savedVoiceDictationEnabled : false;
6699
+ } catch {
6700
+ return false;
6701
+ }
6702
+ };
6703
+
6669
6704
  const loadPreferences = async () => {
6670
- const [aiSessionTitleGenerationEnabled, composerDropEnabled, openApiApiKey, openRouterApiKey, emitStreamingFunctionCallEvents, streamingEnabled, passIncludeObfuscation, useChatNetworkWorkerForRequests] = await Promise.all([loadAiSessionTitleGenerationEnabled(), loadComposerDropEnabled(), loadOpenApiApiKey(), loadOpenRouterApiKey(), loadEmitStreamingFunctionCallEvents(), loadStreamingEnabled(), loadPassIncludeObfuscation(), loadUseChatNetworkWorkerForRequests()]);
6705
+ const [aiSessionTitleGenerationEnabled, composerDropEnabled, openApiApiKey, openRouterApiKey, emitStreamingFunctionCallEvents, streamingEnabled, passIncludeObfuscation, useChatNetworkWorkerForRequests, voiceDictationEnabled] = await Promise.all([loadAiSessionTitleGenerationEnabled(), loadComposerDropEnabled(), loadOpenApiApiKey(), loadOpenRouterApiKey(), loadEmitStreamingFunctionCallEvents(), loadStreamingEnabled(), loadPassIncludeObfuscation(), loadUseChatNetworkWorkerForRequests(), loadVoiceDictationEnabled()]);
6671
6706
  return {
6672
6707
  aiSessionTitleGenerationEnabled,
6673
6708
  composerDropEnabled,
@@ -6676,7 +6711,8 @@ const loadPreferences = async () => {
6676
6711
  openRouterApiKey,
6677
6712
  passIncludeObfuscation,
6678
6713
  streamingEnabled,
6679
- useChatNetworkWorkerForRequests
6714
+ useChatNetworkWorkerForRequests,
6715
+ voiceDictationEnabled
6680
6716
  };
6681
6717
  };
6682
6718
 
@@ -6800,7 +6836,8 @@ const loadContent = async (state, savedState) => {
6800
6836
  openRouterApiKey,
6801
6837
  passIncludeObfuscation,
6802
6838
  streamingEnabled,
6803
- useChatNetworkWorkerForRequests
6839
+ useChatNetworkWorkerForRequests,
6840
+ voiceDictationEnabled
6804
6841
  } = await loadPreferences();
6805
6842
  const legacySavedSessions = getSavedSessions(savedState);
6806
6843
  const storedSessions = await listChatSessions();
@@ -6866,7 +6903,8 @@ const loadContent = async (state, savedState) => {
6866
6903
  sessions,
6867
6904
  streamingEnabled,
6868
6905
  useChatNetworkWorkerForRequests,
6869
- viewMode
6906
+ viewMode,
6907
+ voiceDictationEnabled
6870
6908
  };
6871
6909
  };
6872
6910
 
@@ -7325,6 +7363,7 @@ const HandleDragEnterChatView = 30;
7325
7363
  const HandleDragOverChatView = 31;
7326
7364
  const HandleProjectListScroll = 32;
7327
7365
  const HandleProjectListContextMenu = 33;
7366
+ const HandleClickDictationButton = 34;
7328
7367
 
7329
7368
  const getModelLabel = model => {
7330
7369
  if (model.provider === 'openRouter') {
@@ -7362,14 +7401,26 @@ const getSendButtonClassName = isSendDisabled => {
7362
7401
  return isSendDisabled ? `${IconButton} ${SendButtonDisabled}` : `${IconButton}`;
7363
7402
  };
7364
7403
 
7365
- const getSendButtonDom = isSendDisabled => {
7404
+ const getSendButtonDom = (isSendDisabled, voiceDictationEnabled) => {
7366
7405
  const sendButtonClassName = getSendButtonClassName(isSendDisabled);
7367
- return [{
7406
+ return [...(voiceDictationEnabled ? [{
7407
+ childCount: 1,
7408
+ className: IconButton,
7409
+ name: Dictate,
7410
+ onClick: HandleClickDictationButton,
7411
+ role: Button$2,
7412
+ title: startVoiceDictation(),
7413
+ type: Button$1
7414
+ }, {
7415
+ childCount: 0,
7416
+ className: 'MaskIcon MaskIconMic',
7417
+ type: Div
7418
+ }] : []), {
7419
+ buttonType: 'submit',
7368
7420
  childCount: 1,
7369
7421
  className: sendButtonClassName,
7370
7422
  disabled: isSendDisabled,
7371
7423
  name: Send,
7372
- onClick: HandleSubmit,
7373
7424
  role: Button$2,
7374
7425
  title: sendMessage(),
7375
7426
  type: Button$1
@@ -7415,12 +7466,14 @@ const getUsageOverviewDom = (tokensUsed, tokensMax) => {
7415
7466
  }, text$2(usageLabel)];
7416
7467
  };
7417
7468
 
7418
- const getChatSendAreaDom = (composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight = 28, composerFontSize = 13, composerFontFamily = 'system-ui', composerLineHeight = 20) => {
7469
+ const getChatSendAreaDom = (composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight = 28, composerFontSize = 13, composerFontFamily = 'system-ui', composerLineHeight = 20, voiceDictationEnabled = false) => {
7419
7470
  const isSendDisabled = composerValue.trim() === '';
7471
+ const controlsCount = usageOverviewEnabled ? 3 : 2;
7420
7472
  return [{
7421
7473
  childCount: 1,
7422
7474
  className: ChatSendArea,
7423
- type: Div
7475
+ onSubmit: HandleSubmit,
7476
+ type: Form
7424
7477
  }, {
7425
7478
  childCount: 2,
7426
7479
  className: ChatSendAreaContent,
@@ -7435,10 +7488,10 @@ const getChatSendAreaDom = (composerValue, models, selectedModelId, usageOvervie
7435
7488
  type: TextArea,
7436
7489
  value: composerValue
7437
7490
  }, {
7438
- childCount: usageOverviewEnabled ? 3 : 2,
7491
+ childCount: voiceDictationEnabled ? controlsCount + 1 : controlsCount,
7439
7492
  className: ChatSendAreaBottom,
7440
7493
  type: Div
7441
- }, ...getChatSelectVirtualDom(models, selectedModelId), ...(usageOverviewEnabled ? getUsageOverviewDom(tokensUsed, tokensMax) : []), ...getSendButtonDom(isSendDisabled)];
7494
+ }, ...getChatSelectVirtualDom(models, selectedModelId), ...(usageOverviewEnabled ? getUsageOverviewDom(tokensUsed, tokensMax) : []), ...getSendButtonDom(isSendDisabled, voiceDictationEnabled)];
7442
7495
  };
7443
7496
 
7444
7497
  /**
@@ -24383,11 +24436,17 @@ const getCodeBlockDom = node => {
24383
24436
  }, ...tokenDom];
24384
24437
  };
24385
24438
  const getOrderedListItemDom = item => {
24439
+ const hasNestedUnorderedList = (item.nestedItems?.length || 0) > 0;
24440
+ const nestedUnorderedListDom = hasNestedUnorderedList ? [{
24441
+ childCount: item.nestedItems?.length || 0,
24442
+ className: ChatUnorderedList,
24443
+ type: Ul
24444
+ }, ...(item.nestedItems || []).flatMap(getUnorderedListItemDom)] : [];
24386
24445
  return [{
24387
- childCount: item.children.length,
24446
+ childCount: item.children.length + (hasNestedUnorderedList ? 1 : 0),
24388
24447
  className: ChatOrderedListItem,
24389
24448
  type: Li
24390
- }, ...item.children.flatMap(getInlineNodeDom)];
24449
+ }, ...item.children.flatMap(getInlineNodeDom), ...nestedUnorderedListDom];
24391
24450
  };
24392
24451
  const getUnorderedListItemDom = item => {
24393
24452
  return [{
@@ -24805,20 +24864,20 @@ const getToolCallsDom = message => {
24805
24864
  return [{
24806
24865
  childCount: 2,
24807
24866
  className: ChatToolCalls,
24808
- type: Div$1
24867
+ type: Div
24809
24868
  }, {
24810
24869
  childCount: 1,
24811
24870
  className: ChatToolCallsLabel,
24812
- type: Div$1
24871
+ type: Div
24813
24872
  }, text$2('tools'), {
24814
24873
  childCount: message.toolCalls.length,
24815
24874
  className: ChatOrderedList,
24816
- type: Ol$1
24875
+ type: Ol
24817
24876
  }, ...message.toolCalls.flatMap(getToolCallDom)];
24818
24877
  };
24819
24878
 
24820
24879
  const orderedListItemRegex = /^\s*\d+\.\s+(.*)$/;
24821
- const unorderedListItemRegex = /^\s*[-*]\s+(.*)$/;
24880
+ const unorderedListItemRegex = /^(\s*)[-*]\s+(.*)$/;
24822
24881
  const markdownInlineRegex = /\[([^\]]+)\]\(([^)]+)\)|\*\*([^*]+)\*\*|\*([^*]+)\*|(?<![a-zA-Z0-9])(?<mathDollars>\${1,2})(?!\.|\(["'])(?<mathText>(?:\\.|[^\\\n])*?(?:\\.|[^\\\n$]))\k<mathDollars>(?![a-zA-Z0-9])/g;
24823
24882
  const markdownTableSeparatorCellRegex = /^:?-{3,}:?$/;
24824
24883
  const fencedCodeBlockRegex = /^```/;
@@ -25064,13 +25123,29 @@ const parseMessageContent = rawMessage => {
25064
25123
  }
25065
25124
  const unorderedMatch = line.match(unorderedListItemRegex);
25066
25125
  if (unorderedMatch) {
25126
+ const indentation = unorderedMatch[1];
25127
+ const unorderedText = unorderedMatch[2];
25128
+ if (listType === 'ordered-list' && listItems.length > 0 && indentation.length > 0) {
25129
+ const lastIndex = listItems.length - 1;
25130
+ const previousItem = listItems[lastIndex];
25131
+ const nestedItems = previousItem.nestedItems ? [...previousItem.nestedItems] : [];
25132
+ nestedItems.push({
25133
+ children: parseInlineNodes(unorderedText),
25134
+ type: 'list-item'
25135
+ });
25136
+ listItems[lastIndex] = {
25137
+ ...previousItem,
25138
+ nestedItems
25139
+ };
25140
+ continue;
25141
+ }
25067
25142
  if (listType && listType !== 'unordered-list') {
25068
25143
  flushList();
25069
25144
  }
25070
25145
  flushParagraph();
25071
25146
  listType = 'unordered-list';
25072
25147
  listItems.push({
25073
- children: parseInlineNodes(unorderedMatch[1]),
25148
+ children: parseInlineNodes(unorderedText),
25074
25149
  type: 'list-item'
25075
25150
  });
25076
25151
  continue;
@@ -25130,18 +25205,45 @@ const getEmptyMessagesDom = () => {
25130
25205
  }, text$2(startConversation())];
25131
25206
  };
25132
25207
 
25208
+ const hasMessageText = message => {
25209
+ return message.text.trim().length > 0;
25210
+ };
25211
+ const getDisplayMessages = messages => {
25212
+ const displayMessages = [];
25213
+ for (const message of messages) {
25214
+ if (message.role !== 'assistant' || !message.toolCalls || message.toolCalls.length === 0) {
25215
+ displayMessages.push(message);
25216
+ continue;
25217
+ }
25218
+ displayMessages.push({
25219
+ ...message,
25220
+ text: ''
25221
+ });
25222
+ if (hasMessageText(message)) {
25223
+ const {
25224
+ toolCalls: _toolCalls,
25225
+ ...messageWithoutToolCalls
25226
+ } = message;
25227
+ displayMessages.push({
25228
+ ...messageWithoutToolCalls
25229
+ });
25230
+ }
25231
+ }
25232
+ return displayMessages;
25233
+ };
25133
25234
  const getMessagesDom = (messages, openRouterApiKeyInput, openApiApiKeyInput = '', openRouterApiKeyState = 'idle', messagesScrollTop = 0) => {
25134
25235
  if (messages.length === 0) {
25135
25236
  return getEmptyMessagesDom();
25136
25237
  }
25238
+ const displayMessages = getDisplayMessages(messages);
25137
25239
  return [{
25138
- childCount: messages.length,
25240
+ childCount: displayMessages.length,
25139
25241
  className: 'ChatMessages',
25140
25242
  onContextMenu: HandleMessagesContextMenu,
25141
25243
  onScroll: HandleMessagesScroll,
25142
25244
  scrollTop: messagesScrollTop,
25143
25245
  type: Div
25144
- }, ...messages.flatMap(message => getChatMessageDom(message, openRouterApiKeyInput, openApiApiKeyInput, openRouterApiKeyState))];
25246
+ }, ...displayMessages.flatMap(message => getChatMessageDom(message, openRouterApiKeyInput, openApiApiKeyInput, openRouterApiKeyState))];
25145
25247
  };
25146
25248
 
25147
25249
  const getProjectSessionDom = (session, selectedSessionId) => {
@@ -25229,7 +25331,7 @@ const getProjectListDom = (projects, sessions, projectExpandedIds, selectedProje
25229
25331
  }, text$2('+ Add Project')];
25230
25332
  };
25231
25333
 
25232
- const getChatModeChatFocusVirtualDom = (sessions, selectedSessionId, composerValue, openRouterApiKeyInput, openApiApiKeyInput, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openRouterApiKeyState = 'idle', composerHeight = 28, composerFontSize = 13, composerFontFamily = 'system-ui', composerLineHeight = 20, messagesScrollTop = 0, composerDropActive = false, composerDropEnabled = true, projects = [], projectExpandedIds = [], selectedProjectId = '', projectListScrollTop = 0) => {
25334
+ const getChatModeChatFocusVirtualDom = (sessions, selectedSessionId, composerValue, openRouterApiKeyInput, openApiApiKeyInput, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openRouterApiKeyState = 'idle', composerHeight = 28, composerFontSize = 13, composerFontFamily = 'system-ui', composerLineHeight = 20, messagesScrollTop = 0, composerDropActive = false, composerDropEnabled = true, projects = [], projectExpandedIds = [], selectedProjectId = '', projectListScrollTop = 0, voiceDictationEnabled = false) => {
25233
25335
  const selectedSession = sessions.find(session => session.id === selectedSessionId);
25234
25336
  const selectedSessionTitle = selectedSession?.title || chatTitle();
25235
25337
  const messages = selectedSession ? selectedSession.messages : [];
@@ -25251,7 +25353,7 @@ const getChatModeChatFocusVirtualDom = (sessions, selectedSessionId, composerVal
25251
25353
  }, {
25252
25354
  text: selectedSessionTitle,
25253
25355
  type: Text
25254
- }, ...getProjectListDom(projects, sessions, projectExpandedIds, selectedProjectId, selectedSessionId, projectListScrollTop), ...getMessagesDom(messages, openRouterApiKeyInput, openApiApiKeyInput, openRouterApiKeyState, messagesScrollTop), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight, composerFontSize, composerFontFamily, composerLineHeight), {
25356
+ }, ...getProjectListDom(projects, sessions, projectExpandedIds, selectedProjectId, selectedSessionId, projectListScrollTop), ...getMessagesDom(messages, openRouterApiKeyInput, openApiApiKeyInput, openRouterApiKeyState, messagesScrollTop), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, voiceDictationEnabled), {
25255
25357
  childCount: 1,
25256
25358
  className: mergeClassNames(ChatViewDropOverlay, isDropOverlayVisible ? ChatViewDropOverlayActive : Empty),
25257
25359
  name: ComposerDropTarget,
@@ -25347,7 +25449,7 @@ const getChatHeaderDomDetailMode = selectedSessionTitle => {
25347
25449
  }, text$2(selectedSessionTitle), ...getChatHeaderActionsDom('detail')];
25348
25450
  };
25349
25451
 
25350
- const getChatModeDetailVirtualDom = (sessions, selectedSessionId, composerValue, openRouterApiKeyInput, openApiApiKeyInput, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openRouterApiKeyState = 'idle', composerHeight = 28, composerFontSize = 13, composerFontFamily = 'system-ui', composerLineHeight = 20, messagesScrollTop = 0, composerDropActive = false, composerDropEnabled = true) => {
25452
+ const getChatModeDetailVirtualDom = (sessions, selectedSessionId, composerValue, openRouterApiKeyInput, openApiApiKeyInput, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openRouterApiKeyState = 'idle', composerHeight = 28, composerFontSize = 13, composerFontFamily = 'system-ui', composerLineHeight = 20, messagesScrollTop = 0, composerDropActive = false, composerDropEnabled = true, voiceDictationEnabled = false) => {
25351
25453
  const selectedSession = sessions.find(session => session.id === selectedSessionId);
25352
25454
  const selectedSessionTitle = selectedSession?.title || chatTitle();
25353
25455
  const messages = selectedSession ? selectedSession.messages : [];
@@ -25358,7 +25460,7 @@ const getChatModeDetailVirtualDom = (sessions, selectedSessionId, composerValue,
25358
25460
  onDragEnter: HandleDragEnterChatView,
25359
25461
  onDragOver: HandleDragOverChatView,
25360
25462
  type: Div
25361
- }, ...getChatHeaderDomDetailMode(selectedSessionTitle), ...getMessagesDom(messages, openRouterApiKeyInput, openApiApiKeyInput, openRouterApiKeyState, messagesScrollTop), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight, composerFontSize, composerFontFamily, composerLineHeight), {
25463
+ }, ...getChatHeaderDomDetailMode(selectedSessionTitle), ...getMessagesDom(messages, openRouterApiKeyInput, openApiApiKeyInput, openRouterApiKeyState, messagesScrollTop), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, voiceDictationEnabled), {
25362
25464
  childCount: 1,
25363
25465
  className: mergeClassNames(ChatViewDropOverlay, isDropOverlayVisible ? ChatViewDropOverlayActive : Empty),
25364
25466
  name: ComposerDropTarget,
@@ -25439,7 +25541,7 @@ const getChatListDom = (sessions, selectedSessionId, chatListScrollTop = 0) => {
25439
25541
  }, ...sessions.flatMap(getSessionDom)];
25440
25542
  };
25441
25543
 
25442
- const getChatModeListVirtualDom = (sessions, selectedSessionId, composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight = 28, composerFontSize = 13, composerFontFamily = 'system-ui', composerLineHeight = 20, chatListScrollTop = 0, composerDropActive = false, composerDropEnabled = true) => {
25544
+ const getChatModeListVirtualDom = (sessions, selectedSessionId, composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight = 28, composerFontSize = 13, composerFontFamily = 'system-ui', composerLineHeight = 20, chatListScrollTop = 0, composerDropActive = false, composerDropEnabled = true, voiceDictationEnabled = false) => {
25443
25545
  const isDropOverlayVisible = composerDropEnabled && composerDropActive;
25444
25546
  return [{
25445
25547
  childCount: 4,
@@ -25447,7 +25549,7 @@ const getChatModeListVirtualDom = (sessions, selectedSessionId, composerValue, m
25447
25549
  onDragEnter: HandleDragEnterChatView,
25448
25550
  onDragOver: HandleDragOverChatView,
25449
25551
  type: Div
25450
- }, ...getChatHeaderListModeDom(), ...getChatListDom(sessions, selectedSessionId, chatListScrollTop), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight, composerFontSize, composerFontFamily, composerLineHeight), {
25552
+ }, ...getChatHeaderListModeDom(), ...getChatListDom(sessions, selectedSessionId, chatListScrollTop), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, voiceDictationEnabled), {
25451
25553
  childCount: 1,
25452
25554
  className: mergeClassNames(ChatViewDropOverlay, isDropOverlayVisible ? ChatViewDropOverlayActive : Empty),
25453
25555
  name: ComposerDropTarget,
@@ -25468,14 +25570,14 @@ const getChatModeUnsupportedVirtualDom = () => {
25468
25570
  }, text$2(unknownViewMode())];
25469
25571
  };
25470
25572
 
25471
- const getChatVirtualDom = (sessions, selectedSessionId, composerValue, openRouterApiKeyInput, viewMode, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openApiApiKeyInput, openRouterApiKeyState, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, chatListScrollTop, messagesScrollTop, composerDropActive = false, composerDropEnabled = true, projects = [], projectExpandedIds = [], selectedProjectId = '', projectListScrollTop = 0) => {
25573
+ const getChatVirtualDom = (sessions, selectedSessionId, composerValue, openRouterApiKeyInput, viewMode, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openApiApiKeyInput, openRouterApiKeyState, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, chatListScrollTop, messagesScrollTop, composerDropActive = false, composerDropEnabled = true, projects = [], projectExpandedIds = [], selectedProjectId = '', projectListScrollTop = 0, voiceDictationEnabled = false) => {
25472
25574
  switch (viewMode) {
25473
25575
  case 'chat-focus':
25474
- return getChatModeChatFocusVirtualDom(sessions, selectedSessionId, composerValue, openRouterApiKeyInput, openApiApiKeyInput, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openRouterApiKeyState, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, messagesScrollTop, composerDropActive, composerDropEnabled, projects, projectExpandedIds, selectedProjectId, projectListScrollTop);
25576
+ return getChatModeChatFocusVirtualDom(sessions, selectedSessionId, composerValue, openRouterApiKeyInput, openApiApiKeyInput, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openRouterApiKeyState, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, messagesScrollTop, composerDropActive, composerDropEnabled, projects, projectExpandedIds, selectedProjectId, projectListScrollTop, voiceDictationEnabled);
25475
25577
  case 'detail':
25476
- return getChatModeDetailVirtualDom(sessions, selectedSessionId, composerValue, openRouterApiKeyInput, openApiApiKeyInput, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openRouterApiKeyState, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, messagesScrollTop, composerDropActive, composerDropEnabled);
25578
+ return getChatModeDetailVirtualDom(sessions, selectedSessionId, composerValue, openRouterApiKeyInput, openApiApiKeyInput, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openRouterApiKeyState, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, messagesScrollTop, composerDropActive, composerDropEnabled, voiceDictationEnabled);
25477
25579
  case 'list':
25478
- return getChatModeListVirtualDom(sessions, selectedSessionId, composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, chatListScrollTop, composerDropActive, composerDropEnabled);
25580
+ return getChatModeListVirtualDom(sessions, selectedSessionId, composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, chatListScrollTop, composerDropActive, composerDropEnabled, voiceDictationEnabled);
25479
25581
  default:
25480
25582
  return getChatModeUnsupportedVirtualDom();
25481
25583
  }
@@ -25508,12 +25610,13 @@ const renderItems = (oldState, newState) => {
25508
25610
  tokensUsed,
25509
25611
  uid,
25510
25612
  usageOverviewEnabled,
25511
- viewMode
25613
+ viewMode,
25614
+ voiceDictationEnabled
25512
25615
  } = newState;
25513
25616
  if (initial) {
25514
25617
  return [SetDom2, uid, []];
25515
25618
  }
25516
- const dom = getChatVirtualDom(sessions, selectedSessionId, composerValue, openRouterApiKeyInput, viewMode, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openApiApiKeyInput, openRouterApiKeyState, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, chatListScrollTop, messagesScrollTop, composerDropActive, composerDropEnabled, projects, projectExpandedIds, selectedProjectId, projectListScrollTop);
25619
+ const dom = getChatVirtualDom(sessions, selectedSessionId, composerValue, openRouterApiKeyInput, viewMode, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openApiApiKeyInput, openRouterApiKeyState, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, chatListScrollTop, messagesScrollTop, composerDropActive, composerDropEnabled, projects, projectExpandedIds, selectedProjectId, projectListScrollTop, voiceDictationEnabled);
25517
25620
  return [SetDom2, uid, dom];
25518
25621
  };
25519
25622
 
@@ -25582,6 +25685,63 @@ const render2 = (uid, diffResult) => {
25582
25685
  return commands;
25583
25686
  };
25584
25687
 
25688
+ const handleDictateClickExpression = `(() => {
25689
+ const target = event.target?.closest?.('[name="dictate"]')
25690
+ if (!target) {
25691
+ return ''
25692
+ }
25693
+ const SpeechRecognitionClass = globalThis.SpeechRecognition || globalThis.webkitSpeechRecognition
25694
+ const composer = document.querySelector('[name="composer"]')
25695
+ if (!SpeechRecognitionClass || !composer || !('value' in composer)) {
25696
+ return ''
25697
+ }
25698
+ const state = globalThis.__chatViewDictationState || (globalThis.__chatViewDictationState = {})
25699
+ const existingRecognition = state.recognition
25700
+ if (existingRecognition) {
25701
+ existingRecognition.stop()
25702
+ state.recognition = undefined
25703
+ return ''
25704
+ }
25705
+ const initialValue = typeof composer.value === 'string' ? composer.value : ''
25706
+ const prefix = initialValue && !/\\s$/.test(initialValue) ? \`\${initialValue} \` : initialValue
25707
+ const updateComposerValue = (nextValue) => {
25708
+ composer.value = nextValue
25709
+ composer.dispatchEvent(new Event('input', { bubbles: true }))
25710
+ }
25711
+ const recognition = new SpeechRecognitionClass()
25712
+ recognition.continuous = true
25713
+ recognition.interimResults = true
25714
+ recognition.onresult = (speechEvent) => {
25715
+ let transcript = ''
25716
+ for (let i = 0; i < speechEvent.results.length; i++) {
25717
+ transcript += speechEvent.results[i][0]?.transcript || ''
25718
+ }
25719
+ updateComposerValue(prefix + transcript)
25720
+ }
25721
+ const clearRecognition = () => {
25722
+ if (state.recognition === recognition) {
25723
+ state.recognition = undefined
25724
+ }
25725
+ }
25726
+ recognition.onend = clearRecognition
25727
+ recognition.onerror = clearRecognition
25728
+ const startRecognition = () => {
25729
+ state.recognition = recognition
25730
+ recognition.start()
25731
+ }
25732
+ if (navigator.mediaDevices?.getUserMedia) {
25733
+ navigator.mediaDevices
25734
+ .getUserMedia({ audio: true })
25735
+ .then((stream) => {
25736
+ stream.getTracks().forEach((track) => track.stop())
25737
+ startRecognition()
25738
+ })
25739
+ .catch(() => {})
25740
+ return ''
25741
+ }
25742
+ startRecognition()
25743
+ return ''
25744
+ })()`;
25585
25745
  const renderEventListeners = () => {
25586
25746
  return [{
25587
25747
  name: HandleListContextMenu,
@@ -25590,6 +25750,9 @@ const renderEventListeners = () => {
25590
25750
  }, {
25591
25751
  name: HandleClick,
25592
25752
  params: ['handleClick', TargetName, 'event.target.dataset.id']
25753
+ }, {
25754
+ name: HandleClickDictationButton,
25755
+ params: ['handleClickDictationButton', handleDictateClickExpression]
25593
25756
  }, {
25594
25757
  name: HandleClickReadFile,
25595
25758
  params: ['handleClickReadFile', 'event.target.dataset.uri']
@@ -25811,6 +25974,7 @@ const commandMap = {
25811
25974
  'Chat.handleClickBack': wrapCommand(handleClickBack),
25812
25975
  'Chat.handleClickClose': handleClickClose,
25813
25976
  'Chat.handleClickDelete': wrapCommand(handleClickDelete),
25977
+ 'Chat.handleClickDictationButton': wrapCommand(handleClickDictationButton),
25814
25978
  'Chat.handleClickList': wrapCommand(handleClickList),
25815
25979
  'Chat.handleClickNew': wrapCommand(handleClickNew),
25816
25980
  'Chat.handleClickReadFile': handleClickReadFile,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/chat-view",
3
- "version": "4.2.0",
3
+ "version": "4.3.0",
4
4
  "description": "Chat View Worker",
5
5
  "repository": {
6
6
  "type": "git",