@lvce-editor/chat-view 3.7.0 → 3.9.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.
@@ -2792,400 +2792,6 @@ const openRouterTooManyRequestsMessage = 'OpenRouter rate limit reached (429). P
2792
2792
  const openRouterRequestFailureReasons = ['ContentSecurityPolicyViolation: Check DevTools for details.', 'OpenRouter server offline: Check DevTools for details.', 'Check your internet connection.'];
2793
2793
  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.'];
2794
2794
 
2795
- const delay = async ms => {
2796
- await new Promise(resolve => setTimeout(resolve, ms));
2797
- };
2798
-
2799
- const getMockAiResponse = async (userMessage, delayInMs) => {
2800
- await delay(delayInMs);
2801
- return `Mock AI response: I received "${userMessage}".`;
2802
- };
2803
-
2804
- let queue = [];
2805
- let waiters = [];
2806
- let finished = false;
2807
- let errorResult;
2808
- const reset$1 = () => {
2809
- queue = [];
2810
- waiters = [];
2811
- finished = false;
2812
- errorResult = undefined;
2813
- };
2814
- const setHttpErrorResponse = (statusCode, body) => {
2815
- const rawError = body && typeof body === 'object' ? Reflect.get(body, 'error') : undefined;
2816
- const errorCode = rawError && typeof rawError === 'object' ? Reflect.get(rawError, 'code') : undefined;
2817
- const errorMessage = rawError && typeof rawError === 'object' ? Reflect.get(rawError, 'message') : undefined;
2818
- const errorType = rawError && typeof rawError === 'object' ? Reflect.get(rawError, 'type') : undefined;
2819
- errorResult = {
2820
- details: 'http-error',
2821
- ...(typeof errorCode === 'string' ? {
2822
- errorCode
2823
- } : {}),
2824
- ...(typeof errorMessage === 'string' ? {
2825
- errorMessage
2826
- } : {}),
2827
- ...(typeof errorType === 'string' ? {
2828
- errorType
2829
- } : {}),
2830
- statusCode,
2831
- type: 'error'
2832
- };
2833
- };
2834
- const takeErrorResponse = () => {
2835
- const error = errorResult;
2836
- errorResult = undefined;
2837
- return error;
2838
- };
2839
- const pushChunk = chunk => {
2840
- if (waiters.length > 0) {
2841
- const resolve = waiters.shift();
2842
- resolve?.(chunk);
2843
- return;
2844
- }
2845
- queue.push(chunk);
2846
- };
2847
- const finish = () => {
2848
- finished = true;
2849
- if (waiters.length === 0) {
2850
- return;
2851
- }
2852
- const activeWaiters = waiters;
2853
- waiters = [];
2854
- for (const resolve of activeWaiters) {
2855
- resolve(undefined);
2856
- }
2857
- };
2858
- const readNextChunk = async () => {
2859
- if (queue.length > 0) {
2860
- return queue.shift();
2861
- }
2862
- if (finished) {
2863
- return undefined;
2864
- }
2865
- const {
2866
- promise,
2867
- resolve
2868
- } = Promise.withResolvers();
2869
- waiters.push(resolve);
2870
- return promise;
2871
- };
2872
-
2873
- const parseSseDataLines = eventChunk => {
2874
- const lines = eventChunk.split('\n');
2875
- const dataLines = [];
2876
- for (const line of lines) {
2877
- if (!line.startsWith('data:')) {
2878
- continue;
2879
- }
2880
- dataLines.push(line.slice(5).trimStart());
2881
- }
2882
- return dataLines;
2883
- };
2884
- const emitToolCalls = async (toolCallAccumulator, onToolCallsChunk) => {
2885
- if (!onToolCallsChunk) {
2886
- return;
2887
- }
2888
- const toolCalls = Object.entries(toolCallAccumulator).toSorted((a, b) => Number(a[0]) - Number(b[0])).map(entry => entry[1]).filter(toolCall => !!toolCall.name);
2889
- if (toolCalls.length === 0) {
2890
- return;
2891
- }
2892
- await onToolCallsChunk(toolCalls);
2893
- };
2894
- const getMockOpenApiAssistantText = async (stream, onTextChunk, onToolCallsChunk, onDataEvent, onEventStreamFinished) => {
2895
- const error = takeErrorResponse();
2896
- if (error) {
2897
- return error;
2898
- }
2899
- let text = '';
2900
- let remainder = '';
2901
- let toolCallAccumulator = {};
2902
- let finishedNotified = false;
2903
- const notifyFinished = async () => {
2904
- if (finishedNotified) {
2905
- return;
2906
- }
2907
- finishedNotified = true;
2908
- if (onEventStreamFinished) {
2909
- await onEventStreamFinished();
2910
- }
2911
- };
2912
- const handleParsedSseEvent = async parsed => {
2913
- if (onDataEvent) {
2914
- await onDataEvent(parsed);
2915
- }
2916
- if (!parsed || typeof parsed !== 'object') {
2917
- return;
2918
- }
2919
- const eventType = Reflect.get(parsed, 'type');
2920
- if (eventType === 'response.completed') {
2921
- await notifyFinished();
2922
- return;
2923
- }
2924
- if (eventType === 'response.output_text.delta') {
2925
- const delta = Reflect.get(parsed, 'delta');
2926
- if (typeof delta !== 'string' || !delta) {
2927
- return;
2928
- }
2929
- text += delta;
2930
- if (stream && onTextChunk) {
2931
- await onTextChunk(delta);
2932
- }
2933
- return;
2934
- }
2935
- if (eventType === 'response.output_item.added') {
2936
- const outputIndex = Reflect.get(parsed, 'output_index');
2937
- const item = Reflect.get(parsed, 'item');
2938
- if (typeof outputIndex !== 'number' || !item || typeof item !== 'object') {
2939
- return;
2940
- }
2941
- if (Reflect.get(item, 'type') !== 'function_call') {
2942
- return;
2943
- }
2944
- const name = Reflect.get(item, 'name');
2945
- const argumentsValue = Reflect.get(item, 'arguments');
2946
- const callId = Reflect.get(item, 'call_id');
2947
- toolCallAccumulator = {
2948
- ...toolCallAccumulator,
2949
- [outputIndex]: {
2950
- arguments: typeof argumentsValue === 'string' ? argumentsValue : '',
2951
- ...(typeof callId === 'string' ? {
2952
- id: callId
2953
- } : {}),
2954
- name: typeof name === 'string' ? name : ''
2955
- }
2956
- };
2957
- await emitToolCalls(toolCallAccumulator, onToolCallsChunk);
2958
- return;
2959
- }
2960
- if (eventType === 'response.function_call_arguments.delta' || eventType === 'response.function_call_arguments.done') {
2961
- const outputIndex = Reflect.get(parsed, 'output_index');
2962
- if (typeof outputIndex !== 'number') {
2963
- return;
2964
- }
2965
- const current = toolCallAccumulator[outputIndex] || {
2966
- arguments: '',
2967
- name: ''
2968
- };
2969
- const delta = Reflect.get(parsed, 'delta');
2970
- const argumentsValue = Reflect.get(parsed, 'arguments');
2971
- const name = Reflect.get(parsed, 'name');
2972
- const callId = Reflect.get(parsed, 'call_id');
2973
- const next = {
2974
- arguments: typeof argumentsValue === 'string' ? argumentsValue : typeof delta === 'string' ? `${current.arguments}${delta}` : current.arguments,
2975
- ...(typeof callId === 'string' ? {
2976
- id: callId
2977
- } : current.id ? {
2978
- id: current.id
2979
- } : {}),
2980
- name: typeof name === 'string' && name ? name : current.name
2981
- };
2982
- toolCallAccumulator = {
2983
- ...toolCallAccumulator,
2984
- [outputIndex]: next
2985
- };
2986
- await emitToolCalls(toolCallAccumulator, onToolCallsChunk);
2987
- }
2988
- };
2989
- const consumeSseDataLines = async dataLines => {
2990
- for (const line of dataLines) {
2991
- if (line === '[DONE]') {
2992
- await notifyFinished();
2993
- continue;
2994
- }
2995
- let parsed;
2996
- try {
2997
- parsed = JSON.parse(line);
2998
- } catch {
2999
- continue;
3000
- }
3001
- await handleParsedSseEvent(parsed);
3002
- }
3003
- };
3004
- while (true) {
3005
- const chunk = await readNextChunk();
3006
- if (typeof chunk !== 'string') {
3007
- break;
3008
- }
3009
- if (chunk.startsWith('data:')) {
3010
- remainder += chunk;
3011
- while (true) {
3012
- const separatorIndex = remainder.indexOf('\n\n');
3013
- if (separatorIndex === -1) {
3014
- break;
3015
- }
3016
- const rawEvent = remainder.slice(0, separatorIndex);
3017
- remainder = remainder.slice(separatorIndex + 2);
3018
- const dataLines = parseSseDataLines(rawEvent);
3019
- await consumeSseDataLines(dataLines);
3020
- }
3021
- continue;
3022
- }
3023
- text += chunk;
3024
- if (stream && onTextChunk) {
3025
- await onTextChunk(chunk);
3026
- }
3027
- }
3028
- if (remainder) {
3029
- const dataLines = parseSseDataLines(remainder);
3030
- await consumeSseDataLines(dataLines);
3031
- }
3032
- await notifyFinished();
3033
- return {
3034
- text,
3035
- type: 'success'
3036
- };
3037
- };
3038
-
3039
- const activateByEvent = (event, assetDir, platform) => {
3040
- // @ts-ignore
3041
- return activateByEvent$1(event, assetDir, platform);
3042
- };
3043
-
3044
- const executeProvider = async ({
3045
- assetDir,
3046
- event,
3047
- method,
3048
- noProviderFoundMessage,
3049
- params,
3050
- platform
3051
- }) => {
3052
- await activateByEvent(event, assetDir, platform);
3053
- // @ts-ignore
3054
- const result = invoke$1(method, ...params);
3055
- return result;
3056
- };
3057
-
3058
- const CommandExecute = 'ExtensionHostCommand.executeCommand';
3059
- const FileSystemWriteFile = 'ExtensionHostFileSystem.writeFile';
3060
-
3061
- const normalizeLimitInfo = value => {
3062
- if (!value || typeof value !== 'object') {
3063
- return undefined;
3064
- }
3065
- const limitRemaining = Reflect.get(value, 'limitRemaining');
3066
- const limitReset = Reflect.get(value, 'limitReset');
3067
- const retryAfter = Reflect.get(value, 'retryAfter');
3068
- const usage = Reflect.get(value, 'usage');
3069
- const usageDaily = Reflect.get(value, 'usageDaily');
3070
- const normalized = {
3071
- ...(typeof limitRemaining === 'number' || limitRemaining === null ? {
3072
- limitRemaining
3073
- } : {}),
3074
- ...(typeof limitReset === 'string' || limitReset === null ? {
3075
- limitReset
3076
- } : {}),
3077
- ...(typeof retryAfter === 'string' || retryAfter === null ? {
3078
- retryAfter
3079
- } : {}),
3080
- ...(typeof usage === 'number' ? {
3081
- usage
3082
- } : {}),
3083
- ...(typeof usageDaily === 'number' ? {
3084
- usageDaily
3085
- } : {})
3086
- };
3087
- const hasDetails = typeof limitRemaining === 'number' || limitRemaining === null || typeof limitReset === 'string' || limitReset === null || typeof retryAfter === 'string' || retryAfter === null || typeof usage === 'number' || typeof usageDaily === 'number';
3088
- return hasDetails ? normalized : undefined;
3089
- };
3090
-
3091
- const normalizeMockResult = value => {
3092
- if (typeof value === 'string') {
3093
- return {
3094
- text: value,
3095
- type: 'success'
3096
- };
3097
- }
3098
- if (!value || typeof value !== 'object') {
3099
- return {
3100
- details: 'request-failed',
3101
- type: 'error'
3102
- };
3103
- }
3104
- const type = Reflect.get(value, 'type');
3105
- if (type === 'success') {
3106
- const text = Reflect.get(value, 'text');
3107
- if (typeof text === 'string') {
3108
- return {
3109
- text,
3110
- type: 'success'
3111
- };
3112
- }
3113
- return {
3114
- details: 'request-failed',
3115
- type: 'error'
3116
- };
3117
- }
3118
- if (type === 'error') {
3119
- const details = Reflect.get(value, 'details');
3120
- if (details === 'request-failed' || details === 'too-many-requests' || details === 'http-error') {
3121
- const rawMessage = Reflect.get(value, 'rawMessage');
3122
- const statusCode = Reflect.get(value, 'statusCode');
3123
- const limitInfo = normalizeLimitInfo(Reflect.get(value, 'limitInfo'));
3124
- return {
3125
- details,
3126
- ...(limitInfo ? {
3127
- limitInfo
3128
- } : {}),
3129
- ...(typeof rawMessage === 'string' ? {
3130
- rawMessage
3131
- } : {}),
3132
- ...(typeof statusCode === 'number' ? {
3133
- statusCode
3134
- } : {}),
3135
- type: 'error'
3136
- };
3137
- }
3138
- }
3139
- const text = Reflect.get(value, 'text');
3140
- if (typeof text === 'string') {
3141
- return {
3142
- text,
3143
- type: 'success'
3144
- };
3145
- }
3146
- return {
3147
- details: 'request-failed',
3148
- type: 'error'
3149
- };
3150
- };
3151
-
3152
- const getMockOpenRouterAssistantText = async (messages, modelId, openRouterApiBaseUrl, openRouterApiKey, mockApiCommandId, assetDir, platform) => {
3153
- if (!mockApiCommandId) {
3154
- return {
3155
- details: 'request-failed',
3156
- type: 'error'
3157
- };
3158
- }
3159
- try {
3160
- const result = await executeProvider({
3161
- assetDir,
3162
- event: `onCommand:${mockApiCommandId}`,
3163
- method: CommandExecute,
3164
- noProviderFoundMessage: 'No mock api command found',
3165
- params: [mockApiCommandId, {
3166
- messages,
3167
- modelId,
3168
- openRouterApiBaseUrl,
3169
- openRouterApiKey
3170
- }],
3171
- platform
3172
- });
3173
- return normalizeMockResult(result);
3174
- } catch {
3175
- return {
3176
- details: 'request-failed',
3177
- type: 'error'
3178
- };
3179
- }
3180
- };
3181
-
3182
- const makeApiRequest = async options => {
3183
- return invoke$2('ChatNetwork.makeApiRequest', options);
3184
- };
3185
- const makeStreamingApiRequest = async options => {
3186
- return invoke$2('ChatNetwork.makeStreamingApiRequest', options);
3187
- };
3188
-
3189
2795
  const executeGetWorkspaceUriTool = async (_args, _options) => {
3190
2796
  try {
3191
2797
  const workspaceUri = await getWorkspacePath();
@@ -3316,6 +2922,25 @@ const executeRenderHtmlTool = async (args, _options) => {
3316
2922
  });
3317
2923
  };
