@lvce-editor/chat-view 1.9.0 → 1.10.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.
@@ -1196,8 +1196,8 @@ const settings = i18nString('Settings');
1196
1196
  const closeChat = i18nString('Close Chat');
1197
1197
  const clickToOpenNewChat = i18nString('Click the + button to open a new chat.');
1198
1198
  const startConversation = i18nString('Start a conversation by typing below.');
1199
- const you = i18nString('You');
1200
- const assistant = i18nString('Assistant');
1199
+ i18nString('You');
1200
+ i18nString('Assistant');
1201
1201
  const composePlaceholder = i18nString('Type your message. Enter to send, Shift+Enter for newline.');
1202
1202
  const sendMessage = i18nString('Send message');
1203
1203
  const send = i18nString('Send');
@@ -1245,7 +1245,10 @@ const createDefaultState = () => {
1245
1245
  messages: [],
1246
1246
  title: defaultSessionTitle
1247
1247
  }],
1248
+ tokensMax: 0,
1249
+ tokensUsed: 0,
1248
1250
  uid: 0,
1251
+ usageOverviewEnabled: false,
1249
1252
  viewMode: 'list',
1250
1253
  warningCount: 0,
1251
1254
  width: 0,
@@ -1289,7 +1292,7 @@ const diffFocus = (oldState, newState) => {
1289
1292
  };
1290
1293
 
1291
1294
  const isEqual = (oldState, newState) => {
1292
- return oldState.composerValue === newState.composerValue && oldState.initial === newState.initial && oldState.renamingSessionId === newState.renamingSessionId && oldState.selectedModelId === newState.selectedModelId && oldState.selectedSessionId === newState.selectedSessionId && oldState.sessions === newState.sessions && oldState.viewMode === newState.viewMode;
1295
+ return oldState.composerValue === newState.composerValue && oldState.initial === newState.initial && oldState.renamingSessionId === newState.renamingSessionId && oldState.selectedModelId === newState.selectedModelId && oldState.selectedSessionId === newState.selectedSessionId && oldState.sessions === newState.sessions && oldState.tokensMax === newState.tokensMax && oldState.tokensUsed === newState.tokensUsed && oldState.usageOverviewEnabled === newState.usageOverviewEnabled && oldState.viewMode === newState.viewMode;
1293
1296
  };
1294
1297
 
1295
1298
  const RenderItems = 4;
@@ -2533,16 +2536,21 @@ const ButtonDisabled = 'ButtonDisabled';
2533
2536
  const ButtonPrimary = 'ButtonPrimary';
2534
2537
  const IconButton = 'IconButton';
2535
2538
  const Label = 'Label';
2539
+ const LabelDetail = 'LabelDetail';
2536
2540
  const ChatList = 'ChatList';
2537
2541
  const ChatListEmpty = 'ChatListEmpty';
2538
2542
  const ChatListItem = 'ChatListItem';
2539
2543
  const ChatListItemLabel = 'ChatListItemLabel';
2540
2544
  const Markdown = 'Markdown';
2541
2545
  const Message = 'Message';
2546
+ const ChatMessageContent = 'ChatMessageContent';
2542
2547
  const MessageUser = 'MessageUser';
2543
2548
  const MessageAssistant = 'MessageAssistant';
2544
2549
  const MultilineInputBox = 'MultilineInputBox';
2545
2550
  const Option = 'Option';
2551
+ const TokenUsageOverview = 'TokenUsageOverview';
2552
+ const TokenUsageRing = 'TokenUsageRing';
2553
+ const TokenUsageRingInner = 'TokenUsageRingInner';
2546
2554
  const Select = 'Select';
2547
2555
  const Viewlet = 'Viewlet';
2548
2556
  const ChatWelcomeMessage = 'ChatWelcomeMessage';
@@ -2561,18 +2569,68 @@ const HandleClickDelete = 18;
2561
2569
  const HandleSubmit = 19;
2562
2570
  const HandleModelChange = 20;
2563
2571
 
