@lvce-editor/chat-view 5.4.0 → 6.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.
@@ -476,7 +476,7 @@ const register = commandMap => {
476
476
  const getCommand = key => {
477
477
  return commands[key];
478
478
  };
479
- const execute = (command, ...args) => {
479
+ const execute$1 = (command, ...args) => {
480
480
  const fn = getCommand(command);
481
481
  if (!fn) {
482
482
  throw new CommandNotFoundError(command);
@@ -896,7 +896,7 @@ const logError = () => {
896
896
  };
897
897
  const handleMessage = event => {
898
898
  const actualRequiresSocket = event?.target?.requiresSocket || requiresSocket;
899
- const actualExecute = event?.target?.execute || execute;
899
+ const actualExecute = event?.target?.execute || execute$1;
900
900
  return handleJsonRpcMessage(event.target, event.data, actualExecute, event.target._resolve, preparePrettyError, logError, actualRequiresSocket);
901
901
  };
902
902
 
@@ -1027,7 +1027,7 @@ const createMockRpc = ({
1027
1027
  };
1028
1028
 
1029
1029
  const rpcs = Object.create(null);
1030
- const set$6 = (id, rpc) => {
1030
+ const set$8 = (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$6(rpcId, mockRpc);
1063
+ set$8(rpcId, mockRpc);
1064
1064
  // @ts-ignore
1065
1065
  mockRpc[Symbol.dispose] = () => {
1066
1066
  remove(rpcId);
@@ -1069,20 +1069,20 @@ const create$2 = rpcId => {
1069
1069
  return mockRpc;
1070
1070
  },
1071
1071
  set(rpc) {
1072
- set$6(rpcId, rpc);
1072
+ set$8(rpcId, rpc);
1073
1073
  }
1074
1074
  };
1075
1075
  };
1076
1076
 
1077
1077
  const {
1078
- invoke: invoke$4,
1079
- set: set$5
1078
+ invoke: invoke$5,
1079
+ set: set$7
1080
1080
  } = create$2(6007);
1081
1081
  const getMathBlockDom = async node => {
1082
- return invoke$4('ChatMath.getMathBlockDom', node);
1082
+ return invoke$5('ChatMath.getMathBlockDom', node);
1083
1083
  };
1084
1084
  const getMathInlineDom = async node => {
1085
- return invoke$4('ChatMath.getMathInlineDom', node);
1085
+ return invoke$5('ChatMath.getMathInlineDom', node);
1086
1086
  };
1087
1087
 
1088
1088
  const Button$2 = 'button';
@@ -1158,6 +1158,7 @@ const RestoreFocus = 6;
1158
1158
 
1159
1159
  const ChatNetworkWorker = 6002;
1160
1160
  const ExtensionHostWorker = 44;
1161
+ const OpenerWorker = 4561;
1161
1162
  const RendererWorker = 1;
1162
1163
 
1163
1164
  const FocusSelector = 'Viewlet.focusSelector';
@@ -1171,20 +1172,33 @@ const SetPatches = 'Viewlet.setPatches';
1171
1172
  const FocusChatInput = 8000;
1172
1173
 
1173
1174
  const {
1174
- invoke: invoke$3,
1175
- set: set$4
1175
+ invoke: invoke$4,
1176
+ set: set$6
1176
1177
  } = create$2(ChatNetworkWorker);
1177
1178
 
1179
+ const {
1180
+ invoke: invoke$3,
1181
+ set: set$5
1182
+ } = create$2(6005);
1183
+
1178
1184
  const {
1179
1185
  invoke: invoke$2,
1180
- set: set$3
1186
+ set: set$4
1181
1187
  } = create$2(ExtensionHostWorker);
1182
1188
 
1189
+ const {
1190
+ set: set$3
1191
+ } = create$2(OpenerWorker);
1192
+
1183
1193
  const {
1184
1194
  invoke: invoke$1,
1185
1195
  invokeAndTransfer,
1186
1196
  set: set$2
1187
1197
  } = create$2(RendererWorker);
1198
+ const sendMessagePortToOpenerWorker$1 = async (port, rpcId) => {
1199
+ const command = 'HandleMessagePort.handleMessagePort';
1200
+ await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToOpenerWorker', port, command, rpcId);
1201
+ };
1188
1202
  const sendMessagePortToChatMathWorker$1 = async (port, rpcId) => {
1189
1203
  const command = 'HandleMessagePort.handleMessagePort';
1190
1204
  await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToChatMathWorker', port, command, rpcId);
@@ -1199,6 +1213,9 @@ const sendMessagePortToExtensionHostWorker$1 = async (port, rpcId = 0) => {
1199
1213
  const sendMessagePortToChatNetworkWorker = async port => {
1200
1214
  await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToChatNetworkWorker', port, 'HandleMessagePort.handleMessagePort');
1201
1215
  };
1216
+ const sendMessagePortToChatToolWorker = async port => {
1217
+ await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToChatToolWorker', port, 'HandleMessagePort.handleMessagePort');
1218
+ };
1202
1219
  const writeFile = async (uri, text) => {
1203
1220
  await invoke$1('FileSystem.writeFile', uri, text);
1204
1221
  };
@@ -1604,6 +1621,7 @@ const createDefaultState = () => {
1604
1621
  lastSubmittedSessionId: '',
1605
1622
  listItemHeight: 40,
1606
1623
  maxComposerRows: 5,
1624
+ messagesAutoScrollEnabled: true,
1607
1625
  messagesScrollTop: 0,
1608
1626
  mockAiResponseDelay: 800,
1609
1627
  mockApiCommandId: '',
@@ -1643,9 +1661,10 @@ const createDefaultState = () => {
1643
1661
  tokensUsed: 0,
1644
1662
  uid: 0,
1645
1663
  usageOverviewEnabled: false,
1646
- useChatCoordinatorWorker: false,
1664
+ useChatCoordinatorWorker: true,
1647
1665
  useChatMathWorker: true,
1648
1666
  useChatNetworkWorkerForRequests: false,
1667
+ useChatToolWorker: false,
1649
1668
  useMockApi: false,
1650
1669
  viewMode: 'list',
1651
1670
  voiceDictationEnabled: false,
@@ -3104,6 +3123,10 @@ const getAiResponse$1 = async options => {
3104
3123
  return invoke('ChatCoordinator.getAiResponse', options);
3105
3124
  };
3106
3125
 
3126
+ const execute = async (name, rawArguments, options) => {
3127
+ return invoke$3('ChatTool.execute', name, rawArguments, options);
3128
+ };
3129
+
3107
3130
  const getToolErrorPayload = error => {
3108
3131
  const rawStack = error && typeof error === 'object' ? Reflect.get(error, 'stack') : undefined;
3109
3132
  return {
@@ -3282,6 +3305,12 @@ const parseToolArguments = rawArguments => {
3282
3305
  };
3283
3306
 
3284
3307
  const executeChatTool = async (name, rawArguments, options) => {
3308
+ if (options.useChatToolWorker) {
3309
+ return execute(name, rawArguments, {
3310
+ assetDir: options.assetDir,
3311
+ platform: options.platform
3312
+ });
3313
+ }
3285
3314
  const args = parseToolArguments(rawArguments);
3286
3315
  if (name === 'read_file') {
3287
3316
  return executeReadFileTool(args);
@@ -3870,10 +3899,10 @@ const getOpenApiApiEndpoint = openApiApiBaseUrl => {
3870
3899
  };
3871
3900
 
3872
3901
  const makeApiRequest = async options => {
3873
- return invoke$3('ChatNetwork.makeApiRequest', options);
3902
+ return invoke$4('ChatNetwork.makeApiRequest', options);
3874
3903
  };
3875
3904
  const makeStreamingApiRequest = async options => {
3876
- return invoke$3('ChatNetwork.makeStreamingApiRequest', options);
3905
+ return invoke$4('ChatNetwork.makeStreamingApiRequest', options);
3877
3906
  };
3878
3907
 
3879
3908
  const getTextContent = content => {
@@ -4503,6 +4532,7 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
4503
4532
  onToolCallsChunk,
4504
4533
  stream,
4505
4534
  useChatNetworkWorkerForRequests = false,
4535
+ useChatToolWorker = false,
4506
4536
  webSearchEnabled = false
4507
4537
  } = options ?? {
4508
4538
  stream: false
@@ -4608,7 +4638,11 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
4608
4638
  openAiInput.length = 0;
4609
4639
  const executedToolCalls = [];
4610
4640
  for (const toolCall of streamResult.responseFunctionCalls) {
4611
- const content = await executeChatTool(toolCall.name, toolCall.arguments);
4641
+ const content = await executeChatTool(toolCall.name, toolCall.arguments, {
4642
+ assetDir,
4643
+ platform,
4644
+ useChatToolWorker
4645
+ });
4612
4646
  const executionStatus = getToolCallExecutionStatus(content);
4613
4647
  executedToolCalls.push({
4614
4648
  arguments: toolCall.arguments,
@@ -4749,7 +4783,11 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
4749
4783
  openAiInput.length = 0;
4750
4784
  const executedToolCalls = [];
4751
4785
  for (const toolCall of responseFunctionCalls) {
4752
- const content = await executeChatTool(toolCall.name, toolCall.arguments);
4786
+ const content = await executeChatTool(toolCall.name, toolCall.arguments, {
4787
+ assetDir,
4788
+ platform,
4789
+ useChatToolWorker
4790
+ });
4753
4791
  const executionStatus = getToolCallExecutionStatus(content);
4754
4792
  executedToolCalls.push({
4755
4793
  arguments: toolCall.arguments,
@@ -4817,7 +4855,11 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
4817
4855
  }
4818
4856
  const name = Reflect.get(toolFunction, 'name');
4819
4857
  const rawArguments = Reflect.get(toolFunction, 'arguments');
4820
- const content = typeof name === 'string' ? await executeChatTool(name, rawArguments) : '{}';
4858
+ const content = typeof name === 'string' ? await executeChatTool(name, rawArguments, {
4859
+ assetDir,
4860
+ platform,
4861
+ useChatToolWorker
4862
+ }) : '{}';
4821
4863
  if (typeof name === 'string') {
4822
4864
  const executionStatus = getToolCallExecutionStatus(content);
4823
4865
  executedToolCalls.push({
@@ -5065,7 +5107,7 @@ const getOpenRouterLimitInfo = async (openRouterApiKey, openRouterApiBaseUrl, us
5065
5107
  }
5066
5108
  return normalizedLimitInfo;
5067
5109
  };
5068
- const getOpenRouterAssistantText = async (messages, modelId, openRouterApiKey, openRouterApiBaseUrl, assetDir, platform, useChatNetworkWorkerForRequests = false) => {
5110
+ const getOpenRouterAssistantText = async (messages, modelId, openRouterApiKey, openRouterApiBaseUrl, assetDir, platform, useChatNetworkWorkerForRequests = false, useChatToolWorker = false) => {
5069
5111
  const completionMessages = messages.map(message => ({
5070
5112
  content: message.text,
5071
5113
  role: message.role
@@ -5220,7 +5262,11 @@ const getOpenRouterAssistantText = async (messages, modelId, openRouterApiKey, o
5220
5262
  }
5221
5263
  const name = Reflect.get(toolFunction, 'name');
5222
5264
  const rawArguments = Reflect.get(toolFunction, 'arguments');
5223
- const content = typeof name === 'string' ? await executeChatTool(name, rawArguments) : '{}';
5265
+ const content = typeof name === 'string' ? await executeChatTool(name, rawArguments, {
5266
+ assetDir,
5267
+ platform,
5268
+ useChatToolWorker
5269
+ }) : '{}';
5224
5270
  completionMessages.push({
5225
5271
  content,
5226
5272
  role: 'tool',
@@ -5349,6 +5395,7 @@ const getAiResponse = async ({
5349
5395
  streamingEnabled = true,
5350
5396
  useChatCoordinatorWorker = false,
5351
5397
  useChatNetworkWorkerForRequests = false,
5398
+ useChatToolWorker = false,
5352
5399
  useMockApi,
5353
5400
  userText,
5354
5401
  webSearchEnabled = false
@@ -5374,6 +5421,7 @@ const getAiResponse = async ({
5374
5421
  selectedModelId,
5375
5422
  streamingEnabled,
5376
5423
  useChatNetworkWorkerForRequests,
5424
+ useChatToolWorker,
5377
5425
  useMockApi,
5378
5426
  userText,
5379
5427
  webSearchEnabled
@@ -5429,7 +5477,11 @@ const getAiResponse = async ({
5429
5477
  }
5430
5478
  openAiInput.length = 0;
5431
5479
  for (const toolCall of result.responseFunctionCalls) {
5432
- const content = await executeChatTool(toolCall.name, toolCall.arguments);
5480
+ const content = await executeChatTool(toolCall.name, toolCall.arguments, {
5481
+ assetDir,
5482
+ platform,
5483
+ useChatToolWorker
5484
+ });
5433
5485
  openAiInput.push({
5434
5486
  call_id: toolCall.callId,
5435
5487
  output: content,
@@ -5454,6 +5506,7 @@ const getAiResponse = async ({
5454
5506
  } : {}),
5455
5507
  stream: streamingEnabled,
5456
5508
  useChatNetworkWorkerForRequests,
5509
+ useChatToolWorker,
5457
5510
  webSearchEnabled
5458
5511
  });
5459
5512
  if (result.type === 'success') {
@@ -5480,7 +5533,7 @@ const getAiResponse = async ({
5480
5533
  text = getOpenRouterErrorMessage(result);
5481
5534
  }
5482
5535
  } else if (openRouterApiKey) {
5483
- const result = await getOpenRouterAssistantText(messages, modelId, openRouterApiKey, openRouterApiBaseUrl, assetDir, platform, useChatNetworkWorkerForRequests);
5536
+ const result = await getOpenRouterAssistantText(messages, modelId, openRouterApiKey, openRouterApiBaseUrl, assetDir, platform, useChatNetworkWorkerForRequests, useChatToolWorker);
5484
5537
  if (result.type === 'success') {
5485
5538
  const {
5486
5539
  text: assistantText
@@ -5751,6 +5804,48 @@ const parseLinkToken = (value, start) => {
5751
5804
  }
5752
5805
  return undefined;
5753
5806
  };
5807
+ const parseImageToken = (value, start) => {
5808
+ if (value[start] !== '!' || value[start + 1] !== '[') {
5809
+ return undefined;
5810
+ }
5811
+ const textEnd = value.indexOf(']', start + 2);
5812
+ if (textEnd === -1) {
5813
+ return undefined;
5814
+ }
5815
+ if (value[textEnd + 1] !== '(') {
5816
+ return undefined;
5817
+ }
5818
+ let depth = 1;
5819
+ let index = textEnd + 2;
5820
+ while (index < value.length) {
5821
+ const current = value[index];
5822
+ if (current === '\n') {
5823
+ return undefined;
5824
+ }
5825
+ if (current === '(') {
5826
+ depth++;
5827
+ } else if (current === ')') {
5828
+ depth--;
5829
+ if (depth === 0) {
5830
+ const alt = value.slice(start + 2, textEnd);
5831
+ const src = value.slice(textEnd + 2, index);
5832
+ if (!src) {
5833
+ return undefined;
5834
+ }
5835
+ return {
5836
+ length: index - start + 1,
5837
+ node: {
5838
+ alt,
5839
+ src: sanitizeUrl(src),
5840
+ type: 'image'
5841
+ }
5842
+ };
5843
+ }
5844
+ }
5845
+ index++;
5846
+ }
5847
+ return undefined;
5848
+ };
5754
5849
  const parseBoldToken = (value, start) => {
5755
5850
  if (value[start] !== '*' || value[start + 1] !== '*') {
5756
5851
  return undefined;
@@ -5812,6 +5907,26 @@ const parseItalicToken = (value, start) => {
5812
5907
  }
5813
5908
  };
5814
5909
  };
5910
+ const parseStrikethroughToken = (value, start) => {
5911
+ if (value[start] !== '~' || value[start + 1] !== '~') {
5912
+ return undefined;
5913
+ }
5914
+ const end = value.indexOf('~~', start + 2);
5915
+ if (end === -1) {
5916
+ return undefined;
5917
+ }
5918
+ const text = value.slice(start + 2, end);
5919
+ if (!text || text.includes('\n')) {
5920
+ return undefined;
5921
+ }
5922
+ return {
5923
+ length: end - start + 2,
5924
+ node: {
5925
+ children: parseInlineNodes(text),
5926
+ type: 'strikethrough'
5927
+ }
5928
+ };
5929
+ };
5815
5930
  const parseMathToken = (value, start) => {
5816
5931
  if (value[start] !== '$') {
5817
5932
  return undefined;
@@ -5858,7 +5973,7 @@ const parseMathToken = (value, start) => {
5858
5973
  return undefined;
5859
5974
  };
5860
5975
  const parseInlineToken = (value, start) => {
5861
- return parseLinkToken(value, start) || parseBoldToken(value, start) || parseItalicToken(value, start) || parseMathToken(value, start);
5976
+ return parseImageToken(value, start) || parseLinkToken(value, start) || parseBoldToken(value, start) || parseItalicToken(value, start) || parseLinkToken(value, start) || parseBoldToken(value, start) || parseItalicToken(value, start) || parseStrikethroughToken(value, start) || parseMathToken(value, start);
5862
5977
  };
5863
5978
  const parseInlineNodes = value => {
5864
5979
  const nodes = [];
@@ -5894,105 +6009,311 @@ const parseInlineNodes = value => {
5894
6009
  return nodes;
5895
6010
  };
5896
6011
 
5897
- const isTableSeparatorCell = value => {
5898
- if (!value) {
5899
- return false;
6012
+ const markdownMathBlockDelimiter = '$$';
6013
+ const normalizeEscapedNewlines = value => {
6014
+ if (value.includes('\\n')) {
6015
+ return value.replaceAll(/\\r\\n|\\n/g, '\n');
5900
6016
  }
6017
+ return value;
6018
+ };
6019
+ const normalizeInlineTables = value => {
6020
+ return value.split(/\r?\n/).map(line => {
6021
+ if (!line.includes('|')) {
6022
+ return line;
6023
+ }
6024
+ if (!/\|\s*[-:]{3,}/.test(line)) {
6025
+ return line;
6026
+ }
6027
+ return line.replaceAll(/\|\s+\|/g, '|\n|');
6028
+ }).join('\n');
6029
+ };
6030
+ const parseHeadingLine = line => {
6031
+ const trimmedStart = line.trimStart();
5901
6032
  let index = 0;
5902
- if (value[index] === ':') {
6033
+ while (index < trimmedStart.length && trimmedStart[index] === '#') {
5903
6034
  index++;
5904
6035
  }
5905
- let dashCount = 0;
5906
- while (index < value.length && value[index] === '-') {
5907
- dashCount++;
5908
- index++;
6036
+ if (index === 0 || index > 6) {
6037
+ return undefined;
5909
6038
  }
5910
- if (dashCount < 3) {
5911
- return false;
6039
+ if (trimmedStart[index] !== ' ') {
6040
+ return undefined;
5912
6041
  }
5913
- if (index < value.length && value[index] === ':') {
6042
+ const text = trimmedStart.slice(index).trimStart();
6043
+ return {
6044
+ level: index,
6045
+ text
6046
+ };
6047
+ };
6048
+ const parseOrderedListItemLine = line => {
6049
+ let index = 0;
6050
+ while (index < line.length && line[index] === ' ') {
5914
6051
  index++;
5915
6052
  }
5916
- return index === value.length;
5917
- };
5918
- const isTableSeparatorToken = (token, expectedColumns) => {
5919
- if (!token || token.type !== 'table-row-line') {
5920
- return false;
6053
+ const firstDigit = index;
6054
+ while (index < line.length && line[index] >= '0' && line[index] <= '9') {
6055
+ index++;
5921
6056
  }
5922
- if (token.cells.length !== expectedColumns) {
5923
- return false;
6057
+ if (index === firstDigit || line[index] !== '.') {
6058
+ return undefined;
6059
+ }
6060
+ index++;
6061
+ if (line[index] !== ' ') {
6062
+ return undefined;
6063
+ }
6064
+ while (index < line.length && line[index] === ' ') {
6065
+ index++;
5924
6066
  }
5925
- return token.cells.every(isTableSeparatorCell);
5926
- };
5927
- const toTableCell = value => {
5928
6067
  return {
5929
- children: parseInlineNodes(value),
5930
- type: 'table-cell'
6068
+ text: line.slice(index)
5931
6069
  };
5932
6070
  };
5933
- const toTableRow = token => {
6071
+ const parseUnorderedListItemLine = line => {
6072
+ let indentation = 0;
6073
+ while (indentation < line.length && line[indentation] === ' ') {
6074
+ indentation++;
6075
+ }
6076
+ const marker = line[indentation];
6077
+ if (marker !== '-' && marker !== '*') {
6078
+ return undefined;
6079
+ }
6080
+ let index = indentation + 1;
6081
+ if (line[index] !== ' ') {
6082
+ return undefined;
6083
+ }
6084
+ while (index < line.length && line[index] === ' ') {
6085
+ index++;
6086
+ }
5934
6087
  return {
5935
- cells: token.cells.map(toTableCell),
5936
- type: 'table-row'
6088
+ indentation,
6089
+ text: line.slice(index)
5937
6090
  };
5938
6091
  };
5939
- const getEmptyTextNode = () => {
5940
- return [{
5941
- children: [{
5942
- text: '',
5943
- type: 'text'
5944
- }],
5945
- type: 'text'
5946
- }];
6092
+ const parseBlockQuoteLine = line => {
6093
+ const trimmedStart = line.trimStart();
6094
+ if (!trimmedStart.startsWith('>')) {
6095
+ return undefined;
6096
+ }
6097
+ const content = trimmedStart.slice(1);
6098
+ if (!content) {
6099
+ return '';
6100
+ }
6101
+ if (content.startsWith(' ')) {
6102
+ return content.slice(1);
6103
+ }
6104
+ return content;
5947
6105
  };
5948
- const parseBlockTokens = tokens => {
5949
- if (tokens.length === 0) {
5950
- return getEmptyTextNode();
6106
+ const isTableRow = line => {
6107
+ const trimmed = line.trim();
6108
+ if (!trimmed.startsWith('|') || !trimmed.endsWith('|')) {
6109
+ return false;
5951
6110
  }
5952
- const nodes = [];
5953
- let paragraphLines = [];
5954
- let listItems = [];
5955
- let listType = '';
5956
- const flushParagraph = () => {
5957
- if (paragraphLines.length === 0) {
5958
- return;
5959
- }
5960
- nodes.push({
5961
- children: parseInlineNodes(paragraphLines.join('\n')),
5962
- type: 'text'
5963
- });
5964
- paragraphLines = [];
5965
- };
5966
- const flushList = () => {
5967
- if (listItems.length === 0) {
5968
- return;
6111
+ return trimmed.length > 2 && trimmed.slice(1, -1).includes('|');
6112
+ };
6113
+ const getTableCells = line => {
6114
+ const trimmed = line.trim();
6115
+ return trimmed.slice(1, -1).split('|').map(part => part.trim());
6116
+ };
6117
+ const scanBlockTokens = rawMessage => {
6118
+ const normalizedMessage = normalizeInlineTables(normalizeEscapedNewlines(rawMessage));
6119
+ const lines = normalizedMessage.split(/\r?\n/);
6120
+ const tokens = [];
6121
+ for (let i = 0; i < lines.length; i++) {
6122
+ const line = lines[i];
6123
+ const trimmed = line.trim();
6124
+ if (!trimmed) {
6125
+ tokens.push({
6126
+ type: 'blank-line'
6127
+ });
6128
+ continue;
5969
6129
  }
5970
- nodes.push({
5971
- items: listItems,
5972
- type: listType || 'ordered-list'
5973
- });
5974
- listItems = [];
5975
- listType = '';
5976
- };
5977
- for (let i = 0; i < tokens.length; i++) {
5978
- const token = tokens[i];
5979
- if (token.type === 'blank-line') {
5980
- flushList();
5981
- flushParagraph();
6130
+ const blockQuoteLine = parseBlockQuoteLine(line);
6131
+ if (blockQuoteLine !== undefined) {
6132
+ tokens.push({
6133
+ text: blockQuoteLine,
6134
+ type: 'blockquote-line'
6135
+ });
5982
6136
  continue;
5983
6137
  }
5984
- if (token.type === 'code-block') {
5985
- flushList();
5986
- flushParagraph();
5987
- if (token.language) {
5988
- nodes.push({
5989
- language: token.language,
5990
- text: token.text,
6138
+ if (trimmed.startsWith('```')) {
6139
+ const language = trimmed.slice(3).trim();
6140
+ const codeLines = [];
6141
+ i++;
6142
+ while (i < lines.length && !lines[i].trim().startsWith('```')) {
6143
+ codeLines.push(lines[i]);
6144
+ i++;
6145
+ }
6146
+ if (language) {
6147
+ tokens.push({
6148
+ language,
6149
+ text: codeLines.join('\n'),
5991
6150
  type: 'code-block'
5992
6151
  });
5993
6152
  } else {
5994
- nodes.push({
5995
- text: token.text,
6153
+ tokens.push({
6154
+ text: codeLines.join('\n'),
6155
+ type: 'code-block'
6156
+ });
6157
+ }
6158
+ continue;
6159
+ }
6160
+ if (trimmed === markdownMathBlockDelimiter) {
6161
+ const endIndex = lines.findIndex((candidate, index) => {
6162
+ if (index <= i) {
6163
+ return false;
6164
+ }
6165
+ return candidate.trim() === markdownMathBlockDelimiter;
6166
+ });
6167
+ if (endIndex !== -1) {
6168
+ tokens.push({
6169
+ text: lines.slice(i + 1, endIndex).join('\n').trim(),
6170
+ type: 'math-block'
6171
+ });
6172
+ i = endIndex;
6173
+ continue;
6174
+ }
6175
+ }
6176
+ const heading = parseHeadingLine(line);
6177
+ if (heading) {
6178
+ tokens.push({
6179
+ level: heading.level,
6180
+ text: heading.text,
6181
+ type: 'heading-line'
6182
+ });
6183
+ continue;
6184
+ }
6185
+ const ordered = parseOrderedListItemLine(line);
6186
+ if (ordered) {
6187
+ tokens.push({
6188
+ text: ordered.text,
6189
+ type: 'ordered-list-item-line'
6190
+ });
6191
+ continue;
6192
+ }
6193
+ const unordered = parseUnorderedListItemLine(line);
6194
+ if (unordered) {
6195
+ tokens.push({
6196
+ indentation: unordered.indentation,
6197
+ text: unordered.text,
6198
+ type: 'unordered-list-item-line'
6199
+ });
6200
+ continue;
6201
+ }
6202
+ if (isTableRow(line)) {
6203
+ tokens.push({
6204
+ cells: getTableCells(line),
6205
+ line,
6206
+ type: 'table-row-line'
6207
+ });
6208
+ continue;
6209
+ }
6210
+ tokens.push({
6211
+ text: line,
6212
+ type: 'paragraph-line'
6213
+ });
6214
+ }
6215
+ return tokens;
6216
+ };
6217
+
6218
+ const isTableSeparatorCell = value => {
6219
+ if (!value) {
6220
+ return false;
6221
+ }
6222
+ let index = 0;
6223
+ if (value[index] === ':') {
6224
+ index++;
6225
+ }
6226
+ let dashCount = 0;
6227
+ while (index < value.length && value[index] === '-') {
6228
+ dashCount++;
6229
+ index++;
6230
+ }
6231
+ if (dashCount < 3) {
6232
+ return false;
6233
+ }
6234
+ if (index < value.length && value[index] === ':') {
6235
+ index++;
6236
+ }
6237
+ return index === value.length;
6238
+ };
6239
+ const isTableSeparatorToken = (token, expectedColumns) => {
6240
+ if (!token || token.type !== 'table-row-line') {
6241
+ return false;
6242
+ }
6243
+ if (token.cells.length !== expectedColumns) {
6244
+ return false;
6245
+ }
6246
+ return token.cells.every(isTableSeparatorCell);
6247
+ };
6248
+ const toTableCell = value => {
6249
+ return {
6250
+ children: parseInlineNodes(value),
6251
+ type: 'table-cell'
6252
+ };
6253
+ };
6254
+ const toTableRow = token => {
6255
+ return {
6256
+ cells: token.cells.map(toTableCell),
6257
+ type: 'table-row'
6258
+ };
6259
+ };
6260
+ const getEmptyTextNode = () => {
6261
+ return [{
6262
+ children: [{
6263
+ text: '',
6264
+ type: 'text'
6265
+ }],
6266
+ type: 'text'
6267
+ }];
6268
+ };
6269
+ const parseBlockTokens = tokens => {
6270
+ if (tokens.length === 0) {
6271
+ return getEmptyTextNode();
6272
+ }
6273
+ const nodes = [];
6274
+ let paragraphLines = [];
6275
+ let listItems = [];
6276
+ let listType = '';
6277
+ const flushParagraph = () => {
6278
+ if (paragraphLines.length === 0) {
6279
+ return;
6280
+ }
6281
+ nodes.push({
6282
+ children: parseInlineNodes(paragraphLines.join('\n')),
6283
+ type: 'text'
6284
+ });
6285
+ paragraphLines = [];
6286
+ };
6287
+ const flushList = () => {
6288
+ if (listItems.length === 0) {
6289
+ return;
6290
+ }
6291
+ nodes.push({
6292
+ items: listItems,
6293
+ type: listType || 'ordered-list'
6294
+ });
6295
+ listItems = [];
6296
+ listType = '';
6297
+ };
6298
+ for (let i = 0; i < tokens.length; i++) {
6299
+ const token = tokens[i];
6300
+ if (token.type === 'blank-line') {
6301
+ flushList();
6302
+ flushParagraph();
6303
+ continue;
6304
+ }
6305
+ if (token.type === 'code-block') {
6306
+ flushList();
6307
+ flushParagraph();
6308
+ if (token.language) {
6309
+ nodes.push({
6310
+ language: token.language,
6311
+ text: token.text,
6312
+ type: 'code-block'
6313
+ });
6314
+ } else {
6315
+ nodes.push({
6316
+ text: token.text,
5996
6317
  type: 'code-block'
5997
6318
  });
5998
6319
  }
@@ -6007,6 +6328,24 @@ const parseBlockTokens = tokens => {
6007
6328
  });
6008
6329
  continue;
6009
6330
  }
6331
+ if (token.type === 'blockquote-line') {
6332
+ flushList();
6333
+ flushParagraph();
6334
+ const lines = [];
6335
+ while (i < tokens.length && tokens[i].type === 'blockquote-line') {
6336
+ const quoteToken = tokens[i];
6337
+ if (quoteToken.type === 'blockquote-line') {
6338
+ lines.push(quoteToken.text);
6339
+ }
6340
+ i++;
6341
+ }
6342
+ i--;
6343
+ nodes.push({
6344
+ children: parseBlockTokens(scanBlockTokens(lines.join('\n'))),
6345
+ type: 'blockquote'
6346
+ });
6347
+ continue;
6348
+ }
6010
6349
  if (token.type === 'table-row-line') {
6011
6350
  const expectedColumns = token.cells.length;
6012
6351
  if (isTableSeparatorToken(tokens[i + 1], expectedColumns)) {
@@ -6093,190 +6432,6 @@ const parseBlockTokens = tokens => {
6093
6432
  return nodes.length === 0 ? getEmptyTextNode() : nodes;
6094
6433
  };
6095
6434
 
6096
- const markdownMathBlockDelimiter = '$$';
6097
- const normalizeEscapedNewlines = value => {
6098
- if (value.includes('\\n')) {
6099
- return value.replaceAll(/\\r\\n|\\n/g, '\n');
6100
- }
6101
- return value;
6102
- };
6103
- const normalizeInlineTables = value => {
6104
- return value.split(/\r?\n/).map(line => {
6105
- if (!line.includes('|')) {
6106
- return line;
6107
- }
6108
- if (!/\|\s*[-:]{3,}/.test(line)) {
6109
- return line;
6110
- }
6111
- return line.replaceAll(/\|\s+\|/g, '|\n|');
6112
- }).join('\n');
6113
- };
6114
- const parseHeadingLine = line => {
6115
- const trimmedStart = line.trimStart();
6116
- let index = 0;
6117
- while (index < trimmedStart.length && trimmedStart[index] === '#') {
6118
- index++;
6119
- }
6120
- if (index === 0 || index > 6) {
6121
- return undefined;
6122
- }
6123
- if (trimmedStart[index] !== ' ') {
6124
- return undefined;
6125
- }
6126
- const text = trimmedStart.slice(index).trimStart();
6127
- return {
6128
- level: index,
6129
- text
6130
- };
6131
- };
6132
- const parseOrderedListItemLine = line => {
6133
- let index = 0;
6134
- while (index < line.length && line[index] === ' ') {
6135
- index++;
6136
- }
6137
- const firstDigit = index;
6138
- while (index < line.length && line[index] >= '0' && line[index] <= '9') {
6139
- index++;
6140
- }
6141
- if (index === firstDigit || line[index] !== '.') {
6142
- return undefined;
6143
- }
6144
- index++;
6145
- if (line[index] !== ' ') {
6146
- return undefined;
6147
- }
6148
- while (index < line.length && line[index] === ' ') {
6149
- index++;
6150
- }
6151
- return {
6152
- text: line.slice(index)
6153
- };
6154
- };
6155
- const parseUnorderedListItemLine = line => {
6156
- let indentation = 0;
6157
- while (indentation < line.length && line[indentation] === ' ') {
6158
- indentation++;
6159
- }
6160
- const marker = line[indentation];
6161
- if (marker !== '-' && marker !== '*') {
6162
- return undefined;
6163
- }
6164
- let index = indentation + 1;
6165
- if (line[index] !== ' ') {
6166
- return undefined;
6167
- }
6168
- while (index < line.length && line[index] === ' ') {
6169
- index++;
6170
- }
6171
- return {
6172
- indentation,
6173
- text: line.slice(index)
6174
- };
6175
- };
6176
- const isTableRow = line => {
6177
- const trimmed = line.trim();
6178
- if (!trimmed.startsWith('|') || !trimmed.endsWith('|')) {
6179
- return false;
6180
- }
6181
- return trimmed.length > 2 && trimmed.slice(1, -1).includes('|');
6182
- };
6183
- const getTableCells = line => {
6184
- const trimmed = line.trim();
6185
- return trimmed.slice(1, -1).split('|').map(part => part.trim());
6186
- };
6187
- const scanBlockTokens = rawMessage => {
6188
- const normalizedMessage = normalizeInlineTables(normalizeEscapedNewlines(rawMessage));
6189
- const lines = normalizedMessage.split(/\r?\n/);
6190
- const tokens = [];
6191
- for (let i = 0; i < lines.length; i++) {
6192
- const line = lines[i];
6193
- const trimmed = line.trim();
6194
- if (!trimmed) {
6195
- tokens.push({
6196
- type: 'blank-line'
6197
- });
6198
- continue;
6199
- }
6200
- if (trimmed.startsWith('```')) {
6201
- const language = trimmed.slice(3).trim();
6202
- const codeLines = [];
6203
- i++;
6204
- while (i < lines.length && !lines[i].trim().startsWith('```')) {
6205
- codeLines.push(lines[i]);
6206
- i++;
6207
- }
6208
- if (language) {
6209
- tokens.push({
6210
- language,
6211
- text: codeLines.join('\n'),
6212
- type: 'code-block'
6213
- });
6214
- } else {
6215
- tokens.push({
6216
- text: codeLines.join('\n'),
6217
- type: 'code-block'
6218
- });
6219
- }
6220
- continue;
6221
- }
6222
- if (trimmed === markdownMathBlockDelimiter) {
6223
- const endIndex = lines.findIndex((candidate, index) => {
6224
- if (index <= i) {
6225
- return false;
6226
- }
6227
- return candidate.trim() === markdownMathBlockDelimiter;
6228
- });
6229
- if (endIndex !== -1) {
6230
- tokens.push({
6231
- text: lines.slice(i + 1, endIndex).join('\n').trim(),
6232
- type: 'math-block'
6233
- });
6234
- i = endIndex;
6235
- continue;
6236
- }
6237
- }
6238
- const heading = parseHeadingLine(line);
6239
- if (heading) {
6240
- tokens.push({
6241
- level: heading.level,
6242
- text: heading.text,
6243
- type: 'heading-line'
6244
- });
6245
- continue;
6246
- }
6247
- const ordered = parseOrderedListItemLine(line);
6248
- if (ordered) {
6249
- tokens.push({
6250
- text: ordered.text,
6251
- type: 'ordered-list-item-line'
6252
- });
6253
- continue;
6254
- }
6255
- const unordered = parseUnorderedListItemLine(line);
6256
- if (unordered) {
6257
- tokens.push({
6258
- indentation: unordered.indentation,
6259
- text: unordered.text,
6260
- type: 'unordered-list-item-line'
6261
- });
6262
- continue;
6263
- }
6264
- if (isTableRow(line)) {
6265
- tokens.push({
6266
- cells: getTableCells(line),
6267
- line,
6268
- type: 'table-row-line'
6269
- });
6270
- continue;
6271
- }
6272
- tokens.push({
6273
- text: line,
6274
- type: 'paragraph-line'
6275
- });
6276
- }
6277
- return tokens;
6278
- };
6279
-
6280
6435
  const parseMessageContent = rawMessage => {
6281
6436
  return parseBlockTokens(scanBlockTokens(rawMessage));
6282
6437
  };
@@ -6313,6 +6468,13 @@ const parseMathInline = async children => {
6313
6468
  });
6314
6469
  continue;
6315
6470
  }
6471
+ if (child.type === 'strikethrough') {
6472
+ nextChildren.push({
6473
+ ...child,
6474
+ children: await parseMathInline(child.children)
6475
+ });
6476
+ continue;
6477
+ }
6316
6478
  nextChildren.push(child);
6317
6479
  }
6318
6480
  return nextChildren;
@@ -6341,60 +6503,69 @@ const parseMathTableCell = async cell => {
6341
6503
  children: await parseMathInline(cell.children)
6342
6504
  };
6343
6505
  };
6344
- const parseMessage = async rawMessage => {
6345
- const parsedContent = parseMessageContent(rawMessage);
6346
- const nextParsedContent = [];
6347
- for (const node of parsedContent) {
6348
- if (node.type === 'math-block') {
6349
- const dom = await getMathBlockDom(node);
6350
- nextParsedContent.push({
6351
- dom,
6352
- type: 'math-block-dom'
6353
- });
6354
- continue;
6355
- }
6356
- if (node.type === 'text' || node.type === 'heading') {
6357
- nextParsedContent.push({
6358
- ...node,
6359
- children: await parseMathInline(node.children)
6360
- });
6361
- continue;
6506
+ const parseMathNode = async node => {
6507
+ if (node.type === 'math-block') {
6508
+ const dom = await getMathBlockDom(node);
6509
+ return {
6510
+ dom,
6511
+ type: 'math-block-dom'
6512
+ };
6513
+ }
6514
+ if (node.type === 'text' || node.type === 'heading') {
6515
+ return {
6516
+ ...node,
6517
+ children: await parseMathInline(node.children)
6518
+ };
6519
+ }
6520
+ if (node.type === 'blockquote') {
6521
+ const children = [];
6522
+ for (const child of node.children) {
6523
+ children.push(await parseMathNode(child));
6362
6524
  }
6363
- if (node.type === 'ordered-list' || node.type === 'unordered-list') {
6364
- const items = [];
6365
- for (const item of node.items) {
6366
- items.push(await parseMathListItem(item));
6367
- }
6368
- nextParsedContent.push({
6369
- ...node,
6370
- items
6371
- });
6372
- continue;
6525
+ return {
6526
+ ...node,
6527
+ children
6528
+ };
6529
+ }
6530
+ if (node.type === 'ordered-list' || node.type === 'unordered-list') {
6531
+ const items = [];
6532
+ for (const item of node.items) {
6533
+ items.push(await parseMathListItem(item));
6373
6534
  }
6374
- if (node.type === 'table') {
6375
- const headers = [];
6376
- for (const header of node.headers) {
6377
- headers.push(await parseMathTableCell(header));
6378
- }
6379
- const rows = [];
6380
- for (const row of node.rows) {
6381
- const cells = [];
6382
- for (const cell of row.cells) {
6383
- cells.push(await parseMathTableCell(cell));
6384
- }
6385
- rows.push({
6386
- ...row,
6387
- cells
6388
- });
6535
+ return {
6536
+ ...node,
6537
+ items
6538
+ };
6539
+ }
6540
+ if (node.type === 'table') {
6541
+ const headers = [];
6542
+ for (const header of node.headers) {
6543
+ headers.push(await parseMathTableCell(header));
6544
+ }
6545
+ const rows = [];
6546
+ for (const row of node.rows) {
6547
+ const cells = [];
6548
+ for (const cell of row.cells) {
6549
+ cells.push(await parseMathTableCell(cell));
6389
6550
  }
6390
- nextParsedContent.push({
6391
- ...node,
6392
- headers,
6393
- rows
6551
+ rows.push({
6552
+ ...row,
6553
+ cells
6394
6554
  });
6395
- continue;
6396
6555
  }
6397
- nextParsedContent.push(node);
6556
+ return {
6557
+ ...node,
6558
+ headers,
6559
+ rows
6560
+ };
6561
+ }
6562
+ return node;
6563
+ };
6564
+ const parseMessage = async rawMessage => {
6565
+ const parsedContent = parseMessageContent(rawMessage);
6566
+ const nextParsedContent = [];
6567
+ for (const node of parsedContent) {
6568
+ nextParsedContent.push(await parseMathNode(node));
6398
6569
  }
6399
6570
  return nextParsedContent;
6400
6571
  };
@@ -6591,6 +6762,7 @@ Assistant: ${assistantText}`;
6591
6762
  streamingEnabled: false,
6592
6763
  useChatCoordinatorWorker: state.useChatCoordinatorWorker,
6593
6764
  useChatNetworkWorkerForRequests: state.useChatNetworkWorkerForRequests,
6765
+ useChatToolWorker: state.useChatToolWorker,
6594
6766
  useMockApi,
6595
6767
  userText: titlePrompt,
6596
6768
  webSearchEnabled: false
@@ -6649,6 +6821,12 @@ const getMentionContextMessage = async value => {
6649
6821
  };
6650
6822
  };
6651
6823
 
6824
+ const AutoScrollTopA = Number.MAX_SAFE_INTEGER;
6825
+ const AutoScrollTopB = Number.MAX_SAFE_INTEGER - 1;
6826
+ const getNextAutoScrollTop = currentScrollTop => {
6827
+ return currentScrollTop === AutoScrollTopA ? AutoScrollTopB : AutoScrollTopA;
6828
+ };
6829
+
6652
6830
  const slashCommandRegex = /^\/(clear|export|help|new)(?:\s+.*)?$/;
6653
6831
  const getSlashCommand = value => {
6654
6832
  const trimmed = value.trim();
@@ -6738,6 +6916,9 @@ const handleTextChunkFunction = async (uid, assistantMessageId, chunk, handleTex
6738
6916
  const updated = await updateMessageTextInSelectedSession(handleTextChunkState.latestState.sessions, handleTextChunkState.latestState.parsedMessages, handleTextChunkState.latestState.selectedSessionId, assistantMessageId, updatedText, true);
6739
6917
  const nextState = {
6740
6918
  ...handleTextChunkState.latestState,
6919
+ ...(handleTextChunkState.latestState.messagesAutoScrollEnabled ? {
6920
+ messagesScrollTop: getNextAutoScrollTop(handleTextChunkState.latestState.messagesScrollTop)
6921
+ } : {}),
6741
6922
  parsedMessages: updated.parsedMessages,
6742
6923
  sessions: updated.sessions
6743
6924
  };
@@ -6767,6 +6948,9 @@ const handleToolCallsChunkFunction = async (uid, assistantMessageId, toolCalls,
6767
6948
  const updated = updateMessageToolCallsInSelectedSession(handleTextChunkState.latestState.sessions, handleTextChunkState.latestState.parsedMessages, handleTextChunkState.latestState.selectedSessionId, assistantMessageId, toolCalls);
6768
6949
  const nextState = {
6769
6950
  ...handleTextChunkState.latestState,
6951
+ ...(handleTextChunkState.latestState.messagesAutoScrollEnabled ? {
6952
+ messagesScrollTop: getNextAutoScrollTop(handleTextChunkState.latestState.messagesScrollTop)
6953
+ } : {}),
6770
6954
  parsedMessages: updated.parsedMessages,
6771
6955
  sessions: updated.sessions
6772
6956
  };
@@ -6832,6 +7016,15 @@ const updateSessionTitle = (sessions, selectedSessionId, title) => {
6832
7016
  });
6833
7017
  };
6834
7018
 
7019
+ const withUpdatedMessageScrollTop = state => {
7020
+ if (!state.messagesAutoScrollEnabled) {
7021
+ return state;
7022
+ }
7023
+ return {
7024
+ ...state,
7025
+ messagesScrollTop: getNextAutoScrollTop(state.messagesScrollTop)
7026
+ };
7027
+ };
6835
7028
  const handleSubmit = async state => {
6836
7029
  const {
6837
7030
  aiSessionTitleGenerationEnabled,
@@ -6854,6 +7047,7 @@ const handleSubmit = async state => {
6854
7047
  streamingEnabled,
6855
7048
  useChatCoordinatorWorker,
6856
7049
  useChatNetworkWorkerForRequests,
7050
+ useChatToolWorker,
6857
7051
  useMockApi,
6858
7052
  viewMode,
6859
7053
  webSearchEnabled
@@ -6922,7 +7116,7 @@ const handleSubmit = async state => {
6922
7116
  title: `Chat ${workingSessions.length + 1}`
6923
7117
  };
6924
7118
  await saveChatSession(newSession);
6925
- optimisticState = focusInput({
7119
+ optimisticState = withUpdatedMessageScrollTop(focusInput({
6926
7120
  ...state,
6927
7121
  composerHeight: getMinComposerHeightForState(state),
6928
7122
  composerValue: '',
@@ -6933,7 +7127,7 @@ const handleSubmit = async state => {
6933
7127
  selectedSessionId: newSessionId,
6934
7128
  sessions: [...workingSessions, newSession],
6935
7129
  viewMode: 'detail'
6936
- });
7130
+ }));
6937
7131
  } else {
6938
7132
  await appendChatViewEvent({
6939
7133
  sessionId: selectedSessionId,
@@ -6947,7 +7141,7 @@ const handleSubmit = async state => {
6947
7141
  if (selectedSession) {
6948
7142
  await saveChatSession(selectedSession);
6949
7143
  }
6950
- optimisticState = focusInput({
7144
+ optimisticState = withUpdatedMessageScrollTop(focusInput({
6951
7145
  ...state,
6952
7146
  composerHeight: getMinComposerHeightForState(state),
6953
7147
  composerValue: '',
@@ -6956,7 +7150,7 @@ const handleSubmit = async state => {
6956
7150
  nextMessageId: nextMessageId + 1,
6957
7151
  parsedMessages,
6958
7152
  sessions: updatedSessions
6959
- });
7153
+ }));
6960
7154
  }
6961
7155
  set$1(state.uid, state, optimisticState);
6962
7156
  // @ts-ignore
@@ -7016,6 +7210,7 @@ const handleSubmit = async state => {
7016
7210
  streamingEnabled,
7017
7211
  useChatCoordinatorWorker,
7018
7212
  useChatNetworkWorkerForRequests,
7213
+ useChatToolWorker,
7019
7214
  useMockApi,
7020
7215
  userText,
7021
7216
  webSearchEnabled
@@ -7046,12 +7241,12 @@ const handleSubmit = async state => {
7046
7241
  if (selectedSession) {
7047
7242
  await saveChatSession(selectedSession);
7048
7243
  }
7049
- return focusInput({
7244
+ return withUpdatedMessageScrollTop(focusInput({
7050
7245
  ...latestState,
7051
7246
  nextMessageId: latestState.nextMessageId + 1,
7052
7247
  parsedMessages: finalParsedMessages,
7053
7248
  sessions: updatedSessions
7054
- });
7249
+ }));
7055
7250
  };
7056
7251
 
7057
7252
  const handleClickSend = async state => {
@@ -7313,7 +7508,8 @@ const handleClickDictationButton = async state => {
7313
7508
  };
7314
7509
 
7315
7510
  const handleClickNew = async state => {
7316
- return createSession(state);
7511
+ const newState = await createSession(state);
7512
+ return focusInput(newState);
7317
7513
  };
7318
7514
 
7319
7515
  const handleClickReadFile = async uri => {
@@ -7329,7 +7525,6 @@ const handleClickSessionDebug = async state => {
7329
7525
  };
7330
7526
 
7331
7527
  const handleClickSettings = async () => {
7332
- // TODO
7333
7528
  await invoke$1('Main.openUri', 'app://settings.json');
7334
7529
  };
7335
7530
 
@@ -7574,12 +7769,14 @@ const handleChatListScroll = async (state, chatListScrollTop) => {
7574
7769
  chatListScrollTop
7575
7770
  };
7576
7771
  };
7577
- const handleMessagesScroll = async (state, messagesScrollTop) => {
7578
- if (state.messagesScrollTop === messagesScrollTop) {
7772
+ const handleMessagesScroll = async (state, messagesScrollTop, scrollHeight, clientHeight) => {
7773
+ const messagesAutoScrollEnabled = messagesScrollTop + clientHeight >= scrollHeight - 8;
7774
+ if (state.messagesScrollTop === messagesScrollTop && state.messagesAutoScrollEnabled === messagesAutoScrollEnabled) {
7579
7775
  return state;
7580
7776
  }
7581
7777
  return {
7582
7778
  ...state,
7779
+ messagesAutoScrollEnabled,
7583
7780
  messagesScrollTop
7584
7781
  };
7585
7782
  };
@@ -7612,7 +7809,7 @@ const createExtensionHostRpc = async () => {
7612
7809
 
7613
7810
  const initialize = async () => {
7614
7811
  const rpc = await createExtensionHostRpc();
7615
- set$3(rpc);
7812
+ set$4(rpc);
7616
7813
  };
7617
7814
 
7618
7815
  const isObject = value => {
@@ -7771,9 +7968,9 @@ const loadStreamingEnabled = async () => {
7771
7968
  const loadUseChatCoordinatorWorker = async () => {
7772
7969
  try {
7773
7970
  const savedUseChatCoordinatorWorker = await get('chatView.useChatCoordinatorWorker');
7774
- return typeof savedUseChatCoordinatorWorker === 'boolean' ? savedUseChatCoordinatorWorker : false;
7971
+ return typeof savedUseChatCoordinatorWorker === 'boolean' ? savedUseChatCoordinatorWorker : true;
7775
7972
  } catch {
7776
- return false;
7973
+ return true;
7777
7974
  }
7778
7975
  };
7779
7976
 
@@ -7795,6 +7992,15 @@ const loadUseChatNetworkWorkerForRequests = async () => {
7795
7992
  }
7796
7993
  };
7797
7994
 
7995
+ const loadUseChatToolWorker = async () => {
7996
+ try {
7997
+ const savedUseChatToolWorker = await get('chatView.useChatToolWorker');
7998
+ return typeof savedUseChatToolWorker === 'boolean' ? savedUseChatToolWorker : false;
7999
+ } catch {
8000
+ return false;
8001
+ }
8002
+ };
8003
+
7798
8004
  const loadVoiceDictationEnabled = async () => {
7799
8005
  try {
7800
8006
  const savedVoiceDictationEnabled = await get('chatView.voiceDictationEnabled');
@@ -7805,7 +8011,7 @@ const loadVoiceDictationEnabled = async () => {
7805
8011
  };
7806
8012
 
7807
8013
  const loadPreferences = async () => {
7808
- const [aiSessionTitleGenerationEnabled, composerDropEnabled, openApiApiKey, openRouterApiKey, emitStreamingFunctionCallEvents, streamingEnabled, passIncludeObfuscation, useChatCoordinatorWorker, useChatMathWorker, useChatNetworkWorkerForRequests, voiceDictationEnabled] = await Promise.all([loadAiSessionTitleGenerationEnabled(), loadComposerDropEnabled(), loadOpenApiApiKey(), loadOpenRouterApiKey(), loadEmitStreamingFunctionCallEvents(), loadStreamingEnabled(), loadPassIncludeObfuscation(), loadUseChatCoordinatorWorker(), loadUseChatMathWorker(), loadUseChatNetworkWorkerForRequests(), loadVoiceDictationEnabled()]);
8014
+ const [aiSessionTitleGenerationEnabled, composerDropEnabled, openApiApiKey, openRouterApiKey, emitStreamingFunctionCallEvents, streamingEnabled, passIncludeObfuscation, useChatCoordinatorWorker, useChatMathWorker, useChatNetworkWorkerForRequests, useChatToolWorker, voiceDictationEnabled] = await Promise.all([loadAiSessionTitleGenerationEnabled(), loadComposerDropEnabled(), loadOpenApiApiKey(), loadOpenRouterApiKey(), loadEmitStreamingFunctionCallEvents(), loadStreamingEnabled(), loadPassIncludeObfuscation(), loadUseChatCoordinatorWorker(), loadUseChatMathWorker(), loadUseChatNetworkWorkerForRequests(), loadUseChatToolWorker(), loadVoiceDictationEnabled()]);
7809
8015
  return {
7810
8016
  aiSessionTitleGenerationEnabled,
7811
8017
  composerDropEnabled,
@@ -7817,6 +8023,7 @@ const loadPreferences = async () => {
7817
8023
  useChatCoordinatorWorker,
7818
8024
  useChatMathWorker,
7819
8025
  useChatNetworkWorkerForRequests,
8026
+ useChatToolWorker,
7820
8027
  voiceDictationEnabled
7821
8028
  };
7822
8029
  };
@@ -7957,6 +8164,7 @@ const loadContent = async (state, savedState) => {
7957
8164
  useChatCoordinatorWorker,
7958
8165
  useChatMathWorker,
7959
8166
  useChatNetworkWorkerForRequests,
8167
+ useChatToolWorker,
7960
8168
  voiceDictationEnabled
7961
8169
  } = await loadPreferences();
7962
8170
  const legacySavedSessions = getSavedSessions(savedState);
@@ -8033,6 +8241,7 @@ const loadContent = async (state, savedState) => {
8033
8241
  useChatCoordinatorWorker,
8034
8242
  useChatMathWorker,
8035
8243
  useChatNetworkWorkerForRequests,
8244
+ useChatToolWorker,
8036
8245
  viewMode,
8037
8246
  voiceDictationEnabled
8038
8247
  };
@@ -8343,11 +8552,21 @@ const getCss = (composerHeight, listItemHeight, chatMessageFontSize, chatMessage
8343
8552
  vertical-align: middle;
8344
8553
  }
8345
8554
 
8555
+ .MarkdownQuote {
8556
+ border-left: 3px solid var(--ColorBorder, #3a3d41);
8557
+ margin: 8px 0;
8558
+ padding-left: 12px;
8559
+ }
8560
+
8346
8561
  .MarkdownMathBlock {
8347
8562
  margin: 8px 0;
8348
8563
  overflow-x: auto;
8349
8564
  overflow-y: hidden;
8350
8565
  }
8566
+
8567
+ .StrikeThrough {
8568
+ text-decoration: line-through;
8569
+ }
8351
8570
  `;
8352
8571
  if (!renderHtmlCss.trim()) {
8353
8572
  return baseCss;
@@ -8418,6 +8637,7 @@ const ButtonSecondary = 'ButtonSecondary';
8418
8637
  const Empty = '';
8419
8638
  const FileIcon = 'FileIcon';
8420
8639
  const IconButton = 'IconButton';
8640
+ const ImageElement = 'ImageElement';
8421
8641
  const InputBox = 'InputBox';
8422
8642
  const Label = 'Label';
8423
8643
  const LabelDetail = 'LabelDetail';
@@ -8439,6 +8659,7 @@ const ProjectSessionItemLabel = 'ProjectSessionItemLabel';
8439
8659
  const ProjectSessionItemSelected = 'ProjectSessionItemSelected';
8440
8660
  const ProjectSidebar = 'ProjectSidebar';
8441
8661
  const Markdown = 'Markdown';
8662
+ const MarkdownQuote = 'MarkdownQuote';
8442
8663
  const MarkdownMathBlock = 'MarkdownMathBlock';
8443
8664
  const MarkdownTable = 'MarkdownTable';
8444
8665
  const Message = 'Message';
@@ -8470,6 +8691,7 @@ const TokenAttribute = 'TokenAttribute';
8470
8691
  const TokenValue = 'TokenValue';
8471
8692
  const TokenProperty = 'TokenProperty';
8472
8693
  const Select = 'Select';
8694
+ const StrikeThrough = 'StrikeThrough';
8473
8695
  const Viewlet = 'Viewlet';
8474
8696
  const ChatWelcomeMessage = 'ChatWelcomeMessage';
8475
8697
 
@@ -8544,7 +8766,6 @@ const getSendButtonDom = (isSendDisabled, voiceDictationEnabled) => {
8544
8766
  className: IconButton,
8545
8767
  name: Dictate,
8546
8768
  onClick: HandleClickDictationButton,
8547
- role: Button$2,
8548
8769
  title: startVoiceDictation(),
8549
8770
  type: Button$1
8550
8771
  }, {
@@ -8557,7 +8778,6 @@ const getSendButtonDom = (isSendDisabled, voiceDictationEnabled) => {
8557
8778
  className: sendButtonClassName,
8558
8779
  disabled: isSendDisabled,
8559
8780
  name: Send,
8560
- role: Button$2,
8561
8781
  title: sendMessage(),
8562
8782
  type: Button$1
8563
8783
  }, {
@@ -8602,7 +8822,7 @@ const getUsageOverviewDom = (tokensUsed, tokensMax) => {
8602
8822
  }, text(usageLabel)];
8603
8823
  };
8604
8824
 
8605
- const getChatSendAreaDom = (composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight = 28, composerFontSize = 13, composerFontFamily = 'system-ui', composerLineHeight = 20, voiceDictationEnabled = false) => {
8825
+ const getChatSendAreaDom = (composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, voiceDictationEnabled = false) => {
8606
8826
  const isSendDisabled = composerValue.trim() === '';
8607
8827
  const controlsCount = usageOverviewEnabled ? 3 : 2;
8608
8828
  return [{
@@ -8630,10 +8850,25 @@ const getChatSendAreaDom = (composerValue, models, selectedModelId, usageOvervie
8630
8850
  }, ...getChatSelectVirtualDom(models, selectedModelId), ...(usageOverviewEnabled ? getUsageOverviewDom(tokensUsed, tokensMax) : []), ...getSendButtonDom(isSendDisabled, voiceDictationEnabled)];
8631
8851
  };
8632
8852
 
8853
+ const getImageAltText = alt => {
8854
+ if (!alt.trim()) {
8855
+ return 'image could not be loaded';
8856
+ }
8857
+ return `${alt} (image could not be loaded)`;
8858
+ };
8633
8859
  const getInlineNodeDom = (inlineNode, useChatMathWorker = false) => {
8634
8860
  if (inlineNode.type === 'text') {
8635
8861
  return [text(inlineNode.text)];
8636
8862
  }
8863
+ if (inlineNode.type === 'image') {
8864
+ return [{
8865
+ alt: getImageAltText(inlineNode.alt),
8866
+ childCount: 0,
8867
+ className: ImageElement,
8868
+ src: inlineNode.src,
8869
+ type: Img
8870
+ }];
8871
+ }
8637
8872
  if (inlineNode.type === 'bold') {
8638
8873
  return [{
8639
8874
  childCount: inlineNode.children.length,
@@ -8646,6 +8881,13 @@ const getInlineNodeDom = (inlineNode, useChatMathWorker = false) => {
8646
8881
  type: Em
8647
8882
  }, ...inlineNode.children.flatMap(child => getInlineNodeDom(child, useChatMathWorker))];
8648
8883
  }
8884
+ if (inlineNode.type === 'strikethrough') {
8885
+ return [{
8886
+ childCount: inlineNode.children.length,
8887
+ className: StrikeThrough,
8888
+ type: Span
8889
+ }, ...inlineNode.children.flatMap(child => getInlineNodeDom(child, useChatMathWorker))];
8890
+ }
8649
8891
  if (inlineNode.type === 'math-inline') {
8650
8892
  const fallback = inlineNode.displayMode ? `$$${inlineNode.text}$$` : `$${inlineNode.text}$`;
8651
8893
  return [text(fallback)];
@@ -8883,6 +9125,13 @@ const getHeadingDom = (node, useChatMathWorker) => {
8883
9125
  type: getHeadingElementType(node.level)
8884
9126
  }, ...node.children.flatMap(child => getInlineNodeDom(child, useChatMathWorker))];
8885
9127
  };
9128
+ const getBlockQuoteDom = (node, useChatMathWorker) => {
9129
+ return [{
9130
+ childCount: node.children.length,
9131
+ className: MarkdownQuote,
9132
+ type: Div
9133
+ }, ...node.children.flatMap(child => getMessageNodeDom(child, useChatMathWorker))];
9134
+ };
8886
9135
  const getMessageNodeDom = (node, useChatMathWorker = false) => {
8887
9136
  if (node.type === 'text') {
8888
9137
  return [{
@@ -8910,6 +9159,9 @@ const getMessageNodeDom = (node, useChatMathWorker = false) => {
8910
9159
  if (node.type === 'heading') {
8911
9160
  return getHeadingDom(node, useChatMathWorker);
8912
9161
  }
9162
+ if (node.type === 'blockquote') {
9163
+ return getBlockQuoteDom(node, useChatMathWorker);
9164
+ }
8913
9165
  if (node.type === 'ordered-list') {
8914
9166
  return [{
8915
9167
  childCount: node.items.length,
@@ -8984,7 +9236,7 @@ const getMissingOpenApiApiKeyDom = openApiApiKeyInput => {
8984
9236
  inputPattern: '^sk-.+',
8985
9237
  inputRequired: true,
8986
9238
  inputValue: openApiApiKeyInput,
8987
- openSettingsButtonName: OpenOpenApiApiKeySettings,
9239
+ openSettingsButtonName: OpenOpenApiApiKeyWebsite,
8988
9240
  placeholder: openApiApiKeyPlaceholder(),
8989
9241
  saveButtonName: SaveOpenApiApiKey,
8990
9242
  saveButtonType: 'submit',
@@ -9715,14 +9967,14 @@ const getChatModeChatFocusVirtualDom = (sessions, selectedSessionId, composerVal
9715
9967
  const messages = selectedSession ? selectedSession.messages : [];
9716
9968
  const isDropOverlayVisible = composerDropEnabled && composerDropActive;
9717
9969
  return [{
9718
- childCount: 4,
9970
+ childCount: isDropOverlayVisible ? 4 : 3,
9719
9971
  className: mergeClassNames(Viewlet, Chat, 'ChatFocus'),
9720
9972
  onDragEnter: HandleDragEnterChatView,
9721
9973
  onDragOver: HandleDragOverChatView,
9722
9974
  type: Div
9723
- }, ...getProjectListDom(projects, sessions, projectExpandedIds, selectedProjectId, selectedSessionId, projectListScrollTop), ...getMessagesDom(messages, parsedMessages, openRouterApiKeyInput, openApiApiKeyInput, openRouterApiKeyState, messagesScrollTop, useChatMathWorker), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, voiceDictationEnabled), {
9975
+ }, ...getProjectListDom(projects, sessions, projectExpandedIds, selectedProjectId, selectedSessionId, projectListScrollTop), ...getMessagesDom(messages, parsedMessages, openRouterApiKeyInput, openApiApiKeyInput, openRouterApiKeyState, messagesScrollTop, useChatMathWorker), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, voiceDictationEnabled), ...(isDropOverlayVisible ? [{
9724
9976
  childCount: 1,
9725
- className: mergeClassNames(ChatViewDropOverlay, isDropOverlayVisible ? ChatViewDropOverlayActive : Empty),
9977
+ className: mergeClassNames(ChatViewDropOverlay, ChatViewDropOverlayActive),
9726
9978
  name: ComposerDropTarget,
9727
9979
  onDragLeave: HandleDragLeave,
9728
9980
  onDragOver: HandleDragOver,
@@ -9731,7 +9983,7 @@ const getChatModeChatFocusVirtualDom = (sessions, selectedSessionId, composerVal
9731
9983
  }, {
9732
9984
  text: attachImageAsContext(),
9733
9985
  type: Text
9734
- }];
9986
+ }] : [])];
9735
9987
  };
9736
9988
 
9737
9989
  const getBackButtonVirtualDom = () => {
@@ -9822,14 +10074,14 @@ const getChatModeDetailVirtualDom = (sessions, selectedSessionId, composerValue,
9822
10074
  const messages = selectedSession ? selectedSession.messages : [];
9823
10075
  const isDropOverlayVisible = composerDropEnabled && composerDropActive;
9824
10076
  return [{
9825
- childCount: 4,
10077
+ childCount: isDropOverlayVisible ? 4 : 3,
9826
10078
  className: mergeClassNames(Viewlet, Chat),
9827
10079
  onDragEnter: HandleDragEnterChatView,
9828
10080
  onDragOver: HandleDragOverChatView,
9829
10081
  type: Div
9830
- }, ...getChatHeaderDomDetailMode(selectedSessionTitle), ...getMessagesDom(messages, parsedMessages, openRouterApiKeyInput, openApiApiKeyInput, openRouterApiKeyState, messagesScrollTop, useChatMathWorker), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, voiceDictationEnabled), {
10082
+ }, ...getChatHeaderDomDetailMode(selectedSessionTitle), ...getMessagesDom(messages, parsedMessages, openRouterApiKeyInput, openApiApiKeyInput, openRouterApiKeyState, messagesScrollTop, useChatMathWorker), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, voiceDictationEnabled), ...(isDropOverlayVisible ? [{
9831
10083
  childCount: 1,
9832
- className: mergeClassNames(ChatViewDropOverlay, isDropOverlayVisible ? ChatViewDropOverlayActive : Empty),
10084
+ className: mergeClassNames(ChatViewDropOverlay, ChatViewDropOverlayActive),
9833
10085
  name: ComposerDropTarget,
9834
10086
  onDragLeave: HandleDragLeave,
9835
10087
  onDragOver: HandleDragOver,
@@ -9838,7 +10090,7 @@ const getChatModeDetailVirtualDom = (sessions, selectedSessionId, composerValue,
9838
10090
  }, {
9839
10091
  text: attachImageAsContext(),
9840
10092
  type: Text
9841
- }];
10093
+ }] : [])];
9842
10094
  };
9843
10095
 
9844
10096
  const getChatHeaderListModeDom = () => {
@@ -9911,14 +10163,14 @@ const getChatListDom = (sessions, selectedSessionId, chatListScrollTop = 0) => {
9911
10163
  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) => {
9912
10164
  const isDropOverlayVisible = composerDropEnabled && composerDropActive;
9913
10165
  return [{
9914
- childCount: 4,
10166
+ childCount: isDropOverlayVisible ? 4 : 3,
9915
10167
  className: mergeClassNames(Viewlet, Chat),
9916
10168
  onDragEnter: HandleDragEnterChatView,
9917
10169
  onDragOver: HandleDragOverChatView,
9918
10170
  type: Div
9919
- }, ...getChatHeaderListModeDom(), ...getChatListDom(sessions, selectedSessionId, chatListScrollTop), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, voiceDictationEnabled), {
10171
+ }, ...getChatHeaderListModeDom(), ...getChatListDom(sessions, selectedSessionId, chatListScrollTop), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, voiceDictationEnabled), ...(isDropOverlayVisible ? [{
9920
10172
  childCount: 1,
9921
- className: mergeClassNames(ChatViewDropOverlay, isDropOverlayVisible ? ChatViewDropOverlayActive : Empty),
10173
+ className: mergeClassNames(ChatViewDropOverlay, ChatViewDropOverlayActive),
9922
10174
  name: ComposerDropTarget,
9923
10175
  onDragLeave: HandleDragLeave,
9924
10176
  onDragOver: HandleDragOver,
@@ -9927,7 +10179,7 @@ const getChatModeListVirtualDom = (sessions, selectedSessionId, composerValue, m
9927
10179
  }, {
9928
10180
  text: attachImageAsContext(),
9929
10181
  type: Text
9930
- }];
10182
+ }] : [])];
9931
10183
  };
9932
10184
 
9933
10185
  const getChatModeUnsupportedVirtualDom = () => {
@@ -10199,7 +10451,7 @@ const renderEventListeners = () => {
10199
10451
  params: ['handleChatListScroll', 'event.target.scrollTop']
10200
10452
  }, {
10201
10453
  name: HandleMessagesScroll,
10202
- params: ['handleMessagesScroll', 'event.target.scrollTop']
10454
+ params: ['handleMessagesScroll', 'event.target.scrollTop', 'event.target.scrollHeight', 'event.target.clientHeight']
10203
10455
  }, {
10204
10456
  name: HandleProjectListScroll,
10205
10457
  params: ['handleProjectListScroll', 'event.target.scrollTop']
@@ -10458,18 +10710,40 @@ const initializeChatMathWorker = async () => {
10458
10710
  commandMap: {},
10459
10711
  send: sendMessagePortToChatMathWorker
10460
10712
  });
10461
- set$5(rpc);
10713
+ set$7(rpc);
10462
10714
  };
10463
10715
 
10464
- const send = port => {
10716
+ const send$1 = port => {
10465
10717
  return sendMessagePortToChatNetworkWorker(port);
10466
10718
  };
10467
10719
  const initializeChatNetworkWorker = async () => {
10720
+ const rpc = await create$4({
10721
+ commandMap: {},
10722
+ send: send$1
10723
+ });
10724
+ set$6(rpc);
10725
+ };
10726
+
10727
+ const send = port => {
10728
+ return sendMessagePortToChatToolWorker(port);
10729
+ };
10730
+ const initializeChatToolWorker = async () => {
10468
10731
  const rpc = await create$4({
10469
10732
  commandMap: {},
10470
10733
  send
10471
10734
  });
10472
- set$4(rpc);
10735
+ set$5(rpc);
10736
+ };
10737
+
10738
+ const sendMessagePortToOpenerWorker = async port => {
10739
+ await sendMessagePortToOpenerWorker$1(port, 0);
10740
+ };
10741
+ const initializeOpenerWorker = async () => {
10742
+ const rpc = await create$4({
10743
+ commandMap: {},
10744
+ send: sendMessagePortToOpenerWorker
10745
+ });
10746
+ set$3(rpc);
10473
10747
  };
10474
10748
 
10475
10749
  const listen = async () => {
@@ -10478,7 +10752,7 @@ const listen = async () => {
10478
10752
  commandMap: commandMap
10479
10753
  });
10480
10754
  set$2(rpc);
10481
- await Promise.all([initializeChatNetworkWorker(), initializeChatMathWorker(), initializeChatCoordinatorWorker()]);
10755
+ await Promise.all([initializeChatNetworkWorker(), initializeChatMathWorker(), initializeChatCoordinatorWorker(), initializeChatToolWorker(), initializeOpenerWorker()]);
10482
10756
  };
10483
10757
 
10484
10758
  const main = async () => {