@lvce-editor/chat-view 7.4.0 → 7.5.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.
@@ -1350,6 +1350,9 @@ const sendMessagePortToChatStorageWorker$1 = async port => {
1350
1350
  const activateByEvent$1 = (event, assetDir, platform) => {
1351
1351
  return invoke('ExtensionHostManagement.activateByEvent', event, assetDir, platform);
1352
1352
  };
1353
+ const getWorkspacePath = () => {
1354
+ return invoke('Workspace.getPath');
1355
+ };
1353
1356
  const sendMessagePortToTextMeasurementWorker$1 = async port => {
1354
1357
  const command = 'TextMeasurement.handleMessagePort';
1355
1358
  await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToTextMeasurementWorker', port, command, 0);
@@ -2222,6 +2225,7 @@ Use available project context to provide accurate, practical coding help.
2222
2225
  Prefer using available tools to inspect and modify files in the current workspace.
2223
2226
  When asked to create or update code, read relevant files first and apply changes directly in files instead of only pasting raw code in chat.
2224
2227
  Only provide raw code snippets when explicitly requested or when file editing tools are unavailable.
2228
+ When mentioning inline commands, file names, identifiers, or short code fragments in responses, wrap them in markdown backticks, for example \`nvm install 24.14.1\`.
2225
2229
  When displaying code blocks in responses, use markdown triple backticks (\`\`\`) fences.
2226
2230
  When referencing workspace files in responses (including "files added/changed" lists), use markdown links so users can click them.
2227
2231
  Prefer file links like [src/index.ts]({{workspaceUri}}/src/index.ts) and avoid plain text file paths when a link is appropriate.
@@ -2291,11 +2295,16 @@ const getReasoningEffortLabel = reasoningEffort => {
2291
2295
  }
2292
2296
  };
2293
2297
 
2298
+ const defaultToolEnablement = {
2299
+ run_in_terminal: false
2300
+ };
2294
2301
  const parseToolEnablement = value => {
2295
2302
  if (!value || typeof value !== 'object' || Array.isArray(value)) {
2296
- return {};
2303
+ return defaultToolEnablement;
2297
2304
  }
2298
- const toolEnablement = {};
2305
+ const toolEnablement = {
2306
+ ...defaultToolEnablement
2307
+ };
2299
2308
  for (const [key, enabled] of Object.entries(value)) {
2300
2309
  if (typeof enabled === 'boolean') {
2301
2310
  toolEnablement[key] = enabled;
@@ -2320,10 +2329,13 @@ const validateToolEnablement = value => {
2320
2329
  };
2321
2330
  const isToolEnabled = (toolEnablement, toolName) => {
2322
2331
  if (!toolEnablement) {
2323
- return true;
2332
+ return defaultToolEnablement[toolName] ?? true;
2324
2333
  }
2325
2334
  const enabled = toolEnablement[toolName];
2326
- return typeof enabled === 'boolean' ? enabled : true;
2335
+ if (typeof enabled === 'boolean') {
2336
+ return enabled;
2337
+ }
2338
+ return defaultToolEnablement[toolName] ?? true;
2327
2339
  };
2328
2340
  const filterEnabledTools = (tools, toolEnablement) => {
2329
2341
  return tools.filter(tool => isToolEnabled(toolEnablement, tool.function.name));
@@ -2399,7 +2411,7 @@ const createDefaultState = () => {
2399
2411
  maxToolCalls: defaultMaxToolCalls,
2400
2412
  messagesAutoScrollEnabled: true,
2401
2413
  messagesScrollTop: 0,
2402
- mockAiResponseDelay: 800,
2414
+ mockAiResponseDelay: 0,
2403
2415
  mockApiCommandId: '',
2404
2416
  mockOpenApiRequests: [],
2405
2417
  modelPickerHeaderHeight,
@@ -2431,6 +2443,8 @@ const createDefaultState = () => {
2431
2443
  name: '_blank',
2432
2444
  uri: ''
2433
2445
  }],
2446
+ projectSidebarResizing: false,
2447
+ projectSidebarWidth: 280,
2434
2448
  questionToolEnabled: false,
2435
2449
  reasoningEffort: defaultReasoningEffort,
2436
2450
  reasoningEffortPickerOpen: false,
@@ -2835,7 +2849,7 @@ const getRenderHtmlCss = (sessions, selectedSessionId) => {
2835
2849
  const isEqual$1 = (oldState, newState) => {
2836
2850
  const oldRenderHtmlCss = getRenderHtmlCss(oldState.sessions, oldState.selectedSessionId);
2837
2851
  const newRenderHtmlCss = getRenderHtmlCss(newState.sessions, newState.selectedSessionId);
2838
- return oldState.initial === newState.initial && oldState.chatMessageFontFamily === newState.chatMessageFontFamily && oldState.chatMessageFontSize === newState.chatMessageFontSize && oldState.chatMessageLineHeight === newState.chatMessageLineHeight && oldState.chatFocusContentMaxWidth === newState.chatFocusContentMaxWidth && oldState.chatSendAreaPaddingTop === newState.chatSendAreaPaddingTop && oldState.chatSendAreaPaddingLeft === newState.chatSendAreaPaddingLeft && oldState.chatSendAreaPaddingRight === newState.chatSendAreaPaddingRight && oldState.chatSendAreaPaddingBottom === newState.chatSendAreaPaddingBottom && oldState.composerHeight === newState.composerHeight && oldState.composerAttachmentsHeight === newState.composerAttachmentsHeight && oldState.modelPickerHeight === newState.modelPickerHeight && oldState.composerLineHeight === newState.composerLineHeight && oldState.composerFontFamily === newState.composerFontFamily && oldState.composerFontSize === newState.composerFontSize && oldState.listItemHeight === newState.listItemHeight && oldState.textAreaPaddingTop === newState.textAreaPaddingTop && oldState.textAreaPaddingLeft === newState.textAreaPaddingLeft && oldState.textAreaPaddingRight === newState.textAreaPaddingRight && oldState.textAreaPaddingBottom === newState.textAreaPaddingBottom && oldRenderHtmlCss === newRenderHtmlCss;
2852
+ return oldState.initial === newState.initial && oldState.chatMessageFontFamily === newState.chatMessageFontFamily && oldState.chatMessageFontSize === newState.chatMessageFontSize && oldState.chatMessageLineHeight === newState.chatMessageLineHeight && oldState.chatFocusContentMaxWidth === newState.chatFocusContentMaxWidth && oldState.projectSidebarWidth === newState.projectSidebarWidth && oldState.chatSendAreaPaddingTop === newState.chatSendAreaPaddingTop && oldState.chatSendAreaPaddingLeft === newState.chatSendAreaPaddingLeft && oldState.chatSendAreaPaddingRight === newState.chatSendAreaPaddingRight && oldState.chatSendAreaPaddingBottom === newState.chatSendAreaPaddingBottom && oldState.composerHeight === newState.composerHeight && oldState.composerAttachmentsHeight === newState.composerAttachmentsHeight && oldState.modelPickerHeight === newState.modelPickerHeight && oldState.composerLineHeight === newState.composerLineHeight && oldState.composerFontFamily === newState.composerFontFamily && oldState.composerFontSize === newState.composerFontSize && oldState.listItemHeight === newState.listItemHeight && oldState.textAreaPaddingTop === newState.textAreaPaddingTop && oldState.textAreaPaddingLeft === newState.textAreaPaddingLeft && oldState.textAreaPaddingRight === newState.textAreaPaddingRight && oldState.textAreaPaddingBottom === newState.textAreaPaddingBottom && oldRenderHtmlCss === newRenderHtmlCss;
2839
2853
  };
2840
2854
 
2841
2855
  const diffFocus = (oldState, newState) => {
@@ -3890,37 +3904,27 @@ const openFolder = async () => {
3890
3904
  }
3891
3905
  };
3892
3906
 
3893
- // cspell:ignore gitdir worktrees
3894
- const FileTypeFile = 1;
3895
- const FileTypeDirectory = 2;
3896
- const slashAtEndRegex = /\/$/;
3897
- const gitDirPointerRegex = /^gitdir:\s*(.+)$/m;
3898
- const headRefRegex = /^ref:\s+refs\/heads\/(.+)$/m;
3899
- const toGitUri = (baseUri, ...segments) => {
3900
- const url = new URL(baseUri.endsWith('/') ? baseUri : `${baseUri}/`);
3901
- for (const segment of segments) {
3902
- url.pathname = `${url.pathname.replace(slashAtEndRegex, '')}/${segment.split('/').map(part => encodeURIComponent(part)).join('/')}`;
3903
- }
3904
- return url.toString();
3905
- };
3906
- const decodeFileContent = content => {
3907
- if (typeof content === 'string') {
3908
- return content;
3909
- }
3910
- if (content instanceof Uint8Array) {
3911
- return new TextDecoder().decode(content);
3912
- }
3913
- if (Array.isArray(content)) {
3914
- return new TextDecoder().decode(new Uint8Array(content));
3915
- }
3916
- return '';
3917
- };
3918
- const toFileSystemPath = uri => {
3919
- if (!uri.startsWith('file://')) {
3920
- return uri;
3907
+ const parseEntries = value => {
3908
+ if (!Array.isArray(value)) {
3909
+ return [];
3921
3910
  }
3922
- return decodeURIComponent(new URL(uri).pathname);
3911
+ return value.map(entry => {
3912
+ if (Array.isArray(entry) && typeof entry[0] === 'string' && typeof entry[1] === 'number') {
3913
+ return {
3914
+ name: entry[0],
3915
+ type: entry[1]
3916
+ };
3917
+ }
3918
+ if (entry && typeof entry === 'object' && typeof Reflect.get(entry, 'name') === 'string' && typeof Reflect.get(entry, 'type') === 'number') {
3919
+ return {
3920
+ name: Reflect.get(entry, 'name'),
3921
+ type: Reflect.get(entry, 'type')
3922
+ };
3923
+ }
3924
+ return undefined;
3925
+ }).filter(entry => !!entry);
3923
3926
  };
3927
+
3924
3928
  const getRelativePath = (fromPath, toPath) => {
3925
3929
  if (!fromPath.startsWith('/') || !toPath.startsWith('/')) {
3926
3930
  return toPath;
@@ -3935,6 +3939,14 @@ const getRelativePath = (fromPath, toPath) => {
3935
3939
  const childSegments = toParts.slice(commonPrefixLength);
3936
3940
  return [...parentSegments, ...childSegments].join('/') || '.';
3937
3941
  };
3942
+
3943
+ const toFileSystemPath = uri => {
3944
+ if (!uri.startsWith('file://')) {
3945
+ return uri;
3946
+ }
3947
+ return decodeURIComponent(new URL(uri).pathname);
3948
+ };
3949
+
3938
3950
  const toFileSystemTarget = (workspaceUri, uri) => {
3939
3951
  const workspacePath = toFileSystemPath(workspaceUri);
3940
3952
  const fileSystemPath = toFileSystemPath(uri);
@@ -3943,34 +3955,56 @@ const toFileSystemTarget = (workspaceUri, uri) => {
3943
3955
  }
3944
3956
  return getRelativePath(workspacePath, fileSystemPath);
3945
3957
  };
3946
- const parseEntries = value => {
3947
- if (!Array.isArray(value)) {
3948
- return [];
3958
+
3959
+ const readDir = async (workspaceUri, uri) => {
3960
+ const result = await invoke('FileSystem.readDirWithFileTypes', toFileSystemTarget(workspaceUri, uri));
3961
+ return parseEntries(result);
3962
+ };
3963
+
3964
+ const slashAtEndRegex = /\/$/;
3965
+ const toGitUri = (baseUri, ...segments) => {
3966
+ const url = new URL(baseUri.endsWith('/') ? baseUri : `${baseUri}/`);
3967
+ for (const segment of segments) {
3968
+ url.pathname = `${url.pathname.replace(slashAtEndRegex, '')}/${segment.split('/').map(part => encodeURIComponent(part)).join('/')}`;
3949
3969
  }
3950
- return value.map(entry => {
3951
- if (Array.isArray(entry) && typeof entry[0] === 'string' && typeof entry[1] === 'number') {
3952
- return {
3953
- name: entry[0],
3954
- type: entry[1]
3955
- };
3970
+ return url.toString();
3971
+ };
3972
+
3973
+ const FileTypeFile = 1;
3974
+ const FileTypeDirectory = 2;
3975
+ const collectBranchNames = async (workspaceUri, refsHeadsUri, prefix, branches) => {
3976
+ const entries = await readDir(workspaceUri, refsHeadsUri);
3977
+ for (const entry of entries) {
3978
+ if (entry.type === FileTypeDirectory) {
3979
+ await collectBranchNames(workspaceUri, toGitUri(refsHeadsUri, entry.name), `${prefix}${entry.name}/`, branches);
3980
+ continue;
3956
3981
  }
3957
- if (entry && typeof entry === 'object' && typeof Reflect.get(entry, 'name') === 'string' && typeof Reflect.get(entry, 'type') === 'number') {
3958
- return {
3959
- name: Reflect.get(entry, 'name'),
3960
- type: Reflect.get(entry, 'type')
3961
- };
3982
+ if (entry.type === FileTypeFile) {
3983
+ branches.add(`${prefix}${entry.name}`);
3962
3984
  }
3963
- return undefined;
3964
- }).filter(entry => !!entry);
3985
+ }
3965
3986
  };
3966
- const readDir = async (workspaceUri, uri) => {
3967
- const result = await invoke('FileSystem.readDirWithFileTypes', toFileSystemTarget(workspaceUri, uri));
3968
- return parseEntries(result);
3987
+
3988
+ const decodeFileContent = content => {
3989
+ if (typeof content === 'string') {
3990
+ return content;
3991
+ }
3992
+ if (content instanceof Uint8Array) {
3993
+ return new TextDecoder().decode(content);
3994
+ }
3995
+ if (Array.isArray(content)) {
3996
+ return new TextDecoder().decode(new Uint8Array(content));
3997
+ }
3998
+ return '';
3969
3999
  };
4000
+
3970
4001
  const readTextFile = async (workspaceUri, uri) => {
3971
4002
  const result = await invoke('FileSystem.readFile', toFileSystemTarget(workspaceUri, uri));
3972
4003
  return decodeFileContent(result);
3973
4004
  };
4005
+
4006
+ // cspell:ignore gitdir worktrees
4007
+ const gitDirPointerRegex = /^gitdir:\s*(.+)$/m;
3974
4008
  const getGitDirUri = async workspaceUri => {
3975
4009
  const gitUri = toGitUri(workspaceUri, '.git');
3976
4010
  try {
@@ -3986,18 +4020,8 @@ const getGitDirUri = async workspaceUri => {
3986
4020
  }
3987
4021
  return new URL(match[1].trim(), workspaceUri.endsWith('/') ? workspaceUri : `${workspaceUri}/`).toString();
3988
4022
  };
3989
- const collectBranchNames = async (workspaceUri, refsHeadsUri, prefix, branches) => {
3990
- const entries = await readDir(workspaceUri, refsHeadsUri);
3991
- for (const entry of entries) {
3992
- if (entry.type === FileTypeDirectory) {
3993
- await collectBranchNames(workspaceUri, toGitUri(refsHeadsUri, entry.name), `${prefix}${entry.name}/`, branches);
3994
- continue;
3995
- }
3996
- if (entry.type === FileTypeFile) {
3997
- branches.add(`${prefix}${entry.name}`);
3998
- }
3999
- }
4000
- };
4023
+
4024
+ const headRefRegex = /^ref:\s+refs\/heads\/(.+)$/m;
4001
4025
  const parseCurrentBranch = headContent => {
4002
4026
  const match = headRefRegex.exec(headContent.trim());
4003
4027
  if (match) {
@@ -4005,13 +4029,7 @@ const parseCurrentBranch = headContent => {
4005
4029
  }
4006
4030
  return '';
4007
4031
  };
4008
- const hasGitRepository = async workspaceUri => {
4009
- try {
4010
- return Boolean(await getGitDirUri(workspaceUri));
4011
- } catch {
4012
- return false;
4013
- }
4014
- };
4032
+
4015
4033
  const getGitBranches = async workspaceUri => {
4016
4034
  const gitDirUri = await getGitDirUri(workspaceUri);
4017
4035
  if (!gitDirUri) {
@@ -4044,6 +4062,14 @@ const getGitBranches = async workspaceUri => {
4044
4062
  }));
4045
4063
  };
4046
4064
 
4065
+ const hasGitRepository = async workspaceUri => {
4066
+ try {
4067
+ return Boolean(await getGitDirUri(workspaceUri));
4068
+ } catch {
4069
+ return false;
4070
+ }
4071
+ };
4072
+
4047
4073
  const getSelectedSession = (sessions, selectedSessionId) => {
4048
4074
  return sessions.find(session => session.id === selectedSessionId);
4049
4075
  };
@@ -4642,6 +4668,30 @@ const hasToolError = value => {
4642
4668
  const error = Reflect.get(value, 'error');
4643
4669
  return typeof error === 'string' && error.trim().length > 0;
4644
4670
  };
4671
+ const getTrackedToolExecutionValue = value => {
4672
+ if (typeof value !== 'string') {
4673
+ return value;
4674
+ }
4675
+ try {
4676
+ return JSON.parse(value);
4677
+ } catch {
4678
+ return value;
4679
+ }
4680
+ };
4681
+ const getStoredToolExecutionStatus = result => {
4682
+ let parsed = result;
4683
+ if (typeof result === 'string') {
4684
+ try {
4685
+ parsed = JSON.parse(result);
4686
+ } catch {
4687
+ return 'error';
4688
+ }
4689
+ }
4690
+ if (!parsed || typeof parsed !== 'object') {
4691
+ return 'error';
4692
+ }
4693
+ return hasToolError(parsed) ? 'error' : 'success';
4694
+ };
4645
4695
  const parseWriteFileArguments = rawArguments => {
4646
4696
  let parsed = rawArguments;
4647
4697
  if (typeof rawArguments === 'string') {
@@ -4749,15 +4799,60 @@ const executeChatTool = async (name, rawArguments, options) => {
4749
4799
  // eslint-disable-next-line @typescript-eslint/only-throw-error
4750
4800
  throw new Error('Chat tools must be executed in a web worker environment. Please set useChatToolWorker to true in the options.');
4751
4801
  }
4752
- const workerOutput = await execute(name, rawArguments, {
4802
+ const executionOptions = {
4753
4803
  assetDir: options.assetDir,
4754
4804
  platform: options.platform,
4755
4805
  ...(options.workspaceUri ? {
4756
4806
  workspaceUri: options.workspaceUri
4757
4807
  } : {})
4758
- });
4759
- const outputWithLineCounts = name === 'write_file' ? await withWriteFileLineCounts(workerOutput, rawArguments) : workerOutput;
4760
- return stringifyToolOutput(outputWithLineCounts);
4808
+ };
4809
+ const executionId = options.toolCallId || `${name}-${Date.now()}`;
4810
+ const startedAt = new Date().toISOString();
4811
+ if (options.sessionId) {
4812
+ await appendChatViewEvent({
4813
+ arguments: getTrackedToolExecutionValue(rawArguments),
4814
+ id: executionId,
4815
+ name,
4816
+ options: executionOptions,
4817
+ sessionId: options.sessionId,
4818
+ time: startedAt,
4819
+ timestamp: startedAt,
4820
+ type: 'tool-execution-started'
4821
+ });
4822
+ }
4823
+ try {
4824
+ const workerOutput = await execute(name, rawArguments, executionOptions);
4825
+ const outputWithLineCounts = name === 'write_file' ? await withWriteFileLineCounts(workerOutput, rawArguments) : workerOutput;
4826
+ const result = stringifyToolOutput(outputWithLineCounts);
4827
+ if (options.sessionId) {
4828
+ await appendChatViewEvent({
4829
+ id: executionId,
4830
+ name,
4831
+ result: outputWithLineCounts,
4832
+ sessionId: options.sessionId,
4833
+ status: getStoredToolExecutionStatus(outputWithLineCounts),
4834
+ timestamp: new Date().toISOString(),
4835
+ type: 'tool-execution-finished'
4836
+ });
4837
+ }
4838
+ return result;
4839
+ } catch (error) {
4840
+ const errorResult = {
4841
+ error: error instanceof Error ? error.message : String(error)
4842
+ };
4843
+ if (options.sessionId) {
4844
+ await appendChatViewEvent({
4845
+ id: executionId,
4846
+ name,
4847
+ result: errorResult,
4848
+ sessionId: options.sessionId,
4849
+ status: 'error',
4850
+ timestamp: new Date().toISOString(),
4851
+ type: 'tool-execution-finished'
4852
+ });
4853
+ }
4854
+ throw error;
4855
+ }
4761
4856
  };
4762
4857
 
4763
4858
  const getAskQuestionTool = () => {
@@ -4839,6 +4934,7 @@ const getAttachmentTextPart = attachment => {
4839
4934
  };
4840
4935
  }
4841
4936
  };
4937
+
4842
4938
  const getChatMessageOpenAiContent = message => {
4843
4939
  if (!message.attachments || message.attachments.length === 0) {
4844
4940
  return message.text;
@@ -4870,7 +4966,9 @@ const getClientRequestIdHeader = () => {
4870
4966
  };
4871
4967
 
4872
4968
  const getMockAiResponse = async (userMessage, delayInMs) => {
4873
- await delay(delayInMs);
4969
+ if (delayInMs > 0) {
4970
+ await delay(delayInMs);
4971
+ }
4874
4972
  return `Mock AI response: I received "${userMessage}".`;
4875
4973
  };
4876
4974
 
@@ -5354,6 +5452,51 @@ const makeStreamingApiRequest = async options => {
5354
5452
  return invoke$6('ChatNetwork.makeStreamingApiRequest', options);
5355
5453
  };
5356
5454
 
5455
+ const getNumericCount = parsed => {
5456
+ const count = Reflect.get(parsed, 'count');
5457
+ if (typeof count === 'number' && Number.isFinite(count)) {
5458
+ return count;
5459
+ }
5460
+ const matchCount = Reflect.get(parsed, 'matchCount');
5461
+ if (typeof matchCount === 'number' && Number.isFinite(matchCount)) {
5462
+ return matchCount;
5463
+ }
5464
+ return undefined;
5465
+ };
5466
+ const getArrayCount = parsed => {
5467
+ const matches = Reflect.get(parsed, 'matches');
5468
+ if (Array.isArray(matches)) {
5469
+ return matches.length;
5470
+ }
5471
+ const files = Reflect.get(parsed, 'files');
5472
+ if (Array.isArray(files)) {
5473
+ return files.length;
5474
+ }
5475
+ const results = Reflect.get(parsed, 'results');
5476
+ if (Array.isArray(results)) {
5477
+ return results.length;
5478
+ }
5479
+ return undefined;
5480
+ };
5481
+ const getGlobMatchCount = result => {
5482
+ if (!result) {
5483
+ return undefined;
5484
+ }
5485
+ let parsed;
5486
+ try {
5487
+ parsed = JSON.parse(result);
5488
+ } catch {
5489
+ return undefined;
5490
+ }
5491
+ if (Array.isArray(parsed)) {
5492
+ return parsed.length;
5493
+ }
5494
+ if (!parsed || typeof parsed !== 'object') {
5495
+ return undefined;
5496
+ }
5497
+ return getNumericCount(parsed) ?? getArrayCount(parsed);
5498
+ };
5499
+
5357
5500
  const getTextContent = content => {
5358
5501
  if (typeof content === 'string') {
5359
5502
  return content;
@@ -5518,6 +5661,9 @@ const getToolCallResult = (name, content) => {
5518
5661
  }
5519
5662
  return content;
5520
5663
  }
5664
+ if (name === 'glob') {
5665
+ return getGlobMatchCount(content) === undefined ? undefined : content;
5666
+ }
5521
5667
  if (name !== 'getWorkspaceUri') {
5522
5668
  return undefined;
5523
5669
  }
@@ -6029,6 +6175,7 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
6029
6175
  onToolCallsChunk,
6030
6176
  questionToolEnabled = false,
6031
6177
  reasoningEffort,
6178
+ sessionId,
6032
6179
  stream,
6033
6180
  supportsReasoningEffort = false,
6034
6181
  systemPrompt = '',
@@ -6145,6 +6292,10 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
6145
6292
  const content = await executeChatTool(toolCall.name, toolCall.arguments, {
6146
6293
  assetDir,
6147
6294
  platform,
6295
+ ...(sessionId ? {
6296
+ sessionId
6297
+ } : {}),
6298
+ toolCallId: toolCall.callId,
6148
6299
  ...(toolEnablement ? {
6149
6300
  toolEnablement
6150
6301
  } : {}),
@@ -6298,6 +6449,10 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
6298
6449
  const content = await executeChatTool(toolCall.name, toolCall.arguments, {
6299
6450
  assetDir,
6300
6451
  platform,
6452
+ ...(sessionId ? {
6453
+ sessionId
6454
+ } : {}),
6455
+ toolCallId: toolCall.callId,
6301
6456
  ...(toolEnablement ? {
6302
6457
  toolEnablement
6303
6458
  } : {}),
@@ -6378,6 +6533,10 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
6378
6533
  const content = typeof name === 'string' ? await executeChatTool(name, rawArguments, {
6379
6534
  assetDir,
6380
6535
  platform,
6536
+ ...(sessionId ? {
6537
+ sessionId
6538
+ } : {}),
6539
+ toolCallId: id,
6381
6540
  useChatToolWorker,
6382
6541
  workspaceUri
6383
6542
  }) : '{}';
@@ -6653,7 +6812,7 @@ const getOpenRouterLimitInfo = async (openRouterApiKey, openRouterApiBaseUrl, us
6653
6812
  }
6654
6813
  return normalizedLimitInfo;
6655
6814
  };
6656
- const getOpenRouterAssistantText = async (messages, modelId, openRouterApiKey, openRouterApiBaseUrl, assetDir, platform, useChatNetworkWorkerForRequests = false, useChatToolWorker = true, questionToolEnabled = false, systemPrompt = '', workspaceUri = '', agentMode = defaultAgentMode, toolEnablement) => {
6815
+ const getOpenRouterAssistantText = async (messages, modelId, openRouterApiKey, openRouterApiBaseUrl, assetDir, platform, useChatNetworkWorkerForRequests = false, useChatToolWorker = true, questionToolEnabled = false, systemPrompt = '', workspaceUri = '', agentMode = defaultAgentMode, toolEnablement, sessionId) => {
6657
6816
  const effectiveAgentMode = typeof agentMode === 'boolean' ? defaultAgentMode : agentMode;
6658
6817
  const completionMessages = [...(systemPrompt ? [{
6659
6818
  content: systemPrompt,
@@ -6815,6 +6974,10 @@ const getOpenRouterAssistantText = async (messages, modelId, openRouterApiKey, o
6815
6974
  const content = typeof name === 'string' ? await executeChatTool(name, rawArguments, {
6816
6975
  assetDir,
6817
6976
  platform,
6977
+ ...(sessionId ? {
6978
+ sessionId
6979
+ } : {}),
6980
+ toolCallId: id,
6818
6981
  ...(toolEnablement ? {
6819
6982
  toolEnablement
6820
6983
  } : {}),
@@ -6990,6 +7153,7 @@ const getAiResponse = async ({
6990
7153
  questionToolEnabled = false,
6991
7154
  reasoningEffort,
6992
7155
  selectedModelId,
7156
+ sessionId,
6993
7157
  streamingEnabled = true,
6994
7158
  systemPrompt = '',
6995
7159
  toolEnablement,
@@ -7001,6 +7165,7 @@ const getAiResponse = async ({
7001
7165
  webSearchEnabled = false,
7002
7166
  workspaceUri
7003
7167
  }) => {
7168
+ useChatCoordinatorWorker = false; // TODO enable this
7004
7169
  if (useChatCoordinatorWorker && !authEnabled) {
7005
7170
  try {
7006
7171
  const result = await getAiResponse$1({
@@ -7115,6 +7280,10 @@ const getAiResponse = async ({
7115
7280
  const content = await executeChatTool(toolCall.name, toolCall.arguments, {
7116
7281
  assetDir,
7117
7282
  platform,
7283
+ ...(sessionId ? {
7284
+ sessionId
7285
+ } : {}),
7286
+ toolCallId: toolCall.callId,
7118
7287
  ...(toolEnablement ? {
7119
7288
  toolEnablement
7120
7289
  } : {}),
@@ -7173,6 +7342,9 @@ const getAiResponse = async ({
7173
7342
  ...(reasoningEffort ? {
7174
7343
  reasoningEffort
7175
7344
  } : {}),
7345
+ ...(sessionId ? {
7346
+ sessionId
7347
+ } : {}),
7176
7348
  stream: streamingEnabled,
7177
7349
  supportsReasoningEffort,
7178
7350
  systemPrompt,
@@ -7210,7 +7382,7 @@ const getAiResponse = async ({
7210
7382
  text = getOpenRouterErrorMessage(result);
7211
7383
  }
7212
7384
  } else if (openRouterApiKey) {
7213
- const result = await getOpenRouterAssistantText(messages, modelId, openRouterApiKey, openRouterApiBaseUrl, assetDir, platform, useChatNetworkWorkerForRequests, useChatToolWorker, questionToolEnabled, systemPrompt, workspaceUri, agentMode, toolEnablement);
7385
+ const result = await getOpenRouterAssistantText(messages, modelId, openRouterApiKey, openRouterApiBaseUrl, assetDir, platform, useChatNetworkWorkerForRequests, useChatToolWorker, questionToolEnabled, systemPrompt, workspaceUri, agentMode, toolEnablement, sessionId);
7214
7386
  if (result.type === 'success') {
7215
7387
  const {
7216
7388
  text: assistantText
@@ -7995,8 +8167,19 @@ const getWorkspaceUri = (state, session) => {
7995
8167
  }
7996
8168
  return getProjectUri(state, session?.projectId || state.selectedProjectId);
7997
8169
  };
7998
- const getEffectiveSystemPrompt = (state, session) => {
7999
- const resolvedSystemPrompt = state.systemPrompt.replaceAll(workspaceUriPlaceholder, getWorkspaceUri(state, session) || 'unknown');
8170
+ const resolveWorkspaceUri = async (state, session) => {
8171
+ const workspaceUri = getWorkspaceUri(state, session);
8172
+ if (workspaceUri) {
8173
+ return workspaceUri;
8174
+ }
8175
+ try {
8176
+ return await getWorkspacePath();
8177
+ } catch {
8178
+ return '';
8179
+ }
8180
+ };
8181
+ const getEffectiveSystemPrompt = (state, workspaceUri) => {
8182
+ const resolvedSystemPrompt = state.systemPrompt.replaceAll(workspaceUriPlaceholder, workspaceUri || 'unknown');
8000
8183
  const currentDateInstructions = `Current date: ${getCurrentDate()}.
8001
8184
 
8002
8185
  Do not assume your knowledge cutoff is the same as the current date.`;
@@ -8204,8 +8387,8 @@ const handleSubmit = async state => {
8204
8387
  mockOpenApiRequests
8205
8388
  } = optimisticState;
8206
8389
  const selectedOptimisticSession = optimisticState.sessions.find(session => session.id === optimisticState.selectedSessionId);
8207
- const systemPrompt = getEffectiveSystemPrompt(optimisticState, selectedOptimisticSession);
8208
- const workspaceUri = getWorkspaceUri(optimisticState, selectedOptimisticSession);
8390
+ const workspaceUri = useMockApi ? getWorkspaceUri(optimisticState, selectedOptimisticSession) : await resolveWorkspaceUri(optimisticState, selectedOptimisticSession);
8391
+ const systemPrompt = getEffectiveSystemPrompt(optimisticState, workspaceUri);
8209
8392
  const messages = (selectedOptimisticSession?.messages ?? []).filter(message => !message.inProgress);
8210
8393
  const mentionContextMessage = await getMentionContextMessage(userText);
8211
8394
  const messagesWithMentionContext = mentionContextMessage ? [...messages, mentionContextMessage] : messages;
@@ -8265,6 +8448,7 @@ const handleSubmit = async state => {
8265
8448
  } : {}),
8266
8449
  reasoningEffort,
8267
8450
  selectedModelId,
8451
+ sessionId: optimisticState.selectedSessionId,
8268
8452
  streamingEnabled,
8269
8453
  systemPrompt,
8270
8454
  toolEnablement,
@@ -9412,10 +9596,57 @@ const handlePointerDownModelPickerList = async state => {
9412
9596
  return state;
9413
9597
  };
9414
9598
 
9599
+ const handlePointerDownProjectSidebarSash = async state => {
9600
+ if (state.projectSidebarResizing) {
9601
+ return state;
9602
+ }
9603
+ return {
9604
+ ...state,
9605
+ projectSidebarResizing: true
9606
+ };
9607
+ };
9608
+
9609
+ const minimumProjectSidebarWidth = 180;
9610
+ const minimumChatAreaWidth = 320;
9611
+ const getProjectSidebarWidth = (state, clientX) => {
9612
+ const availableWidth = state.width > 0 ? state.width : state.projectSidebarWidth + minimumChatAreaWidth;
9613
+ const maximumProjectSidebarWidth = Math.max(minimumProjectSidebarWidth, availableWidth - minimumChatAreaWidth);
9614
+ const nextWidth = Math.round(clientX - state.x);
9615
+ return Math.min(Math.max(nextWidth, minimumProjectSidebarWidth), maximumProjectSidebarWidth);
9616
+ };
9617
+ const resizeProjectSidebar = (state, clientX) => {
9618
+ const projectSidebarWidth = getProjectSidebarWidth(state, clientX);
9619
+ if (projectSidebarWidth === state.projectSidebarWidth) {
9620
+ return state;
9621
+ }
9622
+ return {
9623
+ ...state,
9624
+ projectSidebarWidth
9625
+ };
9626
+ };
9627
+
9628
+ const handlePointerMoveProjectSidebarSash = async (state, clientX) => {
9629
+ if (!state.projectSidebarResizing) {
9630
+ return state;
9631
+ }
9632
+ return resizeProjectSidebar(state, clientX);
9633
+ };
9634
+
9415
9635
  const handlePointerUpModelPickerList = async (state, eventY = 0) => {
9416
9636
  return state;
9417
9637
  };
9418
9638
 
9639
+ const handlePointerUpProjectSidebarSash = async (state, clientX) => {
9640
+ if (!state.projectSidebarResizing) {
9641
+ return state;
9642
+ }
9643
+ const nextState = resizeProjectSidebar(state, clientX);
9644
+ return {
9645
+ ...nextState,
9646
+ projectSidebarResizing: false
9647
+ };
9648
+ };
9649
+
9419
9650
  const handleProjectAddButtonContextMenu = async (state, button, x, y) => {
9420
9651
  const {
9421
9652
  uid
@@ -9703,6 +9934,19 @@ const getSavedProjects = savedState => {
9703
9934
  return validProjects;
9704
9935
  };
9705
9936
 
9937
+ const getSavedProjectSidebarWidth = savedState => {
9938
+ if (!isObject$1(savedState)) {
9939
+ return undefined;
9940
+ }
9941
+ const {
9942
+ projectSidebarWidth
9943
+ } = savedState;
9944
+ if (typeof projectSidebarWidth !== 'number') {
9945
+ return undefined;
9946
+ }
9947
+ return projectSidebarWidth;
9948
+ };
9949
+
9706
9950
  const getSavedReasoningEffort = savedState => {
9707
9951
  if (!isObject$1(savedState)) {
9708
9952
  return undefined;
@@ -9923,7 +10167,7 @@ const loadToolEnablement = async () => {
9923
10167
  const savedToolEnablement = await get('chat.toolEnablement');
9924
10168
  return parseToolEnablement(savedToolEnablement);
9925
10169
  } catch {
9926
- return {};
10170
+ return parseToolEnablement(undefined);
9927
10171
  }
9928
10172
  };
9929
10173
 
@@ -10099,6 +10343,7 @@ const loadContent = async (state, savedState) => {
10099
10343
  const chatListScrollTop = getSavedChatListScrollTop(savedState) ?? state.chatListScrollTop;
10100
10344
  const messagesScrollTop = getSavedMessagesScrollTop(savedState) ?? state.messagesScrollTop;
10101
10345
  const projectListScrollTop = getSavedProjectListScrollTop(savedState) ?? state.projectListScrollTop;
10346
+ const projectSidebarWidth = getSavedProjectSidebarWidth(savedState) ?? state.projectSidebarWidth;
10102
10347
  const savedProjectExpandedIds = getSavedProjectExpandedIds(savedState);
10103
10348
  const projectExpandedIds = (savedProjectExpandedIds || state.projectExpandedIds).filter(id => projects.some(project => project.id === id));
10104
10349
  const reasoningEffort = getSavedReasoningEffort(savedState) ?? state.reasoningEffort;
@@ -10153,6 +10398,8 @@ const loadContent = async (state, savedState) => {
10153
10398
  projectExpandedIds,
10154
10399
  projectListScrollTop,
10155
10400
  projects,
10401
+ projectSidebarResizing: false,
10402
+ projectSidebarWidth,
10156
10403
  reasoningEffort,
10157
10404
  reasoningEffortPickerOpen: false,
10158
10405
  reasoningPickerEnabled,
@@ -10341,7 +10588,7 @@ const removeComposerAttachment = async (state, attachmentId) => {
10341
10588
  return handleRemoveComposerAttachment(state, attachmentId);
10342
10589
  };
10343
10590
 
10344
- const getCss = (composerHeight, composerAttachmentsHeight, modelPickerHeight, listItemHeight, chatMessageFontSize, chatMessageLineHeight, chatMessageFontFamily, chatFocusContentMaxWidth, textAreaPaddingTop, textAreaPaddingLeft, textAreaPaddingRight, textAreaPaddingBottom, chatSendAreaPaddingTop, chatSendAreaPaddingLeft, chatSendAreaPaddingRight, chatSendAreaPaddingBottom, renderHtmlCss) => {
10591
+ const getCss = (composerHeight, composerAttachmentsHeight, modelPickerHeight, listItemHeight, chatMessageFontSize, chatMessageLineHeight, chatMessageFontFamily, chatFocusContentMaxWidth, projectSidebarWidth, textAreaPaddingTop, textAreaPaddingLeft, textAreaPaddingRight, textAreaPaddingBottom, chatSendAreaPaddingTop, chatSendAreaPaddingLeft, chatSendAreaPaddingRight, chatSendAreaPaddingBottom, renderHtmlCss) => {
10345
10592
  const buttonsHeight = 20;
10346
10593
  const gap = 10;
10347
10594
  const contentPadding = 10;
@@ -10366,6 +10613,7 @@ const getCss = (composerHeight, composerAttachmentsHeight, modelPickerHeight, li
10366
10613
  --ChatMessageLineHeight: ${chatMessageLineHeight}px;
10367
10614
  --ChatMessageFontFamily: ${chatMessageFontFamily};
10368
10615
  --ChatFocusContentMaxWidth: ${chatFocusContentMaxWidth}px;
10616
+ --ProjectSidebarWidth: ${projectSidebarWidth}px;
10369
10617
  --RunModePickerHeight: ${runModePickerHeight}px;
10370
10618
  }
10371
10619
 
@@ -10679,7 +10927,41 @@ const getCss = (composerHeight, composerAttachmentsHeight, modelPickerHeight, li
10679
10927
  .Viewlet.Chat.ChatFocus{
10680
10928
  display: flex !important;
10681
10929
  min-width: 0;
10930
+ flex-direction: row !important;
10931
+ }
10932
+
10933
+ .ChatFocus > .ProjectSidebar{
10934
+ display: flex;
10935
+ flex: none;
10936
+ flex-direction: column;
10937
+ inline-size: var(--ProjectSidebarWidth);
10938
+ min-inline-size: 0;
10939
+ }
10940
+
10941
+ .ChatFocus > .ProjectSidebar > .ProjectList{
10942
+ flex: 1;
10943
+ min-height: 0;
10682
10944
  }
10945
+
10946
+ .ChatFocus > .Sash.SashVertical{
10947
+ position: relative;
10948
+ flex: none;
10949
+ inline-size: 4px;
10950
+ cursor: col-resize;
10951
+ touch-action: none;
10952
+ }
10953
+
10954
+ .ChatFocus > .Sash.SashVertical::before{
10955
+ content: '';
10956
+ position: absolute;
10957
+ inset: 0;
10958
+ background: color-mix(in srgb, var(--vscode-sideBar-border, var(--WidgetBorder, white)) 75%, transparent);
10959
+ }
10960
+
10961
+ .ChatFocus > .Sash.SashVertical:hover::before{
10962
+ background: var(--vscode-focusBorder, var(--vscode-button-background));
10963
+ }
10964
+
10683
10965
  .ChatFocusMainArea{
10684
10966
  display: flex;
10685
10967
  flex: 1;
@@ -10794,6 +11076,7 @@ const renderCss = (oldState, newState) => {
10794
11076
  composerHeight,
10795
11077
  listItemHeight,
10796
11078
  modelPickerHeight,
11079
+ projectSidebarWidth,
10797
11080
  selectedSessionId,
10798
11081
  sessions,
10799
11082
  textAreaPaddingBottom,
@@ -10803,7 +11086,7 @@ const renderCss = (oldState, newState) => {
10803
11086
  uid
10804
11087
  } = newState;
10805
11088
  const renderHtmlCss = getRenderHtmlCss(sessions, selectedSessionId);
10806
- const css = getCss(composerHeight, composerAttachmentsHeight, modelPickerHeight, listItemHeight, chatMessageFontSize, chatMessageLineHeight, chatMessageFontFamily, chatFocusContentMaxWidth, textAreaPaddingTop, textAreaPaddingLeft, textAreaPaddingRight, textAreaPaddingBottom, chatSendAreaPaddingTop, chatSendAreaPaddingLeft, chatSendAreaPaddingRight, chatSendAreaPaddingBottom, renderHtmlCss);
11089
+ const css = getCss(composerHeight, composerAttachmentsHeight, modelPickerHeight, listItemHeight, chatMessageFontSize, chatMessageLineHeight, chatMessageFontFamily, chatFocusContentMaxWidth, projectSidebarWidth, textAreaPaddingTop, textAreaPaddingLeft, textAreaPaddingRight, textAreaPaddingBottom, chatSendAreaPaddingTop, chatSendAreaPaddingLeft, chatSendAreaPaddingRight, chatSendAreaPaddingBottom, renderHtmlCss);
10807
11090
  return [SetCss, uid, css];
10808
11091
  };
10809
11092
 
@@ -10982,9 +11265,13 @@ const MaskIconChevronRight = 'MaskIconChevronRight';
10982
11265
  const MaskIconChevronUp = 'MaskIconChevronUp';
10983
11266
  const MaskIconClose = 'MaskIconClose';
10984
11267
  const MaskIconDebugPause = 'MaskIconDebugPause';
11268
+ const MaskIconDiff = 'MaskIconDiff';
11269
+ const MaskIconFolder = 'MaskIconFolder';
11270
+ const MaskIconGitCommit = 'MaskIconGitCommit';
10985
11271
  const MaskIconLayoutPanelLeft = 'MaskIconLayoutPanelLeft';
10986
11272
  const MaskIconSearch = 'MaskIconSearch';
10987
11273
  const MaskIconSettingsGear = 'MaskIconSettingsGear';
11274
+ const MaskIconTerminal = 'MaskIconTerminal';
10988
11275
  const Message = 'Message';
10989
11276
  const MessageAssistant = 'MessageAssistant';
10990
11277
  const MessageUser = 'MessageUser';
@@ -11003,6 +11290,8 @@ const ProjectSessionItem = 'ProjectSessionItem';
11003
11290
  const ProjectSessionItemLabel = 'ProjectSessionItemLabel';
11004
11291
  const ProjectSessionItemSelected = 'ProjectSessionItemSelected';
11005
11292
  const ProjectSidebar = 'ProjectSidebar';
11293
+ const Sash = 'Sash';
11294
+ const SashVertical = 'SashVertical';
11006
11295
  const SearchFieldContainer = 'SearchFieldContainer';
11007
11296
  const RunModePickerContainer = 'RunModePickerContainer';
11008
11297
  const RunModePickerPopOver = 'RunModePickerPopOver';
@@ -11071,6 +11360,9 @@ const HandleContextMenuChatImageAttachment = 58;
11071
11360
  const HandleClickGitBranchPickerToggle = 59;
11072
11361
  const HandleErrorComposerAttachmentPreviewOverlay = 60;
11073
11362
  const HandleClickCustomSelectOverlay = 61;
11363
+ const HandlePointerDownProjectSidebarSash = 62;
11364
+ const HandlePointerMoveProjectSidebarSash = 63;
11365
+ const HandlePointerUpProjectSidebarSash = 64;
11074
11366
 
11075
11367
  const getAddContextButtonDom = () => {
11076
11368
  return [{
@@ -11380,34 +11672,51 @@ const getUsageOverviewDom = (tokensUsed, tokensMax) => {
11380
11672
  }, text(usageLabel)];
11381
11673
  };
11382
11674
 
11383
- const getComposerAttachmentLabel = displayType => {
11675
+ const getComposerAttachmentClassName = displayType => {
11384
11676
  switch (displayType) {
11385
11677
  case 'file':
11386
- return 'File';
11678
+ return ChatComposerAttachment;
11387
11679
  case 'image':
11388
- return 'Image';
11680
+ return ChatComposerAttachmentImage;
11389
11681
  case 'invalid-image':
11390
- return 'Invalid image';
11682
+ return ChatComposerAttachmentInvalidImage;
11391
11683
  case 'text-file':
11392
- return 'Text file';
11684
+ return ChatComposerAttachmentTextFile;
11393
11685
  default:
11394
- return displayType;
11686
+ return ChatComposerAttachment;
11395
11687
  }
11396
11688
  };
11397
- const getComposerAttachmentClassName = displayType => {
11689
+
11690
+ const getComposerAttachmentLabel = displayType => {
11398
11691
  switch (displayType) {
11399
11692
  case 'file':
11400
- return ChatComposerAttachment;
11693
+ return 'File';
11401
11694
  case 'image':
11402
- return ChatComposerAttachmentImage;
11695
+ return 'Image';
11403
11696
  case 'invalid-image':
11404
- return ChatComposerAttachmentInvalidImage;
11697
+ return 'Invalid image';
11405
11698
  case 'text-file':
11406
- return ChatComposerAttachmentTextFile;
11699
+ return 'Text file';
11407
11700
  default:
11408
- return ChatComposerAttachment;
11701
+ return displayType;
11702
+ }
11703
+ };
11704
+
11705
+ const getComposerAttachmentPreviewDom = attachment => {
11706
+ if (!attachment.previewSrc) {
11707
+ return [];
11409
11708
  }
11709
+ return [{
11710
+ alt: `Image preview for ${attachment.name}`,
11711
+ childCount: 0,
11712
+ className: ChatComposerAttachmentPreview,
11713
+ name: getComposerAttachmentInputName(attachment.attachmentId),
11714
+ onContextMenu: HandleContextMenuChatImageAttachment,
11715
+ src: attachment.previewSrc,
11716
+ type: Img
11717
+ }];
11410
11718
  };
11719
+
11411
11720
  const getComposerAttachmentRemoveButtonDom = attachment => {
11412
11721
  return [{
11413
11722
  'aria-label': removeAttachment(),
@@ -11423,20 +11732,7 @@ const getComposerAttachmentRemoveButtonDom = attachment => {
11423
11732
  type: Text
11424
11733
  }];
11425
11734
  };
11426
- const getComposerAttachmentPreviewDom = attachment => {
11427
- if (!attachment.previewSrc) {
11428
- return [];
11429
- }
11430
- return [{
11431
- alt: `Image preview for ${attachment.name}`,
11432
- childCount: 0,
11433
- className: ChatComposerAttachmentPreview,
11434
- name: getComposerAttachmentInputName(attachment.attachmentId),
11435
- onContextMenu: HandleContextMenuChatImageAttachment,
11436
- src: attachment.previewSrc,
11437
- type: Img
11438
- }];
11439
- };
11735
+
11440
11736
  const getComposerAttachmentsDom = composerAttachments => {
11441
11737
  if (composerAttachments.length === 0) {
11442
11738
  return [];
@@ -11468,6 +11764,7 @@ const getComposerAttachmentsDom = composerAttachments => {
11468
11764
  }];
11469
11765
  })];
11470
11766
  };
11767
+
11471
11768
  const getComposerTextAreaDom = () => {
11472
11769
  return {
11473
11770
  childCount: 0,
@@ -11482,6 +11779,7 @@ const getComposerTextAreaDom = () => {
11482
11779
  type: TextArea
11483
11780
  };
11484
11781
  };
11782
+
11485
11783
  const getChatSendAreaDom = (composerValue, composerAttachments, agentMode, agentModePickerOpen, gitBranchPickerVisible, gitBranchPickerOpen, gitBranchPickerErrorMessage, gitBranches, fallbackBranchName, hasSpaceForAgentModePicker, modelPickerOpen, models, selectedModelId, reasoningPickerEnabled, reasoningEffort, reasoningEffortPickerOpen, usageOverviewEnabled, tokensUsed, tokensMax, addContextButtonEnabled, showRunMode, hasSpaceForRunModePicker, runMode, runModePickerOpen, todoListToolEnabled, todoListItems, showCreatePullRequestButton = false, voiceDictationEnabled = false, scrollDownButtonEnabled = false, messagesAutoScrollEnabled = true) => {
11486
11784
  const isSendDisabled = composerValue.trim() === '';
11487
11785
  const showAgentModePicker = hasSpaceForAgentModePicker;
@@ -11570,26 +11868,57 @@ const getChatHeaderAuthDom = (authEnabled = false, userState = 'loggedOut', user
11570
11868
  }, text(buttonLabel)];
11571
11869
  };
11572
11870
 
11871
+ const getHeaderActionClassName = disabled => {
11872
+ return mergeClassNames(IconButton, disabled ? IconButtonDisabled : '');
11873
+ };
11874
+ const getHeaderActionVirtualDom = item => {
11875
+ return [{
11876
+ childCount: 1,
11877
+ className: getHeaderActionClassName(item.disabled),
11878
+ disabled: item.disabled,
11879
+ name: item.name,
11880
+ onClick: item.onClick,
11881
+ title: item.title,
11882
+ type: Button$1
11883
+ }, {
11884
+ childCount: 0,
11885
+ className: item.icon,
11886
+ type: Div
11887
+ }];
11888
+ };
11889
+
11573
11890
  const focusHeaderStyle = 'align-items:center;border-bottom:1px solid var(--vscode-panel-border, transparent);display:flex;gap:12px;justify-content:space-between;padding:8px 12px;';
11574
11891
  const focusHeaderMetaStyle = 'align-items:baseline;display:flex;gap:8px;min-width:0;overflow:hidden;';
11575
11892
  const focusHeaderTitleStyle = 'margin:0;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;';
11576
11893
  const focusHeaderProjectStyle = 'overflow:hidden;text-overflow:ellipsis;white-space:nowrap;';
11577
11894
  const focusHeaderActionsStyle = 'display:flex;flex-wrap:wrap;gap:8px;justify-content:flex-end;';
11578
- const focusHeaderButtonStyle = 'white-space:nowrap;';
11579
- const getFocusHeaderActionButtonDom = (label, name) => {
11580
- return [{
11581
- childCount: 1,
11582
- className: mergeClassNames(Button, ButtonSecondary),
11583
- inputType: 'button',
11584
- name,
11585
- onClick: HandleClick,
11586
- style: focusHeaderButtonStyle,
11587
- title: label,
11588
- type: Button$1
11589
- }, text(label)];
11590
- };
11591
11895
  const getChatHeaderDomFocusMode = (selectedSessionTitle, selectedProjectName, authEnabled = false, userState = 'loggedOut', userName = '') => {
11592
- const items = [[addAction(), FocusAddAction], [openInVsCode(), FocusOpenInVsCode], [commit(), FocusCommit], [openTerminal(), FocusOpenTerminal], [showDiff(), FocusShowDiff]];
11896
+ const items = [{
11897
+ icon: mergeClassNames(MaskIcon, MaskIconAdd),
11898
+ name: FocusAddAction,
11899
+ onClick: HandleClick,
11900
+ title: addAction()
11901
+ }, {
11902
+ icon: mergeClassNames(MaskIcon, MaskIconFolder),
11903
+ name: FocusOpenInVsCode,
11904
+ onClick: HandleClick,
11905
+ title: openInVsCode()
11906
+ }, {
11907
+ icon: mergeClassNames(MaskIcon, MaskIconGitCommit),
11908
+ name: FocusCommit,
11909
+ onClick: HandleClick,
11910
+ title: commit()
11911
+ }, {
11912
+ icon: mergeClassNames(MaskIcon, MaskIconTerminal),
11913
+ name: FocusOpenTerminal,
11914
+ onClick: HandleClick,
11915
+ title: openTerminal()
11916
+ }, {
11917
+ icon: mergeClassNames(MaskIcon, MaskIconDiff),
11918
+ name: FocusShowDiff,
11919
+ onClick: HandleClick,
11920
+ title: showDiff()
11921
+ }];
11593
11922
  const hasProjectName = !!selectedProjectName;
11594
11923
  return [{
11595
11924
  childCount: 2 + (authEnabled ? 1 : 0),
@@ -11618,7 +11947,7 @@ const getChatHeaderDomFocusMode = (selectedSessionTitle, selectedProjectName, au
11618
11947
  role: ToolBar,
11619
11948
  style: focusHeaderActionsStyle,
11620
11949
  type: Div
11621
- }, ...items.flatMap(([label, name]) => getFocusHeaderActionButtonDom(label, name))];
11950
+ }, ...items.flatMap(getHeaderActionVirtualDom)];
11622
11951
  };
11623
11952
 
11624
11953
  const getAgentModeOptionsVirtualDom = selectedAgentMode => {
@@ -11654,10 +11983,6 @@ const getAgentModePickerPopOverVirtualDom = selectedAgentMode => {
11654
11983
  return getCustomSelectPopOverVirtualDom(agentModes.length, agentModePickerHeight, getAgentModeOptionsVirtualDom(selectedAgentMode));
11655
11984
  };
11656
11985
 
11657
- const getUsageCostLabel = model => {
11658
- return `${model.usageCost ?? 1}x`;
11659
- };
11660
-
11661
11986
  const getUsageCostDom = detail => {
11662
11987
  if (detail === '') {
11663
11988
  return [];
@@ -11668,6 +11993,11 @@ const getUsageCostDom = detail => {
11668
11993
  type: Span
11669
11994
  }, text(detail)];
11670
11995
  };
11996
+
11997
+ const getUsageCostLabel = model => {
11998
+ return `${model.usageCost ?? 1}x`;
11999
+ };
12000
+
11671
12001
  const getChatModelListItemVirtualDom = (model, selectedModelId) => {
11672
12002
  const detail = getUsageCostLabel(model);
11673
12003
  const hasDetail = detail !== '';
@@ -11733,6 +12063,7 @@ const getModelPickerHeaderDom = modelPickerSearchValue => {
11733
12063
  value: modelPickerSearchValue
11734
12064
  }];
11735
12065
  };
12066
+
11736
12067
  const getChatModelPickerPopOverVirtualDom = (models, selectedModelId, modelPickerSearchValue) => {
11737
12068
  const visibleModels = getVisibleModels(models, modelPickerSearchValue);
11738
12069
  return [{
@@ -11787,15 +12118,6 @@ const getComposerAttachmentPreviewOverlayVirtualDom = (composerAttachments, atta
11787
12118
  }])];
11788
12119
  };
11789
12120
 
11790
- const runModes = ['local', 'background', 'cloud'];
11791
- const runModePickerHeight = runModes.length * 28;
11792
- const getRunModeOptionsVirtualDom = selectedRunMode => {
11793
- return runModes.flatMap(runMode => getCustomSelectOptionVirtualDom(getRunModePickerItemInputName(runMode), runMode, runMode === selectedRunMode));
11794
- };
11795
- const getRunModePickerPopOverVirtualDom = selectedRunMode => {
11796
- return getCustomSelectPopOverVirtualDom(runModes.length, runModePickerHeight, getRunModeOptionsVirtualDom(selectedRunMode), RunModePickerContainer, RunModePickerPopOver, false);
11797
- };
11798
-
11799
12121
  const getDropOverlayVirtualDom = () => {
11800
12122
  return [{
11801
12123
  childCount: 1,
@@ -11810,6 +12132,16 @@ const getDropOverlayVirtualDom = () => {
11810
12132
  type: Text
11811
12133
  }];
11812
12134
  };
12135
+
12136
+ const runModes = ['local', 'background', 'cloud'];
12137
+ const runModePickerHeight = runModes.length * 28;
12138
+ const getRunModeOptionsVirtualDom = selectedRunMode => {
12139
+ return runModes.flatMap(runMode => getCustomSelectOptionVirtualDom(getRunModePickerItemInputName(runMode), runMode, runMode === selectedRunMode));
12140
+ };
12141
+ const getRunModePickerPopOverVirtualDom = selectedRunMode => {
12142
+ return getCustomSelectPopOverVirtualDom(runModes.length, runModePickerHeight, getRunModeOptionsVirtualDom(selectedRunMode), RunModePickerContainer, RunModePickerPopOver, false);
12143
+ };
12144
+
11813
12145
  const getChatOverlaysVirtualDom = ({
11814
12146
  agentMode,
11815
12147
  agentModePickerVisible,
@@ -12448,14 +12780,16 @@ const getReadFileTarget = rawArguments => {
12448
12780
  }
12449
12781
  const uri = Reflect.get(parsed, 'uri');
12450
12782
  const path = Reflect.get(parsed, 'path');
12783
+ const baseUri = Reflect.get(parsed, 'baseUri');
12451
12784
  const uriValue = typeof uri === 'string' ? uri : '';
12452
12785
  const pathValue = typeof path === 'string' ? path : '';
12453
- const title = uriValue || pathValue;
12786
+ const baseUriValue = typeof baseUri === 'string' ? baseUri : '';
12787
+ const title = uriValue || pathValue || baseUriValue;
12454
12788
  if (!title) {
12455
12789
  return undefined;
12456
12790
  }
12457
- // `read_file` tool calls now use absolute `uri`; keep `path` as a legacy fallback for old transcripts.
12458
- const clickableUri = uriValue || pathValue;
12791
+ // File-like tool calls use absolute `uri` where available; keep `path` as a legacy fallback.
12792
+ const clickableUri = uriValue || pathValue || baseUriValue;
12459
12793
  return {
12460
12794
  clickableUri,
12461
12795
  title
@@ -12466,11 +12800,12 @@ const getToolCallFileNameDom = (fileName, {
12466
12800
  clickableProps = {},
12467
12801
  title
12468
12802
  } = {}) => {
12803
+ const resolvedTitle = title ?? clickableProps['data-uri'];
12469
12804
  return [{
12470
12805
  childCount: 1,
12471
12806
  className: ChatToolCallReadFileLink,
12472
- ...(title === undefined ? {} : {
12473
- title
12807
+ ...(resolvedTitle === undefined ? {} : {
12808
+ title: resolvedTitle
12474
12809
  }),
12475
12810
  ...clickableProps,
12476
12811
  type: Span
@@ -12496,7 +12831,6 @@ const getToolCallCreateDirectoryVirtualDom = toolCall => {
12496
12831
  return [{
12497
12832
  childCount: statusLabel ? 4 : 3,
12498
12833
  className: ChatOrderedListItem,
12499
- title: target.title,
12500
12834
  type: Li
12501
12835
  }, {
12502
12836
  childCount: 0,
@@ -12574,7 +12908,7 @@ const getToolCallLabel = toolCall => {
12574
12908
  if (toolCall.name === 'write_file' && !toolCall.status && hasIncompleteJsonArguments(toolCall.arguments)) {
12575
12909
  return `${displayName} (in progress)`;
12576
12910
  }
12577
- if ((toolCall.name === 'list_files' || toolCall.name === 'grep_search') && !toolCall.status && hasIncompleteJsonArguments(toolCall.arguments)) {
12911
+ if ((toolCall.name === 'list_files' || toolCall.name === 'grep_search' || toolCall.name === 'glob') && !toolCall.status && hasIncompleteJsonArguments(toolCall.arguments)) {
12578
12912
  return displayName;
12579
12913
  }
12580
12914
  const argumentPreview = getToolCallArgumentPreview(toolCall.arguments);
@@ -12620,7 +12954,6 @@ const getToolCallEditFileVirtualDom = toolCall => {
12620
12954
  return [{
12621
12955
  childCount: 3,
12622
12956
  className: ChatOrderedListItem,
12623
- title: target.title,
12624
12957
  type: Li
12625
12958
  }, {
12626
12959
  childCount: 0,
@@ -12649,7 +12982,6 @@ const getToolCallGetWorkspaceUriVirtualDom = toolCall => {
12649
12982
  return [{
12650
12983
  childCount: statusLabel ? 4 : 3,
12651
12984
  className: ChatOrderedListItem,
12652
- title: toolCall.result,
12653
12985
  type: Li
12654
12986
  }, {
12655
12987
  childCount: 0,
@@ -12664,6 +12996,21 @@ const getToolCallGetWorkspaceUriVirtualDom = toolCall => {
12664
12996
  }), ...(statusLabel ? [text(statusLabel)] : [])];
12665
12997
  };
12666
12998
 
12999
+ const getGlobPatternLabel = toolCall => {
13000
+ if (toolCall.name !== 'glob') {
13001
+ return '';
13002
+ }
13003
+ try {
13004
+ const parsed = JSON.parse(toolCall.arguments);
13005
+ if (!parsed || typeof parsed !== 'object') {
13006
+ return '';
13007
+ }
13008
+ const pattern = Reflect.get(parsed, 'pattern');
13009
+ return typeof pattern === 'string' && pattern ? ` "${pattern}"` : '';
13010
+ } catch {
13011
+ return '';
13012
+ }
13013
+ };
12667
13014
  const getToolCallReadFileVirtualDom = toolCall => {
12668
13015
  const target = getReadFileTarget(toolCall.arguments);
12669
13016
  if (!target) {
@@ -12672,14 +13019,16 @@ const getToolCallReadFileVirtualDom = toolCall => {
12672
13019
  const fileName = getFileNameFromUri(target.title);
12673
13020
  const toolNameLabel = `${toolCall.name} `;
12674
13021
  const statusLabel = getToolCallStatusLabel(toolCall);
13022
+ const globPatternLabel = getGlobPatternLabel(toolCall);
13023
+ const globMatchCount = toolCall.name === 'glob' && toolCall.status === 'success' ? getGlobMatchCount(toolCall.result) : undefined;
13024
+ const globMatchLabel = typeof globMatchCount === 'number' ? `, ${globMatchCount} ${globMatchCount === 1 ? 'match' : 'matches'}` : '';
12675
13025
  const fileNameClickableProps = target.clickableUri ? {
12676
13026
  'data-uri': target.clickableUri,
12677
13027
  onClick: HandleClickFileName
12678
13028
  } : {};
12679
13029
  return [{
12680
- childCount: statusLabel ? 4 : 3,
13030
+ childCount: 3 + (globPatternLabel ? 1 : 0) + (globMatchLabel ? 1 : 0) + (statusLabel ? 1 : 0),
12681
13031
  className: ChatOrderedListItem,
12682
- title: target.title,
12683
13032
  type: Li
12684
13033
  }, {
12685
13034
  childCount: 0,
@@ -12690,8 +13039,9 @@ const getToolCallReadFileVirtualDom = toolCall => {
12690
13039
  className: ToolCallName,
12691
13040
  type: Span
12692
13041
  }, text(toolNameLabel), ...getToolCallFileNameDom(fileName, {
12693
- clickableProps: fileNameClickableProps
12694
- }), ...(statusLabel ? [text(statusLabel)] : [])];
13042
+ clickableProps: fileNameClickableProps,
13043
+ title: target.title
13044
+ }), ...(globPatternLabel ? [text(globPatternLabel)] : []), ...(globMatchLabel ? [text(globMatchLabel)] : []), ...(statusLabel ? [text(statusLabel)] : [])];
12695
13045
  };
12696
13046
 
12697
13047
  const maxHtmlLength = 40_000;
@@ -13058,7 +13408,6 @@ const getToolCallWriteFileVirtualDom = toolCall => {
13058
13408
  return [{
13059
13409
  childCount: showDiffStats ? statusLabel ? 6 : 5 : statusLabel ? 4 : 3,
13060
13410
  className: ChatOrderedListItem,
13061
- title: target.title,
13062
13411
  type: Li
13063
13412
  }, {
13064
13413
  childCount: 0,
@@ -13088,7 +13437,7 @@ const getToolCallDom = toolCall => {
13088
13437
  return virtualDom;
13089
13438
  }
13090
13439
  }
13091
- if (toolCall.name === 'read_file' || toolCall.name === 'list_files' || toolCall.name === 'list_file') {
13440
+ if (toolCall.name === 'read_file' || toolCall.name === 'list_files' || toolCall.name === 'list_file' || toolCall.name === 'glob') {
13092
13441
  const virtualDom = getToolCallReadFileVirtualDom(toolCall);
13093
13442
  if (virtualDom.length > 0) {
13094
13443
  return virtualDom;
@@ -13578,12 +13927,21 @@ const getChatModeChatFocusVirtualDom = ({
13578
13927
  const hasVisibleOverlays = isDropOverlayVisible || isComposerAttachmentPreviewOverlayVisible || isAgentModePickerVisible || isNewModelPickerVisible || isRunModePickerVisible;
13579
13928
  const chatRootChildCount = 2 + (hasVisibleOverlays ? 1 : 0);
13580
13929
  return [{
13581
- childCount: chatRootChildCount,
13930
+ childCount: chatRootChildCount + 1,
13582
13931
  className: mergeClassNames(Viewlet, Chat, ChatFocus),
13583
13932
  onDragEnter: HandleDragEnterChatView,
13584
13933
  onDragOver: HandleDragOverChatView,
13934
+ onPointerMove: HandlePointerMoveProjectSidebarSash,
13935
+ onPointerUp: HandlePointerUpProjectSidebarSash,
13585
13936
  type: Div
13586
13937
  }, ...getProjectListDom(projects, sessions, projectExpandedIds, selectedProjectId, selectedSessionId, projectListScrollTop, true), {
13938
+ 'aria-orientation': 'vertical',
13939
+ childCount: 0,
13940
+ className: mergeClassNames(Sash, SashVertical),
13941
+ onPointerDown: HandlePointerDownProjectSidebarSash,
13942
+ role: 'separator',
13943
+ type: Div
13944
+ }, {
13587
13945
  childCount: 3,
13588
13946
  className: ChatFocusMainArea,
13589
13947
  type: Div
@@ -13621,25 +13979,6 @@ const getBackButtonVirtualDom = () => {
13621
13979
  }, arrowLeft];
13622
13980
  };
13623
13981
 
13624
- const getHeaderActionClassName = disabled => {
13625
- return mergeClassNames(IconButton, disabled ? IconButtonDisabled : '');
13626
- };
13627
- const getHeaderActionVirtualDom = item => {
13628
- return [{
13629
- childCount: 1,
13630
- className: getHeaderActionClassName(item.disabled),
13631
- disabled: item.disabled,
13632
- name: item.name,
13633
- onClick: item.onClick,
13634
- title: item.title,
13635
- type: Button$1
13636
- }, {
13637
- childCount: 0,
13638
- className: item.icon,
13639
- type: Div
13640
- }];
13641
- };
13642
-
13643
13982
  const getChatHeaderActionsDom = (viewMode, searchEnabled = false) => {
13644
13983
  const toggleTitle = viewMode === 'chat-focus' ? normalChatMode() : chatFocusMode();
13645
13984
  const items = [{
@@ -13814,6 +14153,7 @@ const getChatSearchDom = (hasSearchField, searchValue) => {
13814
14153
  value: searchValue
13815
14154
  }];
13816
14155
  };
14156
+
13817
14157
  const getChatHeaderListModeDom = (authEnabled = false, userState = 'loggedOut', userName = '', authErrorMessage = '', searchEnabled = false, searchFieldVisible = false, searchValue = '') => {
13818
14158
  const hasAuthError = authEnabled && !!authErrorMessage;
13819
14159
  const hasSearchField = searchEnabled && searchFieldVisible;
@@ -14714,6 +15054,17 @@ const renderEventListeners = () => {
14714
15054
  name: HandlePointerDownModelPickerList,
14715
15055
  params: ['handlePointerDownModelPickerList'],
14716
15056
  preventDefault: true
15057
+ }, {
15058
+ name: HandlePointerDownProjectSidebarSash,
15059
+ params: ['handlePointerDownProjectSidebarSash'],
15060
+ preventDefault: true
15061
+ }, {
15062
+ name: HandlePointerMoveProjectSidebarSash,
15063
+ params: ['handlePointerMoveProjectSidebarSash', ClientX]
15064
+ }, {
15065
+ name: HandlePointerUpProjectSidebarSash,
15066
+ params: ['handlePointerUpProjectSidebarSash', ClientX],
15067
+ preventDefault: true
14717
15068
  }, {
14718
15069
  name: HandlePointerUpModelPickerList,
14719
15070
  params: ['handlePointerUpModelPickerList', ClientY],
@@ -14827,6 +15178,7 @@ const saveState = state => {
14827
15178
  projectExpandedIds,
14828
15179
  projectListScrollTop,
14829
15180
  projects,
15181
+ projectSidebarWidth,
14830
15182
  reasoningEffort,
14831
15183
  renamingSessionId,
14832
15184
  searchFieldVisible,
@@ -14849,6 +15201,7 @@ const saveState = state => {
14849
15201
  projectExpandedIds,
14850
15202
  projectListScrollTop,
14851
15203
  projects,
15204
+ projectSidebarWidth,
14852
15205
  reasoningEffort,
14853
15206
  renamingSessionId,
14854
15207
  searchFieldVisible,
@@ -15119,7 +15472,10 @@ const commandMap = {
15119
15472
  'Chat.handleMouseOut': wrapCommand(handleMouseOut),
15120
15473
  'Chat.handleMouseOver': wrapCommand(handleMouseOver),
15121
15474
  'Chat.handlePointerDownModelPickerList': wrapCommand(handlePointerDownModelPickerList),
15475
+ 'Chat.handlePointerDownProjectSidebarSash': wrapCommand(handlePointerDownProjectSidebarSash),
15476
+ 'Chat.handlePointerMoveProjectSidebarSash': wrapCommand(handlePointerMoveProjectSidebarSash),
15122
15477
  'Chat.handlePointerUpModelPickerList': wrapCommand(handlePointerUpModelPickerList),
15478
+ 'Chat.handlePointerUpProjectSidebarSash': wrapCommand(handlePointerUpProjectSidebarSash),
15123
15479
  'Chat.handleProjectAddButtonContextMenu': wrapCommand(handleProjectAddButtonContextMenu),
15124
15480
  'Chat.handleProjectListContextMenu': wrapCommand(handleProjectListContextMenu),
15125
15481
  'Chat.handleProjectListScroll': wrapCommand(handleProjectListScroll),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/chat-view",
3
- "version": "7.4.0",
3
+ "version": "7.5.0",
4
4
  "description": "Chat View Worker",
5
5
  "repository": {
6
6
  "type": "git",