@lvce-editor/chat-view 3.7.0 → 3.8.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.
- package/dist/chatViewWorkerMain.js +576 -538
- package/package.json +1 -1
|
@@ -2792,109 +2792,450 @@ 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
|
|
2796
|
-
|
|
2795
|
+
const executeGetWorkspaceUriTool = async (_args, _options) => {
|
|
2796
|
+
try {
|
|
2797
|
+
const workspaceUri = await getWorkspacePath();
|
|
2798
|
+
return JSON.stringify({
|
|
2799
|
+
workspaceUri
|
|
2800
|
+
});
|
|
2801
|
+
} catch (error) {
|
|
2802
|
+
return JSON.stringify({
|
|
2803
|
+
error: String(error)
|
|
2804
|
+
});
|
|
2805
|
+
}
|
|
2797
2806
|
};
|
|
2798
2807
|
|
|
2799
|
-
const
|
|
2800
|
-
|
|
2801
|
-
|
|
2808
|
+
const isAbsoluteUri$1 = value => {
|
|
2809
|
+
return /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(value);
|
|
2810
|
+
};
|
|
2811
|
+
const executeListFilesTool = async (args, _options) => {
|
|
2812
|
+
const uri = typeof args.uri === 'string' ? args.uri : '';
|
|
2813
|
+
if (!uri || !isAbsoluteUri$1(uri)) {
|
|
2814
|
+
return JSON.stringify({
|
|
2815
|
+
error: 'Invalid argument: uri must be an absolute URI.'
|
|
2816
|
+
});
|
|
2817
|
+
}
|
|
2818
|
+
try {
|
|
2819
|
+
const entries = await invoke('FileSystem.readDirWithFileTypes', uri);
|
|
2820
|
+
return JSON.stringify({
|
|
2821
|
+
entries,
|
|
2822
|
+
uri
|
|
2823
|
+
});
|
|
2824
|
+
} catch (error) {
|
|
2825
|
+
return JSON.stringify({
|
|
2826
|
+
error: String(error),
|
|
2827
|
+
uri
|
|
2828
|
+
});
|
|
2829
|
+
}
|
|
2802
2830
|
};
|
|
2803
2831
|
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2832
|
+
const isPathTraversalAttempt = path => {
|
|
2833
|
+
if (!path) {
|
|
2834
|
+
return false;
|
|
2835
|
+
}
|
|
2836
|
+
if (path.startsWith('/') || path.startsWith('\\')) {
|
|
2837
|
+
return true;
|
|
2838
|
+
}
|
|
2839
|
+
if (path.startsWith('file://')) {
|
|
2840
|
+
return true;
|
|
2841
|
+
}
|
|
2842
|
+
if (/^[a-zA-Z]:[\\/]/.test(path)) {
|
|
2843
|
+
return true;
|
|
2844
|
+
}
|
|
2845
|
+
const segments = path.split(/[\\/]/);
|
|
2846
|
+
return segments.includes('..');
|
|
2813
2847
|
};
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
const
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
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
|
-
};
|
|
2848
|
+
|
|
2849
|
+
const normalizeRelativePath = path => {
|
|
2850
|
+
const segments = path.split(/[\\/]/).filter(segment => segment && segment !== '.');
|
|
2851
|
+
if (segments.length === 0) {
|
|
2852
|
+
return '.';
|
|
2853
|
+
}
|
|
2854
|
+
return segments.join('/');
|
|
2833
2855
|
};
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
return error;
|
|
2856
|
+
|
|
2857
|
+
const isAbsoluteUri = value => {
|
|
2858
|
+
return /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(value);
|
|
2838
2859
|
};
|
|
2839
|
-
const
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2860
|
+
const executeReadFileTool = async (args, _options) => {
|
|
2861
|
+
const uri = typeof args.uri === 'string' ? args.uri : '';
|
|
2862
|
+
if (uri) {
|
|
2863
|
+
if (!isAbsoluteUri(uri)) {
|
|
2864
|
+
return JSON.stringify({
|
|
2865
|
+
error: 'Invalid argument: uri must be an absolute URI.'
|
|
2866
|
+
});
|
|
2867
|
+
}
|
|
2868
|
+
try {
|
|
2869
|
+
const content = await readFile(uri);
|
|
2870
|
+
return JSON.stringify({
|
|
2871
|
+
content,
|
|
2872
|
+
uri
|
|
2873
|
+
});
|
|
2874
|
+
} catch (error) {
|
|
2875
|
+
return JSON.stringify({
|
|
2876
|
+
error: String(error),
|
|
2877
|
+
uri
|
|
2878
|
+
});
|
|
2879
|
+
}
|
|
2844
2880
|
}
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
return;
|
|
2881
|
+
const filePath = typeof args.path === 'string' ? args.path : '';
|
|
2882
|
+
if (!filePath || isPathTraversalAttempt(filePath)) {
|
|
2883
|
+
return JSON.stringify({
|
|
2884
|
+
error: 'Access denied: path must be relative and stay within the open workspace folder.'
|
|
2885
|
+
});
|
|
2851
2886
|
}
|
|
2852
|
-
const
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2887
|
+
const normalizedPath = normalizeRelativePath(filePath);
|
|
2888
|
+
try {
|
|
2889
|
+
const content = await readFile(normalizedPath);
|
|
2890
|
+
return JSON.stringify({
|
|
2891
|
+
content,
|
|
2892
|
+
path: normalizedPath
|
|
2893
|
+
});
|
|
2894
|
+
} catch (error) {
|
|
2895
|
+
return JSON.stringify({
|
|
2896
|
+
error: String(error),
|
|
2897
|
+
path: normalizedPath
|
|
2898
|
+
});
|
|
2856
2899
|
}
|
|
2857
2900
|
};
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2901
|
+
|
|
2902
|
+
const maxPayloadLength = 40_000;
|
|
2903
|
+
const executeRenderHtmlTool = async (args, _options) => {
|
|
2904
|
+
const html = typeof args.html === 'string' ? args.html : '';
|
|
2905
|
+
const css = typeof args.css === 'string' ? args.css : '';
|
|
2906
|
+
const title = typeof args.title === 'string' ? args.title : '';
|
|
2907
|
+
if (!html) {
|
|
2908
|
+
return JSON.stringify({
|
|
2909
|
+
error: 'Missing required argument: html'
|
|
2910
|
+
});
|
|
2861
2911
|
}
|
|
2862
|
-
if (
|
|
2863
|
-
return
|
|
2912
|
+
if (html.length > maxPayloadLength || css.length > maxPayloadLength) {
|
|
2913
|
+
return JSON.stringify({
|
|
2914
|
+
error: 'Payload too large: keep html/css under 40,000 characters each.'
|
|
2915
|
+
});
|
|
2864
2916
|
}
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2917
|
+
return JSON.stringify({
|
|
2918
|
+
css,
|
|
2919
|
+
html,
|
|
2920
|
+
ok: true,
|
|
2921
|
+
title
|
|
2922
|
+
});
|
|
2871
2923
|
};
|
|
2872
2924
|
|
|
2873
|
-
const
|
|
2874
|
-
|
|
2875
|
-
|
|
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;
|
|
2925
|
+
const activateByEvent = (event, assetDir, platform) => {
|
|
2926
|
+
// @ts-ignore
|
|
2927
|
+
return activateByEvent$1(event, assetDir, platform);
|
|
2883
2928
|
};
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
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
|
+
|
|
2944
|
+
const OnFileSystem = 'onFileSystem';
|
|
2945
|
+
|
|
2946
|
+
const executeFileSystemCommand = async (method, params, options) => {
|
|
2947
|
+
return executeProvider({
|
|
2948
|
+
assetDir: options.assetDir,
|
|
2949
|
+
event: OnFileSystem,
|
|
2950
|
+
method,
|
|
2951
|
+
noProviderFoundMessage: 'No file system provider found',
|
|
2952
|
+
params,
|
|
2953
|
+
platform: options.platform
|
|
2954
|
+
});
|
|
2955
|
+
};
|
|
2956
|
+
|
|
2957
|
+
const CommandExecute = 'ExtensionHostCommand.executeCommand';
|
|
2958
|
+
const FileSystemWriteFile = 'ExtensionHostFileSystem.writeFile';
|
|
2959
|
+
|
|
2960
|
+
const executeWriteFileTool = async (args, options) => {
|
|
2961
|
+
const filePath = typeof args.path === 'string' ? args.path : '';
|
|
2962
|
+
const content = typeof args.content === 'string' ? args.content : '';
|
|
2963
|
+
if (!filePath || isPathTraversalAttempt(filePath)) {
|
|
2964
|
+
return JSON.stringify({
|
|
2965
|
+
error: 'Access denied: path must be relative and stay within the open workspace folder.'
|
|
2966
|
+
});
|
|
2887
2967
|
}
|
|
2888
|
-
const
|
|
2889
|
-
|
|
2890
|
-
|
|
2968
|
+
const normalizedPath = normalizeRelativePath(filePath);
|
|
2969
|
+
try {
|
|
2970
|
+
await executeFileSystemCommand(FileSystemWriteFile, ['file', normalizedPath, content], options);
|
|
2971
|
+
return JSON.stringify({
|
|
2972
|
+
ok: true,
|
|
2973
|
+
path: normalizedPath
|
|
2974
|
+
});
|
|
2975
|
+
} catch (error) {
|
|
2976
|
+
return JSON.stringify({
|
|
2977
|
+
error: String(error),
|
|
2978
|
+
path: normalizedPath
|
|
2979
|
+
});
|
|
2891
2980
|
}
|
|
2892
|
-
await onToolCallsChunk(toolCalls);
|
|
2893
2981
|
};
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
if (
|
|
2897
|
-
return
|
|
2982
|
+
|
|
2983
|
+
const parseToolArguments = rawArguments => {
|
|
2984
|
+
if (typeof rawArguments !== 'string') {
|
|
2985
|
+
return {};
|
|
2986
|
+
}
|
|
2987
|
+
try {
|
|
2988
|
+
const parsed = JSON.parse(rawArguments);
|
|
2989
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
2990
|
+
return {};
|
|
2991
|
+
}
|
|
2992
|
+
return parsed;
|
|
2993
|
+
} catch {
|
|
2994
|
+
return {};
|
|
2995
|
+
}
|
|
2996
|
+
};
|
|
2997
|
+
|
|
2998
|
+
const executeChatTool = async (name, rawArguments, options) => {
|
|
2999
|
+
const args = parseToolArguments(rawArguments);
|
|
3000
|
+
if (name === 'read_file') {
|
|
3001
|
+
return executeReadFileTool(args);
|
|
3002
|
+
}
|
|
3003
|
+
if (name === 'write_file') {
|
|
3004
|
+
return executeWriteFileTool(args, options);
|
|
3005
|
+
}
|
|
3006
|
+
if (name === 'list_files') {
|
|
3007
|
+
return executeListFilesTool(args);
|
|
3008
|
+
}
|
|
3009
|
+
if (name === 'getWorkspaceUri') {
|
|
3010
|
+
return executeGetWorkspaceUriTool();
|
|
3011
|
+
}
|
|
3012
|
+
if (name === 'render_html') {
|
|
3013
|
+
return executeRenderHtmlTool(args);
|
|
3014
|
+
}
|
|
3015
|
+
return JSON.stringify({
|
|
3016
|
+
error: `Unknown tool: ${name}`
|
|
3017
|
+
});
|
|
3018
|
+
};
|
|
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 = () => {
|
|
3065
|
+
return {
|
|
3066
|
+
function: {
|
|
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',
|
|
3069
|
+
parameters: {
|
|
3070
|
+
additionalProperties: false,
|
|
3071
|
+
properties: {
|
|
3072
|
+
uri: {
|
|
3073
|
+
description: 'Absolute folder URI within the workspace (for example: file:///workspace/src).',
|
|
3074
|
+
type: 'string'
|
|
3075
|
+
}
|
|
3076
|
+
},
|
|
3077
|
+
required: ['uri'],
|
|
3078
|
+
type: 'object'
|
|
3079
|
+
}
|
|
3080
|
+
},
|
|
3081
|
+
type: 'function'
|
|
3082
|
+
};
|
|
3083
|
+
};
|
|
3084
|
+
const getGetWorkspaceUriTool = () => {
|
|
3085
|
+
return {
|
|
3086
|
+
function: {
|
|
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',
|
|
3103
|
+
parameters: {
|
|
3104
|
+
additionalProperties: false,
|
|
3105
|
+
properties: {
|
|
3106
|
+
css: {
|
|
3107
|
+
description: 'Optional CSS string applied inside the preview document.',
|
|
3108
|
+
type: 'string'
|
|
3109
|
+
},
|
|
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.',
|
|
3116
|
+
type: 'string'
|
|
3117
|
+
}
|
|
3118
|
+
},
|
|
3119
|
+
required: ['html'],
|
|
3120
|
+
type: 'object'
|
|
3121
|
+
}
|
|
3122
|
+
},
|
|
3123
|
+
type: 'function'
|
|
3124
|
+
};
|
|
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;
|
|
2898
3239
|
}
|
|
2899
3240
|
let text = '';
|
|
2900
3241
|
let remainder = '';
|
|
@@ -3036,479 +3377,138 @@ const getMockOpenApiAssistantText = async (stream, onTextChunk, onToolCallsChunk
|
|
|
3036
3377
|
};
|
|
3037
3378
|
};
|
|
3038
3379
|
|
|
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
3380
|
const normalizeLimitInfo = value => {
|
|
3062
3381
|
if (!value || typeof value !== 'object') {
|
|
3063
3382
|
return undefined;
|
|
3064
3383
|
}
|
|
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
|
-
const executeGetWorkspaceUriTool = async (_args, _options) => {
|
|
3190
|
-
try {
|
|
3191
|
-
const workspaceUri = await getWorkspacePath();
|
|
3192
|
-
return JSON.stringify({
|
|
3193
|
-
workspaceUri
|
|
3194
|
-
});
|
|
3195
|
-
} catch (error) {
|
|
3196
|
-
return JSON.stringify({
|
|
3197
|
-
error: String(error)
|
|
3198
|
-
});
|
|
3199
|
-
}
|
|
3200
|
-
};
|
|
3201
|
-
|
|
3202
|
-
const isAbsoluteUri$1 = value => {
|
|
3203
|
-
return /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(value);
|
|
3204
|
-
};
|
|
3205
|
-
const executeListFilesTool = async (args, _options) => {
|
|
3206
|
-
const uri = typeof args.uri === 'string' ? args.uri : '';
|
|
3207
|
-
if (!uri || !isAbsoluteUri$1(uri)) {
|
|
3208
|
-
return JSON.stringify({
|
|
3209
|
-
error: 'Invalid argument: uri must be an absolute URI.'
|
|
3210
|
-
});
|
|
3211
|
-
}
|
|
3212
|
-
try {
|
|
3213
|
-
const entries = await invoke('FileSystem.readDirWithFileTypes', uri);
|
|
3214
|
-
return JSON.stringify({
|
|
3215
|
-
entries,
|
|
3216
|
-
uri
|
|
3217
|
-
});
|
|
3218
|
-
} catch (error) {
|
|
3219
|
-
return JSON.stringify({
|
|
3220
|
-
error: String(error),
|
|
3221
|
-
uri
|
|
3222
|
-
});
|
|
3223
|
-
}
|
|
3224
|
-
};
|
|
3225
|
-
|
|
3226
|
-
const isPathTraversalAttempt = path => {
|
|
3227
|
-
if (!path) {
|
|
3228
|
-
return false;
|
|
3229
|
-
}
|
|
3230
|
-
if (path.startsWith('/') || path.startsWith('\\')) {
|
|
3231
|
-
return true;
|
|
3232
|
-
}
|
|
3233
|
-
if (path.startsWith('file://')) {
|
|
3234
|
-
return true;
|
|
3235
|
-
}
|
|
3236
|
-
if (/^[a-zA-Z]:[\\/]/.test(path)) {
|
|
3237
|
-
return true;
|
|
3238
|
-
}
|
|
3239
|
-
const segments = path.split(/[\\/]/);
|
|
3240
|
-
return segments.includes('..');
|
|
3241
|
-
};
|
|
3242
|
-
|
|
3243
|
-
const normalizeRelativePath = path => {
|
|
3244
|
-
const segments = path.split(/[\\/]/).filter(segment => segment && segment !== '.');
|
|
3245
|
-
if (segments.length === 0) {
|
|
3246
|
-
return '.';
|
|
3247
|
-
}
|
|
3248
|
-
return segments.join('/');
|
|
3249
|
-
};
|
|
3250
|
-
|
|
3251
|
-
const isAbsoluteUri = value => {
|
|
3252
|
-
return /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(value);
|
|
3253
|
-
};
|
|
3254
|
-
const executeReadFileTool = async (args, _options) => {
|
|
3255
|
-
const uri = typeof args.uri === 'string' ? args.uri : '';
|
|
3256
|
-
if (uri) {
|
|
3257
|
-
if (!isAbsoluteUri(uri)) {
|
|
3258
|
-
return JSON.stringify({
|
|
3259
|
-
error: 'Invalid argument: uri must be an absolute URI.'
|
|
3260
|
-
});
|
|
3261
|
-
}
|
|
3262
|
-
try {
|
|
3263
|
-
const content = await readFile(uri);
|
|
3264
|
-
return JSON.stringify({
|
|
3265
|
-
content,
|
|
3266
|
-
uri
|
|
3267
|
-
});
|
|
3268
|
-
} catch (error) {
|
|
3269
|
-
return JSON.stringify({
|
|
3270
|
-
error: String(error),
|
|
3271
|
-
uri
|
|
3272
|
-
});
|
|
3273
|
-
}
|
|
3274
|
-
}
|
|
3275
|
-
const filePath = typeof args.path === 'string' ? args.path : '';
|
|
3276
|
-
if (!filePath || isPathTraversalAttempt(filePath)) {
|
|
3277
|
-
return JSON.stringify({
|
|
3278
|
-
error: 'Access denied: path must be relative and stay within the open workspace folder.'
|
|
3279
|
-
});
|
|
3280
|
-
}
|
|
3281
|
-
const normalizedPath = normalizeRelativePath(filePath);
|
|
3282
|
-
try {
|
|
3283
|
-
const content = await readFile(normalizedPath);
|
|
3284
|
-
return JSON.stringify({
|
|
3285
|
-
content,
|
|
3286
|
-
path: normalizedPath
|
|
3287
|
-
});
|
|
3288
|
-
} catch (error) {
|
|
3289
|
-
return JSON.stringify({
|
|
3290
|
-
error: String(error),
|
|
3291
|
-
path: normalizedPath
|
|
3292
|
-
});
|
|
3293
|
-
}
|
|
3294
|
-
};
|
|
3295
|
-
|
|
3296
|
-
const maxPayloadLength = 40_000;
|
|
3297
|
-
const executeRenderHtmlTool = async (args, _options) => {
|
|
3298
|
-
const html = typeof args.html === 'string' ? args.html : '';
|
|
3299
|
-
const css = typeof args.css === 'string' ? args.css : '';
|
|
3300
|
-
const title = typeof args.title === 'string' ? args.title : '';
|
|
3301
|
-
if (!html) {
|
|
3302
|
-
return JSON.stringify({
|
|
3303
|
-
error: 'Missing required argument: html'
|
|
3304
|
-
});
|
|
3305
|
-
}
|
|
3306
|
-
if (html.length > maxPayloadLength || css.length > maxPayloadLength) {
|
|
3307
|
-
return JSON.stringify({
|
|
3308
|
-
error: 'Payload too large: keep html/css under 40,000 characters each.'
|
|
3309
|
-
});
|
|
3310
|
-
}
|
|
3311
|
-
return JSON.stringify({
|
|
3312
|
-
css,
|
|
3313
|
-
html,
|
|
3314
|
-
ok: true,
|
|
3315
|
-
title
|
|
3316
|
-
});
|
|
3317
|
-
};
|
|
3318
|
-
|
|
3319
|
-
const OnFileSystem = 'onFileSystem';
|
|
3320
|
-
|
|
3321
|
-
const executeFileSystemCommand = async (method, params, options) => {
|
|
3322
|
-
return executeProvider({
|
|
3323
|
-
assetDir: options.assetDir,
|
|
3324
|
-
event: OnFileSystem,
|
|
3325
|
-
method,
|
|
3326
|
-
noProviderFoundMessage: 'No file system provider found',
|
|
3327
|
-
params,
|
|
3328
|
-
platform: options.platform
|
|
3329
|
-
});
|
|
3330
|
-
};
|
|
3331
|
-
|
|
3332
|
-
const executeWriteFileTool = async (args, options) => {
|
|
3333
|
-
const filePath = typeof args.path === 'string' ? args.path : '';
|
|
3334
|
-
const content = typeof args.content === 'string' ? args.content : '';
|
|
3335
|
-
if (!filePath || isPathTraversalAttempt(filePath)) {
|
|
3336
|
-
return JSON.stringify({
|
|
3337
|
-
error: 'Access denied: path must be relative and stay within the open workspace folder.'
|
|
3338
|
-
});
|
|
3339
|
-
}
|
|
3340
|
-
const normalizedPath = normalizeRelativePath(filePath);
|
|
3341
|
-
try {
|
|
3342
|
-
await executeFileSystemCommand(FileSystemWriteFile, ['file', normalizedPath, content], options);
|
|
3343
|
-
return JSON.stringify({
|
|
3344
|
-
ok: true,
|
|
3345
|
-
path: normalizedPath
|
|
3346
|
-
});
|
|
3347
|
-
} catch (error) {
|
|
3348
|
-
return JSON.stringify({
|
|
3349
|
-
error: String(error),
|
|
3350
|
-
path: normalizedPath
|
|
3351
|
-
});
|
|
3352
|
-
}
|
|
3353
|
-
};
|
|
3354
|
-
|
|
3355
|
-
const parseToolArguments = rawArguments => {
|
|
3356
|
-
if (typeof rawArguments !== 'string') {
|
|
3357
|
-
return {};
|
|
3358
|
-
}
|
|
3359
|
-
try {
|
|
3360
|
-
const parsed = JSON.parse(rawArguments);
|
|
3361
|
-
if (!parsed || typeof parsed !== 'object') {
|
|
3362
|
-
return {};
|
|
3363
|
-
}
|
|
3364
|
-
return parsed;
|
|
3365
|
-
} catch {
|
|
3366
|
-
return {};
|
|
3367
|
-
}
|
|
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;
|
|
3368
3408
|
};
|
|
3369
3409
|
|
|
3370
|
-
const
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3410
|
+
const normalizeMockResult = value => {
|
|
3411
|
+
if (typeof value === 'string') {
|
|
3412
|
+
return {
|
|
3413
|
+
text: value,
|
|
3414
|
+
type: 'success'
|
|
3415
|
+
};
|
|
3374
3416
|
}
|
|
3375
|
-
if (
|
|
3376
|
-
return
|
|
3417
|
+
if (!value || typeof value !== 'object') {
|
|
3418
|
+
return {
|
|
3419
|
+
details: 'request-failed',
|
|
3420
|
+
type: 'error'
|
|
3421
|
+
};
|
|
3377
3422
|
}
|
|
3378
|
-
|
|
3379
|
-
|
|
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
|
+
};
|
|
3380
3436
|
}
|
|
3381
|
-
if (
|
|
3382
|
-
|
|
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
|
+
}
|
|
3383
3457
|
}
|
|
3384
|
-
|
|
3385
|
-
|
|
3458
|
+
const text = Reflect.get(value, 'text');
|
|
3459
|
+
if (typeof text === 'string') {
|
|
3460
|
+
return {
|
|
3461
|
+
text,
|
|
3462
|
+
type: 'success'
|
|
3463
|
+
};
|
|
3386
3464
|
}
|
|
3387
|
-
return JSON.stringify({
|
|
3388
|
-
error: `Unknown tool: ${name}`
|
|
3389
|
-
});
|
|
3390
|
-
};
|
|
3391
|
-
|
|
3392
|
-
const getReadFileTool = () => {
|
|
3393
|
-
return {
|
|
3394
|
-
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',
|
|
3397
|
-
parameters: {
|
|
3398
|
-
additionalProperties: false,
|
|
3399
|
-
properties: {
|
|
3400
|
-
uri: {
|
|
3401
|
-
description: 'Absolute file URI within the workspace (for example: file:///workspace/src/index.ts).',
|
|
3402
|
-
type: 'string'
|
|
3403
|
-
}
|
|
3404
|
-
},
|
|
3405
|
-
required: ['uri'],
|
|
3406
|
-
type: 'object'
|
|
3407
|
-
}
|
|
3408
|
-
},
|
|
3409
|
-
type: 'function'
|
|
3410
|
-
};
|
|
3411
|
-
};
|
|
3412
|
-
const getWriteFileTool = () => {
|
|
3413
|
-
return {
|
|
3414
|
-
function: {
|
|
3415
|
-
description: 'Write UTF-8 text content to a file inside the currently open workspace folder.',
|
|
3416
|
-
name: 'write_file',
|
|
3417
|
-
parameters: {
|
|
3418
|
-
additionalProperties: false,
|
|
3419
|
-
properties: {
|
|
3420
|
-
content: {
|
|
3421
|
-
description: 'New UTF-8 text content to write to the file.',
|
|
3422
|
-
type: 'string'
|
|
3423
|
-
},
|
|
3424
|
-
path: {
|
|
3425
|
-
description: 'Relative file path within the workspace (for example: src/index.ts).',
|
|
3426
|
-
type: 'string'
|
|
3427
|
-
}
|
|
3428
|
-
},
|
|
3429
|
-
required: ['path', 'content'],
|
|
3430
|
-
type: 'object'
|
|
3431
|
-
}
|
|
3432
|
-
},
|
|
3433
|
-
type: 'function'
|
|
3434
|
-
};
|
|
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'
|
|
3451
|
-
}
|
|
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'
|
|
3465
|
-
}
|
|
3466
|
-
},
|
|
3467
|
-
type: 'function'
|
|
3468
|
-
};
|
|
3469
|
-
};
|
|
3470
|
-
const getRenderHtmlTool = () => {
|
|
3471
3465
|
return {
|
|
3472
|
-
|
|
3473
|
-
|
|
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'
|
|
3493
|
-
}
|
|
3494
|
-
},
|
|
3495
|
-
type: 'function'
|
|
3466
|
+
details: 'request-failed',
|
|
3467
|
+
type: 'error'
|
|
3496
3468
|
};
|
|
3497
3469
|
};
|
|
3498
|
-
const getBasicChatTools = () => {
|
|
3499
|
-
return [getReadFileTool(), getWriteFileTool(), getListFilesTool(), getGetWorkspaceUriTool(), getRenderHtmlTool()];
|
|
3500
|
-
};
|
|
3501
3470
|
|
|
3502
|
-
const
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
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
|
+
}
|
|
3506
3499
|
};
|
|
3507
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$
|
|
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$
|
|
6578
|
+
reset$2();
|
|
6543
6579
|
pushChunk(mockResponse.text);
|
|
6544
6580
|
finish();
|
|
6545
6581
|
return state;
|
|
@@ -8282,6 +8318,8 @@ const commandMap = {
|
|
|
8282
8318
|
'Chat.initialize': initialize,
|
|
8283
8319
|
'Chat.loadContent': wrapCommand(loadContent),
|
|
8284
8320
|
'Chat.loadContent2': wrapCommand(loadContent),
|
|
8321
|
+
'Chat.mockOpenApiRequestGetAll': wrapGetter(mockOpenApiRequestGetAll),
|
|
8322
|
+
'Chat.mockOpenApiRequestReset': wrapCommand(mockOpenApiRequestReset),
|
|
8285
8323
|
'Chat.mockOpenApiSetHttpErrorResponse': wrapCommand(mockOpenApiSetHttpErrorResponse),
|
|
8286
8324
|
'Chat.mockOpenApiStreamFinish': wrapCommand(mockOpenApiStreamFinish),
|
|
8287
8325
|
'Chat.mockOpenApiStreamPushChunk': wrapCommand(mockOpenApiStreamPushChunk),
|