@lvce-editor/chat-view 6.12.0 → 6.14.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.
@@ -1486,6 +1486,12 @@ const backToChats = () => {
1486
1486
  const settings = () => {
1487
1487
  return i18nString('Settings');
1488
1488
  };
1489
+ const search = () => {
1490
+ return i18nString('Search');
1491
+ };
1492
+ const searchChats = () => {
1493
+ return i18nString('Search chats');
1494
+ };
1489
1495
  const loginToBackend = () => {
1490
1496
  return i18nString('Login to backend');
1491
1497
  };
@@ -1528,6 +1534,9 @@ const sendMessage = () => {
1528
1534
  const startVoiceDictation = () => {
1529
1535
  return i18nString('Start voice dictation');
1530
1536
  };
1537
+ const addContext = () => {
1538
+ return i18nString('Add Context');
1539
+ };
1531
1540
  const save = () => {
1532
1541
  return i18nString('Save');
1533
1542
  };
@@ -1652,6 +1661,7 @@ const createDefaultState = () => {
1652
1661
  const composerFontSize = 13;
1653
1662
  const composerLineHeight = 20;
1654
1663
  return {
1664
+ addContextButtonEnabled: false,
1655
1665
  aiSessionTitleGenerationEnabled: false,
1656
1666
  assetDir: '',
1657
1667
  authAccessToken: '',
@@ -1715,6 +1725,9 @@ const createDefaultState = () => {
1715
1725
  questionToolEnabled: false,
1716
1726
  renamingSessionId: '',
1717
1727
  runMode: 'local',
1728
+ searchEnabled: false,
1729
+ searchFieldVisible: false,
1730
+ searchValue: '',
1718
1731
  selectedModelId: defaultModelId,
1719
1732
  selectedProjectId: defaultProjectId,
1720
1733
  selectedSessionId: defaultSessionId,
@@ -1730,6 +1743,7 @@ const createDefaultState = () => {
1730
1743
  textAreaPaddingLeft: 12,
1731
1744
  textAreaPaddingRight: 12,
1732
1745
  textAreaPaddingTop: 0,
1746
+ todoListToolEnabled: false,
1733
1747
  tokensMax: 0,
1734
1748
  tokensUsed: 0,
1735
1749
  uid: 0,
@@ -2545,7 +2559,7 @@ const isEqualProjectExpandedIds = (a, b) => {
2545
2559
  return true;
2546
2560
  };
2547
2561
  const isEqual = (oldState, newState) => {
2548
- return oldState.authEnabled === newState.authEnabled && oldState.authErrorMessage === newState.authErrorMessage && oldState.authStatus === newState.authStatus && oldState.composerDropActive === newState.composerDropActive && oldState.composerDropEnabled === newState.composerDropEnabled && oldState.composerValue === newState.composerValue && oldState.initial === newState.initial && isEqualProjectExpandedIds(oldState.projectExpandedIds, newState.projectExpandedIds) && oldState.projectListScrollTop === newState.projectListScrollTop && oldState.renamingSessionId === newState.renamingSessionId && oldState.selectedModelId === newState.selectedModelId && oldState.selectedProjectId === newState.selectedProjectId && oldState.selectedSessionId === newState.selectedSessionId && oldState.showRunMode === newState.showRunMode && oldState.runMode === newState.runMode && oldState.sessions === newState.sessions && oldState.tokensMax === newState.tokensMax && oldState.tokensUsed === newState.tokensUsed && oldState.usageOverviewEnabled === newState.usageOverviewEnabled && oldState.useChatMathWorker === newState.useChatMathWorker && oldState.viewMode === newState.viewMode && oldState.voiceDictationEnabled === newState.voiceDictationEnabled;
2562
+ return oldState.addContextButtonEnabled === newState.addContextButtonEnabled && oldState.authEnabled === newState.authEnabled && oldState.authErrorMessage === newState.authErrorMessage && oldState.authStatus === newState.authStatus && oldState.composerDropActive === newState.composerDropActive && oldState.composerDropEnabled === newState.composerDropEnabled && oldState.composerValue === newState.composerValue && oldState.initial === newState.initial && isEqualProjectExpandedIds(oldState.projectExpandedIds, newState.projectExpandedIds) && oldState.projectListScrollTop === newState.projectListScrollTop && oldState.renamingSessionId === newState.renamingSessionId && oldState.selectedModelId === newState.selectedModelId && oldState.selectedProjectId === newState.selectedProjectId && oldState.selectedSessionId === newState.selectedSessionId && oldState.showRunMode === newState.showRunMode && oldState.runMode === newState.runMode && oldState.sessions === newState.sessions && oldState.tokensMax === newState.tokensMax && oldState.tokensUsed === newState.tokensUsed && oldState.usageOverviewEnabled === newState.usageOverviewEnabled && oldState.useChatMathWorker === newState.useChatMathWorker && oldState.viewMode === newState.viewMode && oldState.voiceDictationEnabled === newState.voiceDictationEnabled;
2549
2563
  };
2550
2564
 
2551
2565
  const diffScrollTop = (oldState, newState) => {
@@ -7186,12 +7200,38 @@ const getSseEventType = value => {
7186
7200
  return value && typeof value === 'object' && Reflect.get(value, 'type') === 'response.completed' ? 'sse-response-completed' : 'sse-response-part';
7187
7201
  };
7188
7202
 
7203
+ const getMessageById = (messages, messageId) => {
7204
+ return messages.find(message => message.id === messageId);
7205
+ };
7206
+
7207
+ const getNextHandleTextChunkState = (latestState, parsedMessages, sessions) => {
7208
+ return {
7209
+ ...latestState,
7210
+ ...(latestState.messagesAutoScrollEnabled ? {
7211
+ messagesScrollTop: getNextAutoScrollTop(latestState.messagesScrollTop)
7212
+ } : {}),
7213
+ parsedMessages,
7214
+ sessions
7215
+ };
7216
+ };
7217
+
7218
+ const getSelectedSession = (sessions, selectedSessionId) => {
7219
+ return sessions.find(session => session.id === selectedSessionId);
7220
+ };
7221
+
7222
+ const setAndRerenderHandleTextChunkState = async (uid, previousState, nextState) => {
7223
+ set$1(uid, previousState, nextState);
7224
+ // @ts-ignore
7225
+ await invoke$1('Chat.rerender');
7226
+ };
7227
+
7189
7228
  const getToolCallMergeKey = toolCall => {
7190
7229
  if (toolCall.id) {
7191
7230
  return `id:${toolCall.id}`;
7192
7231
  }
7193
7232
  return `value:${toolCall.name}:${toolCall.arguments}`;
7194
7233
  };
7234
+
7195
7235
  const mergeToolCalls = (existing = [], incoming) => {
7196
7236
  if (incoming.length === 0) {
7197
7237
  return existing;
@@ -7213,8 +7253,9 @@ const mergeToolCalls = (existing = [], incoming) => {
7213
7253
  }
7214
7254
  return merged;
7215
7255
  };
7216
- const updateMessageTextInSelectedSession = async (sessions, parsedMessages, selectedSessionId, messageId, text, inProgress) => {
7217
- let updatedMessage;
7256
+
7257
+ const updateMessageToolCallsInSelectedSession = (sessions, parsedMessages, selectedSessionId, messageId, toolCalls) => {
7258
+ let nextParsedMessages = parsedMessages;
7218
7259
  const updatedSessions = sessions.map(session => {
7219
7260
  if (session.id !== selectedSessionId) {
7220
7261
  return session;
@@ -7225,26 +7266,47 @@ const updateMessageTextInSelectedSession = async (sessions, parsedMessages, sele
7225
7266
  if (message.id !== messageId) {
7226
7267
  return message;
7227
7268
  }
7228
- updatedMessage = {
7269
+ const updatedMessage = {
7229
7270
  ...message,
7230
- inProgress,
7231
- text
7271
+ toolCalls: mergeToolCalls(message.toolCalls, toolCalls)
7232
7272
  };
7273
+ nextParsedMessages = copyParsedMessageContent(nextParsedMessages, message.id, updatedMessage.id);
7233
7274
  return updatedMessage;
7234
7275
  })
7235
7276
  };
7236
7277
  });
7237
- let nextParsedMessages = parsedMessages;
7238
- if (updatedMessage) {
7239
- nextParsedMessages = await parseAndStoreMessageContent(parsedMessages, updatedMessage);
7240
- }
7241
7278
  return {
7242
7279
  parsedMessages: nextParsedMessages,
7243
7280
  sessions: updatedSessions
7244
7281
  };
7245
7282
  };
7246
- const updateMessageToolCallsInSelectedSession = (sessions, parsedMessages, selectedSessionId, messageId, toolCalls) => {
7247
- let nextParsedMessages = parsedMessages;
7283
+
7284
+ const handleToolCallsChunkFunction = async (uid, assistantMessageId, toolCalls, handleTextChunkState) => {
7285
+ const selectedSession = getSelectedSession(handleTextChunkState.latestState.sessions, handleTextChunkState.latestState.selectedSessionId);
7286
+ if (!selectedSession) {
7287
+ return {
7288
+ latestState: handleTextChunkState.latestState,
7289
+ previousState: handleTextChunkState.previousState
7290
+ };
7291
+ }
7292
+ const assistantMessage = getMessageById(selectedSession.messages, assistantMessageId);
7293
+ if (!assistantMessage) {
7294
+ return {
7295
+ latestState: handleTextChunkState.latestState,
7296
+ previousState: handleTextChunkState.previousState
7297
+ };
7298
+ }
7299
+ const updated = updateMessageToolCallsInSelectedSession(handleTextChunkState.latestState.sessions, handleTextChunkState.latestState.parsedMessages, handleTextChunkState.latestState.selectedSessionId, assistantMessageId, toolCalls);
7300
+ const nextState = getNextHandleTextChunkState(handleTextChunkState.latestState, updated.parsedMessages, updated.sessions);
7301
+ await setAndRerenderHandleTextChunkState(uid, handleTextChunkState.previousState, nextState);
7302
+ return {
7303
+ latestState: nextState,
7304
+ previousState: nextState
7305
+ };
7306
+ };
7307
+
7308
+ const updateMessageTextInSelectedSession = async (sessions, parsedMessages, selectedSessionId, messageId, text, inProgress) => {
7309
+ let updatedMessage;
7248
7310
  const updatedSessions = sessions.map(session => {
7249
7311
  if (session.id !== selectedSessionId) {
7250
7312
  return session;
@@ -7255,15 +7317,19 @@ const updateMessageToolCallsInSelectedSession = (sessions, parsedMessages, selec
7255
7317
  if (message.id !== messageId) {
7256
7318
  return message;
7257
7319
  }
7258
- const updatedMessage = {
7320
+ updatedMessage = {
7259
7321
  ...message,
7260
- toolCalls: mergeToolCalls(message.toolCalls, toolCalls)
7322
+ inProgress,
7323
+ text
7261
7324
  };
7262
- nextParsedMessages = copyParsedMessageContent(nextParsedMessages, message.id, updatedMessage.id);
7263
7325
  return updatedMessage;
7264
7326
  })
7265
7327
  };
7266
7328
  });
7329
+ let nextParsedMessages = parsedMessages;
7330
+ if (updatedMessage) {
7331
+ nextParsedMessages = await parseAndStoreMessageContent(parsedMessages, updatedMessage);
7332
+ }
7267
7333
  return {
7268
7334
  parsedMessages: nextParsedMessages,
7269
7335
  sessions: updatedSessions
@@ -7302,38 +7368,6 @@ const handleTextChunkFunction = async (uid, assistantMessageId, chunk, handleTex
7302
7368
  previousState: nextState
7303
7369
  };
7304
7370
  };
7305
- const handleToolCallsChunkFunction = async (uid, assistantMessageId, toolCalls, handleTextChunkState) => {
7306
- const selectedSession = handleTextChunkState.latestState.sessions.find(session => session.id === handleTextChunkState.latestState.selectedSessionId);
7307
- if (!selectedSession) {
7308
- return {
7309
- latestState: handleTextChunkState.latestState,
7310
- previousState: handleTextChunkState.previousState
7311
- };
7312
- }
7313
- const assistantMessage = selectedSession.messages.find(message => message.id === assistantMessageId);
7314
- if (!assistantMessage) {
7315
- return {
7316
- latestState: handleTextChunkState.latestState,
7317
- previousState: handleTextChunkState.previousState
7318
- };
7319
- }
7320
- const updated = updateMessageToolCallsInSelectedSession(handleTextChunkState.latestState.sessions, handleTextChunkState.latestState.parsedMessages, handleTextChunkState.latestState.selectedSessionId, assistantMessageId, toolCalls);
7321
- const nextState = {
7322
- ...handleTextChunkState.latestState,
7323
- ...(handleTextChunkState.latestState.messagesAutoScrollEnabled ? {
7324
- messagesScrollTop: getNextAutoScrollTop(handleTextChunkState.latestState.messagesScrollTop)
7325
- } : {}),
7326
- parsedMessages: updated.parsedMessages,
7327
- sessions: updated.sessions
7328
- };
7329
- set$1(uid, handleTextChunkState.previousState, nextState);
7330
- // @ts-ignore
7331
- await invoke$1('Chat.rerender');
7332
- return {
7333
- latestState: nextState,
7334
- previousState: nextState
7335
- };
7336
- };
7337
7371
 
7338
7372
  const hasLegacyStreamingToolCalls = parsed => {
7339
7373
  if (!parsed || typeof parsed !== 'object') {
@@ -7646,13 +7680,16 @@ const handleClickSend = async state => {
7646
7680
  };
7647
7681
 
7648
7682
  const Composer = 'composer';
7683
+ const Search = 'search';
7649
7684
  const ComposerDropTarget = 'composer-drop-target';
7685
+ const AddContext = 'add-context';
7650
7686
  const Dictate = 'dictate';
7651
7687
  const Send = 'send';
7652
7688
  const Back = 'back';
7653
7689
  const Model = 'model';
7654
7690
  const RunMode = 'runMode';
7655
7691
  const ToggleChatFocus = 'toggle-chat-focus';
7692
+ const ToggleSearch = 'toggle-search';
7656
7693
  const CreateProject = 'create-project';
7657
7694
  const CreateSession = 'create-session';
7658
7695
  const CreateSessionInProjectPrefix = 'create-session-in-project:';
@@ -7831,6 +7868,12 @@ const handleClick = async (state, name, id = '') => {
7831
7868
  }
7832
7869
  case name === ToggleChatFocus:
7833
7870
  return toggleChatFocusMode(state);
7871
+ case name === ToggleSearch:
7872
+ return {
7873
+ ...state,
7874
+ searchFieldVisible: !state.searchFieldVisible,
7875
+ searchValue: state.searchFieldVisible ? '' : state.searchValue
7876
+ };
7834
7877
  case isProjectInputName(name):
7835
7878
  {
7836
7879
  const projectId = getProjectIdFromInputName(name);
@@ -8008,6 +8051,13 @@ const handleDropFiles = async (state, name, files = []) => {
8008
8051
  return nextState;
8009
8052
  };
8010
8053
 
8054
+ const handleSearchValueChange = (state, newValue) => {
8055
+ return {
8056
+ ...state,
8057
+ searchValue: newValue
8058
+ };
8059
+ };
8060
+
8011
8061
  const handleInput = async (state, name, value, inputSource = 'user') => {
8012
8062
  const {
8013
8063
  selectedSessionId
@@ -8024,6 +8074,9 @@ const handleInput = async (state, name, value, inputSource = 'user') => {
8024
8074
  openRouterApiKeyInput: value
8025
8075
  };
8026
8076
  }
8077
+ if (name === Search) {
8078
+ return handleSearchValueChange(state, value);
8079
+ }
8027
8080
  if (name !== Composer) {
8028
8081
  return state;
8029
8082
  }
@@ -8234,6 +8287,13 @@ const initialize = async () => {
8234
8287
  set$4(rpc);
8235
8288
  };
8236
8289
 
8290
+ const ensureBlankProject = (projects, fallbackBlankProject) => {
8291
+ if (projects.some(project => project.name === '_blank')) {
8292
+ return projects;
8293
+ }
8294
+ return [fallbackBlankProject, ...projects];
8295
+ };
8296
+
8237
8297
  const isObject$1 = value => {
8238
8298
  return typeof value === 'object' && value !== null;
8239
8299
  };
@@ -8251,6 +8311,32 @@ const getSavedChatListScrollTop = savedState => {
8251
8311
  return chatListScrollTop;
8252
8312
  };
8253
8313
 
8314
+ const getSavedComposerValue = savedState => {
8315
+ if (!isObject$1(savedState)) {
8316
+ return undefined;
8317
+ }
8318
+ const {
8319
+ composerValue
8320
+ } = savedState;
8321
+ if (typeof composerValue !== 'string') {
8322
+ return undefined;
8323
+ }
8324
+ return composerValue;
8325
+ };
8326
+
8327
+ const getSavedLastNormalViewMode = savedState => {
8328
+ if (!isObject$1(savedState)) {
8329
+ return undefined;
8330
+ }
8331
+ const {
8332
+ lastNormalViewMode
8333
+ } = savedState;
8334
+ if (lastNormalViewMode !== 'list' && lastNormalViewMode !== 'detail') {
8335
+ return undefined;
8336
+ }
8337
+ return lastNormalViewMode;
8338
+ };
8339
+
8254
8340
  const getSavedMessagesScrollTop = savedState => {
8255
8341
  if (!isObject$1(savedState)) {
8256
8342
  return undefined;
@@ -8264,6 +8350,58 @@ const getSavedMessagesScrollTop = savedState => {
8264
8350
  return messagesScrollTop;
8265
8351
  };
8266
8352
 
8353
+ const getSavedProjectExpandedIds = savedState => {
8354
+ if (!isObject$1(savedState)) {
8355
+ return undefined;
8356
+ }
8357
+ const {
8358
+ projectExpandedIds
8359
+ } = savedState;
8360
+ if (!Array.isArray(projectExpandedIds)) {
8361
+ return undefined;
8362
+ }
8363
+ const ids = projectExpandedIds.filter(id => typeof id === 'string');
8364
+ if (ids.length === 0) {
8365
+ return undefined;
8366
+ }
8367
+ return ids;
8368
+ };
8369
+
8370
+ const getSavedProjectListScrollTop = savedState => {
8371
+ if (!isObject$1(savedState)) {
8372
+ return undefined;
8373
+ }
8374
+ const {
8375
+ projectListScrollTop
8376
+ } = savedState;
8377
+ if (typeof projectListScrollTop !== 'number') {
8378
+ return undefined;
8379
+ }
8380
+ return projectListScrollTop;
8381
+ };
8382
+
8383
+ const getSavedProjects = savedState => {
8384
+ if (!isObject$1(savedState)) {
8385
+ return undefined;
8386
+ }
8387
+ const {
8388
+ projects
8389
+ } = savedState;
8390
+ if (!Array.isArray(projects)) {
8391
+ return undefined;
8392
+ }
8393
+ const validProjects = projects.filter(project => {
8394
+ if (!isObject$1(project)) {
8395
+ return false;
8396
+ }
8397
+ return typeof project.id === 'string' && typeof project.name === 'string' && typeof project.uri === 'string';
8398
+ });
8399
+ if (validProjects.length === 0) {
8400
+ return undefined;
8401
+ }
8402
+ return validProjects;
8403
+ };
8404
+
8267
8405
  const getSavedSelectedModelId = savedState => {
8268
8406
  if (!isObject$1(savedState)) {
8269
8407
  return undefined;
@@ -8277,6 +8415,19 @@ const getSavedSelectedModelId = savedState => {
8277
8415
  return selectedModelId;
8278
8416
  };
8279
8417
 
8418
+ const getSavedSelectedProjectId = savedState => {
8419
+ if (!isObject$1(savedState)) {
8420
+ return undefined;
8421
+ }
8422
+ const {
8423
+ selectedProjectId
8424
+ } = savedState;
8425
+ if (typeof selectedProjectId !== 'string') {
8426
+ return undefined;
8427
+ }
8428
+ return selectedProjectId;
8429
+ };
8430
+
8280
8431
  const getSavedSelectedSessionId = savedState => {
8281
8432
  if (!isObject$1(savedState)) {
8282
8433
  return undefined;
@@ -8414,6 +8565,15 @@ const loadPassIncludeObfuscation = async () => {
8414
8565
  }
8415
8566
  };
8416
8567
 
8568
+ const loadSearchEnabled = async () => {
8569
+ try {
8570
+ const savedSearchEnabled = await get('chatView.searchEnabled');
8571
+ return typeof savedSearchEnabled === 'boolean' ? savedSearchEnabled : false;
8572
+ } catch {
8573
+ return false;
8574
+ }
8575
+ };
8576
+
8417
8577
  const loadStreamingEnabled = async () => {
8418
8578
  try {
8419
8579
  const savedStreamingEnabled = await get('chatView.streamingEnabled');
@@ -8423,6 +8583,15 @@ const loadStreamingEnabled = async () => {
8423
8583
  }
8424
8584
  };
8425
8585
 
8586
+ const loadTodoListToolEnabled = async () => {
8587
+ try {
8588
+ const savedTodoListToolEnabled = await get('chatView.todoListToolEnabled');
8589
+ return typeof savedTodoListToolEnabled === 'boolean' ? savedTodoListToolEnabled : false;
8590
+ } catch {
8591
+ return false;
8592
+ }
8593
+ };
8594
+
8426
8595
  const loadUseChatCoordinatorWorker = async () => {
8427
8596
  try {
8428
8597
  const savedUseChatCoordinatorWorker = await get('chatView.useChatCoordinatorWorker');
@@ -8469,7 +8638,7 @@ const loadVoiceDictationEnabled = async () => {
8469
8638
  };
8470
8639
 
8471
8640
  const loadPreferences = async () => {
8472
- const [aiSessionTitleGenerationEnabled, authAccessToken, authEnabled, authRefreshToken, backendUrl, composerDropEnabled, openApiApiKey, openRouterApiKey, emitStreamingFunctionCallEvents, streamingEnabled, passIncludeObfuscation, useChatCoordinatorWorker, useChatMathWorker, useChatNetworkWorkerForRequests, useChatToolWorker, voiceDictationEnabled] = await Promise.all([loadAiSessionTitleGenerationEnabled(), loadBackendAccessToken(), loadAuthEnabled(), loadBackendRefreshToken(), loadBackendUrl(), loadComposerDropEnabled(), loadOpenApiApiKey(), loadOpenRouterApiKey(), loadEmitStreamingFunctionCallEvents(), loadStreamingEnabled(), loadPassIncludeObfuscation(), loadUseChatCoordinatorWorker(), loadUseChatMathWorker(), loadUseChatNetworkWorkerForRequests(), loadUseChatToolWorker(), loadVoiceDictationEnabled()]);
8641
+ const [aiSessionTitleGenerationEnabled, authAccessToken, authEnabled, authRefreshToken, backendUrl, composerDropEnabled, openApiApiKey, openRouterApiKey, emitStreamingFunctionCallEvents, searchEnabled, streamingEnabled, todoListToolEnabled, passIncludeObfuscation, useChatCoordinatorWorker, useChatMathWorker, useChatNetworkWorkerForRequests, useChatToolWorker, voiceDictationEnabled] = await Promise.all([loadAiSessionTitleGenerationEnabled(), loadBackendAccessToken(), loadAuthEnabled(), loadBackendRefreshToken(), loadBackendUrl(), loadComposerDropEnabled(), loadOpenApiApiKey(), loadOpenRouterApiKey(), loadEmitStreamingFunctionCallEvents(), loadSearchEnabled(), loadStreamingEnabled(), loadTodoListToolEnabled(), loadPassIncludeObfuscation(), loadUseChatCoordinatorWorker(), loadUseChatMathWorker(), loadUseChatNetworkWorkerForRequests(), loadUseChatToolWorker(), loadVoiceDictationEnabled()]);
8473
8642
  return {
8474
8643
  aiSessionTitleGenerationEnabled,
8475
8644
  authAccessToken,
@@ -8481,7 +8650,9 @@ const loadPreferences = async () => {
8481
8650
  openApiApiKey,
8482
8651
  openRouterApiKey,
8483
8652
  passIncludeObfuscation,
8653
+ searchEnabled,
8484
8654
  streamingEnabled,
8655
+ todoListToolEnabled,
8485
8656
  useChatCoordinatorWorker,
8486
8657
  useChatMathWorker,
8487
8658
  useChatNetworkWorkerForRequests,
@@ -8520,97 +8691,7 @@ const toSummarySession = session => {
8520
8691
  projectId: session.projectId
8521
8692
  };
8522
8693
  };
8523
- const getSavedSelectedProjectId = savedState => {
8524
- if (!isObject$1(savedState)) {
8525
- return undefined;
8526
- }
8527
- const {
8528
- selectedProjectId
8529
- } = savedState;
8530
- if (typeof selectedProjectId !== 'string') {
8531
- return undefined;
8532
- }
8533
- return selectedProjectId;
8534
- };
8535
- const getSavedProjects = savedState => {
8536
- if (!isObject$1(savedState)) {
8537
- return undefined;
8538
- }
8539
- const {
8540
- projects
8541
- } = savedState;
8542
- if (!Array.isArray(projects)) {
8543
- return undefined;
8544
- }
8545
- const validProjects = projects.filter(project => {
8546
- if (!isObject$1(project)) {
8547
- return false;
8548
- }
8549
- return typeof project.id === 'string' && typeof project.name === 'string' && typeof project.uri === 'string';
8550
- });
8551
- if (validProjects.length === 0) {
8552
- return undefined;
8553
- }
8554
- return validProjects;
8555
- };
8556
- const ensureBlankProject = (projects, fallbackBlankProject) => {
8557
- if (projects.some(project => project.name === '_blank')) {
8558
- return projects;
8559
- }
8560
- return [fallbackBlankProject, ...projects];
8561
- };
8562
- const getSavedProjectListScrollTop = savedState => {
8563
- if (!isObject$1(savedState)) {
8564
- return undefined;
8565
- }
8566
- const {
8567
- projectListScrollTop
8568
- } = savedState;
8569
- if (typeof projectListScrollTop !== 'number') {
8570
- return undefined;
8571
- }
8572
- return projectListScrollTop;
8573
- };
8574
- const getSavedProjectExpandedIds = savedState => {
8575
- if (!isObject$1(savedState)) {
8576
- return undefined;
8577
- }
8578
- const {
8579
- projectExpandedIds
8580
- } = savedState;
8581
- if (!Array.isArray(projectExpandedIds)) {
8582
- return undefined;
8583
- }
8584
- const ids = projectExpandedIds.filter(id => typeof id === 'string');
8585
- if (ids.length === 0) {
8586
- return undefined;
8587
- }
8588
- return ids;
8589
- };
8590
- const getSavedLastNormalViewMode = savedState => {
8591
- if (!isObject$1(savedState)) {
8592
- return undefined;
8593
- }
8594
- const {
8595
- lastNormalViewMode
8596
- } = savedState;
8597
- if (lastNormalViewMode !== 'list' && lastNormalViewMode !== 'detail') {
8598
- return undefined;
8599
- }
8600
- return lastNormalViewMode;
8601
- };
8602
- const getSavedComposerValue = savedState => {
8603
- if (!isObject$1(savedState)) {
8604
- return undefined;
8605
- }
8606
- const {
8607
- composerValue
8608
- } = savedState;
8609
- if (typeof composerValue !== 'string') {
8610
- return undefined;
8611
- }
8612
- return composerValue;
8613
- };
8694
+
8614
8695
  const loadContent = async (state, savedState) => {
8615
8696
  const savedSelectedModelId = getSavedSelectedModelId(savedState);
8616
8697
  const savedViewMode = getSavedViewMode(savedState);
@@ -8626,7 +8707,9 @@ const loadContent = async (state, savedState) => {
8626
8707
  openApiApiKey,
8627
8708
  openRouterApiKey,
8628
8709
  passIncludeObfuscation,
8710
+ searchEnabled,
8629
8711
  streamingEnabled,
8712
+ todoListToolEnabled,
8630
8713
  useChatCoordinatorWorker,
8631
8714
  useChatMathWorker,
8632
8715
  useChatNetworkWorkerForRequests,
@@ -8704,11 +8787,15 @@ const loadContent = async (state, savedState) => {
8704
8787
  projectExpandedIds,
8705
8788
  projectListScrollTop,
8706
8789
  projects,
8790
+ searchEnabled,
8791
+ searchFieldVisible: false,
8792
+ searchValue: '',
8707
8793
  selectedModelId,
8708
8794
  selectedProjectId,
8709
8795
  selectedSessionId,
8710
8796
  sessions,
8711
8797
  streamingEnabled,
8798
+ todoListToolEnabled,
8712
8799
  useChatCoordinatorWorker,
8713
8800
  useChatMathWorker,
8714
8801
  useChatNetworkWorkerForRequests,
@@ -8826,10 +8913,11 @@ const registerMockResponse = (state, mockResponse) => {
8826
8913
  };
8827
8914
 
8828
8915
  const getCss = (composerHeight, listItemHeight, chatMessageFontSize, chatMessageLineHeight, chatMessageFontFamily, textAreaPaddingTop, textAreaPaddingLeft, textAreaPaddingRight, textAreaPaddingBottom, chatSendAreaPaddingTop, chatSendAreaPaddingLeft, chatSendAreaPaddingRight, chatSendAreaPaddingBottom, renderHtmlCss) => {
8916
+ const chatSendAreaHeight = composerHeight + chatSendAreaPaddingTop + chatSendAreaPaddingBottom;
8829
8917
  const baseCss = `:root {
8830
8918
  --ChatInputBoxHeight: ${composerHeight}px;
8831
8919
  --ChatTextAreaHeight: ${composerHeight}px;
8832
- --ChatSendAreaHeight: ${composerHeight + 62}px;
8920
+ --ChatSendAreaHeight: ${chatSendAreaHeight}px;
8833
8921
  --ChatTextAreaPaddingTop: ${textAreaPaddingTop}px;
8834
8922
  --ChatTextAreaPaddingLeft: ${textAreaPaddingLeft}px;
8835
8923
  --ChatTextAreaPaddingRight: ${textAreaPaddingRight}px;
@@ -8842,344 +8930,168 @@ const getCss = (composerHeight, listItemHeight, chatMessageFontSize, chatMessage
8842
8930
  --ChatMessageFontSize: ${chatMessageFontSize}px;
8843
8931
  --ChatMessageLineHeight: ${chatMessageLineHeight}px;
8844
8932
  --ChatMessageFontFamily: ${chatMessageFontFamily};
8845
- }
8846
-
8847
-
8848
- .ChatSendArea{
8849
- height: var(--ChatSendAreaHeight);
8850
- padding: var(--ChatSendAreaPaddingTop) var(--ChatSendAreaPaddingRight) var(--ChatSendAreaPaddingBottom) var(--ChatSendAreaPaddingLeft);
8851
- }
8852
-
8853
- .Viewlet.Chat.ChatFocus {
8854
- background: linear-gradient(180deg, var(--ColorViewBackground, #1d2229) 0%, #1f252d 100%);
8855
- display: grid;
8856
- grid-template-columns: 320px 1fr;
8857
- grid-template-rows: auto 1fr auto;
8858
- }
8859
-
8860
- .Chat.ChatFocus .ChatHeader {
8861
- grid-column: 1 / 3;
8862
- }
8933
+ }`;
8934
+ if (!renderHtmlCss.trim()) {
8935
+ return `${baseCss}
8863
8936
 
8864
- .ChatHeader .Label {
8865
- text-decoration: underline;
8866
- text-underline-offset: 5px;
8937
+ .ChatTodoList {
8938
+ background: var(--vscode-editorWidget-background);
8939
+ border: 1px solid var(--vscode-editorWidget-border);
8940
+ border-radius: 6px;
8941
+ margin-bottom: 8px;
8942
+ overflow: hidden;
8867
8943
  }
8868
8944
 
8869
- .Chat.ChatFocus .ProjectSidebar {
8870
- background: color-mix(in srgb, var(--ColorSideBarBackground, #232b35) 88%, #1f2b38 12%);
8871
- border-right: 1px solid var(--ColorBorder, #3a3d41);
8872
- box-shadow: inset -1px 0 0 rgba(0, 0, 0, 0.2);
8873
- display: flex;
8874
- flex-direction: column;
8875
- grid-column: 1;
8876
- grid-row: 2 / 4;
8877
- min-height: 0;
8945
+ .ChatTodoListHeader {
8946
+ border-bottom: 1px solid var(--vscode-editorWidget-border);
8947
+ color: var(--vscode-descriptionForeground);
8948
+ font-size: 12px;
8949
+ line-height: 18px;
8950
+ padding: 6px 10px;
8878
8951
  }
8879
8952
 
8880
- .Chat.ChatFocus .ProjectList {
8881
- min-height: 0;
8953
+ .ChatTodoListItems {
8954
+ list-style: none;
8955
+ margin: 0;
8956
+ max-height: 180px;
8882
8957
  overflow: auto;
8883
- padding: 10px 8px 12px;
8884
- scrollbar-color: color-mix(in srgb, var(--ColorScrollBarSliderBackground, #4b5563) 78%, transparent)
8885
- color-mix(in srgb, var(--ColorSideBarBackground, #232b35) 92%, transparent);
8886
- scrollbar-width: thin;
8887
- }
8888
-
8889
- .Chat.ChatFocus .ProjectList::-webkit-scrollbar {
8890
- height: 10px;
8891
- width: 10px;
8892
- }
8893
-
8894
- .Chat.ChatFocus .ProjectList::-webkit-scrollbar-track {
8895
- background: color-mix(in srgb, var(--ColorSideBarBackground, #232b35) 94%, transparent);
8896
- border-radius: 999px;
8897
- }
8898
-
8899
- .Chat.ChatFocus .ProjectList::-webkit-scrollbar-thumb {
8900
- background: color-mix(in srgb, var(--ColorScrollBarSliderBackground, #4b5563) 70%, transparent);
8901
- border: 2px solid color-mix(in srgb, var(--ColorSideBarBackground, #232b35) 94%, transparent);
8902
- border-radius: 999px;
8903
- }
8904
-
8905
- .Chat.ChatFocus .ProjectList::-webkit-scrollbar-thumb:hover {
8906
- background: color-mix(in srgb, var(--ColorScrollBarSliderHoverBackground, #667284) 80%, transparent);
8958
+ padding: 4px 0;
8907
8959
  }
8908
8960
 
8909
- .ProjectListGroup {
8910
- border: 1px solid transparent;
8911
- border-radius: 8px;
8912
- margin-bottom: 6px;
8913
- overflow: hidden;
8914
- }
8915
-
8916
- .ProjectListItem {
8917
- align-items: center;
8918
- display: flex;
8919
- gap: 6px;
8920
- min-height: calc(var(--ChatListItemHeight) - 2px);
8921
- }
8922
-
8923
- .ProjectListItemLabel {
8961
+ .ChatTodoListItem {
8924
8962
  align-items: center;
8925
- border-radius: 6px;
8926
- color: var(--ColorForeground, #d5dbe3);
8927
- cursor: pointer;
8963
+ color: var(--vscode-foreground);
8928
8964
  display: flex;
8929
- flex: 1;
8930
- font-weight: 500;
8931
- gap: 2px;
8932
- overflow: hidden;
8965
+ font-size: 12px;
8966
+ line-height: 18px;
8967
+ min-height: 24px;
8933
8968
  padding: 0 10px;
8934
- text-overflow: ellipsis;
8935
- transition: background-color 80ms ease, color 80ms ease;
8936
- white-space: nowrap;
8937
8969
  }
8938
8970
 
8939
- .ProjectListChevron {
8940
- color: color-mix(in srgb, var(--ColorForeground, #c8d0da) 70%, transparent);
8971
+ .ChatTodoListItem::before {
8972
+ color: var(--vscode-descriptionForeground);
8973
+ content: "○";
8941
8974
  display: inline-block;
8942
- flex: 0 0 12px;
8943
- font-size: 11px;
8944
- margin-right: 4px;
8945
- text-align: center;
8946
- width: 12px;
8975
+ margin-right: 8px;
8976
+ width: 1em;
8947
8977
  }
8948
8978
 
8949
- .ProjectListItemSelected {
8950
- background: color-mix(in srgb, var(--ColorListInactiveSelectionBackground, #39424d) 84%, #2f3741 16%);
8979
+ .ChatTodoListItemTodo::before {
8980
+ content: "○";
8951
8981
  }
8952
8982
 
8953
- .ProjectListItem:not(.ProjectListItemSelected):hover,
8954
- .ProjectListItem:not(.ProjectListItemSelected):focus-within {
8955
- background: color-mix(in srgb, var(--ColorListHoverBackground, #38414b) 50%, transparent);
8983
+ .ChatTodoListItem.todo::before {
8984
+ content: "○";
8956
8985
  }
8957
8986
 
8958
- .ProjectListItemSelected .ProjectListItemLabel {
8959
- color: var(--ColorListInactiveSelectionForeground, #e5ebf2);
8987
+ .ChatTodoListItemInProgress::before {
8988
+ color: var(--vscode-textLink-foreground);
8989
+ content: "◐";
8960
8990
  }
8961
8991
 
8962
- .ProjectListItemActions {
8963
- display: flex;
8964
- padding-right: 6px;
8992
+ .ChatTodoListItem.inProgress::before {
8993
+ color: var(--vscode-textLink-foreground);
8994
+ content: "◐";
8965
8995
  }
8966
8996
 
8967
- .ProjectListItemAddChatButton {
8968
- align-items: center;
8969
- background: color-mix(in srgb, var(--ColorButtonSecondaryBackground, #3a434f) 76%, transparent);
8970
- border: 0;
8971
- border-radius: 5px;
8972
- color: var(--ColorForeground, #d0d8e2);
8973
- cursor: pointer;
8974
- display: inline-flex;
8975
- font-size: 13px;
8976
- font-weight: 500;
8977
- height: 18px;
8978
- justify-content: center;
8979
- opacity: 0;
8980
- padding: 0;
8981
- transition: opacity 90ms ease, background-color 90ms ease;
8982
- visibility: hidden;
8983
- width: 18px;
8997
+ .ChatTodoListItemCompleted {
8998
+ color: var(--vscode-disabledForeground);
8984
8999
  }
8985
9000
 
8986
- .ProjectListItem:hover .ProjectListItemAddChatButton,
8987
- .ProjectListItem:focus-within .ProjectListItemAddChatButton {
8988
- opacity: 1;
8989
- visibility: visible;
9001
+ .ChatTodoListItem.completed {
9002
+ color: var(--vscode-disabledForeground);
8990
9003
  }
8991
9004
 
8992
- .ProjectListItemAddChatButton:hover,
8993
- .ProjectListItemAddChatButton:focus-visible {
8994
- background: color-mix(in srgb, var(--ColorButtonSecondaryHoverBackground, #4a5460) 82%, transparent);
9005
+ .ChatTodoListItemCompleted::before {
9006
+ color: var(--vscode-testing-iconPassed);
9007
+ content: "✓";
8995
9008
  }
8996
9009
 
8997
- .ProjectSessionItem {
8998
- align-items: center;
8999
- display: flex;
9000
- min-height: calc(var(--ChatListItemHeight) - 5px);
9001
- }
9010
+ .ChatTodoListItem.completed::before {
9011
+ color: var(--vscode-testing-iconPassed);
9012
+ content: "✓";
9013
+ }`;
9014
+ }
9015
+ return `${baseCss}
9002
9016
 
9003
- .ProjectSessionItemLabel {
9017
+ .ChatTodoList {
9018
+ background: var(--vscode-editorWidget-background);
9019
+ border: 1px solid var(--vscode-editorWidget-border);
9004
9020
  border-radius: 6px;
9005
- color: color-mix(in srgb, var(--ColorForeground, #cfd7df) 92%, transparent);
9006
- cursor: pointer;
9007
- display: block;
9008
- flex: 1;
9009
- font-size: 12.5px;
9021
+ margin-bottom: 8px;
9010
9022
  overflow: hidden;
9011
- padding: 0 10px 0 28px;
9012
- text-overflow: ellipsis;
9013
- transition: background-color 80ms ease, color 80ms ease;
9014
- white-space: nowrap;
9015
- }
9016
-
9017
- .ProjectSessionItemSelected {
9018
- background: color-mix(in srgb, var(--ColorListInactiveSelectionBackground, #353f4a) 86%, #2c3540 14%);
9019
- }
9020
-
9021
- .ProjectSessionItem:not(.ProjectSessionItemSelected):hover,
9022
- .ProjectSessionItem:not(.ProjectSessionItemSelected):focus-within {
9023
- background: color-mix(in srgb, var(--ColorListHoverBackground, #38414c) 46%, transparent);
9024
- }
9025
-
9026
- .ProjectSessionItemSelected .ProjectSessionItemLabel {
9027
- color: var(--ColorListInactiveSelectionForeground, #f2f6fc);
9028
9023
  }
9029
9024
 
9030
- .Chat.ChatFocus .ProjectAddButton {
9031
- background: color-mix(in srgb, var(--ColorButtonSecondaryBackground, #21252c) 72%, transparent);
9032
- border: 0;
9033
- border-top: 1px solid color-mix(in srgb, var(--ColorBorder, #3a3d41) 70%, transparent);
9034
- color: var(--ColorForeground, #d2d9e2);
9035
- cursor: pointer;
9036
- font-size: 12.5px;
9037
- letter-spacing: 0.01em;
9038
- margin-top: auto;
9039
- min-height: var(--ChatListItemHeight);
9040
- padding: 0 12px;
9041
- text-align: left;
9042
- transition: background-color 80ms ease;
9025
+ .ChatTodoListHeader {
9026
+ border-bottom: 1px solid var(--vscode-editorWidget-border);
9027
+ color: var(--vscode-descriptionForeground);
9028
+ font-size: 12px;
9029
+ line-height: 18px;
9030
+ padding: 6px 10px;
9043
9031
  }
9044
9032
 
9045
- .Chat.ChatFocus .ProjectAddButton:hover,
9046
- .Chat.ChatFocus .ProjectAddButton:focus-visible {
9047
- background: color-mix(in srgb, var(--ColorButtonSecondaryHoverBackground, #2a3039) 78%, transparent);
9048
- }
9049
-
9050
- .ChatList,
9051
- .ChatListEmpty,
9052
- .ChatMessages {
9033
+ .ChatTodoListItems {
9034
+ list-style: none;
9053
9035
  margin: 0;
9054
- min-height: 0;
9055
- padding: 0;
9056
- }
9057
-
9058
- .Chat.ChatFocus .ChatList,
9059
- .Chat.ChatFocus .ChatListEmpty {
9060
- display: none;
9061
- }
9062
-
9063
- .Chat.ChatFocus .ChatMessages {
9064
- grid-column: 2;
9065
- grid-row: 2;
9066
- }
9067
-
9068
- .Chat.ChatFocus .ChatSendArea {
9069
- grid-column: 2;
9070
- grid-row: 3;
9071
- height: var(--ChatSendAreaHeight);
9072
- min-height: var(--ChatSendAreaHeight);
9073
- }
9074
-
9075
- .Chat .MultilineInputBox {
9076
- height: var(--ChatTextAreaHeight);
9077
- min-height: var(--ChatTextAreaHeight);
9078
- padding: var(--ChatTextAreaPaddingTop) var(--ChatTextAreaPaddingRight) var(--ChatTextAreaPaddingBottom) var(--ChatTextAreaPaddingLeft);
9036
+ max-height: 180px;
9037
+ overflow: auto;
9038
+ padding: 4px 0;
9079
9039
  }
9080
9040
 
9081
- .Select {
9082
- -moz-appearance: none;
9083
- -webkit-appearance: none;
9084
- appearance: none;
9085
- background-image:
9086
- linear-gradient(45deg, transparent 50%, color-mix(in srgb, var(--ColorForeground, #d5dbe3) 84%, transparent) 50%),
9087
- linear-gradient(135deg, color-mix(in srgb, var(--ColorForeground, #d5dbe3) 84%, transparent) 50%, transparent 50%);
9088
- background-position:
9089
- calc(100% - 10px) 50%,
9090
- calc(100% - 6px) 50%;
9091
- background-repeat: no-repeat;
9092
- background-size:
9093
- 4px 4px,
9094
- 4px 4px;
9095
- max-width: 60px;
9096
- padding-right: 16px;
9041
+ .ChatTodoListItem {
9042
+ align-items: center;
9043
+ color: var(--vscode-foreground);
9044
+ display: flex;
9045
+ font-size: 12px;
9046
+ line-height: 18px;
9047
+ min-height: 24px;
9048
+ padding: 0 10px;
9097
9049
  }
9098
9050
 
9099
- .MarkdownMathInline {
9051
+ .ChatTodoListItem::before {
9052
+ color: var(--vscode-descriptionForeground);
9053
+ content: "○";
9100
9054
  display: inline-block;
9101
- max-width: 100%;
9102
- vertical-align: middle;
9103
- }
9104
-
9105
- .MarkdownQuote {
9106
- border-left: 3px solid var(--ColorBorder, #3a3d41);
9107
- margin: 8px 0;
9108
- padding-left: 12px;
9055
+ margin-right: 8px;
9056
+ width: 1em;
9109
9057
  }
9110
9058
 
9111
- .MarkdownMathBlock {
9112
- margin: 8px 0;
9113
- overflow-x: auto;
9114
- overflow-y: hidden;
9059
+ .ChatTodoListItemTodo::before {
9060
+ content: "○";
9115
9061
  }
9116
9062
 
9117
- .ChatMessageContent hr,
9118
- .ChatToolCallRenderHtmlBody hr {
9119
- border: 0;
9120
- border-top: 1px solid color-mix(in srgb, var(--ColorBorder, #3a3d41) 78%, transparent);
9121
- display: block;
9122
- height: 0;
9123
- margin: 12px 0;
9124
- width: 100%;
9063
+ .ChatTodoListItem.todo::before {
9064
+ content: "○";
9125
9065
  }
9126
9066
 
9127
- .StrikeThrough {
9128
- text-decoration: line-through;
9067
+ .ChatTodoListItemInProgress::before {
9068
+ color: var(--vscode-textLink-foreground);
9069
+ content: "◐";
9129
9070
  }
9130
9071
 
9131
- /* syntax highlight token colors */
9132
- .TokenComment {
9133
- color: var(--ColorSymbolIconColorForeground, #7f8794);
9072
+ .ChatTodoListItem.inProgress::before {
9073
+ color: var(--vscode-textLink-foreground);
9074
+ content: "◐";
9134
9075
  }
9135
9076
 
9136
- .TokenString {
9137
- color: var(--ColorChartsGreen, #a6d189);
9077
+ .ChatTodoListItemCompleted {
9078
+ color: var(--vscode-disabledForeground);
9138
9079
  }
9139
9080
 
9140
- .TokenNumber,
9141
- .TokenValue {
9142
- color: var(--ColorChartsBlue, #8caaee);
9081
+ .ChatTodoListItem.completed {
9082
+ color: var(--vscode-disabledForeground);
9143
9083
  }
9144
9084
 
9145
- .TokenKeyword,
9146
- .TokenTag {
9147
- color: var(--ColorChartsPurple, #ca9ee6);
9085
+ .ChatTodoListItemCompleted::before {
9086
+ color: var(--vscode-testing-iconPassed);
9087
+ content: "✓";
9148
9088
  }
9149
9089
 
9150
- .TokenAttribute,
9151
- .TokenProperty {
9152
- color: var(--ColorChartsOrange, #ef9f76);
9090
+ .ChatTodoListItem.completed::before {
9091
+ color: var(--vscode-testing-iconPassed);
9092
+ content: "✓";
9153
9093
  }
9154
9094
 
9155
- .ChatToolCallQuestionText {
9156
- margin-bottom: 6px;
9157
- }
9158
-
9159
- .ChatToolCallQuestionOptions {
9160
- display: flex;
9161
- flex-wrap: wrap;
9162
- gap: 6px;
9163
- }
9164
-
9165
- .ChatToolCallQuestionOption {
9166
- background: color-mix(in srgb, var(--ColorBadgeBackground, #2f3640) 70%, transparent);
9167
- border: 1px solid color-mix(in srgb, var(--ColorBorder, #3a3d41) 70%, transparent);
9168
- border-radius: 999px;
9169
- color: var(--ColorForeground, #d5dbe3);
9170
- display: inline-block;
9171
- max-width: 100%;
9172
- overflow: hidden;
9173
- padding: 2px 8px;
9174
- text-overflow: ellipsis;
9175
- white-space: nowrap;
9176
- }
9177
- `;
9178
- if (!renderHtmlCss.trim()) {
9179
- return baseCss;
9180
- }
9181
- return `${baseCss}
9182
-
9183
9095
  /* render_html tool css */
9184
9096
  ${renderHtmlCss}`;
9185
9097
  };
@@ -9245,6 +9157,13 @@ const ChatViewDropOverlayActive = 'ChatViewDropOverlayActive';
9245
9157
  const SendButtonDisabled = 'SendButtonDisabled';
9246
9158
  const ChatSendAreaBottom = 'ChatSendAreaBottom';
9247
9159
  const ChatSendAreaContent = 'ChatSendAreaContent';
9160
+ const ChatTodoList = 'ChatTodoList';
9161
+ const ChatTodoListHeader = 'ChatTodoListHeader';
9162
+ const ChatTodoListItems = 'ChatTodoListItems';
9163
+ const ChatTodoListItem = 'ChatTodoListItem';
9164
+ const ChatTodoListItemTodo = 'ChatTodoListItemTodo';
9165
+ const ChatTodoListItemInProgress = 'ChatTodoListItemInProgress';
9166
+ const ChatTodoListItemCompleted = 'ChatTodoListItemCompleted';
9248
9167
  const Chat = 'Chat';
9249
9168
  const ChatHeader = 'ChatHeader';
9250
9169
  const Button = 'Button';
@@ -9286,6 +9205,7 @@ const ChatMessageContent = 'ChatMessageContent';
9286
9205
  const ChatToolCalls = 'ChatToolCalls';
9287
9206
  const ChatToolCallsLabel = 'ChatToolCallsLabel';
9288
9207
  const ChatToolCallReadFileLink = 'ChatToolCallReadFileLink';
9208
+ const ChatToolCallFileName = 'ChatToolCallFileName';
9289
9209
  const ChatToolCallQuestionOption = 'ChatToolCallQuestionOption';
9290
9210
  const ChatToolCallQuestionOptions = 'ChatToolCallQuestionOptions';
9291
9211
  const ChatToolCallQuestionText = 'ChatToolCallQuestionText';
@@ -9312,6 +9232,7 @@ const TokenTag = 'TokenTag';
9312
9232
  const TokenAttribute = 'TokenAttribute';
9313
9233
  const TokenValue = 'TokenValue';
9314
9234
  const TokenProperty = 'TokenProperty';
9235
+ const SearchFieldContainer = 'SearchFieldContainer';
9315
9236
  const Select = 'Select';
9316
9237
  const StrikeThrough = 'StrikeThrough';
9317
9238
  const Viewlet = 'Viewlet';
@@ -9346,6 +9267,7 @@ const HandleProjectListContextMenu = 33;
9346
9267
  const HandleClickDictationButton = 34;
9347
9268
  const HandleMissingApiKeySubmit = 35;
9348
9269
  const HandleRunModeChange = 36;
9270
+ const HandleSearchInput = 37;
9349
9271
 
9350
9272
  const getModelLabel = model => {
9351
9273
  if (model.provider === 'openRouter') {
@@ -9432,6 +9354,18 @@ const getSendButtonDom = (isSendDisabled, voiceDictationEnabled) => {
9432
9354
  type: Div
9433
9355
  }];
9434
9356
  };
9357
+ const getAddContextButtonDom = () => {
9358
+ return [{
9359
+ childCount: 1,
9360
+ className: IconButton,
9361
+ name: AddContext,
9362
+ title: addContext(),
9363
+ type: Button$1
9364
+ }, {
9365
+ text: addContext(),
9366
+ type: Text
9367
+ }];
9368
+ };
9435
9369
 
9436
9370
  const clampToPercentage = (tokensUsed, tokensMax) => {
9437
9371
  if (tokensMax <= 0) {
@@ -9468,19 +9402,48 @@ const getUsageOverviewDom = (tokensUsed, tokensMax) => {
9468
9402
  }, text(usageLabel)];
9469
9403
  };
9470
9404
 
9471
- const getChatSendAreaDom = (composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, showRunMode, runMode, voiceDictationEnabled = false) => {
9405
+ const getChatSendAreaDom = (composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, addContextButtonEnabled, showRunMode, runMode, todoListToolEnabled, todoListItems, voiceDictationEnabled = false) => {
9472
9406
  const isSendDisabled = composerValue.trim() === '';
9473
- const controlsCount = 2 + (usageOverviewEnabled ? 1 : 0) + (showRunMode ? 1 : 0);
9407
+ const controlsCount = 2 + (usageOverviewEnabled ? 1 : 0) + (showRunMode ? 1 : 0) + (addContextButtonEnabled ? 1 : 0);
9408
+ const hasTodoList = todoListToolEnabled && todoListItems.length > 0;
9409
+ const todoHeaderText = `Todos (${todoListItems.filter(item => item.status === 'completed').length}/${todoListItems.length})`;
9410
+ const getTodoItemClassName = status => {
9411
+ if (status === 'completed') {
9412
+ return `${ChatTodoListItem} ${ChatTodoListItemCompleted} completed`;
9413
+ }
9414
+ if (status === 'inProgress') {
9415
+ return `${ChatTodoListItem} ${ChatTodoListItemInProgress} inProgress`;
9416
+ }
9417
+ return `${ChatTodoListItem} ${ChatTodoListItemTodo} todo`;
9418
+ };
9474
9419
  return [{
9475
9420
  childCount: 1,
9476
9421
  className: ChatSendArea,
9477
9422
  onSubmit: HandleSubmit,
9478
9423
  type: Form
9479
9424
  }, {
9480
- childCount: 2,
9425
+ childCount: hasTodoList ? 3 : 2,
9481
9426
  className: ChatSendAreaContent,
9482
9427
  type: Div
9428
+ }, ...(hasTodoList ? [{
9429
+ childCount: 2,
9430
+ className: ChatTodoList,
9431
+ type: Div
9432
+ }, {
9433
+ childCount: 1,
9434
+ className: ChatTodoListHeader,
9435
+ type: Div
9483
9436
  }, {
9437
+ ...text(todoHeaderText)
9438
+ }, {
9439
+ childCount: todoListItems.length,
9440
+ className: ChatTodoListItems,
9441
+ type: Ul
9442
+ }, ...todoListItems.flatMap(item => [{
9443
+ childCount: 1,
9444
+ className: getTodoItemClassName(item.status),
9445
+ type: Li
9446
+ }, text(item.text)])] : []), {
9484
9447
  childCount: 0,
9485
9448
  className: MultilineInputBox,
9486
9449
  name: Composer,
@@ -9493,7 +9456,7 @@ const getChatSendAreaDom = (composerValue, models, selectedModelId, usageOvervie
9493
9456
  childCount: voiceDictationEnabled ? controlsCount + 1 : controlsCount,
9494
9457
  className: ChatSendAreaBottom,
9495
9458
  type: Div
9496
- }, ...getChatSelectVirtualDom(models, selectedModelId), ...(showRunMode ? getRunModeSelectVirtualDom(runMode) : []), ...(usageOverviewEnabled ? getUsageOverviewDom(tokensUsed, tokensMax) : []), ...getSendButtonDom(isSendDisabled, voiceDictationEnabled)];
9459
+ }, ...getChatSelectVirtualDom(models, selectedModelId), ...(showRunMode ? getRunModeSelectVirtualDom(runMode) : []), ...(usageOverviewEnabled ? getUsageOverviewDom(tokensUsed, tokensMax) : []), ...(addContextButtonEnabled ? getAddContextButtonDom() : []), ...getSendButtonDom(isSendDisabled, voiceDictationEnabled)];
9497
9460
  };
9498
9461
 
9499
9462
  const getImageAltText = alt => {
@@ -9893,41 +9856,38 @@ const getMissingApiKeyDom = ({
9893
9856
  inputName,
9894
9857
  inputPattern,
9895
9858
  inputRequired = false,
9896
- inputValue,
9897
9859
  openSettingsButtonName,
9898
9860
  placeholder,
9899
9861
  saveButtonDisabled = false,
9900
9862
  saveButtonName,
9901
- saveButtonText = save(),
9902
- saveButtonType = 'button',
9903
- useForm = false
9863
+ saveButtonText = save()
9904
9864
  }) => {
9905
9865
  return [{
9906
9866
  childCount: 2,
9907
- method: useForm ? 'GET' : undefined,
9908
- onSubmit: useForm ? HandleMissingApiKeySubmit : undefined,
9909
- type: useForm ? Form : Div
9867
+ method: 'GET',
9868
+ onSubmit: HandleMissingApiKeySubmit,
9869
+ type: Form
9910
9870
  }, {
9911
9871
  childCount: 0,
9912
9872
  className: InputBox,
9913
9873
  name: inputName,
9914
9874
  onInput: HandleInput,
9915
- pattern: inputPattern,
9875
+ ...(inputPattern ? {
9876
+ pattern: inputPattern
9877
+ } : {}),
9916
9878
  placeholder,
9917
9879
  required: inputRequired,
9918
- type: Input,
9919
- value: inputValue
9880
+ type: Input
9920
9881
  }, {
9921
9882
  childCount: 2,
9922
9883
  className: Actions,
9923
9884
  type: Div
9924
9885
  }, {
9925
- buttonType: saveButtonType,
9926
9886
  childCount: 1,
9927
9887
  className: mergeClassNames(Button, ButtonPrimary),
9928
9888
  disabled: saveButtonDisabled,
9889
+ inputType: 'submit',
9929
9890
  name: saveButtonName,
9930
- onClick: useForm ? undefined : HandleClick,
9931
9891
  type: Button$1
9932
9892
  }, text(saveButtonText), {
9933
9893
  childCount: 1,
@@ -9939,34 +9899,28 @@ const getMissingApiKeyDom = ({
9939
9899
  }, text(getApiKeyText)];
9940
9900
  };
9941
9901
 
9942
- const getMissingOpenApiApiKeyDom = openApiApiKeyInput => {
9902
+ const getMissingOpenApiApiKeyDom = () => {
9943
9903
  return getMissingApiKeyDom({
9944
9904
  getApiKeyText: getOpenApiApiKey(),
9945
9905
  inputName: OpenApiApiKeyInput,
9946
9906
  inputPattern: '^sk-.+',
9947
9907
  inputRequired: true,
9948
- inputValue: openApiApiKeyInput,
9949
9908
  openSettingsButtonName: OpenOpenApiApiKeyWebsite,
9950
9909
  placeholder: openApiApiKeyPlaceholder(),
9951
- saveButtonName: SaveOpenApiApiKey,
9952
- saveButtonType: 'submit',
9953
- useForm: true
9910
+ saveButtonName: SaveOpenApiApiKey
9954
9911
  });
9955
9912
  };
9956
9913
 
9957
- const getMissingOpenRouterApiKeyDom = (openRouterApiKeyInput, openRouterApiKeyState = 'idle') => {
9914
+ const getMissingOpenRouterApiKeyDom = (openRouterApiKeyState = 'idle') => {
9958
9915
  const isSaving = openRouterApiKeyState === 'saving';
9959
9916
  return getMissingApiKeyDom({
9960
9917
  getApiKeyText: getOpenRouterApiKey(),
9961
9918
  inputName: OpenRouterApiKeyInput,
9962
- inputValue: openRouterApiKeyInput,
9963
9919
  openSettingsButtonName: OpenOpenRouterApiKeySettings,
9964
9920
  placeholder: openRouterApiKeyPlaceholder(),
9965
9921
  saveButtonDisabled: isSaving,
9966
9922
  saveButtonName: SaveOpenRouterApiKey,
9967
- saveButtonText: isSaving ? saving() : save(),
9968
- saveButtonType: 'submit',
9969
- useForm: true
9923
+ saveButtonText: isSaving ? saving() : save()
9970
9924
  });
9971
9925
  };
9972
9926
 
@@ -10168,6 +10122,10 @@ const getToolCallEditFileVirtualDom = toolCall => {
10168
10122
  title: target.clickableUri,
10169
10123
  ...fileNameClickableProps,
10170
10124
  type: Span
10125
+ }, {
10126
+ childCount: 1,
10127
+ className: ChatToolCallFileName,
10128
+ type: Span
10171
10129
  }, text(fileName)];
10172
10130
  };
10173
10131
 
@@ -10192,6 +10150,10 @@ const getToolCallGetWorkspaceUriVirtualDom = toolCall => {
10192
10150
  'data-uri': toolCall.result,
10193
10151
  onClick: HandleClickReadFile,
10194
10152
  type: Span
10153
+ }, {
10154
+ childCount: 1,
10155
+ className: ChatToolCallFileName,
10156
+ type: Span
10195
10157
  }, text(fileName), ...(statusLabel ? [text(statusLabel)] : [])];
10196
10158
  };
10197
10159
 
@@ -10277,6 +10239,10 @@ const getToolCallReadFileVirtualDom = toolCall => {
10277
10239
  className: ChatToolCallReadFileLink,
10278
10240
  ...fileNameClickableProps,
10279
10241
  type: Span
10242
+ }, {
10243
+ childCount: 1,
10244
+ className: ChatToolCallFileName,
10245
+ type: Span
10280
10246
  }, text(fileName), ...(statusLabel ? [text(statusLabel)] : [])];
10281
10247
  };
10282
10248
 
@@ -10628,6 +10594,7 @@ const getToolCallWriteFileVirtualDom = toolCall => {
10628
10594
  }
10629
10595
  const fileName = getFileNameFromUri(target.title);
10630
10596
  const statusLabel = getToolCallStatusLabel(toolCall);
10597
+ const showDiffStats = toolCall.status !== 'error' && toolCall.status !== 'not-found';
10631
10598
  const {
10632
10599
  linesAdded,
10633
10600
  linesDeleted
@@ -10637,7 +10604,7 @@ const getToolCallWriteFileVirtualDom = toolCall => {
10637
10604
  onClick: HandleClickReadFile
10638
10605
  } : {};
10639
10606
  return [{
10640
- childCount: statusLabel ? 6 : 5,
10607
+ childCount: showDiffStats ? statusLabel ? 6 : 5 : statusLabel ? 4 : 3,
10641
10608
  className: ChatOrderedListItem,
10642
10609
  title: target.title,
10643
10610
  type: Li
@@ -10650,7 +10617,11 @@ const getToolCallWriteFileVirtualDom = toolCall => {
10650
10617
  className: ChatToolCallReadFileLink,
10651
10618
  ...fileNameClickableProps,
10652
10619
  type: Span
10653
- }, text(fileName), {
10620
+ }, {
10621
+ childCount: 1,
10622
+ className: ChatToolCallFileName,
10623
+ type: Span
10624
+ }, text(fileName), ...(showDiffStats ? [{
10654
10625
  childCount: 1,
10655
10626
  className: Insertion,
10656
10627
  type: Span
@@ -10658,7 +10629,7 @@ const getToolCallWriteFileVirtualDom = toolCall => {
10658
10629
  childCount: 1,
10659
10630
  className: Deletion,
10660
10631
  type: Span
10661
- }, text(` -${linesDeleted}`), ...(statusLabel ? [text(statusLabel)] : [])];
10632
+ }, text(` -${linesDeleted}`)] : []), ...(statusLabel ? [text(statusLabel)] : [])];
10662
10633
  };
10663
10634
 
10664
10635
  const getToolCallDom = toolCall => {
@@ -10725,7 +10696,7 @@ const getToolCallsDom = message => {
10725
10696
  }, ...message.toolCalls.flatMap(getToolCallDom)];
10726
10697
  };
10727
10698
 
10728
- const getChatMessageDom = (message, parsedMessageContent, openRouterApiKeyInput, openApiApiKeyInput = '', openRouterApiKeyState = 'idle', useChatMathWorker = false) => {
10699
+ const getChatMessageDom = (message, parsedMessageContent, _openRouterApiKeyInput, _openApiApiKeyInput = '', openRouterApiKeyState = 'idle', useChatMathWorker = false) => {
10729
10700
  const roleClassName = message.role === 'user' ? MessageUser : MessageAssistant;
10730
10701
  const isOpenApiApiKeyMissingMessage = message.role === 'assistant' && message.text === openApiApiKeyRequiredMessage;
10731
10702
  const isOpenRouterApiKeyMissingMessage = message.role === 'assistant' && message.text === openRouterApiKeyRequiredMessage;
@@ -10743,7 +10714,7 @@ const getChatMessageDom = (message, parsedMessageContent, openRouterApiKeyInput,
10743
10714
  childCount: extraChildCount,
10744
10715
  className: ChatMessageContent,
10745
10716
  type: Div
10746
- }, ...toolCallsDom, ...messageDom, ...(isOpenApiApiKeyMissingMessage ? getMissingOpenApiApiKeyDom(openApiApiKeyInput) : []), ...(isOpenRouterApiKeyMissingMessage ? getMissingOpenRouterApiKeyDom(openRouterApiKeyInput, openRouterApiKeyState) : []), ...(isOpenRouterRequestFailedMessage ? getOpenRouterRequestFailedDom() : []), ...(isOpenRouterTooManyRequestsMessage ? getOpenRouterTooManyRequestsDom() : [])];
10717
+ }, ...toolCallsDom, ...messageDom, ...(isOpenApiApiKeyMissingMessage ? getMissingOpenApiApiKeyDom() : []), ...(isOpenRouterApiKeyMissingMessage ? getMissingOpenRouterApiKeyDom(openRouterApiKeyState) : []), ...(isOpenRouterRequestFailedMessage ? getOpenRouterRequestFailedDom() : []), ...(isOpenRouterTooManyRequestsMessage ? getOpenRouterTooManyRequestsDom() : [])];
10747
10718
  };
10748
10719
 
10749
10720
  const getEmptyMessagesDom = () => {
@@ -10896,6 +10867,7 @@ const getProjectListDom = (projects, sessions, projectExpandedIds, selectedProje
10896
10867
  };
10897
10868
 
10898
10869
  const getChatModeChatFocusVirtualDom = ({
10870
+ addContextButtonEnabled,
10899
10871
  authEnabled = false,
10900
10872
  authErrorMessage = '',
10901
10873
  authStatus = 'signed-out',
@@ -10921,6 +10893,8 @@ const getChatModeChatFocusVirtualDom = ({
10921
10893
  selectedSessionId,
10922
10894
  sessions,
10923
10895
  showRunMode,
10896
+ todoListItems,
10897
+ todoListToolEnabled,
10924
10898
  tokensMax,
10925
10899
  tokensUsed,
10926
10900
  usageOverviewEnabled,
@@ -10936,7 +10910,7 @@ const getChatModeChatFocusVirtualDom = ({
10936
10910
  onDragEnter: HandleDragEnterChatView,
10937
10911
  onDragOver: HandleDragOverChatView,
10938
10912
  type: Div
10939
- }, ...getProjectListDom(projects, sessions, projectExpandedIds, selectedProjectId, selectedSessionId, projectListScrollTop), ...getMessagesDom(messages, parsedMessages, openRouterApiKeyInput, openApiApiKeyInput, openRouterApiKeyState, messagesScrollTop, useChatMathWorker, true), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, showRunMode, runMode, voiceDictationEnabled), ...(isDropOverlayVisible ? [{
10913
+ }, ...getProjectListDom(projects, sessions, projectExpandedIds, selectedProjectId, selectedSessionId, projectListScrollTop), ...getMessagesDom(messages, parsedMessages, openRouterApiKeyInput, openApiApiKeyInput, openRouterApiKeyState, messagesScrollTop, useChatMathWorker, true), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, addContextButtonEnabled, showRunMode, runMode, todoListToolEnabled, todoListItems, voiceDictationEnabled), ...(isDropOverlayVisible ? [{
10940
10914
  childCount: 1,
10941
10915
  className: mergeClassNames(ChatViewDropOverlay, ChatViewDropOverlayActive),
10942
10916
  name: ComposerDropTarget,
@@ -10982,7 +10956,7 @@ const getHeaderActionVirtualDom = item => {
10982
10956
  }];
10983
10957
  };
10984
10958
 
10985
- const getChatHeaderActionsDom = (viewMode, authEnabled = false, authStatus = 'signed-out') => {
10959
+ const getChatHeaderActionsDom = (viewMode, authEnabled = false, authStatus = 'signed-out', searchEnabled = false) => {
10986
10960
  const toggleTitle = viewMode === 'chat-focus' ? normalChatMode() : chatFocusMode();
10987
10961
  const isSigningIn = authStatus === 'signing-in';
10988
10962
  const authAction = authEnabled && authStatus !== 'signed-in' ? {
@@ -11003,7 +10977,12 @@ const getChatHeaderActionsDom = (viewMode, authEnabled = false, authStatus = 'si
11003
10977
  name: ToggleChatFocus,
11004
10978
  onClick: HandleClick,
11005
10979
  title: toggleTitle
11006
- }, {
10980
+ }, ...(searchEnabled ? [{
10981
+ icon: 'MaskIcon MaskIconSearch',
10982
+ name: ToggleSearch,
10983
+ onClick: HandleClick,
10984
+ title: search()
10985
+ }] : []), {
11007
10986
  icon: 'MaskIcon MaskIconDebugPause',
11008
10987
  name: SessionDebug,
11009
10988
  onClick: HandleClickSessionDebug,
@@ -11053,6 +11032,7 @@ const getChatHeaderDomDetailMode = (selectedSessionTitle, authEnabled = false, a
11053
11032
  };
11054
11033
 
11055
11034
  const getChatModeDetailVirtualDom = ({
11035
+ addContextButtonEnabled,
11056
11036
  authEnabled = false,
11057
11037
  authErrorMessage = '',
11058
11038
  authStatus = 'signed-out',
@@ -11074,6 +11054,8 @@ const getChatModeDetailVirtualDom = ({
11074
11054
  selectedSessionId,
11075
11055
  sessions,
11076
11056
  showRunMode,
11057
+ todoListItems,
11058
+ todoListToolEnabled,
11077
11059
  tokensMax,
11078
11060
  tokensUsed,
11079
11061
  usageOverviewEnabled,
@@ -11090,7 +11072,7 @@ const getChatModeDetailVirtualDom = ({
11090
11072
  onDragEnter: HandleDragEnterChatView,
11091
11073
  onDragOver: HandleDragOverChatView,
11092
11074
  type: Div
11093
- }, ...getChatHeaderDomDetailMode(selectedSessionTitle, authEnabled, authStatus, authErrorMessage), ...getMessagesDom(messages, parsedMessages, openRouterApiKeyInput, openApiApiKeyInput, openRouterApiKeyState, messagesScrollTop, useChatMathWorker), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, showRunMode, runMode, voiceDictationEnabled), ...(isDropOverlayVisible ? [{
11075
+ }, ...getChatHeaderDomDetailMode(selectedSessionTitle, authEnabled, authStatus, authErrorMessage), ...getMessagesDom(messages, parsedMessages, openRouterApiKeyInput, openApiApiKeyInput, openRouterApiKeyState, messagesScrollTop, useChatMathWorker), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, addContextButtonEnabled, showRunMode, runMode, todoListToolEnabled, todoListItems, voiceDictationEnabled), ...(isDropOverlayVisible ? [{
11094
11076
  childCount: 1,
11095
11077
  className: mergeClassNames(ChatViewDropOverlay, ChatViewDropOverlayActive),
11096
11078
  name: ComposerDropTarget,
@@ -11104,17 +11086,32 @@ const getChatModeDetailVirtualDom = ({
11104
11086
  }] : [])];
11105
11087
  };
11106
11088
 
11107
- const getChatHeaderListModeDom = (authEnabled = false, authStatus = 'signed-out', authErrorMessage = '') => {
11089
+ const getChatHeaderListModeDom = (authEnabled = false, authStatus = 'signed-out', authErrorMessage = '', searchEnabled = false, searchFieldVisible = false, searchValue = '') => {
11108
11090
  const hasAuthError = authEnabled && !!authErrorMessage;
11091
+ const hasSearchField = searchEnabled && searchFieldVisible;
11092
+ const headerChildCount = 2 + (hasAuthError ? 1 : 0) + (hasSearchField ? 1 : 0);
11109
11093
  return [{
11110
- childCount: hasAuthError ? 3 : 2,
11094
+ childCount: headerChildCount,
11111
11095
  className: ChatHeader,
11112
11096
  type: Div
11113
11097
  }, {
11114
11098
  childCount: 1,
11115
11099
  className: Label,
11116
11100
  type: Span
11117
- }, text(chats()), ...getChatHeaderActionsDom('list', authEnabled, authStatus), ...(hasAuthError ? [{
11101
+ }, text(chats()), ...getChatHeaderActionsDom('list', authEnabled, authStatus, searchEnabled), ...(hasSearchField ? [{
11102
+ childCount: 1,
11103
+ className: SearchFieldContainer,
11104
+ type: Div
11105
+ }, {
11106
+ childCount: 0,
11107
+ className: InputBox,
11108
+ inputType: 'search',
11109
+ name: Search,
11110
+ onInput: HandleSearchInput,
11111
+ placeholder: searchChats(),
11112
+ type: Input,
11113
+ value: searchValue
11114
+ }] : []), ...(hasAuthError ? [{
11118
11115
  childCount: 1,
11119
11116
  className: ChatAuthError,
11120
11117
  type: Span
@@ -11177,6 +11174,7 @@ const getChatListDom = (sessions, selectedSessionId, chatListScrollTop = 0) => {
11177
11174
  };
11178
11175
 
11179
11176
  const getChatModeListVirtualDom = ({
11177
+ addContextButtonEnabled,
11180
11178
  authEnabled = false,
11181
11179
  authErrorMessage = '',
11182
11180
  authStatus = 'signed-out',
@@ -11190,23 +11188,30 @@ const getChatModeListVirtualDom = ({
11190
11188
  composerValue,
11191
11189
  models,
11192
11190
  runMode,
11191
+ searchEnabled = false,
11192
+ searchFieldVisible = false,
11193
+ searchValue = '',
11193
11194
  selectedModelId,
11194
11195
  selectedSessionId,
11195
11196
  sessions,
11196
11197
  showRunMode,
11198
+ todoListItems,
11199
+ todoListToolEnabled,
11197
11200
  tokensMax,
11198
11201
  tokensUsed,
11199
11202
  usageOverviewEnabled,
11200
11203
  voiceDictationEnabled = false
11201
11204
  }) => {
11202
11205
  const isDropOverlayVisible = composerDropEnabled && composerDropActive;
11206
+ const searchValueTrimmed = searchValue.trim().toLowerCase();
11207
+ const visibleSessions = searchEnabled && searchValueTrimmed ? sessions.filter(session => session.title.toLowerCase().includes(searchValueTrimmed)) : sessions;
11203
11208
  return [{
11204
11209
  childCount: isDropOverlayVisible ? 4 : 3,
11205
11210
  className: mergeClassNames(Viewlet, Chat),
11206
11211
  onDragEnter: HandleDragEnterChatView,
11207
11212
  onDragOver: HandleDragOverChatView,
11208
11213
  type: Div
11209
- }, ...getChatHeaderListModeDom(authEnabled, authStatus, authErrorMessage), ...getChatListDom(sessions, selectedSessionId, chatListScrollTop), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, showRunMode, runMode, voiceDictationEnabled), ...(isDropOverlayVisible ? [{
11214
+ }, ...getChatHeaderListModeDom(authEnabled, authStatus, authErrorMessage, searchEnabled, searchFieldVisible, searchValue), ...getChatListDom(visibleSessions, selectedSessionId, chatListScrollTop), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, addContextButtonEnabled, showRunMode, runMode, todoListToolEnabled, todoListItems, voiceDictationEnabled), ...(isDropOverlayVisible ? [{
11210
11215
  childCount: 1,
11211
11216
  className: mergeClassNames(ChatViewDropOverlay, ChatViewDropOverlayActive),
11212
11217
  name: ComposerDropTarget,
@@ -11227,6 +11232,62 @@ const getChatModeUnsupportedVirtualDom = () => {
11227
11232
  }, text(unknownViewMode())];
11228
11233
  };
11229
11234
 
11235
+ const isTodoStatus = status => {
11236
+ return status === 'todo' || status === 'inProgress' || status === 'completed';
11237
+ };
11238
+ const parseTodoListArguments = rawArguments => {
11239
+ let parsed;
11240
+ try {
11241
+ parsed = JSON.parse(rawArguments);
11242
+ } catch {
11243
+ return [];
11244
+ }
11245
+ if (!parsed || typeof parsed !== 'object') {
11246
+ return [];
11247
+ }
11248
+ const rawTodos = Reflect.get(parsed, 'todos');
11249
+ if (!Array.isArray(rawTodos)) {
11250
+ return [];
11251
+ }
11252
+ const todos = [];
11253
+ for (const rawTodo of rawTodos) {
11254
+ if (!rawTodo || typeof rawTodo !== 'object') {
11255
+ continue;
11256
+ }
11257
+ const text = Reflect.get(rawTodo, 'text');
11258
+ const status = Reflect.get(rawTodo, 'status');
11259
+ if (typeof text !== 'string' || !isTodoStatus(status)) {
11260
+ continue;
11261
+ }
11262
+ todos.push({
11263
+ status,
11264
+ text
11265
+ });
11266
+ }
11267
+ return todos;
11268
+ };
11269
+
11270
+ const getTodoListItems = (sessions, selectedSessionId) => {
11271
+ const selectedSession = sessions.find(session => session.id === selectedSessionId);
11272
+ if (!selectedSession) {
11273
+ return [];
11274
+ }
11275
+ let todoItems = [];
11276
+ for (const message of selectedSession.messages) {
11277
+ if (message.role !== 'assistant' || !message.toolCalls) {
11278
+ continue;
11279
+ }
11280
+ for (const toolCall of message.toolCalls) {
11281
+ if (toolCall.name !== 'todo_list') {
11282
+ continue;
11283
+ }
11284
+ const parsedTodos = parseTodoListArguments(toolCall.arguments);
11285
+ todoItems = parsedTodos;
11286
+ }
11287
+ }
11288
+ return todoItems;
11289
+ };
11290
+
11230
11291
  const getFallbackParsedMessages = sessions => {
11231
11292
  const parsedMessages = [];
11232
11293
  for (const session of sessions) {
@@ -11245,6 +11306,7 @@ const getFallbackParsedMessages = sessions => {
11245
11306
  };
11246
11307
  const getChatVirtualDom = options => {
11247
11308
  const {
11309
+ addContextButtonEnabled,
11248
11310
  authEnabled = false,
11249
11311
  authErrorMessage = '',
11250
11312
  authStatus = 'signed-out',
@@ -11266,11 +11328,15 @@ const getChatVirtualDom = options => {
11266
11328
  projectListScrollTop = 0,
11267
11329
  projects = [],
11268
11330
  runMode,
11331
+ searchEnabled = false,
11332
+ searchFieldVisible = false,
11333
+ searchValue = '',
11269
11334
  selectedModelId,
11270
11335
  selectedProjectId = '',
11271
11336
  selectedSessionId,
11272
11337
  sessions,
11273
11338
  showRunMode,
11339
+ todoListToolEnabled,
11274
11340
  tokensMax,
11275
11341
  tokensUsed,
11276
11342
  usageOverviewEnabled,
@@ -11279,9 +11345,11 @@ const getChatVirtualDom = options => {
11279
11345
  voiceDictationEnabled = false
11280
11346
  } = options;
11281
11347
  const parsedMessages = parsedMessagesInput ?? getFallbackParsedMessages(sessions);
11348
+ const todoListItems = getTodoListItems(sessions, selectedSessionId);
11282
11349
  switch (viewMode) {
11283
11350
  case 'chat-focus':
11284
11351
  return getChatModeChatFocusVirtualDom({
11352
+ addContextButtonEnabled,
11285
11353
  authEnabled,
11286
11354
  authErrorMessage,
11287
11355
  authStatus,
@@ -11307,6 +11375,8 @@ const getChatVirtualDom = options => {
11307
11375
  selectedSessionId,
11308
11376
  sessions,
11309
11377
  showRunMode,
11378
+ todoListItems,
11379
+ todoListToolEnabled,
11310
11380
  tokensMax,
11311
11381
  tokensUsed,
11312
11382
  usageOverviewEnabled,
@@ -11315,6 +11385,7 @@ const getChatVirtualDom = options => {
11315
11385
  });
11316
11386
  case 'detail':
11317
11387
  return getChatModeDetailVirtualDom({
11388
+ addContextButtonEnabled,
11318
11389
  authEnabled,
11319
11390
  authErrorMessage,
11320
11391
  authStatus,
@@ -11336,6 +11407,8 @@ const getChatVirtualDom = options => {
11336
11407
  selectedSessionId,
11337
11408
  sessions,
11338
11409
  showRunMode,
11410
+ todoListItems,
11411
+ todoListToolEnabled,
11339
11412
  tokensMax,
11340
11413
  tokensUsed,
11341
11414
  usageOverviewEnabled,
@@ -11344,6 +11417,7 @@ const getChatVirtualDom = options => {
11344
11417
  });
11345
11418
  case 'list':
11346
11419
  return getChatModeListVirtualDom({
11420
+ addContextButtonEnabled,
11347
11421
  authEnabled,
11348
11422
  authErrorMessage,
11349
11423
  authStatus,
@@ -11357,10 +11431,15 @@ const getChatVirtualDom = options => {
11357
11431
  composerValue,
11358
11432
  models,
11359
11433
  runMode,
11434
+ searchEnabled,
11435
+ searchFieldVisible,
11436
+ searchValue,
11360
11437
  selectedModelId,
11361
11438
  selectedSessionId,
11362
11439
  sessions,
11363
11440
  showRunMode,
11441
+ todoListItems,
11442
+ todoListToolEnabled,
11364
11443
  tokensMax,
11365
11444
  tokensUsed,
11366
11445
  usageOverviewEnabled,
@@ -11373,6 +11452,7 @@ const getChatVirtualDom = options => {
11373
11452
 
11374
11453
  const renderItems = (oldState, newState) => {
11375
11454
  const {
11455
+ addContextButtonEnabled,
11376
11456
  authEnabled,
11377
11457
  authErrorMessage,
11378
11458
  authStatus,
@@ -11395,11 +11475,15 @@ const renderItems = (oldState, newState) => {
11395
11475
  projectListScrollTop,
11396
11476
  projects,
11397
11477
  runMode,
11478
+ searchEnabled,
11479
+ searchFieldVisible,
11480
+ searchValue,
11398
11481
  selectedModelId,
11399
11482
  selectedProjectId,
11400
11483
  selectedSessionId,
11401
11484
  sessions,
11402
11485
  showRunMode,
11486
+ todoListToolEnabled,
11403
11487
  tokensMax,
11404
11488
  tokensUsed,
11405
11489
  uid,
@@ -11412,6 +11496,7 @@ const renderItems = (oldState, newState) => {
11412
11496
  return [SetDom2, uid, []];
11413
11497
  }
11414
11498
  const dom = getChatVirtualDom({
11499
+ addContextButtonEnabled,
11415
11500
  authEnabled,
11416
11501
  authErrorMessage,
11417
11502
  authStatus,
@@ -11433,11 +11518,15 @@ const renderItems = (oldState, newState) => {
11433
11518
  projectListScrollTop,
11434
11519
  projects,
11435
11520
  runMode,
11521
+ searchEnabled,
11522
+ searchFieldVisible,
11523
+ searchValue,
11436
11524
  selectedModelId,
11437
11525
  selectedProjectId,
11438
11526
  selectedSessionId,
11439
11527
  sessions,
11440
11528
  showRunMode,
11529
+ todoListToolEnabled,
11441
11530
  tokensMax,
11442
11531
  tokensUsed,
11443
11532
  usageOverviewEnabled,
@@ -11621,6 +11710,9 @@ const renderEventListeners = () => {
11621
11710
  }, {
11622
11711
  name: HandleInput,
11623
11712
  params: ['handleInput', TargetName, TargetValue]
11713
+ }, {
11714
+ name: HandleSearchInput,
11715
+ params: ['handleSearchValueChange', TargetValue]
11624
11716
  }, {
11625
11717
  name: HandleDragEnter,
11626
11718
  params: ['handleDragEnter', TargetName, 'Array.from(event.dataTransfer?.files || []).length > 0'],
@@ -11676,7 +11768,8 @@ const renderEventListeners = () => {
11676
11768
  params: ['handleKeyDown', Key, ShiftKey]
11677
11769
  }, {
11678
11770
  name: HandleSubmit,
11679
- params: ['handleSubmit']
11771
+ params: ['handleSubmit'],
11772
+ preventDefault: true
11680
11773
  }, {
11681
11774
  name: HandleMissingApiKeySubmit,
11682
11775
  params: ['handleMissingApiKeySubmit', 'event.submitter?.name || ""'],
@@ -11724,6 +11817,8 @@ const saveState = state => {
11724
11817
  projectListScrollTop,
11725
11818
  projects,
11726
11819
  renamingSessionId,
11820
+ searchFieldVisible,
11821
+ searchValue,
11727
11822
  selectedModelId,
11728
11823
  selectedProjectId,
11729
11824
  selectedSessionId,
@@ -11739,6 +11834,8 @@ const saveState = state => {
11739
11834
  projectListScrollTop,
11740
11835
  projects,
11741
11836
  renamingSessionId,
11837
+ searchFieldVisible,
11838
+ searchValue,
11742
11839
  selectedModelId,
11743
11840
  selectedProjectId,
11744
11841
  selectedSessionId,
@@ -11746,6 +11843,13 @@ const saveState = state => {
11746
11843
  };
11747
11844
  };
11748
11845
 
11846
+ const setAddContextButtonEnabled = (state, addContextButtonEnabled) => {
11847
+ return {
11848
+ ...state,
11849
+ addContextButtonEnabled
11850
+ };
11851
+ };
11852
+
11749
11853
  const setAuthEnabled = (state, authEnabled) => {
11750
11854
  return {
11751
11855
  ...state,
@@ -11776,9 +11880,12 @@ const dummySessions = [{
11776
11880
  const setChatList = state => {
11777
11881
  return {
11778
11882
  ...state,
11883
+ searchEnabled: true,
11884
+ searchFieldVisible: false,
11885
+ searchValue: '',
11779
11886
  selectedSessionId: dummySessions[0].id,
11780
11887
  sessions: dummySessions,
11781
- viewMode: 'detail'
11888
+ viewMode: 'list'
11782
11889
  };
11783
11890
  };
11784
11891
 
@@ -11796,6 +11903,15 @@ const setQuestionToolEnabled = (state, questionToolEnabled) => {
11796
11903
  };
11797
11904
  };
11798
11905
 
11906
+ const setSearchEnabled = (state, searchEnabled) => {
11907
+ return {
11908
+ ...state,
11909
+ searchEnabled,
11910
+ searchFieldVisible: searchEnabled ? state.searchFieldVisible : false,
11911
+ searchValue: searchEnabled ? state.searchValue : ''
11912
+ };
11913
+ };
11914
+
11799
11915
  const setShowRunMode = (state, showRunMode) => {
11800
11916
  return {
11801
11917
  ...state,
@@ -11810,6 +11926,13 @@ const setStreamingEnabled = (state, streamingEnabled) => {
11810
11926
  };
11811
11927
  };
11812
11928
 
11929
+ const setTodoListToolEnabled = (state, todoListToolEnabled) => {
11930
+ return {
11931
+ ...state,
11932
+ todoListToolEnabled
11933
+ };
11934
+ };
11935
+
11813
11936
  const setUseChatCoordinatorWorker = async (state, useChatCoordinatorWorker, persist = true) => {
11814
11937
  if (persist) {
11815
11938
  await update({
@@ -11900,6 +12023,7 @@ const commandMap = {
11900
12023
  'Chat.handleProjectListContextMenu': wrapCommand(handleProjectListContextMenu),
11901
12024
  'Chat.handleProjectListScroll': wrapCommand(handleProjectListScroll),
11902
12025
  'Chat.handleRunModeChange': wrapCommand(handleRunModeChange),
12026
+ 'Chat.handleSearchValueChange': wrapCommand(handleSearchValueChange),
11903
12027
  'Chat.handleSubmit': wrapCommand(handleSubmit),
11904
12028
  'Chat.initialize': initialize,
11905
12029
  'Chat.loadContent': wrapCommand(loadContent),
@@ -11920,14 +12044,17 @@ const commandMap = {
11920
12044
  'Chat.reset': wrapCommand(reset),
11921
12045
  'Chat.resize': wrapCommand(resize),
11922
12046
  'Chat.saveState': wrapGetter(saveState),
12047
+ 'Chat.setAddContextButtonEnabled': wrapCommand(setAddContextButtonEnabled),
11923
12048
  'Chat.setAuthEnabled': wrapCommand(setAuthEnabled),
11924
12049
  'Chat.setBackendUrl': wrapCommand(setBackendUrl),
11925
12050
  'Chat.setChatList': wrapCommand(setChatList),
11926
12051
  'Chat.setEmitStreamingFunctionCallEvents': wrapCommand(setEmitStreamingFunctionCallEvents),
11927
12052
  'Chat.setOpenRouterApiKey': wrapCommand(setOpenRouterApiKey),
11928
12053
  'Chat.setQuestionToolEnabled': wrapCommand(setQuestionToolEnabled),
12054
+ 'Chat.setSearchEnabled': wrapCommand(setSearchEnabled),
11929
12055
  'Chat.setShowRunMode': wrapCommand(setShowRunMode),
11930
12056
  'Chat.setStreamingEnabled': wrapCommand(setStreamingEnabled),
12057
+ 'Chat.setTodoListToolEnabled': wrapCommand(setTodoListToolEnabled),
11931
12058
  'Chat.setUseChatCoordinatorWorker': wrapCommand(setUseChatCoordinatorWorker),
11932
12059
  'Chat.setUseChatMathWorker': wrapCommand(setUseChatMathWorker),
11933
12060
  'Chat.setUseChatNetworkWorkerForRequests': wrapCommand(setUseChatNetworkWorkerForRequests),