2564
- const getChatSendAreaDom = (composerValue, models, selectedModelId) => {
2565
- const isSendDisabled = composerValue.trim() === '';
2572
+ const getModelOptionDOm = (model, selectedModelId) => {
2573
+ return [{
2574
+ childCount: 1,
2575
+ className: Option,
2576
+ selected: model.id === selectedModelId,
2577
+ type: Option$1,
2578
+ value: model.id
2579
+ }, text(model.name)];
2580
+ };
2581
+
2582
+ const getSendButtonDom = isSendDisabled => {
2566
2583
  const sendButtonClassName = isSendDisabled ? `${Button} ${ButtonPrimary} ${ButtonDisabled}` : `${Button} ${ButtonPrimary}`;
2567
- const modelOptions = models.flatMap(model => {
2568
- return [{
2569
- childCount: 1,
2570
- className: Option,
2571
- selected: model.id === selectedModelId,
2572
- type: Option$1,
2573
- value: model.id
2574
- }, text(model.name)];
2575
- });
2584
+ return [{
2585
+ childCount: 1,
2586
+ className: sendButtonClassName,
2587
+ disabled: isSendDisabled,
2588
+ name: 'send',
2589
+ onClick: HandleSubmit,
2590
+ role: Button$2,
2591
+ title: sendMessage,
2592
+ type: Button$1
2593
+ }, text(send)];
2594
+ };
2595
+
2596
+ const clampToPercentage = (tokensUsed, tokensMax) => {
2597
+ if (tokensMax <= 0) {
2598
+ return 0;
2599
+ }
2600
+ const percentage = tokensUsed / tokensMax * 100;
2601
+ return Math.max(0, Math.min(100, percentage));
2602
+ };
2603
+
2604
+ const getUsageOverviewDom = (tokensUsed, tokensMax) => {
2605
+ const usagePercent = clampToPercentage(tokensUsed, tokensMax);
2606
+ const usageLabel = `${tokensUsed} / ${tokensMax}`;
2607
+ const usageTitle = `${tokensUsed} of ${tokensMax} tokens used (${Math.round(usagePercent)}%)`;
2608
+ return [{
2609
+ childCount: 3,
2610
+ className: TokenUsageOverview,
2611
+ type: Div
2612
+ }, {
2613
+ childCount: 1,
2614
+ className: TokenUsageRing,
2615
+ style: `background: conic-gradient(var(--vscode-button-background) ${usagePercent}%, var(--vscode-editorWidget-border) 0);`,
2616
+ title: usageTitle,
2617
+ type: Div
2618
+ }, {
2619
+ childCount: 0,
2620
+ className: TokenUsageRingInner,
2621
+ style: 'background: var(--vscode-editor-background);',
2622
+ type: Div
2623
+ }, {
2624
+ childCount: 1,
2625
+ className: LabelDetail,
2626
+ title: usageTitle,
2627
+ type: Span
2628
+ }, text(usageLabel)];
2629
+ };
2630
+
2631
+ const getChatSendAreaDom = (composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax) => {
2632
+ const isSendDisabled = composerValue.trim() === '';
2633
+ const modelOptions = models.flatMap(model => getModelOptionDOm(model, selectedModelId));
2576
2634
  return [{
2577
2635
  childCount: 1,
2578
2636
  className: ChatSendArea,
@@ -2591,7 +2649,7 @@ const getChatSendAreaDom = (composerValue, models, selectedModelId) => {
2591
2649
  type: TextArea,
2592
2650
  value: composerValue
2593
2651
  }, {
2594
- childCount: 2,
2652
+ childCount: usageOverviewEnabled ? 3 : 2,
2595
2653
  className: ChatSendAreaBottom,
2596
2654
  type: Div
2597
2655
  }, {
@@ -2601,16 +2659,7 @@ const getChatSendAreaDom = (composerValue, models, selectedModelId) => {
2601
2659
  onInput: HandleModelChange,
2602
2660
  type: Select$1,
2603
2661
  value: selectedModelId
2604
- }, ...modelOptions, {
2605
- childCount: 1,
2606
- className: sendButtonClassName,
2607
- disabled: isSendDisabled,
2608
- name: 'send',
2609
- onClick: HandleSubmit,
2610
- role: Button$2,
2611
- title: sendMessage,
2612
- type: Button$1
2613
- }, text(send)];
2662
+ }, ...modelOptions, ...(usageOverviewEnabled ? getUsageOverviewDom(tokensUsed, tokensMax) : []), ...getSendButtonDom(isSendDisabled)];
2614
2663
  };
2615
2664
 
2616
2665
  const getHeaderActionVirtualDom = item => {
@@ -2658,7 +2707,11 @@ const getChatHeaderBackButtonVirtualDom = () => {
2658
2707
  role: Button$2,
2659
2708
  title: backToChats,
2660
2709
  type: Button$1
2661
- }, text('←')];
2710
+ }, {
2711
+ childCount: 0,
2712
+ className: 'MaskIcon MaskIconArrowLeft',
2713
+ type: Div
2714
+ }];
2662
2715
  };
2663
2716
 