3318
2924
 
2925
+ const activateByEvent = (event, assetDir, platform) => {
2926
+ // @ts-ignore
2927
+ return activateByEvent$1(event, assetDir, platform);
2928
+ };
2929
+
2930
+ const executeProvider = async ({
2931
+ assetDir,
2932
+ event,
2933
+ method,
2934
+ noProviderFoundMessage,
2935
+ params,
2936
+ platform
2937
+ }) => {
2938
+ await activateByEvent(event, assetDir, platform);
2939
+ // @ts-ignore
2940
+ const result = invoke$1(method, ...params);
2941
+ return result;
2942
+ };
2943
+
3319
2944
  const OnFileSystem = 'onFileSystem';
3320
2945
 
3321
2946
  const executeFileSystemCommand = async (method, params, options) => {
@@ -3329,6 +2954,9 @@ const executeFileSystemCommand = async (method, params, options) => {
3329
2954
  });
3330
2955
  };
3331
2956
 
2957
+ const CommandExecute = 'ExtensionHostCommand.executeCommand';
2958
+ const FileSystemWriteFile = 'ExtensionHostFileSystem.writeFile';
2959
+
3332
2960
  const executeWriteFileTool = async (args, options) => {
3333
2961
  const filePath = typeof args.path === 'string' ? args.path : '';
3334
2962
  const content = typeof args.content === 'string' ? args.content : '';
@@ -3388,17 +3016,61 @@ const executeChatTool = async (name, rawArguments, options) => {
3388
3016
  error: `Unknown tool: ${name}`
3389
3017
  });
