@lvce-editor/chat-view 6.5.0 → 6.7.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.
@@ -1492,6 +1492,15 @@ const backToChats = () => {
1492
1492
  const settings = () => {
1493
1493
  return i18nString('Settings');
1494
1494
  };
1495
+ const loginToBackend = () => {
1496
+ return i18nString('Login to backend');
1497
+ };
1498
+ const logoutFromBackend = () => {
1499
+ return i18nString('Logout from backend');
1500
+ };
1501
+ const loggingInToBackend = () => {
1502
+ return i18nString('Logging in to backend');
1503
+ };
1495
1504
  const chatFocusMode = () => {
1496
1505
  return i18nString('Switch to chat focus mode');
1497
1506
  };
@@ -1651,6 +1660,12 @@ const createDefaultState = () => {
1651
1660
  return {
1652
1661
  aiSessionTitleGenerationEnabled: false,
1653
1662
  assetDir: '',
1663
+ authAccessToken: '',
1664
+ authEnabled: false,
1665
+ authErrorMessage: '',
1666
+ authRefreshToken: '',
1667
+ authStatus: 'signed-out',
1668
+ backendUrl: '',
1654
1669
  chatListScrollTop: 0,
1655
1670
  chatMessageFontFamily: 'system-ui',
1656
1671
  chatMessageFontSize,
@@ -1719,6 +1734,9 @@ const createDefaultState = () => {
1719
1734
  useChatNetworkWorkerForRequests: false,
1720
1735
  useChatToolWorker: false,
1721
1736
  useMockApi: false,
1737
+ userName: '',
1738
+ userSubscriptionPlan: '',
1739
+ userUsedTokens: 0,
1722
1740
  viewMode: 'list',
1723
1741
  voiceDictationEnabled: false,
1724
1742
  warningCount: 0,
@@ -2522,7 +2540,7 @@ const isEqualProjectExpandedIds = (a, b) => {
2522
2540
  return true;
2523
2541
  };
2524
2542
  const isEqual = (oldState, newState) => {
2525
- return oldState.composerDropActive === newState.composerDropActive && oldState.composerDropEnabled === newState.composerDropEnabled && oldState.composerValue === newState.composerValue && oldState.initial === newState.initial && isEqualProjectExpandedIds(oldState.projectExpandedIds, newState.projectExpandedIds) && oldState.projectListScrollTop === newState.projectListScrollTop && oldState.renamingSessionId === newState.renamingSessionId && oldState.selectedModelId === newState.selectedModelId && oldState.selectedProjectId === newState.selectedProjectId && oldState.selectedSessionId === newState.selectedSessionId && oldState.sessions === newState.sessions && oldState.tokensMax === newState.tokensMax && oldState.tokensUsed === newState.tokensUsed && oldState.usageOverviewEnabled === newState.usageOverviewEnabled && oldState.useChatMathWorker === newState.useChatMathWorker && oldState.viewMode === newState.viewMode && oldState.voiceDictationEnabled === newState.voiceDictationEnabled;
2543
+ 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.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;
2526
2544
  };
2527
2545
 
2528
2546
  const diffScrollTop = (oldState, newState) => {
@@ -2567,6 +2585,20 @@ const diff2 = uid => {
2567
2585
  return result;
2568
2586
  };
2569
2587
 
2588
+ const getAuthState = state => {
2589
+ return {
2590
+ authAccessToken: state.authAccessToken,
2591
+ authEnabled: state.authEnabled,
2592
+ authErrorMessage: state.authErrorMessage,
2593
+ authRefreshToken: state.authRefreshToken,
2594
+ authStatus: state.authStatus,
2595
+ backendUrl: state.backendUrl,
2596
+ userName: state.userName,
2597
+ userSubscriptionPlan: state.userSubscriptionPlan,
2598
+ userUsedTokens: state.userUsedTokens
2599
+ };
2600
+ };
2601
+
2570
2602
  const mergeClassNames = (...classNames) => {
2571
2603
  return classNames.filter(Boolean).join(' ');
2572
2604
  };
@@ -3138,6 +3170,130 @@ const handleClickCreateProject = async state => {
3138
3170
  };
3139
3171
  };
3140
3172
 
3173
+ let nextLoginResponse;
3174
+ const setNextLoginResponse = response => {
3175
+ nextLoginResponse = response;
3176
+ };
3177
+ const hasPendingMockLoginResponse = () => {
3178
+ return !!nextLoginResponse;
3179
+ };
3180
+ const consumeNextLoginResponse = async () => {
3181
+ if (!nextLoginResponse) {
3182
+ return undefined;
3183
+ }
3184
+ const response = nextLoginResponse;
3185
+ nextLoginResponse = undefined;
3186
+ if (response.delay > 0) {
3187
+ await new Promise(resolve => setTimeout(resolve, response.delay));
3188
+ }
3189
+ if (response.type === 'error') {
3190
+ throw new Error(response.message);
3191
+ }
3192
+ return response.response;
3193
+ };
3194
+
3195
+ const get = async key => {
3196
+ return getPreference(key);
3197
+ };
3198
+ const update = async settings => {
3199
+ await invoke$1('Preferences.update', settings);
3200
+ };
3201
+
3202
+ const isLoginResponse = value => {
3203
+ if (!value || typeof value !== 'object') {
3204
+ return false;
3205
+ }
3206
+ return true;
3207
+ };
3208
+ const trimTrailingSlashes = value => {
3209
+ return value.replace(/\/+$/, '');
3210
+ };
3211
+ const handleClickLogin = async state => {
3212
+ if (!state.backendUrl) {
3213
+ return {
3214
+ ...state,
3215
+ authErrorMessage: 'Backend URL is missing.',
3216
+ authStatus: 'signed-out'
3217
+ };
3218
+ }
3219
+ const signingInState = {
3220
+ ...state,
3221
+ authErrorMessage: '',
3222
+ authStatus: 'signing-in'
3223
+ };
3224
+ if (state.uid) {
3225
+ set$1(state.uid, state, signingInState);
3226
+ await invoke$1('Chat.rerender');
3227
+ }
3228
+ let usedMockResponse = false;
3229
+ try {
3230
+ usedMockResponse = hasPendingMockLoginResponse();
3231
+ const response = usedMockResponse ? await consumeNextLoginResponse() : await invoke$1('Auth.login', state.backendUrl);
3232
+ if (!isLoginResponse(response)) {
3233
+ return {
3234
+ ...signingInState,
3235
+ authErrorMessage: 'Backend returned an invalid login response.',
3236
+ authStatus: 'signed-out'
3237
+ };
3238
+ }
3239
+ if (typeof response.error === 'string' && response.error) {
3240
+ return {
3241
+ ...signingInState,
3242
+ authErrorMessage: response.error,
3243
+ authStatus: 'signed-out'
3244
+ };
3245
+ }
3246
+ const accessToken = typeof response.accessToken === 'string' ? response.accessToken : '';
3247
+ const refreshToken = typeof response.refreshToken === 'string' ? response.refreshToken : '';
3248
+ await update({
3249
+ 'secrets.chatBackendAccessToken': accessToken,
3250
+ 'secrets.chatBackendRefreshToken': refreshToken
3251
+ });
3252
+ return {
3253
+ ...signingInState,
3254
+ authAccessToken: accessToken,
3255
+ authErrorMessage: '',
3256
+ authRefreshToken: refreshToken,
3257
+ authStatus: accessToken ? 'signed-in' : 'signed-out',
3258
+ userName: typeof response.userName === 'string' ? response.userName : state.userName,
3259
+ userSubscriptionPlan: typeof response.subscriptionPlan === 'string' ? response.subscriptionPlan : state.userSubscriptionPlan,
3260
+ userUsedTokens: typeof response.usedTokens === 'number' ? response.usedTokens : state.userUsedTokens
3261
+ };
3262
+ } catch (error) {
3263
+ const errorMessage = error instanceof Error && error.message ? error.message : 'Backend authentication failed.';
3264
+ if (!usedMockResponse) {
3265
+ await invoke$1('Main.openUri', `${trimTrailingSlashes(state.backendUrl)}/auth/login`);
3266
+ }
3267
+ return {
3268
+ ...signingInState,
3269
+ authErrorMessage: errorMessage,
3270
+ authStatus: 'signed-out'
3271
+ };
3272
+ }
3273
+ };
3274
+
3275
+ const handleClickLogout = async state => {
3276
+ try {
3277
+ await invoke$1('Auth.logout', state.backendUrl);
3278
+ } catch {
3279
+ // Ignore logout bridge errors and still clear local auth state.
3280
+ }
3281
+ await update({
3282
+ 'secrets.chatBackendAccessToken': '',
3283
+ 'secrets.chatBackendRefreshToken': ''
3284
+ });
3285
+ return {
3286
+ ...state,
3287
+ authAccessToken: '',
3288
+ authErrorMessage: '',
3289
+ authRefreshToken: '',
3290
+ authStatus: 'signed-out',
3291
+ userName: '',
3292
+ userSubscriptionPlan: '',
3293
+ userUsedTokens: 0
3294
+ };
3295
+ };
3296
+
3141
3297
  const handleClickOpenApiApiKeySettings = async state => {
3142
3298
  await invoke$1('Main.openUri', 'app://settings.json');
3143
3299
  return state;
@@ -3166,6 +3322,9 @@ const openRouterRequestFailedMessage = 'OpenRouter request failed. Possible reas
3166
3322
  const openRouterTooManyRequestsMessage = 'OpenRouter rate limit reached (429). Please try again soon. Helpful tips:';
3167
3323
  const openRouterRequestFailureReasons = ['ContentSecurityPolicyViolation: Check DevTools for details.', 'OpenRouter server offline: Check DevTools for details.', 'Check your internet connection.'];
3168
3324
  const openRouterTooManyRequestsReasons = ['Wait a short time and retry your request.', 'Reduce request frequency to avoid rate limits.', 'Use a different model if this one is saturated.'];
3325
+ const backendUrlRequiredMessage = 'Backend URL is not configured. Configure your backend URL and try again.';
3326
+ const backendAccessTokenRequiredMessage = 'You are not logged in. Click Login to continue.';
3327
+ const backendCompletionFailedMessage = 'Backend completion request failed.';
3169
3328
 
3170
3329
  let rpc;
3171
3330
  const set = value => {
@@ -5463,8 +5622,51 @@ const getAll = () => {
5463
5622
 
5464
5623
  /* eslint-disable prefer-destructuring */
5465
5624
 
5625
+ const getBackendCompletionsEndpoint = backendUrl => {
5626
+ const trimmedBackendUrl = backendUrl.replace(/\/+$/, '');
5627
+ return `${trimmedBackendUrl}/v1/chat/completions`;
5628
+ };
5629
+ const getEffectiveBackendModelId = selectedModelId => {
5630
+ const separatorIndex = selectedModelId.indexOf('/');
5631
+ if (separatorIndex === -1) {
5632
+ return selectedModelId;
5633
+ }
5634
+ return selectedModelId.slice(separatorIndex + 1);
5635
+ };
5636
+ const getBackendAssistantText = async (messages, selectedModelId, backendUrl, authAccessToken) => {
5637
+ let response;
5638
+ try {
5639
+ response = await fetch(getBackendCompletionsEndpoint(backendUrl), {
5640
+ body: JSON.stringify({
5641
+ messages: messages.map(message => ({
5642
+ content: message.text,
5643
+ role: message.role
5644
+ })),
5645
+ model: getEffectiveBackendModelId(selectedModelId),
5646
+ stream: false
5647
+ }),
5648
+ headers: {
5649
+ Authorization: `Bearer ${authAccessToken}`,
5650
+ 'Content-Type': 'application/json',
5651
+ ...getClientRequestIdHeader()
5652
+ },
5653
+ method: 'POST'
5654
+ });
5655
+ } catch {
5656
+ return backendCompletionFailedMessage;
5657
+ }
5658
+ if (!response.ok) {
5659
+ return backendCompletionFailedMessage;
5660
+ }
5661
+ const json = await response.json();
5662
+ const content = json.choices?.[0]?.message?.content;
5663
+ return typeof content === 'string' && content ? content : backendCompletionFailedMessage;
5664
+ };
5466
5665
  const getAiResponse = async ({
5467
5666
  assetDir,
5667
+ authAccessToken,
5668
+ authEnabled = false,
5669
+ backendUrl = '',
5468
5670
  messageId,
5469
5671
  messages,
5470
5672
  mockAiResponseDelay = 800,
@@ -5490,7 +5692,7 @@ const getAiResponse = async ({
5490
5692
  userText,
5491
5693
  webSearchEnabled = false
5492
5694
  }) => {
5493
- if (useChatCoordinatorWorker) {
5695
+ if (useChatCoordinatorWorker && !authEnabled) {
5494
5696
  try {
5495
5697
  const result = await getAiResponse$1({
5496
5698
  assetDir,
@@ -5530,9 +5732,18 @@ const getAiResponse = async ({
5530
5732
  }
5531
5733
  }
5532
5734
  let text = '';
5735
+ if (authEnabled) {
5736
+ if (!backendUrl) {
5737
+ text = backendUrlRequiredMessage;
5738
+ } else if (authAccessToken) {
5739
+ text = await getBackendAssistantText(messages, selectedModelId, backendUrl, authAccessToken);
5740
+ } else {
5741
+ text = backendAccessTokenRequiredMessage;
5742
+ }
5743
+ }
5533
5744
  const usesOpenApiModel = isOpenApiModel(selectedModelId, models);
5534
5745
  const usesOpenRouterModel = isOpenRouterModel(selectedModelId, models);
5535
- if (usesOpenApiModel) {
5746
+ if (!text && usesOpenApiModel) {
5536
5747
  if (useMockApi) {
5537
5748
  const openAiInput = messages.map(message => ({
5538
5749
  content: message.text,
@@ -5610,7 +5821,7 @@ const getAiResponse = async ({
5610
5821
  } else {
5611
5822
  text = openApiApiKeyRequiredMessage;
5612
5823
  }
5613
- } else if (usesOpenRouterModel) {
5824
+ } else if (!text && usesOpenRouterModel) {
5614
5825
  const modelId = getOpenRouterModelId(selectedModelId);
5615
5826
  if (useMockApi) {
5616
5827
  const result = await getMockOpenRouterAssistantText(messages, modelId, openRouterApiBaseUrl, openRouterApiKey, mockApiCommandId, assetDir, platform);
@@ -5652,13 +5863,6 @@ const getAiResponse = async ({
5652
5863
  return message;
5653
5864
  };
5654
5865
 
5655
- const get = async key => {
5656
- return getPreference(key);
5657
- };
5658
- const update = async settings => {
5659
- await invoke$1('Preferences.update', settings);
5660
- };
5661
-
5662
5866
  const setOpenApiApiKey = async (state, openApiApiKey, persist = true) => {
5663
5867
  if (persist) {
5664
5868
  await update({
@@ -6824,6 +7028,9 @@ const sanitizeGeneratedTitle = value => {
6824
7028
 
6825
7029
  const getAiSessionTitle = async (state, userText, assistantText) => {
6826
7030
  const {
7031
+ authAccessToken,
7032
+ authEnabled,
7033
+ backendUrl,
6827
7034
  models,
6828
7035
  openApiApiBaseUrl,
6829
7036
  openApiApiKey,
@@ -6837,13 +7044,13 @@ const getAiSessionTitle = async (state, userText, assistantText) => {
6837
7044
  }
6838
7045
  const usesOpenApiModel = isOpenApiModel(selectedModelId, models);
6839
7046
  const usesOpenRouterModel = isOpenRouterModel(selectedModelId, models);
6840
- if (usesOpenApiModel && !openApiApiKey) {
7047
+ if (!authEnabled && usesOpenApiModel && !openApiApiKey) {
6841
7048
  return '';
6842
7049
  }
6843
- if (usesOpenRouterModel && !openRouterApiKey) {
7050
+ if (!authEnabled && usesOpenRouterModel && !openRouterApiKey) {
6844
7051
  return '';
6845
7052
  }
6846
- if (!usesOpenApiModel && !usesOpenRouterModel) {
7053
+ if (!authEnabled && !usesOpenApiModel && !usesOpenRouterModel) {
6847
7054
  return '';
6848
7055
  }
6849
7056
  const titlePrompt = `Create a concise title (max 6 words) for this conversation. Respond only with the title, no punctuation at the end.
@@ -6860,6 +7067,9 @@ Assistant: ${assistantText}`;
6860
7067
  };
6861
7068
  const titleResponse = await getAiResponse({
6862
7069
  assetDir: state.assetDir,
7070
+ authAccessToken,
7071
+ authEnabled,
7072
+ backendUrl,
6863
7073
  messages: [promptMessage],
6864
7074
  mockAiResponseDelay: state.mockAiResponseDelay,
6865
7075
  mockApiCommandId: state.mockApiCommandId,
@@ -7169,6 +7379,9 @@ const handleSubmit = async state => {
7169
7379
  const {
7170
7380
  aiSessionTitleGenerationEnabled,
7171
7381
  assetDir,
7382
+ authAccessToken,
7383
+ authEnabled,
7384
+ backendUrl,
7172
7385
  composerValue,
7173
7386
  emitStreamingFunctionCallEvents,
7174
7387
  mockAiResponseDelay,
@@ -7308,6 +7521,9 @@ const handleSubmit = async state => {
7308
7521
  } : undefined;
7309
7522
  const assistantMessage = await getAiResponse({
7310
7523
  assetDir,
7524
+ authAccessToken,
7525
+ authEnabled,
7526
+ backendUrl,
7311
7527
  messageId: assistantMessageId,
7312
7528
  messages: messagesWithMentionContext,
7313
7529
  mockAiResponseDelay,
@@ -7415,6 +7631,8 @@ const CreateSession = 'create-session';
7415
7631
  const CreateSessionInProjectPrefix = 'create-session-in-project:';
7416
7632
  const SessionDebug = 'session-debug';
7417
7633
  const Settings = 'settings';
7634
+ const Login = 'login';
7635
+ const Logout = 'logout';
7418
7636
  const CloseChat = 'close-chat';
7419
7637
  const SessionDelete = 'SessionDelete';
7420
7638
  const ProjectPrefix = 'project:';
@@ -7620,6 +7838,10 @@ const handleClick = async (state, name, id = '') => {
7620
7838
  return handleClickOpenApiApiKeySettings(state);
7621
7839
  case name === OpenOpenApiApiKeyWebsite:
7622
7840
  return handleClickOpenApiApiKeyWebsite(state);
7841
+ case name === Login:
7842
+ return handleClickLogin(state);
7843
+ case name === Logout:
7844
+ return handleClickLogout(state);
7623
7845
  default:
7624
7846
  return state;
7625
7847
  }
@@ -7649,7 +7871,8 @@ const handleClickDictationButton = async state => {
7649
7871
 
7650
7872
  const handleClickNew = async state => {
7651
7873
  const newState = await createSession(state);
7652
- return focusInput(newState);
7874
+ const clearedState = await clearInput(newState);
7875
+ return focusInput(clearedState);
7653
7876
  };
7654
7877
 
7655
7878
  const handleClickReadFile = async uri => {
@@ -7964,12 +8187,12 @@ const initialize = async () => {
7964
8187
  set$4(rpc);
7965
8188
  };
7966
8189
 
7967
- const isObject = value => {
8190
+ const isObject$1 = value => {
7968
8191
  return typeof value === 'object' && value !== null;
7969
8192
  };
7970
8193
 
7971
8194
  const getSavedChatListScrollTop = savedState => {
7972
- if (!isObject(savedState)) {
8195
+ if (!isObject$1(savedState)) {
7973
8196
  return undefined;
7974
8197
  }
7975
8198
  const {
@@ -7982,7 +8205,7 @@ const getSavedChatListScrollTop = savedState => {
7982
8205
  };
7983
8206
 
7984
8207
  const getSavedMessagesScrollTop = savedState => {
7985
- if (!isObject(savedState)) {
8208
+ if (!isObject$1(savedState)) {
7986
8209
  return undefined;
7987
8210
  }
7988
8211
  const {
@@ -7995,7 +8218,7 @@ const getSavedMessagesScrollTop = savedState => {
7995
8218
  };
7996
8219
 
7997
8220
  const getSavedSelectedModelId = savedState => {
7998
- if (!isObject(savedState)) {
8221
+ if (!isObject$1(savedState)) {
7999
8222
  return undefined;
8000
8223
  }
8001
8224
  const {
@@ -8008,7 +8231,7 @@ const getSavedSelectedModelId = savedState => {
8008
8231
  };
8009
8232
 
8010
8233
  const getSavedSelectedSessionId = savedState => {
8011
- if (!isObject(savedState)) {
8234
+ if (!isObject$1(savedState)) {
8012
8235
  return undefined;
8013
8236
  }
8014
8237
  const {
@@ -8021,7 +8244,7 @@ const getSavedSelectedSessionId = savedState => {
8021
8244
  };
8022
8245
 
8023
8246
  const getSavedSessions = savedState => {
8024
- if (!isObject(savedState)) {
8247
+ if (!isObject$1(savedState)) {
8025
8248
  return undefined;
8026
8249
  }
8027
8250
  const {
@@ -8034,7 +8257,7 @@ const getSavedSessions = savedState => {
8034
8257
  };
8035
8258
 
8036
8259
  const getSavedViewMode = savedState => {
8037
- if (!isObject(savedState)) {
8260
+ if (!isObject$1(savedState)) {
8038
8261
  return undefined;
8039
8262
  }
8040
8263
  const {
@@ -8055,6 +8278,42 @@ const loadAiSessionTitleGenerationEnabled = async () => {
8055
8278
  }
8056
8279
  };
8057
8280
 
8281
+ const loadAuthEnabled = async () => {
8282
+ try {
8283
+ const savedAuthEnabled = await get('chat.authEnabled');
8284
+ return typeof savedAuthEnabled === 'boolean' ? savedAuthEnabled : false;
8285
+ } catch {
8286
+ return false;
8287
+ }
8288
+ };
8289
+
8290
+ const loadBackendAccessToken = async () => {
8291
+ try {
8292
+ const savedAccessToken = await get('secrets.chatBackendAccessToken');
8293
+ return typeof savedAccessToken === 'string' ? savedAccessToken : '';
8294
+ } catch {
8295
+ return '';
8296
+ }
8297
+ };
8298
+
8299
+ const loadBackendRefreshToken = async () => {
8300
+ try {
8301
+ const savedRefreshToken = await get('secrets.chatBackendRefreshToken');
8302
+ return typeof savedRefreshToken === 'string' ? savedRefreshToken : '';
8303
+ } catch {
8304
+ return '';
8305
+ }
8306
+ };
8307
+
8308
+ const loadBackendUrl = async () => {
8309
+ try {
8310
+ const savedBackendUrl = await get('chat.backendUrl');
8311
+ return typeof savedBackendUrl === 'string' ? savedBackendUrl : '';
8312
+ } catch {
8313
+ return '';
8314
+ }
8315
+ };
8316
+
8058
8317
  const loadComposerDropEnabled = async () => {
8059
8318
  try {
8060
8319
  const savedComposerDropEnabled = await get('chatView.composerDropEnabled');
@@ -8163,9 +8422,13 @@ const loadVoiceDictationEnabled = async () => {
8163
8422
  };
8164
8423
 
8165
8424
  const loadPreferences = async () => {
8166
- const [aiSessionTitleGenerationEnabled, composerDropEnabled, openApiApiKey, openRouterApiKey, emitStreamingFunctionCallEvents, streamingEnabled, passIncludeObfuscation, useChatCoordinatorWorker, useChatMathWorker, useChatNetworkWorkerForRequests, useChatToolWorker, voiceDictationEnabled] = await Promise.all([loadAiSessionTitleGenerationEnabled(), loadComposerDropEnabled(), loadOpenApiApiKey(), loadOpenRouterApiKey(), loadEmitStreamingFunctionCallEvents(), loadStreamingEnabled(), loadPassIncludeObfuscation(), loadUseChatCoordinatorWorker(), loadUseChatMathWorker(), loadUseChatNetworkWorkerForRequests(), loadUseChatToolWorker(), loadVoiceDictationEnabled()]);
8425
+ 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()]);
8167
8426
  return {
8168
8427
  aiSessionTitleGenerationEnabled,
8428
+ authAccessToken,
8429
+ authEnabled,
8430
+ authRefreshToken,
8431
+ backendUrl,
8169
8432
  composerDropEnabled,
8170
8433
  emitStreamingFunctionCallEvents,
8171
8434
  openApiApiKey,
@@ -8211,7 +8474,7 @@ const toSummarySession = session => {
8211
8474
  };
8212
8475
  };
8213
8476
  const getSavedSelectedProjectId = savedState => {
8214
- if (!isObject(savedState)) {
8477
+ if (!isObject$1(savedState)) {
8215
8478
  return undefined;
8216
8479
  }
8217
8480
  const {
@@ -8223,7 +8486,7 @@ const getSavedSelectedProjectId = savedState => {
8223
8486
  return selectedProjectId;
8224
8487
  };
8225
8488
  const getSavedProjects = savedState => {
8226
- if (!isObject(savedState)) {
8489
+ if (!isObject$1(savedState)) {
8227
8490
  return undefined;
8228
8491
  }
8229
8492
  const {
@@ -8233,7 +8496,7 @@ const getSavedProjects = savedState => {
8233
8496
  return undefined;
8234
8497
  }
8235
8498
  const validProjects = projects.filter(project => {
8236
- if (!isObject(project)) {
8499
+ if (!isObject$1(project)) {
8237
8500
  return false;
8238
8501
  }
8239
8502
  return typeof project.id === 'string' && typeof project.name === 'string' && typeof project.uri === 'string';
@@ -8250,7 +8513,7 @@ const ensureBlankProject = (projects, fallbackBlankProject) => {
8250
8513
  return [fallbackBlankProject, ...projects];
8251
8514
  };
8252
8515
  const getSavedProjectListScrollTop = savedState => {
8253
- if (!isObject(savedState)) {
8516
+ if (!isObject$1(savedState)) {
8254
8517
  return undefined;
8255
8518
  }
8256
8519
  const {
@@ -8262,7 +8525,7 @@ const getSavedProjectListScrollTop = savedState => {
8262
8525
  return projectListScrollTop;
8263
8526
  };
8264
8527
  const getSavedProjectExpandedIds = savedState => {
8265
- if (!isObject(savedState)) {
8528
+ if (!isObject$1(savedState)) {
8266
8529
  return undefined;
8267
8530
  }
8268
8531
  const {
@@ -8278,7 +8541,7 @@ const getSavedProjectExpandedIds = savedState => {
8278
8541
  return ids;
8279
8542
  };
8280
8543
  const getSavedLastNormalViewMode = savedState => {
8281
- if (!isObject(savedState)) {
8544
+ if (!isObject$1(savedState)) {
8282
8545
  return undefined;
8283
8546
  }
8284
8547
  const {
@@ -8290,7 +8553,7 @@ const getSavedLastNormalViewMode = savedState => {
8290
8553
  return lastNormalViewMode;
8291
8554
  };
8292
8555
  const getSavedComposerValue = savedState => {
8293
- if (!isObject(savedState)) {
8556
+ if (!isObject$1(savedState)) {
8294
8557
  return undefined;
8295
8558
  }
8296
8559
  const {
@@ -8307,6 +8570,10 @@ const loadContent = async (state, savedState) => {
8307
8570
  const savedComposerValue = getSavedComposerValue(savedState);
8308
8571
  const {
8309
8572
  aiSessionTitleGenerationEnabled,
8573
+ authAccessToken,
8574
+ authEnabled,
8575
+ authRefreshToken,
8576
+ backendUrl,
8310
8577
  composerDropEnabled,
8311
8578
  emitStreamingFunctionCallEvents,
8312
8579
  openApiApiKey,
@@ -8368,6 +8635,11 @@ const loadContent = async (state, savedState) => {
8368
8635
  return {
8369
8636
  ...state,
8370
8637
  aiSessionTitleGenerationEnabled,
8638
+ authAccessToken,
8639
+ authEnabled,
8640
+ authRefreshToken,
8641
+ authStatus: authAccessToken ? 'signed-in' : 'signed-out',
8642
+ backendUrl,
8371
8643
  chatListScrollTop,
8372
8644
  composerDropActive: false,
8373
8645
  composerDropEnabled,
@@ -8399,6 +8671,36 @@ const loadContent = async (state, savedState) => {
8399
8671
  };
8400
8672
  };
8401
8673
 
8674
+ const isObject = value => {
8675
+ return !!value && typeof value === 'object';
8676
+ };
8677
+ const getDelay = payload => {
8678
+ if (!isObject(payload)) {
8679
+ return 0;
8680
+ }
8681
+ const {
8682
+ delay
8683
+ } = payload;
8684
+ return typeof delay === 'number' && delay > 0 ? delay : 0;
8685
+ };
8686
+ const mockBackendAuthResponse = (state, payload) => {
8687
+ const delay = getDelay(payload);
8688
+ if (payload.type === 'error') {
8689
+ setNextLoginResponse({
8690
+ delay,
8691
+ message: payload.message || 'Backend authentication failed.',
8692
+ type: 'error'
8693
+ });
8694
+ return state;
8695
+ }
8696
+ setNextLoginResponse({
8697
+ delay,
8698
+ response: payload,
8699
+ type: 'success'
8700
+ });
8701
+ return state;
8702
+ };
8703
+
8402
8704
  const mockOpenApiRequestGetAll = _state => {
8403
8705
  return getAll();
8404
8706
  };
@@ -8799,6 +9101,7 @@ const renderFocusContext = (oldState, newState) => {
8799
9101
  const Actions = 'Actions';
8800
9102
  const ChatActions = 'ChatActions';
8801
9103
  const ChatName = 'ChatName';
9104
+ const ChatAuthError = 'ChatAuthError';
8802
9105
  const ChatSendArea = 'ChatSendArea';
8803
9106
  const ChatViewDropOverlay = 'ChatViewDropOverlay';
8804
9107
  const ChatViewDropOverlayActive = 'ChatViewDropOverlayActive';
@@ -8813,6 +9116,7 @@ const ButtonSecondary = 'ButtonSecondary';
8813
9116
  const Empty = '';
8814
9117
  const FileIcon = 'FileIcon';
8815
9118
  const IconButton = 'IconButton';
9119
+ const IconButtonDisabled = 'IconButtonDisabled';
8816
9120
  const ImageElement = 'ImageElement';
8817
9121
  const InputBox = 'InputBox';
8818
9122
  const Label = 'Label';
@@ -10185,7 +10489,7 @@ const getProjectListDom = (projects, sessions, projectExpandedIds, selectedProje
10185
10489
  }, text('+ Add Project')];
10186
10490
  };
10187
10491
 
10188
- const getChatModeChatFocusVirtualDom = (sessions, selectedSessionId, composerValue, openRouterApiKeyInput, openApiApiKeyInput, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openRouterApiKeyState = 'idle', composerHeight = 28, composerFontSize = 13, composerFontFamily = 'system-ui', composerLineHeight = 20, messagesScrollTop = 0, composerDropActive = false, composerDropEnabled = true, projects = [], projectExpandedIds = [], selectedProjectId = '', projectListScrollTop = 0, voiceDictationEnabled = false, useChatMathWorker = false, parsedMessages = []) => {
10492
+ const getChatModeChatFocusVirtualDom = (sessions, selectedSessionId, composerValue, openRouterApiKeyInput, openApiApiKeyInput, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openRouterApiKeyState = 'idle', composerHeight = 28, composerFontSize = 13, composerFontFamily = 'system-ui', composerLineHeight = 20, messagesScrollTop = 0, composerDropActive = false, composerDropEnabled = true, projects = [], projectExpandedIds = [], selectedProjectId = '', projectListScrollTop = 0, voiceDictationEnabled = false, useChatMathWorker = false, parsedMessages = [], authEnabled = false, authStatus = 'signed-out', authErrorMessage = '') => {
10189
10493
  const selectedSession = sessions.find(session => session.id === selectedSessionId);
10190
10494
  const messages = selectedSession ? selectedSession.messages : [];
10191
10495
  const isDropOverlayVisible = composerDropEnabled && composerDropActive;
@@ -10228,7 +10532,8 @@ const getBackButtonVirtualDom = () => {
10228
10532
  const getHeaderActionVirtualDom = item => {
10229
10533
  return [{
10230
10534
  childCount: 1,
10231
- className: IconButton,
10535
+ className: mergeClassNames(IconButton, item.disabled ? IconButtonDisabled : ''),
10536
+ disabled: item.disabled,
10232
10537
  name: item.name,
10233
10538
  onClick: item.onClick,
10234
10539
  title: item.title,
@@ -10240,8 +10545,22 @@ const getHeaderActionVirtualDom = item => {
10240
10545
  }];
10241
10546
  };
10242
10547
 
10243
- const getChatHeaderActionsDom = viewMode => {
10548
+ const getChatHeaderActionsDom = (viewMode, authEnabled = false, authStatus = 'signed-out') => {
10244
10549
  const toggleTitle = viewMode === 'chat-focus' ? normalChatMode() : chatFocusMode();
10550
+ const isSigningIn = authStatus === 'signing-in';
10551
+ const authAction = authEnabled && authStatus !== 'signed-in' ? {
10552
+ disabled: isSigningIn,
10553
+ icon: 'MaskIcon MaskIconAccount',
10554
+ name: Login,
10555
+ onClick: HandleClick,
10556
+ title: isSigningIn ? loggingInToBackend() : loginToBackend()
10557
+ } : authEnabled ? {
10558
+ disabled: false,
10559
+ icon: 'MaskIcon MaskIconSignOut',
10560
+ name: Logout,
10561
+ onClick: HandleClick,
10562
+ title: logoutFromBackend()
10563
+ } : undefined;
10245
10564
  const items = [{
10246
10565
  icon: 'MaskIcon MaskIconLayoutPanelLeft',
10247
10566
  name: ToggleChatFocus,
@@ -10262,7 +10581,7 @@ const getChatHeaderActionsDom = viewMode => {
10262
10581
  name: Settings,
10263
10582
  onClick: HandleClickSettings,
10264
10583
  title: settings()
10265
- }, {
10584
+ }, ...(authAction ? [authAction] : []), {
10266
10585
  icon: 'MaskIcon MaskIconClose',
10267
10586
  name: CloseChat,
10268
10587
  onClick: HandleClickClose,
@@ -10275,9 +10594,10 @@ const getChatHeaderActionsDom = viewMode => {
10275
10594
  }, ...items.flatMap(getHeaderActionVirtualDom)];
10276
10595
  };
10277
10596
 
10278
- const getChatHeaderDomDetailMode = selectedSessionTitle => {
10597
+ const getChatHeaderDomDetailMode = (selectedSessionTitle, authEnabled = false, authStatus = 'signed-out', authErrorMessage = '') => {
10598
+ const hasAuthError = authEnabled && !!authErrorMessage;
10279
10599
  return [{
10280
- childCount: 2,
10600
+ childCount: hasAuthError ? 3 : 2,
10281
10601
  className: ChatHeader,
10282
10602
  type: Div
10283
10603
  }, {
@@ -10288,10 +10608,14 @@ const getChatHeaderDomDetailMode = selectedSessionTitle => {
10288
10608
  childCount: 1,
10289
10609
  className: Label,
10290
10610
  type: Span
10291
- }, text(selectedSessionTitle), ...getChatHeaderActionsDom('detail')];
10611
+ }, text(selectedSessionTitle), ...getChatHeaderActionsDom('detail', authEnabled, authStatus), ...(hasAuthError ? [{
10612
+ childCount: 1,
10613
+ className: ChatAuthError,
10614
+ type: Span
10615
+ }, text(authErrorMessage)] : [])];
10292
10616
  };
10293
10617
 
10294
- const getChatModeDetailVirtualDom = (sessions, selectedSessionId, composerValue, openRouterApiKeyInput, openApiApiKeyInput, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openRouterApiKeyState = 'idle', composerHeight = 28, composerFontSize = 13, composerFontFamily = 'system-ui', composerLineHeight = 20, messagesScrollTop = 0, composerDropActive = false, composerDropEnabled = true, voiceDictationEnabled = false, useChatMathWorker = false, parsedMessages = []) => {
10618
+ const getChatModeDetailVirtualDom = (sessions, selectedSessionId, composerValue, openRouterApiKeyInput, openApiApiKeyInput, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openRouterApiKeyState = 'idle', composerHeight = 28, composerFontSize = 13, composerFontFamily = 'system-ui', composerLineHeight = 20, messagesScrollTop = 0, composerDropActive = false, composerDropEnabled = true, voiceDictationEnabled = false, useChatMathWorker = false, parsedMessages = [], authEnabled = false, authStatus = 'signed-out', authErrorMessage = '') => {
10295
10619
  const selectedSession = sessions.find(session => session.id === selectedSessionId);
10296
10620
  const selectedSessionTitle = selectedSession?.title || chatTitle();
10297
10621
  const messages = selectedSession ? selectedSession.messages : [];
@@ -10302,7 +10626,7 @@ const getChatModeDetailVirtualDom = (sessions, selectedSessionId, composerValue,
10302
10626
  onDragEnter: HandleDragEnterChatView,
10303
10627
  onDragOver: HandleDragOverChatView,
10304
10628
  type: Div
10305
- }, ...getChatHeaderDomDetailMode(selectedSessionTitle), ...getMessagesDom(messages, parsedMessages, openRouterApiKeyInput, openApiApiKeyInput, openRouterApiKeyState, messagesScrollTop, useChatMathWorker), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, voiceDictationEnabled), ...(isDropOverlayVisible ? [{
10629
+ }, ...getChatHeaderDomDetailMode(selectedSessionTitle, authEnabled, authStatus, authErrorMessage), ...getMessagesDom(messages, parsedMessages, openRouterApiKeyInput, openApiApiKeyInput, openRouterApiKeyState, messagesScrollTop, useChatMathWorker), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, voiceDictationEnabled), ...(isDropOverlayVisible ? [{
10306
10630
  childCount: 1,
10307
10631
  className: mergeClassNames(ChatViewDropOverlay, ChatViewDropOverlayActive),
10308
10632
  name: ComposerDropTarget,
@@ -10316,16 +10640,21 @@ const getChatModeDetailVirtualDom = (sessions, selectedSessionId, composerValue,
10316
10640
  }] : [])];
10317
10641
  };
10318
10642
 
10319
- const getChatHeaderListModeDom = () => {
10643
+ const getChatHeaderListModeDom = (authEnabled = false, authStatus = 'signed-out', authErrorMessage = '') => {
10644
+ const hasAuthError = authEnabled && !!authErrorMessage;
10320
10645
  return [{
10321
- childCount: 2,
10646
+ childCount: hasAuthError ? 3 : 2,
10322
10647
  className: ChatHeader,
10323
10648
  type: Div
10324
10649
  }, {
10325
10650
  childCount: 1,
10326
10651
  className: Label,
10327
10652
  type: Span
10328
- }, text(chats()), ...getChatHeaderActionsDom('list')];
10653
+ }, text(chats()), ...getChatHeaderActionsDom('list', authEnabled, authStatus), ...(hasAuthError ? [{
10654
+ childCount: 1,
10655
+ className: ChatAuthError,
10656
+ type: Span
10657
+ }, text(authErrorMessage)] : [])];
10329
10658
  };
10330
10659
 
10331
10660
  const getEmptyChatSessionsDom = () => {
@@ -10383,7 +10712,7 @@ const getChatListDom = (sessions, selectedSessionId, chatListScrollTop = 0) => {
10383
10712
  }, ...sessions.flatMap(getSessionDom)];
10384
10713
  };
10385
10714
 
10386
- const getChatModeListVirtualDom = (sessions, selectedSessionId, composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight = 28, composerFontSize = 13, composerFontFamily = 'system-ui', composerLineHeight = 20, chatListScrollTop = 0, composerDropActive = false, composerDropEnabled = true, voiceDictationEnabled = false) => {
10715
+ const getChatModeListVirtualDom = (sessions, selectedSessionId, composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight = 28, composerFontSize = 13, composerFontFamily = 'system-ui', composerLineHeight = 20, chatListScrollTop = 0, composerDropActive = false, composerDropEnabled = true, voiceDictationEnabled = false, authEnabled = false, authStatus = 'signed-out', authErrorMessage = '') => {
10387
10716
  const isDropOverlayVisible = composerDropEnabled && composerDropActive;
10388
10717
  return [{
10389
10718
  childCount: isDropOverlayVisible ? 4 : 3,
@@ -10391,7 +10720,7 @@ const getChatModeListVirtualDom = (sessions, selectedSessionId, composerValue, m
10391
10720
  onDragEnter: HandleDragEnterChatView,
10392
10721
  onDragOver: HandleDragOverChatView,
10393
10722
  type: Div
10394
- }, ...getChatHeaderListModeDom(), ...getChatListDom(sessions, selectedSessionId, chatListScrollTop), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, voiceDictationEnabled), ...(isDropOverlayVisible ? [{
10723
+ }, ...getChatHeaderListModeDom(authEnabled, authStatus, authErrorMessage), ...getChatListDom(sessions, selectedSessionId, chatListScrollTop), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, voiceDictationEnabled), ...(isDropOverlayVisible ? [{
10395
10724
  childCount: 1,
10396
10725
  className: mergeClassNames(ChatViewDropOverlay, ChatViewDropOverlayActive),
10397
10726
  name: ComposerDropTarget,
@@ -10428,15 +10757,15 @@ const getFallbackParsedMessages = sessions => {
10428
10757
  }
10429
10758
  return parsedMessages;
10430
10759
  };
10431
- const getChatVirtualDom = (sessions, selectedSessionId, composerValue, openRouterApiKeyInput, viewMode, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openApiApiKeyInput, openRouterApiKeyState, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, chatListScrollTop, messagesScrollTop, composerDropActive = false, composerDropEnabled = true, projects = [], projectExpandedIds = [], selectedProjectId = '', projectListScrollTop = 0, voiceDictationEnabled = false, useChatMathWorker = false, parsedMessages) => {
10760
+ const getChatVirtualDom = (sessions, selectedSessionId, composerValue, openRouterApiKeyInput, viewMode, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openApiApiKeyInput, openRouterApiKeyState, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, chatListScrollTop, messagesScrollTop, composerDropActive = false, composerDropEnabled = true, projects = [], projectExpandedIds = [], selectedProjectId = '', projectListScrollTop = 0, voiceDictationEnabled = false, useChatMathWorker = false, parsedMessages, authEnabled = false, authStatus = 'signed-out', authErrorMessage = '') => {
10432
10761
  const effectiveParsedMessages = parsedMessages || getFallbackParsedMessages(sessions);
10433
10762
  switch (viewMode) {
10434
10763
  case 'chat-focus':
10435
- return getChatModeChatFocusVirtualDom(sessions, selectedSessionId, composerValue, openRouterApiKeyInput, openApiApiKeyInput, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openRouterApiKeyState, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, messagesScrollTop, composerDropActive, composerDropEnabled, projects, projectExpandedIds, selectedProjectId, projectListScrollTop, voiceDictationEnabled, useChatMathWorker, effectiveParsedMessages);
10764
+ return getChatModeChatFocusVirtualDom(sessions, selectedSessionId, composerValue, openRouterApiKeyInput, openApiApiKeyInput, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openRouterApiKeyState, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, messagesScrollTop, composerDropActive, composerDropEnabled, projects, projectExpandedIds, selectedProjectId, projectListScrollTop, voiceDictationEnabled, useChatMathWorker, effectiveParsedMessages, authEnabled, authStatus, authErrorMessage);
10436
10765
  case 'detail':
10437
- return getChatModeDetailVirtualDom(sessions, selectedSessionId, composerValue, openRouterApiKeyInput, openApiApiKeyInput, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openRouterApiKeyState, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, messagesScrollTop, composerDropActive, composerDropEnabled, voiceDictationEnabled, useChatMathWorker, effectiveParsedMessages);
10766
+ return getChatModeDetailVirtualDom(sessions, selectedSessionId, composerValue, openRouterApiKeyInput, openApiApiKeyInput, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openRouterApiKeyState, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, messagesScrollTop, composerDropActive, composerDropEnabled, voiceDictationEnabled, useChatMathWorker, effectiveParsedMessages, authEnabled, authStatus, authErrorMessage);
10438
10767
  case 'list':
10439
- return getChatModeListVirtualDom(sessions, selectedSessionId, composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, chatListScrollTop, composerDropActive, composerDropEnabled, voiceDictationEnabled);
10768
+ return getChatModeListVirtualDom(sessions, selectedSessionId, composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, chatListScrollTop, composerDropActive, composerDropEnabled, voiceDictationEnabled, authEnabled, authStatus, authErrorMessage);
10440
10769
  default:
10441
10770
  return getChatModeUnsupportedVirtualDom();
10442
10771
  }
@@ -10444,6 +10773,9 @@ const getChatVirtualDom = (sessions, selectedSessionId, composerValue, openRoute
10444
10773
 
10445
10774
  const renderItems = (oldState, newState) => {
10446
10775
  const {
10776
+ authEnabled,
10777
+ authErrorMessage,
10778
+ authStatus,
10447
10779
  chatListScrollTop,
10448
10780
  composerDropActive,
10449
10781
  composerDropEnabled,
@@ -10477,7 +10809,7 @@ const renderItems = (oldState, newState) => {
10477
10809
  if (initial) {
10478
10810
  return [SetDom2, uid, []];
10479
10811
  }
10480
- const dom = getChatVirtualDom(sessions, selectedSessionId, composerValue, openRouterApiKeyInput, viewMode, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openApiApiKeyInput, openRouterApiKeyState, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, chatListScrollTop, messagesScrollTop, composerDropActive, composerDropEnabled, projects, projectExpandedIds, selectedProjectId, projectListScrollTop, voiceDictationEnabled, useChatMathWorker, parsedMessages);
10812
+ const dom = getChatVirtualDom(sessions, selectedSessionId, composerValue, openRouterApiKeyInput, viewMode, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openApiApiKeyInput, openRouterApiKeyState, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, chatListScrollTop, messagesScrollTop, composerDropActive, composerDropEnabled, projects, projectExpandedIds, selectedProjectId, projectListScrollTop, voiceDictationEnabled, useChatMathWorker, parsedMessages, authEnabled, authStatus, authErrorMessage);
10481
10813
  return [SetDom2, uid, dom];
10482
10814
  };
10483
10815
 
@@ -10776,6 +11108,20 @@ const saveState = state => {
10776
11108
  };
10777
11109
  };
10778
11110
 
11111
+ const setAuthEnabled = (state, authEnabled) => {
11112
+ return {
11113
+ ...state,
11114
+ authEnabled
11115
+ };
11116
+ };
11117
+
11118
+ const setBackendUrl = (state, backendUrl) => {
11119
+ return {
11120
+ ...state,
11121
+ backendUrl
11122
+ };
11123
+ };
11124
+
10779
11125
  const dummySessions = [{
10780
11126
  id: 'session-a',
10781
11127
  messages: [],
@@ -10869,6 +11215,7 @@ const commandMap = {
10869
11215
  'Chat.deleteSessionAtIndex': wrapCommand(deleteSessionAtIndex),
10870
11216
  'Chat.diff2': diff2,
10871
11217
  'Chat.enterNewLine': wrapCommand(handleNewline),
11218
+ 'Chat.getAuthState': wrapGetter(getAuthState),
10872
11219
  'Chat.getCommandIds': getCommandIds,
10873
11220
  'Chat.getKeyBindings': getKeyBindings,
10874
11221
  'Chat.getMenuEntries': getMenuEntries,
@@ -10904,6 +11251,7 @@ const commandMap = {
10904
11251
  'Chat.initialize': initialize,
10905
11252
  'Chat.loadContent': wrapCommand(loadContent),
10906
11253
  'Chat.loadContent2': wrapCommand(loadContent),
11254
+ 'Chat.mockBackendAuthResponse': wrapCommand(mockBackendAuthResponse),
10907
11255
  'Chat.mockOpenApiRequestGetAll': wrapGetter(mockOpenApiRequestGetAll),
10908
11256
  'Chat.mockOpenApiRequestReset': wrapCommand(mockOpenApiRequestReset),
10909
11257
  'Chat.mockOpenApiSetHttpErrorResponse': wrapCommand(mockOpenApiSetHttpErrorResponse),
@@ -10919,6 +11267,8 @@ const commandMap = {
10919
11267
  'Chat.reset': wrapCommand(reset),
10920
11268
  'Chat.resize': wrapCommand(resize),
10921
11269
  'Chat.saveState': wrapGetter(saveState),
11270
+ 'Chat.setAuthEnabled': wrapCommand(setAuthEnabled),
11271
+ 'Chat.setBackendUrl': wrapCommand(setBackendUrl),
10922
11272
  'Chat.setChatList': wrapCommand(setChatList),
10923
11273
  'Chat.setEmitStreamingFunctionCallEvents': wrapCommand(setEmitStreamingFunctionCallEvents),
10924
11274
  'Chat.setOpenRouterApiKey': wrapCommand(setOpenRouterApiKey),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/chat-view",
3
- "version": "6.5.0",
3
+ "version": "6.7.0",
4
4
  "description": "Chat View Worker",
5
5
  "repository": {
6
6
  "type": "git",