2664
2717
  const getChatHeaderDomDetailMode = selectedSessionTitle => {
@@ -2680,14 +2733,14 @@ const getChatHeaderDomDetailMode = selectedSessionTitle => {
2680
2733
  const getChatMessageDom = message => {
2681
2734
  const roleClassName = message.role === 'user' ? MessageUser : MessageAssistant;
2682
2735
  return [{
2683
- childCount: 2,
2736
+ childCount: 1,
2684
2737
  className: mergeClassNames(Message, roleClassName),
2685
2738
  type: Div
2686
2739
  }, {
2687
2740
  childCount: 1,
2688
- className: Label,
2741
+ className: ChatMessageContent,
2689
2742
  type: Div
2690
- }, text(`${message.role === 'user' ? you : assistant} · ${message.time}`), {
2743
+ }, {
2691
2744
  childCount: 1,
2692
2745
  className: Markdown,
2693
2746
  type: P
@@ -2709,7 +2762,7 @@ const getMessagesDom = messages => {
2709
2762
  }, ...messages.flatMap(getChatMessageDom)];
2710
2763
  };
2711
2764
 
2712
- const getChatModeDetailVirtualDom = (sessions, selectedSessionId, composerValue, models, selectedModelId) => {
2765
+ const getChatModeDetailVirtualDom = (sessions, selectedSessionId, composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax) => {
2713
2766
  const selectedSession = sessions.find(session => session.id === selectedSessionId);
2714
2767
  const selectedSessionTitle = selectedSession?.title || chatTitle;
2715
2768
  const messages = selectedSession ? selectedSession.messages : [];
@@ -2717,7 +2770,7 @@ const getChatModeDetailVirtualDom = (sessions, selectedSessionId, composerValue,
2717
2770
  childCount: 3,
2718
2771
  className: mergeClassNames(Viewlet, Chat),
2719
2772
  type: Div
2720
- }, ...getChatHeaderDomDetailMode(selectedSessionTitle), ...getMessagesDom(messages), ...getChatSendAreaDom(composerValue, models, selectedModelId)];
2773
+ }, ...getChatHeaderDomDetailMode(selectedSessionTitle), ...getMessagesDom(messages), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax)];
2721
2774
  };
2722
2775
 
2723
2776
  const getChatHeaderListModeDom = () => {
@@ -2786,12 +2839,12 @@ const getChatListDom = (sessions, selectedSessionId) => {
2786
2839
  }, ...sessions.flatMap(getSessionDom)];
2787
2840
  };
2788
2841
 
2789
- const getChatModeListVirtualDom = (sessions, selectedSessionId, composerValue, models, selectedModelId) => {
2842
+ const getChatModeListVirtualDom = (sessions, selectedSessionId, composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax) => {
2790
2843
  return [{
2791
2844
  childCount: 3,
2792
2845
  className: mergeClassNames(Viewlet, Chat),
2793
2846
  type: Div
2794
- }, ...getChatHeaderListModeDom(), ...getChatListDom(sessions), ...getChatSendAreaDom(composerValue, models, selectedModelId)];
2847
+ }, ...getChatHeaderListModeDom(), ...getChatListDom(sessions), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax)];
2795
2848
  };
2796
2849
 
2797
2850
  const getChatModeUnsupportedVirtualDom = () => {
@@ -2801,12 +2854,12 @@ const getChatModeUnsupportedVirtualDom = () => {
2801
2854
  }, text('Unknown view mode')];
2802
2855
  };
2803
2856
 
2804
- const getChatVirtualDom = (sessions, selectedSessionId, composerValue, viewMode, models, selectedModelId) => {
2857
+ const getChatVirtualDom = (sessions, selectedSessionId, composerValue, viewMode, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax) => {
2805
2858
  switch (viewMode) {
2806
2859
  case 'detail':
2807
- return getChatModeDetailVirtualDom(sessions, selectedSessionId, composerValue, models, selectedModelId);
2860
+ return getChatModeDetailVirtualDom(sessions, selectedSessionId, composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax);
2808
2861
  case 'list':
2809
- return getChatModeListVirtualDom(sessions, selectedSessionId, composerValue, models, selectedModelId);
2862
+ return getChatModeListVirtualDom(sessions, selectedSessionId, composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax);
2810
2863
  default:
2811
2864
  return getChatModeUnsupportedVirtualDom();
2812
2865
  }
@@ -2820,13 +2873,16 @@ const renderItems = (oldState, newState) => {
2820
2873
  selectedModelId,
2821
2874
  selectedSessionId,
2822
2875
  sessions,
2876
+ tokensMax,
2877
+ tokensUsed,
2823
2878
  uid,
2879
+ usageOverviewEnabled,
2824
2880
  viewMode
2825
2881
  } = newState;
2826
2882
  if (initial) {
2827
2883
  return [SetDom2, uid, []];
2828
2884
  }
2829
- const dom = getChatVirtualDom(sessions, selectedSessionId, composerValue, viewMode, models, selectedModelId);
2885
+ const dom = getChatVirtualDom(sessions, selectedSessionId, composerValue, viewMode, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax);
2830
2886
  return [SetDom2, uid, dom];
2831
2887
  };
2832
2888
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/chat-view",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "description": "Chat View Worker",
5
5
  "repository": {
6
6
  "type": "git",