3390
3018
  };
3391
-
3392
- const getReadFileTool = () => {
3019
+
3020
+ const getReadFileTool = () => {
3021
+ return {
3022
+ function: {
3023
+ description: 'Read UTF-8 text content from a file inside the currently open workspace folder. Only pass an absolute URI.',
3024
+ name: 'read_file',
3025
+ parameters: {
3026
+ additionalProperties: false,
3027
+ properties: {
3028
+ uri: {
3029
+ description: 'Absolute file URI within the workspace (for example: file:///workspace/src/index.ts).',
3030
+ type: 'string'
3031
+ }
3032
+ },
3033
+ required: ['uri'],
3034
+ type: 'object'
3035
+ }
3036
+ },
3037
+ type: 'function'
3038
+ };
3039
+ };
3040
+ const getWriteFileTool = () => {
3041
+ return {
3042
+ function: {
3043
+ description: 'Write UTF-8 text content to a file inside the currently open workspace folder.',
3044
+ name: 'write_file',
3045
+ parameters: {
3046
+ additionalProperties: false,
3047
+ properties: {
3048
+ content: {
3049
+ description: 'New UTF-8 text content to write to the file.',
3050
+ type: 'string'
3051
+ },
3052
+ path: {
3053
+ description: 'Relative file path within the workspace (for example: src/index.ts).',
3054
+ type: 'string'
3055
+ }
3056
+ },
3057
+ required: ['path', 'content'],
3058
+ type: 'object'
3059
+ }
3060
+ },
3061
+ type: 'function'
3062
+ };
3063
+ };
3064
+ const getListFilesTool = () => {
3393
3065
  return {
3394
3066
  function: {
3395
- description: 'Read UTF-8 text content from a file inside the currently open workspace folder. Only pass an absolute URI.',
3396
- name: 'read_file',
3067
+ description: 'List direct children (files and folders) for a folder URI inside the currently open workspace folder. Only pass an absolute URI.',
3068
+ name: 'list_files',
3397
3069
  parameters: {
3398
3070
  additionalProperties: false,
3399
3071
  properties: {
3400
3072
  uri: {
3401
- description: 'Absolute file URI within the workspace (for example: file:///workspace/src/index.ts).',
3073
+ description: 'Absolute folder URI within the workspace (for example: file:///workspace/src).',
3402
3074
  type: 'string'
3403
3075
  }
3404
3076
  },
@@ -3409,106 +3081,434 @@ const getReadFileTool = () => {
3409
3081
  type: 'function'
3410
3082
  };
3411
3083
  };
3412
- const getWriteFileTool = () => {
3084
+ const getGetWorkspaceUriTool = () => {
3413
3085
  return {
3414
3086
  function: {
3415
- description: 'Write UTF-8 text content to a file inside the currently open workspace folder.',
3416
- name: 'write_file',
3087
+ description: 'Get the URI of the currently open workspace folder.',
3088
+ name: 'getWorkspaceUri',
3089
+ parameters: {
3090
+ additionalProperties: false,
3091
+ properties: {},
3092
+ type: 'object'
3093
+ }
3094
+ },
3095
+ type: 'function'
3096
+ };
3097
+ };
3098
+ const getRenderHtmlTool = () => {
3099
+ return {
3100
+ function: {
3101
+ description: 'Render custom HTML and optional CSS directly in the chat tool call list using native chat UI rendering. Use this for structured cards, tables, and small dashboards. After calling this tool, do not repeat the same HTML, data table, or long content again as plain text unless the user explicitly asks for a text-only version.',
3102
+ name: 'render_html',
3417
3103
  parameters: {
3418
3104
  additionalProperties: false,
3419
3105
  properties: {
3420
- content: {
3421
- description: 'New UTF-8 text content to write to the file.',
3106
+ css: {
3107
+ description: 'Optional CSS string applied inside the preview document.',
3422
3108
  type: 'string'
3423
3109
  },
3424
- path: {
3425
- description: 'Relative file path within the workspace (for example: src/index.ts).',
3110
+ html: {
3111
+ description: 'HTML string to render in the preview document.',
3112
+ type: 'string'
3113
+ },
3114
+ title: {
3115
+ description: 'Optional short title for the preview.',
3426
3116
  type: 'string'
3427
3117
  }
3428
3118
  },
3429
- required: ['path', 'content'],
3119
+ required: ['html'],
3430
3120
  type: 'object'
3431
3121
  }
3432
3122
  },
3433
3123
  type: 'function'
3434
3124
  };
3435
- };
3436
- const getListFilesTool = () => {
3437
- return {
3438
- function: {
3439
- description: 'List direct children (files and folders) for a folder URI inside the currently open workspace folder. Only pass an absolute URI.',
3440
- name: 'list_files',
3441
- parameters: {
3442
- additionalProperties: false,
3443
- properties: {
3444
- uri: {
3445
- description: 'Absolute folder URI within the workspace (for example: file:///workspace/src).',
3446
- type: 'string'
3447
- }
3448
- },
3449
- required: ['uri'],
3450
- type: 'object'
3125
+ };
3126
+ const getBasicChatTools = () => {
3127
+ return [getReadFileTool(), getWriteFileTool(), getListFilesTool(), getGetWorkspaceUriTool(), getRenderHtmlTool()];
3128
+ };
3129
+
3130
+ const getClientRequestIdHeader = () => {
3131
+ return {
3132
+ 'x-client-request-id': crypto.randomUUID()
3133
+ };
3134
+ };
3135
+
3136
+ const delay = async ms => {
3137
+ await new Promise(resolve => setTimeout(resolve, ms));
3138
+ };
3139
+
3140
+ const getMockAiResponse = async (userMessage, delayInMs) => {
3141
+ await delay(delayInMs);
3142
+ return `Mock AI response: I received "${userMessage}".`;
3143
+ };
3144
+
3145
+ let queue = [];
3146
+ let waiters = [];
3147
+ let finished = false;
3148
+ let errorResult;
3149
+ const reset$2 = () => {
3150
+ queue = [];
3151
+ waiters = [];
3152
+ finished = false;
3153
+ errorResult = undefined;
3154
+ };
3155
+ const setHttpErrorResponse = (statusCode, body) => {
3156
+ const rawError = body && typeof body === 'object' ? Reflect.get(body, 'error') : undefined;
3157
+ const errorCode = rawError && typeof rawError === 'object' ? Reflect.get(rawError, 'code') : undefined;
3158
+ const errorMessage = rawError && typeof rawError === 'object' ? Reflect.get(rawError, 'message') : undefined;
3159
+ const errorType = rawError && typeof rawError === 'object' ? Reflect.get(rawError, 'type') : undefined;
3160
+ errorResult = {
3161
+ details: 'http-error',
3162
+ ...(typeof errorCode === 'string' ? {
3163
+ errorCode
3164
+ } : {}),
3165
+ ...(typeof errorMessage === 'string' ? {
3166
+ errorMessage
3167
+ } : {}),
3168
+ ...(typeof errorType === 'string' ? {
3169
+ errorType
3170
+ } : {}),
3171
+ statusCode,
3172
+ type: 'error'
3173
+ };
3174
+ };
3175
+ const takeErrorResponse = () => {
3176
+ const error = errorResult;
3177
+ errorResult = undefined;
3178
+ return error;
3179
+ };
3180
+ const pushChunk = chunk => {
3181
+ if (waiters.length > 0) {
3182
+ const resolve = waiters.shift();
3183
+ resolve?.(chunk);
3184
+ return;
3185
+ }
3186
+ queue.push(chunk);
3187
+ };
3188
+ const finish = () => {
3189
+ finished = true;
3190
+ if (waiters.length === 0) {
3191
+ return;
3192
+ }
3193
+ const activeWaiters = waiters;
3194
+ waiters = [];
3195
+ for (const resolve of activeWaiters) {
3196
+ resolve(undefined);
3197
+ }
3198
+ };
3199
+ const readNextChunk = async () => {
3200
+ if (queue.length > 0) {
3201
+ return queue.shift();
3202
+ }
3203
+ if (finished) {
3204
+ return undefined;
3205
+ }
3206
+ const {
3207
+ promise,
3208
+ resolve
3209
+ } = Promise.withResolvers();
3210
+ waiters.push(resolve);
3211
+ return promise;
3212
+ };
3213
+
3214
+ const parseSseDataLines = eventChunk => {
3215
+ const lines = eventChunk.split('\n');
3216
+ const dataLines = [];
3217
+ for (const line of lines) {
3218
+ if (!line.startsWith('data:')) {
3219
+ continue;
3220
+ }
3221
+ dataLines.push(line.slice(5).trimStart());
3222
+ }
3223
+ return dataLines;
3224
+ };
3225
+ const emitToolCalls = async (toolCallAccumulator, onToolCallsChunk) => {
3226
+ if (!onToolCallsChunk) {
3227
+ return;
3228
+ }
3229
+ const toolCalls = Object.entries(toolCallAccumulator).toSorted((a, b) => Number(a[0]) - Number(b[0])).map(entry => entry[1]).filter(toolCall => !!toolCall.name);
3230
+ if (toolCalls.length === 0) {
3231
+ return;
3232
+ }
3233
+ await onToolCallsChunk(toolCalls);
3234
+ };
3235
+ const getMockOpenApiAssistantText = async (stream, onTextChunk, onToolCallsChunk, onDataEvent, onEventStreamFinished) => {
3236
+ const error = takeErrorResponse();
3237
+ if (error) {
3238
+ return error;
3239
+ }
3240
+ let text = '';
3241
+ let remainder = '';
3242
+ let toolCallAccumulator = {};
3243
+ let finishedNotified = false;
3244
+ const notifyFinished = async () => {
3245
+ if (finishedNotified) {
3246
+ return;
3247
+ }
3248
+ finishedNotified = true;
3249
+ if (onEventStreamFinished) {
3250
+ await onEventStreamFinished();
3251
+ }
3252
+ };
3253
+ const handleParsedSseEvent = async parsed => {
3254
+ if (onDataEvent) {
3255
+ await onDataEvent(parsed);
3256
+ }
3257
+ if (!parsed || typeof parsed !== 'object') {
3258
+ return;
3259
+ }
3260
+ const eventType = Reflect.get(parsed, 'type');
3261
+ if (eventType === 'response.completed') {
3262
+ await notifyFinished();
3263
+ return;
3264
+ }
3265
+ if (eventType === 'response.output_text.delta') {
3266
+ const delta = Reflect.get(parsed, 'delta');
3267
+ if (typeof delta !== 'string' || !delta) {
3268
+ return;
3269
+ }
3270
+ text += delta;
3271
+ if (stream && onTextChunk) {
3272
+ await onTextChunk(delta);
3273
+ }
3274
+ return;
3275
+ }
3276
+ if (eventType === 'response.output_item.added') {
3277
+ const outputIndex = Reflect.get(parsed, 'output_index');
3278
+ const item = Reflect.get(parsed, 'item');
3279
+ if (typeof outputIndex !== 'number' || !item || typeof item !== 'object') {
3280
+ return;
3281
+ }
3282
+ if (Reflect.get(item, 'type') !== 'function_call') {
3283
+ return;
3284
+ }
3285
+ const name = Reflect.get(item, 'name');
3286
+ const argumentsValue = Reflect.get(item, 'arguments');
3287
+ const callId = Reflect.get(item, 'call_id');
3288
+ toolCallAccumulator = {
3289
+ ...toolCallAccumulator,
3290
+ [outputIndex]: {
3291
+ arguments: typeof argumentsValue === 'string' ? argumentsValue : '',
3292
+ ...(typeof callId === 'string' ? {
3293
+ id: callId
3294
+ } : {}),
3295
+ name: typeof name === 'string' ? name : ''
3296
+ }
3297
+ };
3298
+ await emitToolCalls(toolCallAccumulator, onToolCallsChunk);
3299
+ return;
3300
+ }
3301
+ if (eventType === 'response.function_call_arguments.delta' || eventType === 'response.function_call_arguments.done') {
3302
+ const outputIndex = Reflect.get(parsed, 'output_index');
3303
+ if (typeof outputIndex !== 'number') {
3304
+ return;
3305
+ }
3306
+ const current = toolCallAccumulator[outputIndex] || {
3307
+ arguments: '',
3308
+ name: ''
3309
+ };
3310
+ const delta = Reflect.get(parsed, 'delta');
3311
+ const argumentsValue = Reflect.get(parsed, 'arguments');
3312
+ const name = Reflect.get(parsed, 'name');
3313
+ const callId = Reflect.get(parsed, 'call_id');
3314
+ const next = {
3315
+ arguments: typeof argumentsValue === 'string' ? argumentsValue : typeof delta === 'string' ? `${current.arguments}${delta}` : current.arguments,
3316
+ ...(typeof callId === 'string' ? {
3317
+ id: callId
3318
+ } : current.id ? {
3319
+ id: current.id
3320
+ } : {}),
3321
+ name: typeof name === 'string' && name ? name : current.name
3322
+ };
3323
+ toolCallAccumulator = {
3324
+ ...toolCallAccumulator,
3325
+ [outputIndex]: next
3326
+ };
3327
+ await emitToolCalls(toolCallAccumulator, onToolCallsChunk);
3328
+ }
3329
+ };
3330
+ const consumeSseDataLines = async dataLines => {
3331
+ for (const line of dataLines) {
3332
+ if (line === '[DONE]') {
3333
+ await notifyFinished();
3334
+ continue;
3451
3335
  }
3452
- },
3453
- type: 'function'
3454
- };
3455
- };
3456
- const getGetWorkspaceUriTool = () => {
3457
- return {
3458
- function: {
3459
- description: 'Get the URI of the currently open workspace folder.',
3460
- name: 'getWorkspaceUri',
3461
- parameters: {
3462
- additionalProperties: false,
3463
- properties: {},
3464
- type: 'object'
3336
+ let parsed;
3337
+ try {
3338
+ parsed = JSON.parse(line);
3339
+ } catch {
3340
+ continue;
3465
3341
  }
3466
- },
3467
- type: 'function'
3342
+ await handleParsedSseEvent(parsed);
3343
+ }
3468
3344
  };
3469
- };
3470
- const getRenderHtmlTool = () => {
3471
- return {
3472
- function: {
3473
- description: 'Render custom HTML and optional CSS directly in the chat tool call list using native chat UI rendering. Use this for structured cards, tables, and small dashboards. After calling this tool, do not repeat the same HTML, data table, or long content again as plain text unless the user explicitly asks for a text-only version.',
3474
- name: 'render_html',
3475
- parameters: {
3476
- additionalProperties: false,
3477
- properties: {
3478
- css: {
3479
- description: 'Optional CSS string applied inside the preview document.',
3480
- type: 'string'
3481
- },
3482
- html: {
3483
- description: 'HTML string to render in the preview document.',
3484
- type: 'string'
3485
- },
3486
- title: {
3487
- description: 'Optional short title for the preview.',
3488
- type: 'string'
3489
- }
3490
- },
3491
- required: ['html'],
3492
- type: 'object'
3345
+ while (true) {
3346
+ const chunk = await readNextChunk();
3347
+ if (typeof chunk !== 'string') {
3348
+ break;
3349
+ }
3350
+ if (chunk.startsWith('data:')) {
3351
+ remainder += chunk;
3352
+ while (true) {
3353
+ const separatorIndex = remainder.indexOf('\n\n');
3354
+ if (separatorIndex === -1) {
3355
+ break;
3356
+ }
3357
+ const rawEvent = remainder.slice(0, separatorIndex);
3358
+ remainder = remainder.slice(separatorIndex + 2);
3359
+ const dataLines = parseSseDataLines(rawEvent);
3360
+ await consumeSseDataLines(dataLines);
3493
3361
  }
3494
- },
3495
- type: 'function'
3362
+ continue;
3363
+ }
3364
+ text += chunk;
3365
+ if (stream && onTextChunk) {
3366
+ await onTextChunk(chunk);
3367
+ }
3368
+ }
3369
+ if (remainder) {
3370
+ const dataLines = parseSseDataLines(remainder);
3371
+ await consumeSseDataLines(dataLines);
3372
+ }
3373
+ await notifyFinished();
3374
+ return {
3375
+ text,
3376
+ type: 'success'
3496
3377
  };
3497
3378
  };
3498
- const getBasicChatTools = () => {
3499
- return [getReadFileTool(), getWriteFileTool(), getListFilesTool(), getGetWorkspaceUriTool(), getRenderHtmlTool()];
3379
+
3380
+ const normalizeLimitInfo = value => {
3381
+ if (!value || typeof value !== 'object') {
3382
+ return undefined;
3383
+ }
3384
+ const limitRemaining = Reflect.get(value, 'limitRemaining');
3385
+ const limitReset = Reflect.get(value, 'limitReset');
3386
+ const retryAfter = Reflect.get(value, 'retryAfter');
3387
+ const usage = Reflect.get(value, 'usage');
3388
+ const usageDaily = Reflect.get(value, 'usageDaily');
3389
+ const normalized = {
3390
+ ...(typeof limitRemaining === 'number' || limitRemaining === null ? {
3391
+ limitRemaining
3392
+ } : {}),
3393
+ ...(typeof limitReset === 'string' || limitReset === null ? {
3394
+ limitReset
3395
+ } : {}),
3396
+ ...(typeof retryAfter === 'string' || retryAfter === null ? {
3397
+ retryAfter
3398
+ } : {}),
3399
+ ...(typeof usage === 'number' ? {
3400
+ usage
3401
+ } : {}),
3402
+ ...(typeof usageDaily === 'number' ? {
3403
+ usageDaily
3404
+ } : {})
3405
+ };
3406
+ const hasDetails = typeof limitRemaining === 'number' || limitRemaining === null || typeof limitReset === 'string' || limitReset === null || typeof retryAfter === 'string' || retryAfter === null || typeof usage === 'number' || typeof usageDaily === 'number';
3407
+ return hasDetails ? normalized : undefined;
3500
3408
  };
3501
3409
 
3502
- const getClientRequestIdHeader = () => {
3410
+ const normalizeMockResult = value => {
3411
+ if (typeof value === 'string') {
3412
+ return {
3413
+ text: value,
3414
+ type: 'success'
3415
+ };
3416
+ }
3417
+ if (!value || typeof value !== 'object') {
3418
+ return {
3419
+ details: 'request-failed',
3420
+ type: 'error'
3421
+ };
3422
+ }
3423
+ const type = Reflect.get(value, 'type');
3424
+ if (type === 'success') {
3425
+ const text = Reflect.get(value, 'text');
3426
+ if (typeof text === 'string') {
3427
+ return {
3428
+ text,
3429
+ type: 'success'
3430
+ };
3431
+ }
3432
+ return {
3433
+ details: 'request-failed',
3434
+ type: 'error'
3435
+ };
3436
+ }
3437
+ if (type === 'error') {
3438
+ const details = Reflect.get(value, 'details');
3439
+ if (details === 'request-failed' || details === 'too-many-requests' || details === 'http-error') {
3440
+ const rawMessage = Reflect.get(value, 'rawMessage');
3441
+ const statusCode = Reflect.get(value, 'statusCode');
3442
+ const limitInfo = normalizeLimitInfo(Reflect.get(value, 'limitInfo'));
3443
+ return {
3444
+ details,
3445
+ ...(limitInfo ? {
3446
+ limitInfo
3447
+ } : {}),
3448
+ ...(typeof rawMessage === 'string' ? {
3449
+ rawMessage
3450
+ } : {}),
3451
+ ...(typeof statusCode === 'number' ? {
3452
+ statusCode
3453
+ } : {}),
3454
+ type: 'error'
3455
+ };
3456
+ }
3457
+ }
3458
+ const text = Reflect.get(value, 'text');
3459
+ if (typeof text === 'string') {
3460
+ return {
3461
+ text,
3462
+ type: 'success'
3463
+ };
3464
+ }
3503
3465
  return {
3504
- 'x-client-request-id': crypto.randomUUID()
3466
+ details: 'request-failed',
3467
+ type: 'error'
3505
3468
  };
3506
3469
  };
3507
3470
 
3471
+ const getMockOpenRouterAssistantText = async (messages, modelId, openRouterApiBaseUrl, openRouterApiKey, mockApiCommandId, assetDir, platform) => {
3472
+ if (!mockApiCommandId) {
3473
+ return {
3474
+ details: 'request-failed',
3475
+ type: 'error'
3476
+ };
3477
+ }
3478
+ try {
3479
+ const result = await executeProvider({
3480
+ assetDir,
3481
+ event: `onCommand:${mockApiCommandId}`,
3482
+ method: CommandExecute,
3483
+ noProviderFoundMessage: 'No mock api command found',
3484
+ params: [mockApiCommandId, {
3485
+ messages,
3486
+ modelId,
3487
+ openRouterApiBaseUrl,
3488
+ openRouterApiKey
3489
+ }],
3490
+ platform
3491
+ });
3492
+ return normalizeMockResult(result);
3493
+ } catch {
3494
+ return {
3495
+ details: 'request-failed',
3496
+ type: 'error'
3497
+ };
3498
+ }
3499
+ };
3500
+
3508
3501
  const getOpenApiApiEndpoint = openApiApiBaseUrl => {
3509
3502
  return `${openApiApiBaseUrl}/responses`;
3510
3503
  };
3511
3504
 
3505
+ const makeApiRequest = async options => {
3506
+ return invoke$2('ChatNetwork.makeApiRequest', options);
3507
+ };
3508
+ const makeStreamingApiRequest = async options => {
3509
+ return invoke$2('ChatNetwork.makeStreamingApiRequest', options);
3510
+ };
3511
+
3512
3512
  const getTextContent = content => {
3513
3513
  if (typeof content === 'string') {
3514
3514
  return content;
@@ -4933,6 +4933,17 @@ const isOpenRouterModel = (selectedModelId, models) => {
4933
4933
  return selectedModelId.toLowerCase().startsWith('openrouter/');
4934
4934
  };
4935
4935
 
4936
+ let requests = [];
4937
+ const reset$1 = () => {
4938
+ requests = [];
4939
+ };
4940
+ const capture = request => {
4941
+ requests = [...requests, request];
4942
+ };
4943
+ const getAll = () => {
4944
+ return requests;
4945
+ };
4946
+
4936
4947
  const getAiResponse = async ({
4937
4948
  assetDir,
4938
4949
  messageId,
@@ -4962,6 +4973,22 @@ const getAiResponse = async ({
4962
4973
  const usesOpenRouterModel = isOpenRouterModel(selectedModelId, models);
4963
4974
  if (usesOpenApiModel) {
4964
4975
  if (useMockApi) {
4976
+ const openAiInput = messages.map(message => ({
4977
+ content: message.text,
4978
+ role: message.role
4979
+ }));
4980
+ const modelId = getOpenApiModelId(selectedModelId);
4981
+ const headers = {
4982
+ Authorization: `Bearer ${openApiApiKey}`,
4983
+ 'Content-Type': 'application/json',
4984
+ ...getClientRequestIdHeader()
4985
+ };
4986
+ capture({
4987
+ headers,
4988
+ method: 'POST',
4989
+ payload: getOpenAiParams(openAiInput, modelId, streamingEnabled, passIncludeObfuscation, getBasicChatTools(), webSearchEnabled),
4990
+ url: getOpenApiApiEndpoint(openApiApiBaseUrl)
4991
+ });
4965
4992
  const result = await getMockOpenApiAssistantText(streamingEnabled, onTextChunk, onToolCallsChunk, onDataEvent, onEventStreamFinished);
4966
4993
  if (result.type === 'success') {
4967
4994
  const {
@@ -6484,6 +6511,15 @@ const loadContent = async (state, savedState) => {
6484
6511
  };
6485
6512
  };
6486
6513
 
6514
+ const mockOpenApiRequestGetAll = _state => {
6515
+ return getAll();
6516
+ };
6517
+
6518
+ const mockOpenApiRequestReset = state => {
6519
+ reset$1();
6520
+ return state;
6521
+ };
6522
+
6487
6523
  const mockOpenApiSetHttpErrorResponse = (state, statusCode, body) => {
6488
6524
  setHttpErrorResponse(statusCode, body);
6489
6525
  return state;
@@ -6500,7 +6536,7 @@ const mockOpenApiStreamPushChunk = (state, chunk) => {
6500
6536
  };
6501
6537
 
6502
6538
  const mockOpenApiStreamReset = state => {
6503
- reset$1();
6539
+ reset$2();
6504
6540
  return state;
6505
6541
  };
6506
6542
 
@@ -6539,7 +6575,7 @@ const openMockSession = async (state, mockSessionId, mockChatMessages) => {
6539
6575
  };
6540
6576
 
6541
6577
  const registerMockResponse = (state, mockResponse) => {
6542
- reset$1();
6578
+ reset$2();
6543
6579
  pushChunk(mockResponse.text);
6544
6580
  finish();
6545
6581
  return state;
@@ -6882,6 +6918,12 @@ const getInlineNodeDom = inlineNode => {
6882
6918
  type: Strong
6883
6919
  }, text(inlineNode.text)];
6884
6920
  }
6921
+ if (inlineNode.type === 'italic') {
6922
+ return [{
6923
+ childCount: 1,
6924
+ type: Em
6925
+ }, text(inlineNode.text)];
6926
+ }
6885
6927
  return [{
6886
6928
  childCount: 1,
6887
6929
  className: ChatMessageLink,
@@ -7547,7 +7589,7 @@ const getToolCallsDom = message => {
7547
7589
 
7548
7590
  const orderedListItemRegex = /^\s*\d+\.\s+(.*)$/;
7549
7591
  const unorderedListItemRegex = /^\s*[-*]\s+(.*)$/;
7550
- const markdownInlineRegex = /\[([^\]]+)\]\(([^)]+)\)|\*\*([^*]+)\*\*/g;
7592
+ const markdownInlineRegex = /\[([^\]]+)\]\(([^)]+)\)|\*\*([^*]+)\*\*|\*([^*]+)\*/g;
7551
7593
  const markdownTableSeparatorCellRegex = /^:?-{3,}:?$/;
7552
7594
  const fencedCodeBlockRegex = /^```/;
7553
7595
  const markdownHeadingRegex = /^\s*(#{1,6})\s+(.*)$/;
@@ -7610,6 +7652,7 @@ const parseInlineNodes = value => {
7610
7652
  const linkText = match[1];
7611
7653
  const href = match[2];
7612
7654
  const boldText = match[3];
7655
+ const italicText = match[4];
7613
7656
  const index = match.index ?? 0;
7614
7657
  if (index > lastIndex) {
7615
7658
  nodes.push({
@@ -7628,6 +7671,11 @@ const parseInlineNodes = value => {
7628
7671
  text: boldText,
7629
7672
  type: 'bold'
7630
7673
  });
7674
+ } else if (italicText) {
7675
+ nodes.push({
7676
+ text: italicText,
7677
+ type: 'italic'
7678
+ });
7631
7679
  }
7632
7680
  lastIndex = index + fullMatch.length;
7633
7681
  }
@@ -8282,6 +8330,8 @@ const commandMap = {
8282
8330
  'Chat.initialize': initialize,
8283
8331
  'Chat.loadContent': wrapCommand(loadContent),
8284
8332
  'Chat.loadContent2': wrapCommand(loadContent),
8333
+ 'Chat.mockOpenApiRequestGetAll': wrapGetter(mockOpenApiRequestGetAll),
8334
+ 'Chat.mockOpenApiRequestReset': wrapCommand(mockOpenApiRequestReset),
8285
8335
  'Chat.mockOpenApiSetHttpErrorResponse': wrapCommand(mockOpenApiSetHttpErrorResponse),
8286
8336
  'Chat.mockOpenApiStreamFinish': wrapCommand(mockOpenApiStreamFinish),
8287
8337
  'Chat.mockOpenApiStreamPushChunk': wrapCommand(mockOpenApiStreamPushChunk),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/chat-view",
3
- "version": "3.7.0",
3
+ "version": "3.9.0",
4
4
  "description": "Chat View Worker",
5
5
  "repository": {
6
6
  "type": "git",