@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.
- package/dist/chatViewWorkerMain.js +521 -471
- package/package.json +1 -1
|
@@ -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: '
|
|
3396
|
-
name: '
|
|
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
|
|
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
|
|
3084
|
+
const getGetWorkspaceUriTool = () => {
|
|
3413
3085
|
return {
|
|
3414
3086
|
function: {
|
|
3415
|
-
description: '
|
|
3416
|
-
name: '
|
|
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
|
-
|
|
3421
|
-
description: '
|
|
3106
|
+
css: {
|
|
3107
|
+
description: 'Optional CSS string applied inside the preview document.',
|
|
3422
3108
|
type: 'string'
|
|
3423
3109
|
},
|
|
3424
|
-
|
|
3425
|
-
description: '
|
|
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: ['
|
|
3119
|
+
required: ['html'],
|
|
3430
3120
|
type: 'object'
|
|
3431
3121
|
}
|
|
3432
3122
|
},
|
|
3433
3123
|
type: 'function'
|
|
3434
3124
|
};
|
|
3435
|
-
};
|
|
3436
|
-
const
|
|
3437
|
-
return
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
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
|
-
|
|
3454
|
-
|
|
3455
|
-
}
|
|
3456
|
-
|
|
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
|
-
|
|
3342
|
+
await handleParsedSseEvent(parsed);
|
|
3343
|
+
}
|
|
3468
3344
|
};
|
|
3469
|
-
|
|
3470
|
-
const
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3499
|
-
|
|
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
|
|
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
|
-
'
|
|
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$
|
|
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;
|
|
@@ -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 = /\[([^\]]+)\]\(([^)]+)\)|\*\*([^*]+)
|
|
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),
|