@lvce-editor/chat-view 2.4.0 → 2.6.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.
@@ -1078,6 +1078,8 @@ const {
1078
1078
  set: set$3
1079
1079
  } = create$2(6002);
1080
1080
 
1081
+ const Div$1 = 4;
1082
+
1081
1083
  const ClientX = 'event.clientX';
1082
1084
  const ClientY = 'event.clientY';
1083
1085
  const Key = 'event.key';
@@ -2739,22 +2741,166 @@ const readNextChunk = async () => {
2739
2741
  return promise;
2740
2742
  };
2741
2743
 
2742
- const getMockOpenApiAssistantText = async (stream, onTextChunk) => {
2744
+ const parseSseDataLines = eventChunk => {
2745
+ const lines = eventChunk.split('\n');
2746
+ const dataLines = [];
2747
+ for (const line of lines) {
2748
+ if (!line.startsWith('data:')) {
2749
+ continue;
2750
+ }
2751
+ dataLines.push(line.slice(5).trimStart());
2752
+ }
2753
+ return dataLines;
2754
+ };
2755
+ const emitToolCalls = async (toolCallAccumulator, onToolCallsChunk) => {
2756
+ if (!onToolCallsChunk) {
2757
+ return;
2758
+ }
2759
+ const toolCalls = Object.entries(toolCallAccumulator).toSorted((a, b) => Number(a[0]) - Number(b[0])).map(entry => entry[1]).filter(toolCall => !!toolCall.name);
2760
+ if (toolCalls.length === 0) {
2761
+ return;
2762
+ }
2763
+ await onToolCallsChunk(toolCalls);
2764
+ };
2765
+ const getMockOpenApiAssistantText = async (stream, onTextChunk, onToolCallsChunk, onDataEvent, onEventStreamFinished) => {
2743
2766
  const error = takeErrorResponse();
2744
2767
  if (error) {
2745
2768
  return error;
2746
2769
  }
2747
2770
  let text = '';
2771
+ let remainder = '';
2772
+ let toolCallAccumulator = {};
2773
+ let finishedNotified = false;
2774
+ const notifyFinished = async () => {
2775
+ if (finishedNotified) {
2776
+ return;
2777
+ }
2778
+ finishedNotified = true;
2779
+ if (onEventStreamFinished) {
2780
+ await onEventStreamFinished();
2781
+ }
2782
+ };
2783
+ const handleParsedSseEvent = async parsed => {
2784
+ if (onDataEvent) {
2785
+ await onDataEvent(parsed);
2786
+ }
2787
+ if (!parsed || typeof parsed !== 'object') {
2788
+ return;
2789
+ }
2790
+ const eventType = Reflect.get(parsed, 'type');
2791
+ if (eventType === 'response.completed') {
2792
+ await notifyFinished();
2793
+ return;
2794
+ }
2795
+ if (eventType === 'response.output_text.delta') {
2796
+ const delta = Reflect.get(parsed, 'delta');
2797
+ if (typeof delta !== 'string' || !delta) {
2798
+ return;
2799
+ }
2800
+ text += delta;
2801
+ if (stream && onTextChunk) {
2802
+ await onTextChunk(delta);
2803
+ }
2804
+ return;
2805
+ }
2806
+ if (eventType === 'response.output_item.added') {
2807
+ const outputIndex = Reflect.get(parsed, 'output_index');
2808
+ const item = Reflect.get(parsed, 'item');
2809
+ if (typeof outputIndex !== 'number' || !item || typeof item !== 'object') {
2810
+ return;
2811
+ }
2812
+ if (Reflect.get(item, 'type') !== 'function_call') {
2813
+ return;
2814
+ }
2815
+ const name = Reflect.get(item, 'name');
2816
+ const argumentsValue = Reflect.get(item, 'arguments');
2817
+ const callId = Reflect.get(item, 'call_id');
2818
+ toolCallAccumulator = {
2819
+ ...toolCallAccumulator,
2820
+ [outputIndex]: {
2821
+ arguments: typeof argumentsValue === 'string' ? argumentsValue : '',
2822
+ ...(typeof callId === 'string' ? {
2823
+ id: callId
2824
+ } : {}),
2825
+ name: typeof name === 'string' ? name : ''
2826
+ }
2827
+ };
2828
+ await emitToolCalls(toolCallAccumulator, onToolCallsChunk);
2829
+ return;
2830
+ }
2831
+ if (eventType === 'response.function_call_arguments.delta' || eventType === 'response.function_call_arguments.done') {
2832
+ const outputIndex = Reflect.get(parsed, 'output_index');
2833
+ if (typeof outputIndex !== 'number') {
2834
+ return;
2835
+ }
2836
+ const current = toolCallAccumulator[outputIndex] || {
2837
+ arguments: '',
2838
+ name: ''
2839
+ };
2840
+ const delta = Reflect.get(parsed, 'delta');
2841
+ const argumentsValue = Reflect.get(parsed, 'arguments');
2842
+ const name = Reflect.get(parsed, 'name');
2843
+ const callId = Reflect.get(parsed, 'call_id');
2844
+ const next = {
2845
+ arguments: typeof argumentsValue === 'string' ? argumentsValue : typeof delta === 'string' ? `${current.arguments}${delta}` : current.arguments,
2846
+ ...(typeof callId === 'string' ? {
2847
+ id: callId
2848
+ } : current.id ? {
2849
+ id: current.id
2850
+ } : {}),
2851
+ name: typeof name === 'string' && name ? name : current.name
2852
+ };
2853
+ toolCallAccumulator = {
2854
+ ...toolCallAccumulator,
2855
+ [outputIndex]: next
2856
+ };
2857
+ await emitToolCalls(toolCallAccumulator, onToolCallsChunk);
2858
+ }
2859
+ };
2860
+ const consumeSseDataLines = async dataLines => {
2861
+ for (const line of dataLines) {
2862
+ if (line === '[DONE]') {
2863
+ await notifyFinished();
2864
+ continue;
2865
+ }
2866
+ let parsed;
2867
+ try {
2868
+ parsed = JSON.parse(line);
2869
+ } catch {
2870
+ continue;
2871
+ }
2872
+ await handleParsedSseEvent(parsed);
2873
+ }
2874
+ };
2748
2875
  while (true) {
2749
2876
  const chunk = await readNextChunk();
2750
2877
  if (typeof chunk !== 'string') {
2751
2878
  break;
2752
2879
  }
2880
+ if (chunk.startsWith('data:')) {
2881
+ remainder += chunk;
2882
+ while (true) {
2883
+ const separatorIndex = remainder.indexOf('\n\n');
2884
+ if (separatorIndex === -1) {
2885
+ break;
2886
+ }
2887
+ const rawEvent = remainder.slice(0, separatorIndex);
2888
+ remainder = remainder.slice(separatorIndex + 2);
2889
+ const dataLines = parseSseDataLines(rawEvent);
2890
+ await consumeSseDataLines(dataLines);
2891
+ }
2892
+ continue;
2893
+ }
2753
2894
  text += chunk;
2754
2895
  if (stream && onTextChunk) {
2755
2896
  await onTextChunk(chunk);
2756
2897
  }
2757
2898
  }
2899
+ if (remainder) {
2900
+ const dataLines = parseSseDataLines(remainder);
2901
+ await consumeSseDataLines(dataLines);
2902
+ }
2903
+ await notifyFinished();
2758
2904
  return {
2759
2905
  text,
2760
2906
  type: 'success'
@@ -4079,7 +4225,7 @@ const getAiResponse = async ({
4079
4225
  const usesOpenRouterModel = isOpenRouterModel(selectedModelId, models);
4080
4226
  if (usesOpenApiModel) {
4081
4227
  if (useMockApi) {
4082
- const result = await getMockOpenApiAssistantText(streamingEnabled, onTextChunk);
4228
+ const result = await getMockOpenApiAssistantText(streamingEnabled, onTextChunk, onToolCallsChunk, onDataEvent, onEventStreamFinished);
4083
4229
  if (result.type === 'success') {
4084
4230
  const {
4085
4231
  text: assistantText
@@ -5641,6 +5787,27 @@ const getToolCallArgumentPreview = rawArguments => {
5641
5787
  return rawArguments;
5642
5788
  };
5643
5789
 
5790
+ const getToolCallDom = toolCall => {
5791
+ const argumentPreview = getToolCallArgumentPreview(toolCall.arguments);
5792
+ const label = `${toolCall.name} ${argumentPreview}`;
5793
+ return [{
5794
+ childCount: 1,
5795
+ className: Markdown,
5796
+ type: P
5797
+ }, text(label)];
5798
+ };
5799
+
5800
+ const getToolCallsDom = message => {
5801
+ if (message.role !== 'assistant' || !message.toolCalls || message.toolCalls.length === 0) {
5802
+ return [];
5803
+ }
5804
+ return [{
5805
+ childCount: message.toolCalls.length,
5806
+ className: 'ToolCallsContainer',
5807
+ type: Div$1
5808
+ }, ...message.toolCalls.flatMap(getToolCallDom)];
5809
+ };
5810
+
5644
5811
  const orderedListItemRegex = /^\s*\d+\.\s+(.*)$/;
5645
5812
  const parseMessageContent = rawMessage => {
5646
5813
  if (rawMessage === '') {
@@ -5721,20 +5888,6 @@ const getMessageContentDom = nodes => {
5721
5888
  });
5722
5889
  };
5723
5890
 
5724
- const getToolCallsDom = message => {
5725
- if (message.role !== 'assistant' || !message.toolCalls || message.toolCalls.length === 0) {
5726
- return [];
5727
- }
5728
- return message.toolCalls.flatMap(toolCall => {
5729
- const argumentPreview = getToolCallArgumentPreview(toolCall.arguments);
5730
- const label = `${toolCall.name} ${argumentPreview}`;
5731
- return [{
5732
- childCount: 1,
5733
- className: Markdown,
5734
- type: P
5735
- }, text(label)];
5736
- });
5737
- };
5738
5891
  const getChatMessageDom = (message, openRouterApiKeyInput, openApiApiKeyInput = '', openRouterApiKeyState = 'idle') => {
5739
5892
  const roleClassName = message.role === 'user' ? MessageUser : MessageAssistant;
5740
5893
  const isOpenApiApiKeyMissingMessage = message.role === 'assistant' && message.text === openApiApiKeyRequiredMessage;
@@ -5744,7 +5897,8 @@ const getChatMessageDom = (message, openRouterApiKeyInput, openApiApiKeyInput =
5744
5897
  const messageIntermediate = parseMessageContent(message.text);
5745
5898
  const messageDom = getMessageContentDom(messageIntermediate);
5746
5899
  const toolCallsDom = getToolCallsDom(message);
5747
- const extraChildCount = isOpenApiApiKeyMissingMessage || isOpenRouterApiKeyMissingMessage || isOpenRouterRequestFailedMessage || isOpenRouterTooManyRequestsMessage ? messageIntermediate.length + 1 + toolCallsDom.length : messageIntermediate.length + toolCallsDom.length;
5900
+ const toolCallsChildCount = toolCallsDom.length > 0 ? 1 : 0;
5901
+ const extraChildCount = isOpenApiApiKeyMissingMessage || isOpenRouterApiKeyMissingMessage || isOpenRouterRequestFailedMessage || isOpenRouterTooManyRequestsMessage ? messageIntermediate.length + 1 + toolCallsChildCount : messageIntermediate.length + toolCallsChildCount;
5748
5902
  return [{
5749
5903
  childCount: 1,
5750
5904
  className: mergeClassNames(Message, roleClassName),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/chat-view",
3
- "version": "2.4.0",
3
+ "version": "2.6.0",
4
4
  "description": "Chat View Worker",
5
5
  "repository": {
6
6
  "type": "git",