@lvce-editor/chat-view 4.2.0 → 4.4.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.
@@ -851,7 +851,7 @@ const invokeHelper = async (callbacks, ipc, method, params, useSendAndTransfer)
851
851
  const responseMessage = await promise;
852
852
  return unwrapJsonRpcResult(responseMessage);
853
853
  };
854
- const createRpc = ipc => {
854
+ const createRpc$1 = ipc => {
855
855
  const callbacks = Object.create(null);
856
856
  ipc._resolve = (id, response) => {
857
857
  const fn = callbacks[id];
@@ -931,7 +931,7 @@ const create$6 = async ({
931
931
  });
932
932
  const ipc = IpcParentWithMessagePort$1.wrap(rawIpc);
933
933
  handleIpc(ipc);
934
- const rpc = createRpc(ipc);
934
+ const rpc = createRpc$1(ipc);
935
935
  messagePort.start();
936
936
  return rpc;
937
937
  };
@@ -1002,7 +1002,7 @@ const create$3 = async ({
1002
1002
  register(commandMap);
1003
1003
  const ipc = await listen$1(IpcChildWithModuleWorkerAndMessagePort$1);
1004
1004
  handleIpc(ipc);
1005
- const rpc = createRpc(ipc);
1005
+ const rpc = createRpc$1(ipc);
1006
1006
  return rpc;
1007
1007
  };
1008
1008
 
@@ -1027,7 +1027,7 @@ const createMockRpc = ({
1027
1027
  };
1028
1028
 
1029
1029
  const rpcs = Object.create(null);
1030
- const set$4 = (id, rpc) => {
1030
+ const set$5 = (id, rpc) => {
1031
1031
  rpcs[id] = rpc;
1032
1032
  };
1033
1033
  const get$2 = id => {
@@ -1060,7 +1060,7 @@ const create$2 = rpcId => {
1060
1060
  const mockRpc = createMockRpc({
1061
1061
  commandMap
1062
1062
  });
1063
- set$4(rpcId, mockRpc);
1063
+ set$5(rpcId, mockRpc);
1064
1064
  // @ts-ignore
1065
1065
  mockRpc[Symbol.dispose] = () => {
1066
1066
  remove(rpcId);
@@ -1069,18 +1069,70 @@ const create$2 = rpcId => {
1069
1069
  return mockRpc;
1070
1070
  },
1071
1071
  set(rpc) {
1072
- set$4(rpcId, rpc);
1072
+ set$5(rpcId, rpc);
1073
1073
  }
1074
1074
  };
1075
1075
  };
1076
1076
 
1077
1077
  const {
1078
- invoke: invoke$2,
1079
- set: set$3
1080
- } = create$2(6002);
1078
+ set: set$4
1079
+ } = create$2(6007);
1081
1080
 
1082
- const Div$1 = 4;
1083
- const Ol$1 = 49;
1081
+ const Button$2 = 'button';
1082
+
1083
+ const Audio = 0;
1084
+ const Button$1 = 1;
1085
+ const Col = 2;
1086
+ const ColGroup = 3;
1087
+ const Div = 4;
1088
+ const H1 = 5;
1089
+ const Input = 6;
1090
+ const Span$1 = 8;
1091
+ const Table = 9;
1092
+ const TBody = 10;
1093
+ const Td = 11;
1094
+ const Text = 12;
1095
+ const Th = 13;
1096
+ const THead = 14;
1097
+ const Tr = 15;
1098
+ const I = 16;
1099
+ const Img$1 = 17;
1100
+ const H2 = 22;
1101
+ const H3 = 23;
1102
+ const H4 = 24;
1103
+ const H5 = 25;
1104
+ const H6 = 26;
1105
+ const Article = 27;
1106
+ const Aside = 28;
1107
+ const Footer = 29;
1108
+ const Header = 30;
1109
+ const Nav = 40;
1110
+ const Section = 41;
1111
+ const Dd = 43;
1112
+ const Dl = 44;
1113
+ const Figcaption = 45;
1114
+ const Figure = 46;
1115
+ const Hr = 47;
1116
+ const Li = 48;
1117
+ const Ol = 49;
1118
+ const P = 50;
1119
+ const Pre = 51;
1120
+ const A = 53;
1121
+ const Abbr = 54;
1122
+ const Br = 55;
1123
+ const Tfoot = 59;
1124
+ const Ul = 60;
1125
+ const TextArea = 62;
1126
+ const Select$1 = 63;
1127
+ const Option$1 = 64;
1128
+ const Code = 65;
1129
+ const Label$1 = 66;
1130
+ const Dt = 67;
1131
+ const Main = 69;
1132
+ const Strong = 70;
1133
+ const Em = 71;
1134
+ const Form = 78;
1135
+ const Reference = 100;
1084
1136
 
1085
1137
  const ClientX = 'event.clientX';
1086
1138
  const ClientY = 'event.clientY';
@@ -1089,6 +1141,11 @@ const ShiftKey = 'event.shiftKey';
1089
1141
  const TargetName = 'event.target.name';
1090
1142
  const TargetValue = 'event.target.value';
1091
1143
 
1144
+ const Enter = 3;
1145
+
1146
+ const Shift = 1 << 10 >>> 0;
1147
+
1148
+ const ChatNetworkWorker = 6002;
1092
1149
  const ExtensionHostWorker = 44;
1093
1150
  const RendererWorker = 1;
1094
1151
 
@@ -1102,6 +1159,11 @@ const SetPatches = 'Viewlet.setPatches';
1102
1159
 
1103
1160
  const FocusChatInput = 8000;
1104
1161
 
1162
+ const {
1163
+ invoke: invoke$2,
1164
+ set: set$3
1165
+ } = create$2(ChatNetworkWorker);
1166
+
1105
1167
  const {
1106
1168
  invoke: invoke$1,
1107
1169
  set: set$2
@@ -1376,6 +1438,9 @@ const openApiApiKeyPlaceholder = () => {
1376
1438
  const sendMessage = () => {
1377
1439
  return i18nString('Send message');
1378
1440
  };
1441
+ const startVoiceDictation = () => {
1442
+ return i18nString('Start voice dictation');
1443
+ };
1379
1444
  const save = () => {
1380
1445
  return i18nString('Save');
1381
1446
  };
@@ -1566,6 +1631,7 @@ const createDefaultState = () => {
1566
1631
  useChatNetworkWorkerForRequests: false,
1567
1632
  useMockApi: false,
1568
1633
  viewMode: 'list',
1634
+ voiceDictationEnabled: false,
1569
1635
  warningCount: 0,
1570
1636
  webSearchEnabled: true,
1571
1637
  width: 0,
@@ -2369,7 +2435,7 @@ const isEqualProjectExpandedIds = (a, b) => {
2369
2435
  return true;
2370
2436
  };
2371
2437
  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;
2438
+ 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
2439
  };
2374
2440
 
2375
2441
  const diffScrollTop = (oldState, newState) => {
@@ -2414,65 +2480,6 @@ const diff2 = uid => {
2414
2480
  return result;
2415
2481
  };
2416
2482
 
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
2483
  const mergeClassNames = (...classNames) => {
2477
2484
  return classNames.filter(Boolean).join(' ');
2478
2485
  };
@@ -2954,6 +2961,17 @@ const openRouterTooManyRequestsMessage = 'OpenRouter rate limit reached (429). P
2954
2961
  const openRouterRequestFailureReasons = ['ContentSecurityPolicyViolation: Check DevTools for details.', 'OpenRouter server offline: Check DevTools for details.', 'Check your internet connection.'];
2955
2962
  const openRouterTooManyRequestsReasons = ['Wait a short time and retry your request.', 'Reduce request frequency to avoid rate limits.', 'Use a different model if this one is saturated.'];
2956
2963
 
2964
+ const getToolErrorPayload = error => {
2965
+ const rawStack = error && typeof error === 'object' ? Reflect.get(error, 'stack') : undefined;
2966
+ return {
2967
+ error: String(error),
2968
+ ...(typeof rawStack === 'string' && rawStack.trim() ? {
2969
+ errorStack: rawStack,
2970
+ stack: rawStack
2971
+ } : {})
2972
+ };
2973
+ };
2974
+
2957
2975
  const executeGetWorkspaceUriTool = async (_args, _options) => {
2958
2976
  try {
2959
2977
  const workspaceUri = await getWorkspacePath();
@@ -2961,9 +2979,7 @@ const executeGetWorkspaceUriTool = async (_args, _options) => {
2961
2979
  workspaceUri
2962
2980
  });
2963
2981
  } catch (error) {
2964
- return JSON.stringify({
2965
- error: String(error)
2966
- });
2982
+ return JSON.stringify(getToolErrorPayload(error));
2967
2983
  }
2968
2984
  };
2969
2985
 
@@ -2985,7 +3001,7 @@ const executeListFilesTool = async (args, _options) => {
2985
3001
  });
2986
3002
  } catch (error) {
2987
3003
  return JSON.stringify({
2988
- error: String(error),
3004
+ ...getToolErrorPayload(error),
2989
3005
  uri
2990
3006
  });
2991
3007
  }
@@ -3035,7 +3051,7 @@ const executeReadFileTool = async (args, _options) => {
3035
3051
  });
3036
3052
  } catch (error) {
3037
3053
  return JSON.stringify({
3038
- error: String(error),
3054
+ ...getToolErrorPayload(error),
3039
3055
  uri
3040
3056
  });
3041
3057
  }
@@ -3055,7 +3071,7 @@ const executeReadFileTool = async (args, _options) => {
3055
3071
  });
3056
3072
  } catch (error) {
3057
3073
  return JSON.stringify({
3058
- error: String(error),
3074
+ ...getToolErrorPayload(error),
3059
3075
  path: normalizedPath
3060
3076
  });
3061
3077
  }
@@ -3101,7 +3117,7 @@ const executeWriteFileTool = async (args, _options) => {
3101
3117
  });
3102
3118
  } catch (error) {
3103
3119
  return JSON.stringify({
3104
- error: String(error),
3120
+ ...getToolErrorPayload(error),
3105
3121
  path: normalizedPath
3106
3122
  });
3107
3123
  }
@@ -3338,6 +3354,36 @@ const readNextChunk = async () => {
3338
3354
  return promise;
3339
3355
  };
3340
3356
 
3357
+ const getResponseFunctionCalls$1 = value => {
3358
+ if (!value || typeof value !== 'object') {
3359
+ return [];
3360
+ }
3361
+ const output = Reflect.get(value, 'output');
3362
+ if (!Array.isArray(output)) {
3363
+ return [];
3364
+ }
3365
+ const responseFunctionCalls = [];
3366
+ for (const item of output) {
3367
+ if (!item || typeof item !== 'object') {
3368
+ continue;
3369
+ }
3370
+ if (Reflect.get(item, 'type') !== 'function_call') {
3371
+ continue;
3372
+ }
3373
+ const callId = Reflect.get(item, 'call_id');
3374
+ const name = Reflect.get(item, 'name');
3375
+ const rawArguments = Reflect.get(item, 'arguments');
3376
+ if (typeof callId !== 'string' || typeof name !== 'string') {
3377
+ continue;
3378
+ }
3379
+ responseFunctionCalls.push({
3380
+ arguments: typeof rawArguments === 'string' ? rawArguments : '',
3381
+ callId,
3382
+ name
3383
+ });
3384
+ }
3385
+ return responseFunctionCalls;
3386
+ };
3341
3387
  const parseSseDataLines = eventChunk => {
3342
3388
  const lines = eventChunk.split('\n');
3343
3389
  const dataLines = [];
@@ -3367,6 +3413,9 @@ const getMockOpenApiAssistantText = async (stream, onTextChunk, onToolCallsChunk
3367
3413
  let text = '';
3368
3414
  let remainder = '';
3369
3415
  let toolCallAccumulator = {};
3416
+ let responseFunctionCalls = [];
3417
+ let responseId;
3418
+ let requestDone = false;
3370
3419
  let finishedNotified = false;
3371
3420
  const notifyFinished = async () => {
3372
3421
  if (finishedNotified) {
@@ -3386,6 +3435,13 @@ const getMockOpenApiAssistantText = async (stream, onTextChunk, onToolCallsChunk
3386
3435
  }
3387
3436
  const eventType = Reflect.get(parsed, 'type');
3388
3437
  if (eventType === 'response.completed') {
3438
+ const response = Reflect.get(parsed, 'response');
3439
+ responseFunctionCalls = getResponseFunctionCalls$1(response);
3440
+ const parsedResponseId = response && typeof response === 'object' ? Reflect.get(response, 'id') : undefined;
3441
+ if (typeof parsedResponseId === 'string' && parsedResponseId) {
3442
+ responseId = parsedResponseId;
3443
+ }
3444
+ requestDone = true;
3389
3445
  await notifyFinished();
3390
3446
  return;
3391
3447
  }
@@ -3457,8 +3513,9 @@ const getMockOpenApiAssistantText = async (stream, onTextChunk, onToolCallsChunk
3457
3513
  const consumeSseDataLines = async dataLines => {
3458
3514
  for (const line of dataLines) {
3459
3515
  if (line === '[DONE]') {
3516
+ requestDone = true;
3460
3517
  await notifyFinished();
3461
- continue;
3518
+ break;
3462
3519
  }
3463
3520
  let parsed;
3464
3521
  try {
@@ -3467,9 +3524,12 @@ const getMockOpenApiAssistantText = async (stream, onTextChunk, onToolCallsChunk
3467
3524
  continue;
3468
3525
  }
3469
3526
  await handleParsedSseEvent(parsed);
3527
+ if (requestDone) {
3528
+ break;
3529
+ }
3470
3530
  }
3471
3531
  };
3472
- while (true) {
3532
+ while (!requestDone) {
3473
3533
  const chunk = await readNextChunk();
3474
3534
  if (typeof chunk !== 'string') {
3475
3535
  break;
@@ -3485,6 +3545,9 @@ const getMockOpenApiAssistantText = async (stream, onTextChunk, onToolCallsChunk
3485
3545
  remainder = remainder.slice(separatorIndex + 2);
3486
3546
  const dataLines = parseSseDataLines(rawEvent);
3487
3547
  await consumeSseDataLines(dataLines);
3548
+ if (requestDone) {
3549
+ break;
3550
+ }
3488
3551
  }
3489
3552
  continue;
3490
3553
  }
@@ -3493,12 +3556,16 @@ const getMockOpenApiAssistantText = async (stream, onTextChunk, onToolCallsChunk
3493
3556
  await onTextChunk(chunk);
3494
3557
  }
3495
3558
  }
3496
- if (remainder) {
3559
+ if (!requestDone && remainder) {
3497
3560
  const dataLines = parseSseDataLines(remainder);
3498
3561
  await consumeSseDataLines(dataLines);
3499
3562
  }
3500
3563
  await notifyFinished();
3501
3564
  return {
3565
+ ...(responseId ? {
3566
+ responseId
3567
+ } : {}),
3568
+ responseFunctionCalls,
3502
3569
  text,
3503
3570
  type: 'success'
3504
3571
  };
@@ -3774,13 +3841,21 @@ const getToolCallExecutionStatus = content => {
3774
3841
  status: 'success'
3775
3842
  };
3776
3843
  }
3844
+ const rawStack = Reflect.get(parsed, 'errorStack') ?? Reflect.get(parsed, 'stack');
3845
+ const errorStack = typeof rawStack === 'string' && rawStack.trim() ? rawStack : undefined;
3777
3846
  const errorMessage = getShortToolErrorMessage(rawError);
3778
3847
  if (/not[\s_-]?found|enoent/i.test(errorMessage)) {
3779
3848
  return {
3849
+ ...(errorStack ? {
3850
+ errorStack
3851
+ } : {}),
3780
3852
  status: 'not-found'
3781
3853
  };
3782
3854
  }
3783
3855
  return {
3856
+ ...(errorStack ? {
3857
+ errorStack
3858
+ } : {}),
3784
3859
  errorMessage,
3785
3860
  status: 'error'
3786
3861
  };
@@ -4385,9 +4460,15 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
4385
4460
  const executionStatus = getToolCallExecutionStatus(content);
4386
4461
  executedToolCalls.push({
4387
4462
  arguments: toolCall.arguments,
4463
+ ...(executionStatus.errorStack ? {
4464
+ errorStack: executionStatus.errorStack
4465
+ } : {}),
4388
4466
  ...(executionStatus.errorMessage ? {
4389
4467
  errorMessage: executionStatus.errorMessage
4390
4468
  } : {}),
4469
+ ...(executionStatus.errorStack ? {
4470
+ errorStack: executionStatus.errorStack
4471
+ } : {}),
4391
4472
  id: toolCall.callId,
4392
4473
  name: toolCall.name,
4393
4474
  ...(executionStatus.status ? {
@@ -4520,9 +4601,15 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
4520
4601
  const executionStatus = getToolCallExecutionStatus(content);
4521
4602
  executedToolCalls.push({
4522
4603
  arguments: toolCall.arguments,
4604
+ ...(executionStatus.errorStack ? {
4605
+ errorStack: executionStatus.errorStack
4606
+ } : {}),
4523
4607
  ...(executionStatus.errorMessage ? {
4524
4608
  errorMessage: executionStatus.errorMessage
4525
4609
  } : {}),
4610
+ ...(executionStatus.errorStack ? {
4611
+ errorStack: executionStatus.errorStack
4612
+ } : {}),
4526
4613
  id: toolCall.callId,
4527
4614
  name: toolCall.name,
4528
4615
  ...(executionStatus.status ? {
@@ -4583,9 +4670,15 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
4583
4670
  const executionStatus = getToolCallExecutionStatus(content);
4584
4671
  executedToolCalls.push({
4585
4672
  arguments: typeof rawArguments === 'string' ? rawArguments : '',
4673
+ ...(executionStatus.errorStack ? {
4674
+ errorStack: executionStatus.errorStack
4675
+ } : {}),
4586
4676
  ...(executionStatus.errorMessage ? {
4587
4677
  errorMessage: executionStatus.errorMessage
4588
4678
  } : {}),
4679
+ ...(executionStatus.errorStack ? {
4680
+ errorStack: executionStatus.errorStack
4681
+ } : {}),
4589
4682
  id,
4590
4683
  name,
4591
4684
  ...(executionStatus.status ? {
@@ -5080,6 +5173,8 @@ const getAll = () => {
5080
5173
  return requests;
5081
5174
  };
5082
5175
 
5176
+ /* eslint-disable prefer-destructuring */
5177
+
5083
5178
  const getAiResponse = async ({
5084
5179
  assetDir,
5085
5180
  messageId,
@@ -5119,20 +5214,36 @@ const getAiResponse = async ({
5119
5214
  'Content-Type': 'application/json',
5120
5215
  ...getClientRequestIdHeader()
5121
5216
  };
5122
- capture({
5123
- headers,
5124
- method: 'POST',
5125
- payload: getOpenAiParams(openAiInput, modelId, streamingEnabled, passIncludeObfuscation, getBasicChatTools(), webSearchEnabled),
5126
- url: getOpenApiApiEndpoint(openApiApiBaseUrl)
5127
- });
5128
- const result = await getMockOpenApiAssistantText(streamingEnabled, onTextChunk, onToolCallsChunk, onDataEvent, onEventStreamFinished);
5129
- if (result.type === 'success') {
5130
- const {
5131
- text: assistantText
5132
- } = result;
5133
- text = assistantText;
5134
- } else {
5135
- text = getOpenApiErrorMessage(result);
5217
+ const maxToolIterations = 4;
5218
+ let previousResponseId;
5219
+ for (let i = 0; i <= maxToolIterations; i++) {
5220
+ capture({
5221
+ headers,
5222
+ method: 'POST',
5223
+ payload: getOpenAiParams(openAiInput, modelId, streamingEnabled, passIncludeObfuscation, getBasicChatTools(), webSearchEnabled, previousResponseId),
5224
+ url: getOpenApiApiEndpoint(openApiApiBaseUrl)
5225
+ });
5226
+ const result = await getMockOpenApiAssistantText(streamingEnabled, onTextChunk, onToolCallsChunk, onDataEvent, onEventStreamFinished);
5227
+ if (result.type !== 'success') {
5228
+ text = getOpenApiErrorMessage(result);
5229
+ break;
5230
+ }
5231
+ text = result.text;
5232
+ if (result.responseId) {
5233
+ previousResponseId = result.responseId;
5234
+ }
5235
+ if (result.responseFunctionCalls.length === 0) {
5236
+ break;
5237
+ }
5238
+ openAiInput.length = 0;
5239
+ for (const toolCall of result.responseFunctionCalls) {
5240
+ const content = await executeChatTool(toolCall.name, toolCall.arguments);
5241
+ openAiInput.push({
5242
+ call_id: toolCall.callId,
5243
+ output: content,
5244
+ type: 'function_call_output'
5245
+ });
5246
+ }
5136
5247
  }
5137
5248
  } else if (openApiApiKey) {
5138
5249
  const result = await getOpenApiAssistantText(messages, getOpenApiModelId(selectedModelId), openApiApiKey, openApiApiBaseUrl, assetDir, platform, {
@@ -5960,6 +6071,7 @@ const handleClickSend = async state => {
5960
6071
 
5961
6072
  const Composer = 'composer';
5962
6073
  const ComposerDropTarget = 'composer-drop-target';
6074
+ const Dictate = 'dictate';
5963
6075
  const Send = 'send';
5964
6076
  const Back = 'back';
5965
6077
  const Model = 'model';
@@ -6201,6 +6313,10 @@ const handleClickDelete = async (state, sessionId = '') => {
6201
6313
  return deleteSession(state, sessionId);
6202
6314
  };
6203
6315
 
6316
+ const handleClickDictationButton = async state => {
6317
+ return state;
6318
+ };
6319
+
6204
6320
  const handleClickNew = async state => {
6205
6321
  return createSession(state);
6206
6322
  };
@@ -6499,7 +6615,7 @@ const createExtensionHostRpc = async () => {
6499
6615
  }
6500
6616
  };
6501
6617
 
6502
- const initialize = async () => {
6618
+ const initialize$1 = async () => {
6503
6619
  const rpc = await createExtensionHostRpc();
6504
6620
  set$2(rpc);
6505
6621
  };
@@ -6666,8 +6782,17 @@ const loadUseChatNetworkWorkerForRequests = async () => {
6666
6782
  }
6667
6783
  };
6668
6784
 
6785
+ const loadVoiceDictationEnabled = async () => {
6786
+ try {
6787
+ const savedVoiceDictationEnabled = await get('chatView.voiceDictationEnabled');
6788
+ return typeof savedVoiceDictationEnabled === 'boolean' ? savedVoiceDictationEnabled : false;
6789
+ } catch {
6790
+ return false;
6791
+ }
6792
+ };
6793
+
6669
6794
  const loadPreferences = async () => {
6670
- const [aiSessionTitleGenerationEnabled, composerDropEnabled, openApiApiKey, openRouterApiKey, emitStreamingFunctionCallEvents, streamingEnabled, passIncludeObfuscation, useChatNetworkWorkerForRequests] = await Promise.all([loadAiSessionTitleGenerationEnabled(), loadComposerDropEnabled(), loadOpenApiApiKey(), loadOpenRouterApiKey(), loadEmitStreamingFunctionCallEvents(), loadStreamingEnabled(), loadPassIncludeObfuscation(), loadUseChatNetworkWorkerForRequests()]);
6795
+ const [aiSessionTitleGenerationEnabled, composerDropEnabled, openApiApiKey, openRouterApiKey, emitStreamingFunctionCallEvents, streamingEnabled, passIncludeObfuscation, useChatNetworkWorkerForRequests, voiceDictationEnabled] = await Promise.all([loadAiSessionTitleGenerationEnabled(), loadComposerDropEnabled(), loadOpenApiApiKey(), loadOpenRouterApiKey(), loadEmitStreamingFunctionCallEvents(), loadStreamingEnabled(), loadPassIncludeObfuscation(), loadUseChatNetworkWorkerForRequests(), loadVoiceDictationEnabled()]);
6671
6796
  return {
6672
6797
  aiSessionTitleGenerationEnabled,
6673
6798
  composerDropEnabled,
@@ -6676,7 +6801,8 @@ const loadPreferences = async () => {
6676
6801
  openRouterApiKey,
6677
6802
  passIncludeObfuscation,
6678
6803
  streamingEnabled,
6679
- useChatNetworkWorkerForRequests
6804
+ useChatNetworkWorkerForRequests,
6805
+ voiceDictationEnabled
6680
6806
  };
6681
6807
  };
6682
6808
 
@@ -6800,7 +6926,8 @@ const loadContent = async (state, savedState) => {
6800
6926
  openRouterApiKey,
6801
6927
  passIncludeObfuscation,
6802
6928
  streamingEnabled,
6803
- useChatNetworkWorkerForRequests
6929
+ useChatNetworkWorkerForRequests,
6930
+ voiceDictationEnabled
6804
6931
  } = await loadPreferences();
6805
6932
  const legacySavedSessions = getSavedSessions(savedState);
6806
6933
  const storedSessions = await listChatSessions();
@@ -6866,7 +6993,8 @@ const loadContent = async (state, savedState) => {
6866
6993
  sessions,
6867
6994
  streamingEnabled,
6868
6995
  useChatNetworkWorkerForRequests,
6869
- viewMode
6996
+ viewMode,
6997
+ voiceDictationEnabled
6870
6998
  };
6871
6999
  };
6872
7000
 
@@ -7325,6 +7453,7 @@ const HandleDragEnterChatView = 30;
7325
7453
  const HandleDragOverChatView = 31;
7326
7454
  const HandleProjectListScroll = 32;
7327
7455
  const HandleProjectListContextMenu = 33;
7456
+ const HandleClickDictationButton = 34;
7328
7457
 
7329
7458
  const getModelLabel = model => {
7330
7459
  if (model.provider === 'openRouter') {
@@ -7362,14 +7491,26 @@ const getSendButtonClassName = isSendDisabled => {
7362
7491
  return isSendDisabled ? `${IconButton} ${SendButtonDisabled}` : `${IconButton}`;
7363
7492
  };
7364
7493
 
7365
- const getSendButtonDom = isSendDisabled => {
7494
+ const getSendButtonDom = (isSendDisabled, voiceDictationEnabled) => {
7366
7495
  const sendButtonClassName = getSendButtonClassName(isSendDisabled);
7367
- return [{
7496
+ return [...(voiceDictationEnabled ? [{
7497
+ childCount: 1,
7498
+ className: IconButton,
7499
+ name: Dictate,
7500
+ onClick: HandleClickDictationButton,
7501
+ role: Button$2,
7502
+ title: startVoiceDictation(),
7503
+ type: Button$1
7504
+ }, {
7505
+ childCount: 0,
7506
+ className: 'MaskIcon MaskIconMic',
7507
+ type: Div
7508
+ }] : []), {
7509
+ buttonType: 'submit',
7368
7510
  childCount: 1,
7369
7511
  className: sendButtonClassName,
7370
7512
  disabled: isSendDisabled,
7371
7513
  name: Send,
7372
- onClick: HandleSubmit,
7373
7514
  role: Button$2,
7374
7515
  title: sendMessage(),
7375
7516
  type: Button$1
@@ -7415,12 +7556,14 @@ const getUsageOverviewDom = (tokensUsed, tokensMax) => {
7415
7556
  }, text$2(usageLabel)];
7416
7557
  };
7417
7558
 
7418
- const getChatSendAreaDom = (composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight = 28, composerFontSize = 13, composerFontFamily = 'system-ui', composerLineHeight = 20) => {
7559
+ const getChatSendAreaDom = (composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight = 28, composerFontSize = 13, composerFontFamily = 'system-ui', composerLineHeight = 20, voiceDictationEnabled = false) => {
7419
7560
  const isSendDisabled = composerValue.trim() === '';
7561
+ const controlsCount = usageOverviewEnabled ? 3 : 2;
7420
7562
  return [{
7421
7563
  childCount: 1,
7422
7564
  className: ChatSendArea,
7423
- type: Div
7565
+ onSubmit: HandleSubmit,
7566
+ type: Form
7424
7567
  }, {
7425
7568
  childCount: 2,
7426
7569
  className: ChatSendAreaContent,
@@ -7435,10 +7578,10 @@ const getChatSendAreaDom = (composerValue, models, selectedModelId, usageOvervie
7435
7578
  type: TextArea,
7436
7579
  value: composerValue
7437
7580
  }, {
7438
- childCount: usageOverviewEnabled ? 3 : 2,
7581
+ childCount: voiceDictationEnabled ? controlsCount + 1 : controlsCount,
7439
7582
  className: ChatSendAreaBottom,
7440
7583
  type: Div
7441
- }, ...getChatSelectVirtualDom(models, selectedModelId), ...(usageOverviewEnabled ? getUsageOverviewDom(tokensUsed, tokensMax) : []), ...getSendButtonDom(isSendDisabled)];
7584
+ }, ...getChatSelectVirtualDom(models, selectedModelId), ...(usageOverviewEnabled ? getUsageOverviewDom(tokensUsed, tokensMax) : []), ...getSendButtonDom(isSendDisabled, voiceDictationEnabled)];
7442
7585
  };
7443
7586
 
7444
7587
  /**
@@ -24383,11 +24526,17 @@ const getCodeBlockDom = node => {
24383
24526
  }, ...tokenDom];
24384
24527
  };
24385
24528
  const getOrderedListItemDom = item => {
24529
+ const hasNestedUnorderedList = (item.nestedItems?.length || 0) > 0;
24530
+ const nestedUnorderedListDom = hasNestedUnorderedList ? [{
24531
+ childCount: item.nestedItems?.length || 0,
24532
+ className: ChatUnorderedList,
24533
+ type: Ul
24534
+ }, ...(item.nestedItems || []).flatMap(getUnorderedListItemDom)] : [];
24386
24535
  return [{
24387
- childCount: item.children.length,
24536
+ childCount: item.children.length + (hasNestedUnorderedList ? 1 : 0),
24388
24537
  className: ChatOrderedListItem,
24389
24538
  type: Li
24390
- }, ...item.children.flatMap(getInlineNodeDom)];
24539
+ }, ...item.children.flatMap(getInlineNodeDom), ...nestedUnorderedListDom];
24391
24540
  };
24392
24541
  const getUnorderedListItemDom = item => {
24393
24542
  return [{
@@ -24805,20 +24954,20 @@ const getToolCallsDom = message => {
24805
24954
  return [{
24806
24955
  childCount: 2,
24807
24956
  className: ChatToolCalls,
24808
- type: Div$1
24957
+ type: Div
24809
24958
  }, {
24810
24959
  childCount: 1,
24811
24960
  className: ChatToolCallsLabel,
24812
- type: Div$1
24961
+ type: Div
24813
24962
  }, text$2('tools'), {
24814
24963
  childCount: message.toolCalls.length,
24815
24964
  className: ChatOrderedList,
24816
- type: Ol$1
24965
+ type: Ol
24817
24966
  }, ...message.toolCalls.flatMap(getToolCallDom)];
24818
24967
  };
24819
24968
 
24820
24969
  const orderedListItemRegex = /^\s*\d+\.\s+(.*)$/;
24821
- const unorderedListItemRegex = /^\s*[-*]\s+(.*)$/;
24970
+ const unorderedListItemRegex = /^(\s*)[-*]\s+(.*)$/;
24822
24971
  const markdownInlineRegex = /\[([^\]]+)\]\(([^)]+)\)|\*\*([^*]+)\*\*|\*([^*]+)\*|(?<![a-zA-Z0-9])(?<mathDollars>\${1,2})(?!\.|\(["'])(?<mathText>(?:\\.|[^\\\n])*?(?:\\.|[^\\\n$]))\k<mathDollars>(?![a-zA-Z0-9])/g;
24823
24972
  const markdownTableSeparatorCellRegex = /^:?-{3,}:?$/;
24824
24973
  const fencedCodeBlockRegex = /^```/;
@@ -25064,13 +25213,29 @@ const parseMessageContent = rawMessage => {
25064
25213
  }
25065
25214
  const unorderedMatch = line.match(unorderedListItemRegex);
25066
25215
  if (unorderedMatch) {
25216
+ const indentation = unorderedMatch[1];
25217
+ const unorderedText = unorderedMatch[2];
25218
+ if (listType === 'ordered-list' && listItems.length > 0 && indentation.length > 0) {
25219
+ const lastIndex = listItems.length - 1;
25220
+ const previousItem = listItems[lastIndex];
25221
+ const nestedItems = previousItem.nestedItems ? [...previousItem.nestedItems] : [];
25222
+ nestedItems.push({
25223
+ children: parseInlineNodes(unorderedText),
25224
+ type: 'list-item'
25225
+ });
25226
+ listItems[lastIndex] = {
25227
+ ...previousItem,
25228
+ nestedItems
25229
+ };
25230
+ continue;
25231
+ }
25067
25232
  if (listType && listType !== 'unordered-list') {
25068
25233
  flushList();
25069
25234
  }
25070
25235
  flushParagraph();
25071
25236
  listType = 'unordered-list';
25072
25237
  listItems.push({
25073
- children: parseInlineNodes(unorderedMatch[1]),
25238
+ children: parseInlineNodes(unorderedText),
25074
25239
  type: 'list-item'
25075
25240
  });
25076
25241
  continue;
@@ -25130,18 +25295,45 @@ const getEmptyMessagesDom = () => {
25130
25295
  }, text$2(startConversation())];
25131
25296
  };
25132
25297
 
25298
+ const hasMessageText = message => {
25299
+ return message.text.trim().length > 0;
25300
+ };
25301
+ const getDisplayMessages = messages => {
25302
+ const displayMessages = [];
25303
+ for (const message of messages) {
25304
+ if (message.role !== 'assistant' || !message.toolCalls || message.toolCalls.length === 0) {
25305
+ displayMessages.push(message);
25306
+ continue;
25307
+ }
25308
+ displayMessages.push({
25309
+ ...message,
25310
+ text: ''
25311
+ });
25312
+ if (hasMessageText(message)) {
25313
+ const {
25314
+ toolCalls: _toolCalls,
25315
+ ...messageWithoutToolCalls
25316
+ } = message;
25317
+ displayMessages.push({
25318
+ ...messageWithoutToolCalls
25319
+ });
25320
+ }
25321
+ }
25322
+ return displayMessages;
25323
+ };
25133
25324
  const getMessagesDom = (messages, openRouterApiKeyInput, openApiApiKeyInput = '', openRouterApiKeyState = 'idle', messagesScrollTop = 0) => {
25134
25325
  if (messages.length === 0) {
25135
25326
  return getEmptyMessagesDom();
25136
25327
  }
25328
+ const displayMessages = getDisplayMessages(messages);
25137
25329
  return [{
25138
- childCount: messages.length,
25330
+ childCount: displayMessages.length,
25139
25331
  className: 'ChatMessages',
25140
25332
  onContextMenu: HandleMessagesContextMenu,
25141
25333
  onScroll: HandleMessagesScroll,
25142
25334
  scrollTop: messagesScrollTop,
25143
25335
  type: Div
25144
- }, ...messages.flatMap(message => getChatMessageDom(message, openRouterApiKeyInput, openApiApiKeyInput, openRouterApiKeyState))];
25336
+ }, ...displayMessages.flatMap(message => getChatMessageDom(message, openRouterApiKeyInput, openApiApiKeyInput, openRouterApiKeyState))];
25145
25337
  };
25146
25338
 
25147
25339
  const getProjectSessionDom = (session, selectedSessionId) => {
@@ -25229,7 +25421,7 @@ const getProjectListDom = (projects, sessions, projectExpandedIds, selectedProje
25229
25421
  }, text$2('+ Add Project')];
25230
25422
  };
25231
25423
 
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) => {
25424
+ 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
25425
  const selectedSession = sessions.find(session => session.id === selectedSessionId);
25234
25426
  const selectedSessionTitle = selectedSession?.title || chatTitle();
25235
25427
  const messages = selectedSession ? selectedSession.messages : [];
@@ -25251,7 +25443,7 @@ const getChatModeChatFocusVirtualDom = (sessions, selectedSessionId, composerVal
25251
25443
  }, {
25252
25444
  text: selectedSessionTitle,
25253
25445
  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), {
25446
+ }, ...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
25447
  childCount: 1,
25256
25448
  className: mergeClassNames(ChatViewDropOverlay, isDropOverlayVisible ? ChatViewDropOverlayActive : Empty),
25257
25449
  name: ComposerDropTarget,
@@ -25347,7 +25539,7 @@ const getChatHeaderDomDetailMode = selectedSessionTitle => {
25347
25539
  }, text$2(selectedSessionTitle), ...getChatHeaderActionsDom('detail')];
25348
25540
  };
25349
25541
 
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) => {
25542
+ 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
25543
  const selectedSession = sessions.find(session => session.id === selectedSessionId);
25352
25544
  const selectedSessionTitle = selectedSession?.title || chatTitle();
25353
25545
  const messages = selectedSession ? selectedSession.messages : [];
@@ -25358,7 +25550,7 @@ const getChatModeDetailVirtualDom = (sessions, selectedSessionId, composerValue,
25358
25550
  onDragEnter: HandleDragEnterChatView,
25359
25551
  onDragOver: HandleDragOverChatView,
25360
25552
  type: Div
25361
- }, ...getChatHeaderDomDetailMode(selectedSessionTitle), ...getMessagesDom(messages, openRouterApiKeyInput, openApiApiKeyInput, openRouterApiKeyState, messagesScrollTop), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight, composerFontSize, composerFontFamily, composerLineHeight), {
25553
+ }, ...getChatHeaderDomDetailMode(selectedSessionTitle), ...getMessagesDom(messages, openRouterApiKeyInput, openApiApiKeyInput, openRouterApiKeyState, messagesScrollTop), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, voiceDictationEnabled), {
25362
25554
  childCount: 1,
25363
25555
  className: mergeClassNames(ChatViewDropOverlay, isDropOverlayVisible ? ChatViewDropOverlayActive : Empty),
25364
25556
  name: ComposerDropTarget,
@@ -25439,7 +25631,7 @@ const getChatListDom = (sessions, selectedSessionId, chatListScrollTop = 0) => {
25439
25631
  }, ...sessions.flatMap(getSessionDom)];
25440
25632
  };
25441
25633
 
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) => {
25634
+ 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
25635
  const isDropOverlayVisible = composerDropEnabled && composerDropActive;
25444
25636
  return [{
25445
25637
  childCount: 4,
@@ -25447,7 +25639,7 @@ const getChatModeListVirtualDom = (sessions, selectedSessionId, composerValue, m
25447
25639
  onDragEnter: HandleDragEnterChatView,
25448
25640
  onDragOver: HandleDragOverChatView,
25449
25641
  type: Div
25450
- }, ...getChatHeaderListModeDom(), ...getChatListDom(sessions, selectedSessionId, chatListScrollTop), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight, composerFontSize, composerFontFamily, composerLineHeight), {
25642
+ }, ...getChatHeaderListModeDom(), ...getChatListDom(sessions, selectedSessionId, chatListScrollTop), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, voiceDictationEnabled), {
25451
25643
  childCount: 1,
25452
25644
  className: mergeClassNames(ChatViewDropOverlay, isDropOverlayVisible ? ChatViewDropOverlayActive : Empty),
25453
25645
  name: ComposerDropTarget,
@@ -25468,14 +25660,14 @@ const getChatModeUnsupportedVirtualDom = () => {
25468
25660
  }, text$2(unknownViewMode())];
25469
25661
  };
25470
25662
 
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) => {
25663
+ 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
25664
  switch (viewMode) {
25473
25665
  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);
25666
+ 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
25667
  case 'detail':
25476
- return getChatModeDetailVirtualDom(sessions, selectedSessionId, composerValue, openRouterApiKeyInput, openApiApiKeyInput, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openRouterApiKeyState, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, messagesScrollTop, composerDropActive, composerDropEnabled);
25668
+ return getChatModeDetailVirtualDom(sessions, selectedSessionId, composerValue, openRouterApiKeyInput, openApiApiKeyInput, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openRouterApiKeyState, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, messagesScrollTop, composerDropActive, composerDropEnabled, voiceDictationEnabled);
25477
25669
  case 'list':
25478
- return getChatModeListVirtualDom(sessions, selectedSessionId, composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, chatListScrollTop, composerDropActive, composerDropEnabled);
25670
+ return getChatModeListVirtualDom(sessions, selectedSessionId, composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, chatListScrollTop, composerDropActive, composerDropEnabled, voiceDictationEnabled);
25479
25671
  default:
25480
25672
  return getChatModeUnsupportedVirtualDom();
25481
25673
  }
@@ -25508,12 +25700,13 @@ const renderItems = (oldState, newState) => {
25508
25700
  tokensUsed,
25509
25701
  uid,
25510
25702
  usageOverviewEnabled,
25511
- viewMode
25703
+ viewMode,
25704
+ voiceDictationEnabled
25512
25705
  } = newState;
25513
25706
  if (initial) {
25514
25707
  return [SetDom2, uid, []];
25515
25708
  }
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);
25709
+ 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
25710
  return [SetDom2, uid, dom];
25518
25711
  };
25519
25712
 
@@ -25582,6 +25775,63 @@ const render2 = (uid, diffResult) => {
25582
25775
  return commands;
25583
25776
  };
25584
25777
 
25778
+ const handleDictateClickExpression = `(() => {
25779
+ const target = event.target?.closest?.('[name="dictate"]')
25780
+ if (!target) {
25781
+ return ''
25782
+ }
25783
+ const SpeechRecognitionClass = globalThis.SpeechRecognition || globalThis.webkitSpeechRecognition
25784
+ const composer = document.querySelector('[name="composer"]')
25785
+ if (!SpeechRecognitionClass || !composer || !('value' in composer)) {
25786
+ return ''
25787
+ }
25788
+ const state = globalThis.__chatViewDictationState || (globalThis.__chatViewDictationState = {})
25789
+ const existingRecognition = state.recognition
25790
+ if (existingRecognition) {
25791
+ existingRecognition.stop()
25792
+ state.recognition = undefined
25793
+ return ''
25794
+ }
25795
+ const initialValue = typeof composer.value === 'string' ? composer.value : ''
25796
+ const prefix = initialValue && !/\\s$/.test(initialValue) ? \`\${initialValue} \` : initialValue
25797
+ const updateComposerValue = (nextValue) => {
25798
+ composer.value = nextValue
25799
+ composer.dispatchEvent(new Event('input', { bubbles: true }))
25800
+ }
25801
+ const recognition = new SpeechRecognitionClass()
25802
+ recognition.continuous = true
25803
+ recognition.interimResults = true
25804
+ recognition.onresult = (speechEvent) => {
25805
+ let transcript = ''
25806
+ for (let i = 0; i < speechEvent.results.length; i++) {
25807
+ transcript += speechEvent.results[i][0]?.transcript || ''
25808
+ }
25809
+ updateComposerValue(prefix + transcript)
25810
+ }
25811
+ const clearRecognition = () => {
25812
+ if (state.recognition === recognition) {
25813
+ state.recognition = undefined
25814
+ }
25815
+ }
25816
+ recognition.onend = clearRecognition
25817
+ recognition.onerror = clearRecognition
25818
+ const startRecognition = () => {
25819
+ state.recognition = recognition
25820
+ recognition.start()
25821
+ }
25822
+ if (navigator.mediaDevices?.getUserMedia) {
25823
+ navigator.mediaDevices
25824
+ .getUserMedia({ audio: true })
25825
+ .then((stream) => {
25826
+ stream.getTracks().forEach((track) => track.stop())
25827
+ startRecognition()
25828
+ })
25829
+ .catch(() => {})
25830
+ return ''
25831
+ }
25832
+ startRecognition()
25833
+ return ''
25834
+ })()`;
25585
25835
  const renderEventListeners = () => {
25586
25836
  return [{
25587
25837
  name: HandleListContextMenu,
@@ -25590,6 +25840,9 @@ const renderEventListeners = () => {
25590
25840
  }, {
25591
25841
  name: HandleClick,
25592
25842
  params: ['handleClick', TargetName, 'event.target.dataset.id']
25843
+ }, {
25844
+ name: HandleClickDictationButton,
25845
+ params: ['handleClickDictationButton', handleDictateClickExpression]
25593
25846
  }, {
25594
25847
  name: HandleClickReadFile,
25595
25848
  params: ['handleClickReadFile', 'event.target.dataset.uri']
@@ -25811,6 +26064,7 @@ const commandMap = {
25811
26064
  'Chat.handleClickBack': wrapCommand(handleClickBack),
25812
26065
  'Chat.handleClickClose': handleClickClose,
25813
26066
  'Chat.handleClickDelete': wrapCommand(handleClickDelete),
26067
+ 'Chat.handleClickDictationButton': wrapCommand(handleClickDictationButton),
25814
26068
  'Chat.handleClickList': wrapCommand(handleClickList),
25815
26069
  'Chat.handleClickNew': wrapCommand(handleClickNew),
25816
26070
  'Chat.handleClickReadFile': handleClickReadFile,
@@ -25829,7 +26083,7 @@ const commandMap = {
25829
26083
  'Chat.handleProjectListContextMenu': wrapCommand(handleProjectListContextMenu),
25830
26084
  'Chat.handleProjectListScroll': wrapCommand(handleProjectListScroll),
25831
26085
  'Chat.handleSubmit': wrapCommand(handleSubmit),
25832
- 'Chat.initialize': initialize,
26086
+ 'Chat.initialize': initialize$1,
25833
26087
  'Chat.loadContent': wrapCommand(loadContent),
25834
26088
  'Chat.loadContent2': wrapCommand(loadContent),
25835
26089
  'Chat.mockOpenApiRequestGetAll': wrapGetter(mockOpenApiRequestGetAll),
@@ -25855,6 +26109,33 @@ const commandMap = {
25855
26109
  'Chat.useMockApi': wrapCommand(useMockApi)
25856
26110
  };
25857
26111
 
26112
+ let initialized = false;
26113
+ const sendMessagePortToChatMathWorker = async port => {
26114
+ try {
26115
+ await invoke('sendMessagePortToChatMathWorker', port);
26116
+ } catch {
26117
+ await invoke('SendMessagePortToChatMathWorker.sendMessagePortToChatMathWorker', port);
26118
+ }
26119
+ };
26120
+ const createRpc = () => {
26121
+ return create$4({
26122
+ commandMap: {},
26123
+ send: sendMessagePortToChatMathWorker
26124
+ });
26125
+ };
26126
+ const initialize = async () => {
26127
+ if (initialized) {
26128
+ return;
26129
+ }
26130
+ const rpc = await createRpc();
26131
+ set$4(rpc);
26132
+ initialized = true;
26133
+ };
26134
+
26135
+ const initializeChatMathWorker = async () => {
26136
+ await initialize();
26137
+ };
26138
+
25858
26139
  const send = port => {
25859
26140
  return sendMessagePortToChatNetworkWorker(port);
25860
26141
  };
@@ -25872,7 +26153,7 @@ const listen = async () => {
25872
26153
  commandMap: commandMap
25873
26154
  });
25874
26155
  set$1(rpc);
25875
- await initializeChatNetworkWorker();
26156
+ await Promise.all([initializeChatNetworkWorker(), initializeChatMathWorker()]);
25876
26157
  };
25877
26158
 
25878
26159
  const main = async () => {
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.4.0",
4
4
  "description": "Chat View Worker",
5
5
  "repository": {
6
6
  "type": "git",