@lvce-editor/chat-view 2.2.0 → 2.4.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 +543 -247
- package/package.json +1 -1
|
@@ -1478,6 +1478,7 @@ const createDefaultState = () => {
|
|
|
1478
1478
|
listItemHeight: 40,
|
|
1479
1479
|
maxComposerRows: 5,
|
|
1480
1480
|
messagesScrollTop: 0,
|
|
1481
|
+
mockAiResponseDelay: 800,
|
|
1481
1482
|
mockApiCommandId: '',
|
|
1482
1483
|
models: getDefaultModels(),
|
|
1483
1484
|
nextMessageId: 1,
|
|
@@ -2138,10 +2139,14 @@ const replaySession$1 = (id, summary, events) => {
|
|
|
2138
2139
|
}
|
|
2139
2140
|
return {
|
|
2140
2141
|
...message,
|
|
2141
|
-
inProgress:
|
|
2142
|
+
...(event.inProgress === undefined ? {} : {
|
|
2143
|
+
inProgress: event.inProgress
|
|
2144
|
+
}),
|
|
2142
2145
|
text: event.text,
|
|
2143
2146
|
time: event.time,
|
|
2144
|
-
toolCalls:
|
|
2147
|
+
...(event.toolCalls === undefined ? {} : {
|
|
2148
|
+
toolCalls: event.toolCalls
|
|
2149
|
+
})
|
|
2145
2150
|
};
|
|
2146
2151
|
});
|
|
2147
2152
|
continue;
|
|
@@ -2439,10 +2444,14 @@ const replaySession = (id, title, events) => {
|
|
|
2439
2444
|
}
|
|
2440
2445
|
return {
|
|
2441
2446
|
...message,
|
|
2442
|
-
inProgress:
|
|
2447
|
+
...(event.inProgress === undefined ? {} : {
|
|
2448
|
+
inProgress: event.inProgress
|
|
2449
|
+
}),
|
|
2443
2450
|
text: event.text,
|
|
2444
2451
|
time: event.time,
|
|
2445
|
-
toolCalls:
|
|
2452
|
+
...(event.toolCalls === undefined ? {} : {
|
|
2453
|
+
toolCalls: event.toolCalls
|
|
2454
|
+
})
|
|
2446
2455
|
};
|
|
2447
2456
|
});
|
|
2448
2457
|
continue;
|
|
@@ -2656,18 +2665,45 @@ const delay = async ms => {
|
|
|
2656
2665
|
await new Promise(resolve => setTimeout(resolve, ms));
|
|
2657
2666
|
};
|
|
2658
2667
|
|
|
2659
|
-
const getMockAiResponse = async userMessage => {
|
|
2660
|
-
await delay(
|
|
2668
|
+
const getMockAiResponse = async (userMessage, delayInMs) => {
|
|
2669
|
+
await delay(delayInMs);
|
|
2661
2670
|
return `Mock AI response: I received "${userMessage}".`;
|
|
2662
2671
|
};
|
|
2663
2672
|
|
|
2664
2673
|
let queue = [];
|
|
2665
2674
|
let waiters = [];
|
|
2666
2675
|
let finished = false;
|
|
2676
|
+
let errorResult;
|
|
2667
2677
|
const reset$1 = () => {
|
|
2668
2678
|
queue = [];
|
|
2669
2679
|
waiters = [];
|
|
2670
2680
|
finished = false;
|
|
2681
|
+
errorResult = undefined;
|
|
2682
|
+
};
|
|
2683
|
+
const setHttpErrorResponse = (statusCode, body) => {
|
|
2684
|
+
const rawError = body && typeof body === 'object' ? Reflect.get(body, 'error') : undefined;
|
|
2685
|
+
const errorCode = rawError && typeof rawError === 'object' ? Reflect.get(rawError, 'code') : undefined;
|
|
2686
|
+
const errorMessage = rawError && typeof rawError === 'object' ? Reflect.get(rawError, 'message') : undefined;
|
|
2687
|
+
const errorType = rawError && typeof rawError === 'object' ? Reflect.get(rawError, 'type') : undefined;
|
|
2688
|
+
errorResult = {
|
|
2689
|
+
details: 'http-error',
|
|
2690
|
+
...(typeof errorCode === 'string' ? {
|
|
2691
|
+
errorCode
|
|
2692
|
+
} : {}),
|
|
2693
|
+
...(typeof errorMessage === 'string' ? {
|
|
2694
|
+
errorMessage
|
|
2695
|
+
} : {}),
|
|
2696
|
+
...(typeof errorType === 'string' ? {
|
|
2697
|
+
errorType
|
|
2698
|
+
} : {}),
|
|
2699
|
+
statusCode,
|
|
2700
|
+
type: 'error'
|
|
2701
|
+
};
|
|
2702
|
+
};
|
|
2703
|
+
const takeErrorResponse = () => {
|
|
2704
|
+
const error = errorResult;
|
|
2705
|
+
errorResult = undefined;
|
|
2706
|
+
return error;
|
|
2671
2707
|
};
|
|
2672
2708
|
const pushChunk = chunk => {
|
|
2673
2709
|
if (waiters.length > 0) {
|
|
@@ -2695,12 +2731,19 @@ const readNextChunk = async () => {
|
|
|
2695
2731
|
if (finished) {
|
|
2696
2732
|
return undefined;
|
|
2697
2733
|
}
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2734
|
+
const {
|
|
2735
|
+
promise,
|
|
2736
|
+
resolve
|
|
2737
|
+
} = Promise.withResolvers();
|
|
2738
|
+
waiters.push(resolve);
|
|
2739
|
+
return promise;
|
|
2701
2740
|
};
|
|
2702
2741
|
|
|
2703
2742
|
const getMockOpenApiAssistantText = async (stream, onTextChunk) => {
|
|
2743
|
+
const error = takeErrorResponse();
|
|
2744
|
+
if (error) {
|
|
2745
|
+
return error;
|
|
2746
|
+
}
|
|
2704
2747
|
let text = '';
|
|
2705
2748
|
while (true) {
|
|
2706
2749
|
const chunk = await readNextChunk();
|
|
@@ -2750,13 +2793,23 @@ const normalizeLimitInfo = value => {
|
|
|
2750
2793
|
const usage = Reflect.get(value, 'usage');
|
|
2751
2794
|
const usageDaily = Reflect.get(value, 'usageDaily');
|
|
2752
2795
|
const normalized = {
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2796
|
+
...(typeof limitRemaining === 'number' || limitRemaining === null ? {
|
|
2797
|
+
limitRemaining
|
|
2798
|
+
} : {}),
|
|
2799
|
+
...(typeof limitReset === 'string' || limitReset === null ? {
|
|
2800
|
+
limitReset
|
|
2801
|
+
} : {}),
|
|
2802
|
+
...(typeof retryAfter === 'string' || retryAfter === null ? {
|
|
2803
|
+
retryAfter
|
|
2804
|
+
} : {}),
|
|
2805
|
+
...(typeof usage === 'number' ? {
|
|
2806
|
+
usage
|
|
2807
|
+
} : {}),
|
|
2808
|
+
...(typeof usageDaily === 'number' ? {
|
|
2809
|
+
usageDaily
|
|
2810
|
+
} : {})
|
|
2758
2811
|
};
|
|
2759
|
-
const hasDetails =
|
|
2812
|
+
const hasDetails = typeof limitRemaining === 'number' || limitRemaining === null || typeof limitReset === 'string' || limitReset === null || typeof retryAfter === 'string' || retryAfter === null || typeof usage === 'number' || typeof usageDaily === 'number';
|
|
2760
2813
|
return hasDetails ? normalized : undefined;
|
|
2761
2814
|
};
|
|
2762
2815
|
|
|
@@ -2792,11 +2845,18 @@ const normalizeMockResult = value => {
|
|
|
2792
2845
|
if (details === 'request-failed' || details === 'too-many-requests' || details === 'http-error') {
|
|
2793
2846
|
const rawMessage = Reflect.get(value, 'rawMessage');
|
|
2794
2847
|
const statusCode = Reflect.get(value, 'statusCode');
|
|
2848
|
+
const limitInfo = normalizeLimitInfo(Reflect.get(value, 'limitInfo'));
|
|
2795
2849
|
return {
|
|
2796
2850
|
details,
|
|
2797
|
-
limitInfo
|
|
2798
|
-
|
|
2799
|
-
|
|
2851
|
+
...(limitInfo ? {
|
|
2852
|
+
limitInfo
|
|
2853
|
+
} : {}),
|
|
2854
|
+
...(typeof rawMessage === 'string' ? {
|
|
2855
|
+
rawMessage
|
|
2856
|
+
} : {}),
|
|
2857
|
+
...(typeof statusCode === 'number' ? {
|
|
2858
|
+
statusCode
|
|
2859
|
+
} : {}),
|
|
2800
2860
|
type: 'error'
|
|
2801
2861
|
};
|
|
2802
2862
|
}
|
|
@@ -3027,11 +3087,8 @@ const getClientRequestIdHeader = () => {
|
|
|
3027
3087
|
};
|
|
3028
3088
|
};
|
|
3029
3089
|
|
|
3030
|
-
const getOpenApiApiEndpoint =
|
|
3031
|
-
|
|
3032
|
-
return `${openApiApiBaseUrl}/chat/completions?stream=true`;
|
|
3033
|
-
}
|
|
3034
|
-
return `${openApiApiBaseUrl}/chat/completions`;
|
|
3090
|
+
const getOpenApiApiEndpoint = openApiApiBaseUrl => {
|
|
3091
|
+
return `${openApiApiBaseUrl}/responses`;
|
|
3035
3092
|
};
|
|
3036
3093
|
|
|
3037
3094
|
const getTextContent = content => {
|
|
@@ -3055,18 +3112,50 @@ const getTextContent = content => {
|
|
|
3055
3112
|
return textParts.join('\n');
|
|
3056
3113
|
};
|
|
3057
3114
|
|
|
3058
|
-
const
|
|
3115
|
+
const getOpenAiTools = tools => {
|
|
3116
|
+
return tools.map(tool => {
|
|
3117
|
+
if (!tool || typeof tool !== 'object') {
|
|
3118
|
+
return tool;
|
|
3119
|
+
}
|
|
3120
|
+
const type = Reflect.get(tool, 'type');
|
|
3121
|
+
const toolFunction = Reflect.get(tool, 'function');
|
|
3122
|
+
if (type !== 'function' || !toolFunction || typeof toolFunction !== 'object') {
|
|
3123
|
+
return tool;
|
|
3124
|
+
}
|
|
3125
|
+
const name = Reflect.get(toolFunction, 'name');
|
|
3126
|
+
const description = Reflect.get(toolFunction, 'description');
|
|
3127
|
+
const parameters = Reflect.get(toolFunction, 'parameters');
|
|
3128
|
+
return {
|
|
3129
|
+
...(typeof description === 'string' ? {
|
|
3130
|
+
description
|
|
3131
|
+
} : {}),
|
|
3132
|
+
...(typeof name === 'string' ? {
|
|
3133
|
+
name
|
|
3134
|
+
} : {}),
|
|
3135
|
+
...(parameters && typeof parameters === 'object' ? {
|
|
3136
|
+
parameters
|
|
3137
|
+
} : {}),
|
|
3138
|
+
type: 'function'
|
|
3139
|
+
};
|
|
3140
|
+
});
|
|
3141
|
+
};
|
|
3142
|
+
const getOpenAiParams = (input, modelId, stream, includeObfuscation, tools, previousResponseId) => {
|
|
3059
3143
|
return {
|
|
3060
|
-
|
|
3144
|
+
input,
|
|
3061
3145
|
model: modelId,
|
|
3062
3146
|
...(stream ? {
|
|
3063
|
-
stream: true
|
|
3147
|
+
stream: true,
|
|
3148
|
+
...(includeObfuscation ? {} : {
|
|
3149
|
+
stream_options: {
|
|
3150
|
+
include_obfuscation: false
|
|
3151
|
+
}
|
|
3152
|
+
})
|
|
3064
3153
|
} : {}),
|
|
3065
|
-
...(
|
|
3066
|
-
|
|
3154
|
+
...(previousResponseId ? {
|
|
3155
|
+
previous_response_id: previousResponseId
|
|
3067
3156
|
} : {}),
|
|
3068
3157
|
tool_choice: 'auto',
|
|
3069
|
-
tools
|
|
3158
|
+
tools: getOpenAiTools(tools)
|
|
3070
3159
|
};
|
|
3071
3160
|
};
|
|
3072
3161
|
const getStreamChunkText = content => {
|
|
@@ -3084,6 +3173,75 @@ const getStreamChunkText = content => {
|
|
|
3084
3173
|
return typeof text === 'string' ? text : '';
|
|
3085
3174
|
}).join('');
|
|
3086
3175
|
};
|
|
3176
|
+
const getResponseOutputText = parsed => {
|
|
3177
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
3178
|
+
return '';
|
|
3179
|
+
}
|
|
3180
|
+
const outputText = Reflect.get(parsed, 'output_text');
|
|
3181
|
+
if (typeof outputText === 'string') {
|
|
3182
|
+
return outputText;
|
|
3183
|
+
}
|
|
3184
|
+
const output = Reflect.get(parsed, 'output');
|
|
3185
|
+
if (!Array.isArray(output)) {
|
|
3186
|
+
return '';
|
|
3187
|
+
}
|
|
3188
|
+
const chunks = [];
|
|
3189
|
+
for (const outputItem of output) {
|
|
3190
|
+
if (!outputItem || typeof outputItem !== 'object') {
|
|
3191
|
+
continue;
|
|
3192
|
+
}
|
|
3193
|
+
const itemType = Reflect.get(outputItem, 'type');
|
|
3194
|
+
if (itemType !== 'message') {
|
|
3195
|
+
continue;
|
|
3196
|
+
}
|
|
3197
|
+
const content = Reflect.get(outputItem, 'content');
|
|
3198
|
+
if (!Array.isArray(content)) {
|
|
3199
|
+
continue;
|
|
3200
|
+
}
|
|
3201
|
+
for (const part of content) {
|
|
3202
|
+
if (!part || typeof part !== 'object') {
|
|
3203
|
+
continue;
|
|
3204
|
+
}
|
|
3205
|
+
const partType = Reflect.get(part, 'type');
|
|
3206
|
+
const text = Reflect.get(part, 'text');
|
|
3207
|
+
if ((partType === 'output_text' || partType === 'text') && typeof text === 'string') {
|
|
3208
|
+
chunks.push(text);
|
|
3209
|
+
}
|
|
3210
|
+
}
|
|
3211
|
+
}
|
|
3212
|
+
return chunks.join('');
|
|
3213
|
+
};
|
|
3214
|
+
const getResponseFunctionCalls = parsed => {
|
|
3215
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
3216
|
+
return [];
|
|
3217
|
+
}
|
|
3218
|
+
const output = Reflect.get(parsed, 'output');
|
|
3219
|
+
if (!Array.isArray(output)) {
|
|
3220
|
+
return [];
|
|
3221
|
+
}
|
|
3222
|
+
const calls = [];
|
|
3223
|
+
for (const outputItem of output) {
|
|
3224
|
+
if (!outputItem || typeof outputItem !== 'object') {
|
|
3225
|
+
continue;
|
|
3226
|
+
}
|
|
3227
|
+
const itemType = Reflect.get(outputItem, 'type');
|
|
3228
|
+
if (itemType !== 'function_call') {
|
|
3229
|
+
continue;
|
|
3230
|
+
}
|
|
3231
|
+
const callId = Reflect.get(outputItem, 'call_id');
|
|
3232
|
+
const name = Reflect.get(outputItem, 'name');
|
|
3233
|
+
const rawArguments = Reflect.get(outputItem, 'arguments');
|
|
3234
|
+
if (typeof callId !== 'string' || typeof name !== 'string') {
|
|
3235
|
+
continue;
|
|
3236
|
+
}
|
|
3237
|
+
calls.push({
|
|
3238
|
+
arguments: typeof rawArguments === 'string' ? rawArguments : '',
|
|
3239
|
+
callId,
|
|
3240
|
+
name
|
|
3241
|
+
});
|
|
3242
|
+
}
|
|
3243
|
+
return calls;
|
|
3244
|
+
};
|
|
3087
3245
|
const parseSseEvent = eventChunk => {
|
|
3088
3246
|
const lines = eventChunk.split('\n');
|
|
3089
3247
|
const dataLines = [];
|
|
@@ -3130,7 +3288,11 @@ const updateToolCallAccumulator = (accumulator, chunk) => {
|
|
|
3130
3288
|
}
|
|
3131
3289
|
const next = {
|
|
3132
3290
|
arguments: args,
|
|
3133
|
-
|
|
3291
|
+
...(typeof id === 'string' ? {
|
|
3292
|
+
id
|
|
3293
|
+
} : current.id ? {
|
|
3294
|
+
id: current.id
|
|
3295
|
+
} : {}),
|
|
3134
3296
|
name
|
|
3135
3297
|
};
|
|
3136
3298
|
if (JSON.stringify(next) !== JSON.stringify(current)) {
|
|
@@ -3159,7 +3321,136 @@ const parseOpenApiStream = async (response, onTextChunk, onToolCallsChunk, onDat
|
|
|
3159
3321
|
let remainder = '';
|
|
3160
3322
|
let text = '';
|
|
3161
3323
|
let done = false;
|
|
3324
|
+
let finishedNotified = false;
|
|
3162
3325
|
let toolCallAccumulator = {};
|
|
3326
|
+
const notifyFinished = async () => {
|
|
3327
|
+
if (finishedNotified) {
|
|
3328
|
+
return;
|
|
3329
|
+
}
|
|
3330
|
+
finishedNotified = true;
|
|
3331
|
+
if (onEventStreamFinished) {
|
|
3332
|
+
await onEventStreamFinished();
|
|
3333
|
+
}
|
|
3334
|
+
};
|
|
3335
|
+
const emitToolCallAccumulator = async () => {
|
|
3336
|
+
if (!onToolCallsChunk) {
|
|
3337
|
+
return;
|
|
3338
|
+
}
|
|
3339
|
+
const toolCalls = Object.entries(toolCallAccumulator).toSorted((a, b) => Number(a[0]) - Number(b[0])).map(entry => entry[1]).filter(toolCall => !!toolCall.name);
|
|
3340
|
+
if (toolCalls.length === 0) {
|
|
3341
|
+
return;
|
|
3342
|
+
}
|
|
3343
|
+
await onToolCallsChunk(toolCalls);
|
|
3344
|
+
};
|
|
3345
|
+
const handleParsedStreamEvent = async parsed => {
|
|
3346
|
+
if (onDataEvent) {
|
|
3347
|
+
await onDataEvent(parsed);
|
|
3348
|
+
}
|
|
3349
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
3350
|
+
return;
|
|
3351
|
+
}
|
|
3352
|
+
const eventType = Reflect.get(parsed, 'type');
|
|
3353
|
+
if (eventType === 'response.completed') {
|
|
3354
|
+
await notifyFinished();
|
|
3355
|
+
return;
|
|
3356
|
+
}
|
|
3357
|
+
if (eventType === 'response.output_text.delta') {
|
|
3358
|
+
const delta = Reflect.get(parsed, 'delta');
|
|
3359
|
+
if (typeof delta !== 'string' || !delta) {
|
|
3360
|
+
return;
|
|
3361
|
+
}
|
|
3362
|
+
text += delta;
|
|
3363
|
+
if (onTextChunk) {
|
|
3364
|
+
await onTextChunk(delta);
|
|
3365
|
+
}
|
|
3366
|
+
return;
|
|
3367
|
+
}
|
|
3368
|
+
if (eventType === 'response.output_item.added') {
|
|
3369
|
+
const outputIndex = Reflect.get(parsed, 'output_index');
|
|
3370
|
+
const item = Reflect.get(parsed, 'item');
|
|
3371
|
+
if (typeof outputIndex !== 'number' || !item || typeof item !== 'object') {
|
|
3372
|
+
return;
|
|
3373
|
+
}
|
|
3374
|
+
const itemType = Reflect.get(item, 'type');
|
|
3375
|
+
if (itemType !== 'function_call') {
|
|
3376
|
+
return;
|
|
3377
|
+
}
|
|
3378
|
+
const callId = Reflect.get(item, 'call_id');
|
|
3379
|
+
const name = Reflect.get(item, 'name');
|
|
3380
|
+
const rawArguments = Reflect.get(item, 'arguments');
|
|
3381
|
+
const next = {
|
|
3382
|
+
arguments: typeof rawArguments === 'string' ? rawArguments : '',
|
|
3383
|
+
...(typeof callId === 'string' ? {
|
|
3384
|
+
id: callId
|
|
3385
|
+
} : {}),
|
|
3386
|
+
name: typeof name === 'string' ? name : ''
|
|
3387
|
+
};
|
|
3388
|
+
toolCallAccumulator = {
|
|
3389
|
+
...toolCallAccumulator,
|
|
3390
|
+
[outputIndex]: next
|
|
3391
|
+
};
|
|
3392
|
+
await emitToolCallAccumulator();
|
|
3393
|
+
return;
|
|
3394
|
+
}
|
|
3395
|
+
if (eventType === 'response.function_call_arguments.delta' || eventType === 'response.function_call_arguments.done') {
|
|
3396
|
+
const outputIndex = Reflect.get(parsed, 'output_index');
|
|
3397
|
+
if (typeof outputIndex !== 'number') {
|
|
3398
|
+
return;
|
|
3399
|
+
}
|
|
3400
|
+
const current = toolCallAccumulator[outputIndex] || {
|
|
3401
|
+
arguments: '',
|
|
3402
|
+
name: ''
|
|
3403
|
+
};
|
|
3404
|
+
const name = Reflect.get(parsed, 'name');
|
|
3405
|
+
const callId = Reflect.get(parsed, 'call_id');
|
|
3406
|
+
const delta = Reflect.get(parsed, 'delta');
|
|
3407
|
+
const rawArguments = Reflect.get(parsed, 'arguments');
|
|
3408
|
+
const next = {
|
|
3409
|
+
arguments: typeof rawArguments === 'string' ? rawArguments : typeof delta === 'string' ? `${current.arguments}${delta}` : current.arguments,
|
|
3410
|
+
...(typeof callId === 'string' ? {
|
|
3411
|
+
id: callId
|
|
3412
|
+
} : current.id ? {
|
|
3413
|
+
id: current.id
|
|
3414
|
+
} : {}),
|
|
3415
|
+
name: typeof name === 'string' && name ? name : current.name
|
|
3416
|
+
};
|
|
3417
|
+
toolCallAccumulator = {
|
|
3418
|
+
...toolCallAccumulator,
|
|
3419
|
+
[outputIndex]: next
|
|
3420
|
+
};
|
|
3421
|
+
await emitToolCallAccumulator();
|
|
3422
|
+
return;
|
|
3423
|
+
}
|
|
3424
|
+
const choices = Reflect.get(parsed, 'choices');
|
|
3425
|
+
if (!Array.isArray(choices)) {
|
|
3426
|
+
return;
|
|
3427
|
+
}
|
|
3428
|
+
const firstChoice = choices[0];
|
|
3429
|
+
if (!firstChoice || typeof firstChoice !== 'object') {
|
|
3430
|
+
return;
|
|
3431
|
+
}
|
|
3432
|
+
const delta = Reflect.get(firstChoice, 'delta');
|
|
3433
|
+
if (!delta || typeof delta !== 'object') {
|
|
3434
|
+
return;
|
|
3435
|
+
}
|
|
3436
|
+
const toolCalls = Reflect.get(delta, 'tool_calls');
|
|
3437
|
+
const updatedToolCallResult = Array.isArray(toolCalls) ? updateToolCallAccumulator(toolCallAccumulator, toolCalls) : undefined;
|
|
3438
|
+
if (updatedToolCallResult) {
|
|
3439
|
+
toolCallAccumulator = updatedToolCallResult.nextAccumulator;
|
|
3440
|
+
}
|
|
3441
|
+
if (updatedToolCallResult && onToolCallsChunk) {
|
|
3442
|
+
await onToolCallsChunk(updatedToolCallResult.toolCalls);
|
|
3443
|
+
}
|
|
3444
|
+
const content = Reflect.get(delta, 'content');
|
|
3445
|
+
const chunkText = getStreamChunkText(content);
|
|
3446
|
+
if (!chunkText) {
|
|
3447
|
+
return;
|
|
3448
|
+
}
|
|
3449
|
+
text += chunkText;
|
|
3450
|
+
if (onTextChunk) {
|
|
3451
|
+
await onTextChunk(chunkText);
|
|
3452
|
+
}
|
|
3453
|
+
};
|
|
3163
3454
|
while (!done) {
|
|
3164
3455
|
const {
|
|
3165
3456
|
done: streamDone,
|
|
@@ -3185,9 +3476,7 @@ const parseOpenApiStream = async (response, onTextChunk, onToolCallsChunk, onDat
|
|
|
3185
3476
|
}
|
|
3186
3477
|
for (const line of dataLines) {
|
|
3187
3478
|
if (line === '[DONE]') {
|
|
3188
|
-
|
|
3189
|
-
await onEventStreamFinished();
|
|
3190
|
-
}
|
|
3479
|
+
await notifyFinished();
|
|
3191
3480
|
done = true;
|
|
3192
3481
|
break;
|
|
3193
3482
|
}
|
|
@@ -3197,41 +3486,7 @@ const parseOpenApiStream = async (response, onTextChunk, onToolCallsChunk, onDat
|
|
|
3197
3486
|
} catch {
|
|
3198
3487
|
continue;
|
|
3199
3488
|
}
|
|
3200
|
-
|
|
3201
|
-
continue;
|
|
3202
|
-
}
|
|
3203
|
-
if (onDataEvent) {
|
|
3204
|
-
await onDataEvent(parsed);
|
|
3205
|
-
}
|
|
3206
|
-
const choices = Reflect.get(parsed, 'choices');
|
|
3207
|
-
if (!Array.isArray(choices)) {
|
|
3208
|
-
continue;
|
|
3209
|
-
}
|
|
3210
|
-
const firstChoice = choices[0];
|
|
3211
|
-
if (!firstChoice || typeof firstChoice !== 'object') {
|
|
3212
|
-
continue;
|
|
3213
|
-
}
|
|
3214
|
-
const delta = Reflect.get(firstChoice, 'delta');
|
|
3215
|
-
if (!delta || typeof delta !== 'object') {
|
|
3216
|
-
continue;
|
|
3217
|
-
}
|
|
3218
|
-
const toolCalls = Reflect.get(delta, 'tool_calls');
|
|
3219
|
-
const updatedToolCallResult = Array.isArray(toolCalls) ? updateToolCallAccumulator(toolCallAccumulator, toolCalls) : undefined;
|
|
3220
|
-
if (updatedToolCallResult) {
|
|
3221
|
-
toolCallAccumulator = updatedToolCallResult.nextAccumulator;
|
|
3222
|
-
}
|
|
3223
|
-
if (updatedToolCallResult && onToolCallsChunk) {
|
|
3224
|
-
await onToolCallsChunk(updatedToolCallResult.toolCalls);
|
|
3225
|
-
}
|
|
3226
|
-
const content = Reflect.get(delta, 'content');
|
|
3227
|
-
const chunkText = getStreamChunkText(content);
|
|
3228
|
-
if (!chunkText) {
|
|
3229
|
-
continue;
|
|
3230
|
-
}
|
|
3231
|
-
text += chunkText;
|
|
3232
|
-
if (onTextChunk) {
|
|
3233
|
-
await onTextChunk(chunkText);
|
|
3234
|
-
}
|
|
3489
|
+
await handleParsedStreamEvent(parsed);
|
|
3235
3490
|
}
|
|
3236
3491
|
}
|
|
3237
3492
|
}
|
|
@@ -3239,9 +3494,7 @@ const parseOpenApiStream = async (response, onTextChunk, onToolCallsChunk, onDat
|
|
|
3239
3494
|
const dataLines = parseSseEvent(remainder);
|
|
3240
3495
|
for (const line of dataLines) {
|
|
3241
3496
|
if (line === '[DONE]') {
|
|
3242
|
-
|
|
3243
|
-
await onEventStreamFinished();
|
|
3244
|
-
}
|
|
3497
|
+
await notifyFinished();
|
|
3245
3498
|
continue;
|
|
3246
3499
|
}
|
|
3247
3500
|
let parsed;
|
|
@@ -3250,43 +3503,10 @@ const parseOpenApiStream = async (response, onTextChunk, onToolCallsChunk, onDat
|
|
|
3250
3503
|
} catch {
|
|
3251
3504
|
continue;
|
|
3252
3505
|
}
|
|
3253
|
-
|
|
3254
|
-
continue;
|
|
3255
|
-
}
|
|
3256
|
-
if (onDataEvent) {
|
|
3257
|
-
await onDataEvent(parsed);
|
|
3258
|
-
}
|
|
3259
|
-
const choices = Reflect.get(parsed, 'choices');
|
|
3260
|
-
if (!Array.isArray(choices)) {
|
|
3261
|
-
continue;
|
|
3262
|
-
}
|
|
3263
|
-
const firstChoice = choices[0];
|
|
3264
|
-
if (!firstChoice || typeof firstChoice !== 'object') {
|
|
3265
|
-
continue;
|
|
3266
|
-
}
|
|
3267
|
-
const delta = Reflect.get(firstChoice, 'delta');
|
|
3268
|
-
if (!delta || typeof delta !== 'object') {
|
|
3269
|
-
continue;
|
|
3270
|
-
}
|
|
3271
|
-
const toolCalls = Reflect.get(delta, 'tool_calls');
|
|
3272
|
-
const updatedToolCallResult = Array.isArray(toolCalls) ? updateToolCallAccumulator(toolCallAccumulator, toolCalls) : undefined;
|
|
3273
|
-
if (updatedToolCallResult) {
|
|
3274
|
-
toolCallAccumulator = updatedToolCallResult.nextAccumulator;
|
|
3275
|
-
}
|
|
3276
|
-
if (updatedToolCallResult && onToolCallsChunk) {
|
|
3277
|
-
await onToolCallsChunk(updatedToolCallResult.toolCalls);
|
|
3278
|
-
}
|
|
3279
|
-
const content = Reflect.get(delta, 'content');
|
|
3280
|
-
const chunkText = getStreamChunkText(content);
|
|
3281
|
-
if (!chunkText) {
|
|
3282
|
-
continue;
|
|
3283
|
-
}
|
|
3284
|
-
text += chunkText;
|
|
3285
|
-
if (onTextChunk) {
|
|
3286
|
-
await onTextChunk(chunkText);
|
|
3287
|
-
}
|
|
3506
|
+
await handleParsedStreamEvent(parsed);
|
|
3288
3507
|
}
|
|
3289
3508
|
}
|
|
3509
|
+
await notifyFinished();
|
|
3290
3510
|
return {
|
|
3291
3511
|
text,
|
|
3292
3512
|
type: 'success'
|
|
@@ -3310,9 +3530,15 @@ const getOpenApiErrorDetails = async response => {
|
|
|
3310
3530
|
const errorMessage = Reflect.get(error, 'message');
|
|
3311
3531
|
const errorType = Reflect.get(error, 'type');
|
|
3312
3532
|
return {
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3533
|
+
...(typeof errorCode === 'string' ? {
|
|
3534
|
+
errorCode
|
|
3535
|
+
} : {}),
|
|
3536
|
+
...(typeof errorMessage === 'string' ? {
|
|
3537
|
+
errorMessage
|
|
3538
|
+
} : {}),
|
|
3539
|
+
...(typeof errorType === 'string' ? {
|
|
3540
|
+
errorType
|
|
3541
|
+
} : {})
|
|
3316
3542
|
};
|
|
3317
3543
|
};
|
|
3318
3544
|
const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApiApiBaseUrl, assetDir, platform, options) => {
|
|
@@ -3326,17 +3552,18 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
|
|
|
3326
3552
|
} = options ?? {
|
|
3327
3553
|
stream: false
|
|
3328
3554
|
};
|
|
3329
|
-
const
|
|
3555
|
+
const openAiInput = messages.map(message => ({
|
|
3330
3556
|
content: message.text,
|
|
3331
3557
|
role: message.role
|
|
3332
3558
|
}));
|
|
3333
3559
|
const tools = getBasicChatTools();
|
|
3334
3560
|
const maxToolIterations = 4;
|
|
3561
|
+
let previousResponseId;
|
|
3335
3562
|
for (let i = 0; i <= maxToolIterations; i++) {
|
|
3336
3563
|
let response;
|
|
3337
3564
|
try {
|
|
3338
|
-
response = await fetch(getOpenApiApiEndpoint(openApiApiBaseUrl
|
|
3339
|
-
body: JSON.stringify(getOpenAiParams(
|
|
3565
|
+
response = await fetch(getOpenApiApiEndpoint(openApiApiBaseUrl), {
|
|
3566
|
+
body: JSON.stringify(getOpenAiParams(openAiInput, modelId, stream, includeObfuscation, tools, previousResponseId)),
|
|
3340
3567
|
headers: {
|
|
3341
3568
|
Authorization: `Bearer ${openApiApiKey}`,
|
|
3342
3569
|
'Content-Type': 'application/json',
|
|
@@ -3358,9 +3585,15 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
|
|
|
3358
3585
|
} = await getOpenApiErrorDetails(response);
|
|
3359
3586
|
return {
|
|
3360
3587
|
details: 'http-error',
|
|
3361
|
-
errorCode
|
|
3362
|
-
|
|
3363
|
-
|
|
3588
|
+
...(errorCode ? {
|
|
3589
|
+
errorCode
|
|
3590
|
+
} : {}),
|
|
3591
|
+
...(errorMessage ? {
|
|
3592
|
+
errorMessage
|
|
3593
|
+
} : {}),
|
|
3594
|
+
...(errorType ? {
|
|
3595
|
+
errorType
|
|
3596
|
+
} : {}),
|
|
3364
3597
|
statusCode: response.status,
|
|
3365
3598
|
type: 'error'
|
|
3366
3599
|
};
|
|
@@ -3383,56 +3616,83 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
|
|
|
3383
3616
|
type: 'success'
|
|
3384
3617
|
};
|
|
3385
3618
|
}
|
|
3386
|
-
const
|
|
3387
|
-
if (
|
|
3388
|
-
|
|
3389
|
-
text: '',
|
|
3390
|
-
type: 'success'
|
|
3391
|
-
};
|
|
3619
|
+
const parsedResponseId = Reflect.get(parsed, 'id');
|
|
3620
|
+
if (typeof parsedResponseId === 'string' && parsedResponseId) {
|
|
3621
|
+
previousResponseId = parsedResponseId;
|
|
3392
3622
|
}
|
|
3393
|
-
const
|
|
3394
|
-
if (
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3623
|
+
const responseFunctionCalls = getResponseFunctionCalls(parsed);
|
|
3624
|
+
if (responseFunctionCalls.length > 0) {
|
|
3625
|
+
openAiInput.length = 0;
|
|
3626
|
+
for (const toolCall of responseFunctionCalls) {
|
|
3627
|
+
const content = await executeChatTool(toolCall.name, toolCall.arguments, {
|
|
3628
|
+
assetDir,
|
|
3629
|
+
platform
|
|
3630
|
+
});
|
|
3631
|
+
openAiInput.push({
|
|
3632
|
+
call_id: toolCall.callId,
|
|
3633
|
+
output: content,
|
|
3634
|
+
type: 'function_call_output'
|
|
3635
|
+
});
|
|
3636
|
+
}
|
|
3637
|
+
continue;
|
|
3399
3638
|
}
|
|
3400
|
-
const
|
|
3401
|
-
if (
|
|
3639
|
+
const outputText = getResponseOutputText(parsed);
|
|
3640
|
+
if (outputText) {
|
|
3402
3641
|
return {
|
|
3403
|
-
text:
|
|
3642
|
+
text: outputText,
|
|
3404
3643
|
type: 'success'
|
|
3405
3644
|
};
|
|
3406
3645
|
}
|
|
3407
|
-
const
|
|
3408
|
-
if (Array.isArray(
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3646
|
+
const choices = Reflect.get(parsed, 'choices');
|
|
3647
|
+
if (Array.isArray(choices)) {
|
|
3648
|
+
const firstChoice = choices[0];
|
|
3649
|
+
if (!firstChoice || typeof firstChoice !== 'object') {
|
|
3650
|
+
return {
|
|
3651
|
+
text: '',
|
|
3652
|
+
type: 'success'
|
|
3653
|
+
};
|
|
3654
|
+
}
|
|
3655
|
+
const message = Reflect.get(firstChoice, 'message');
|
|
3656
|
+
if (!message || typeof message !== 'object') {
|
|
3657
|
+
return {
|
|
3658
|
+
text: '',
|
|
3659
|
+
type: 'success'
|
|
3660
|
+
};
|
|
3661
|
+
}
|
|
3662
|
+
const toolCalls = Reflect.get(message, 'tool_calls');
|
|
3663
|
+
if (Array.isArray(toolCalls) && toolCalls.length > 0) {
|
|
3664
|
+
openAiInput.length = 0;
|
|
3665
|
+
for (const toolCall of toolCalls) {
|
|
3666
|
+
if (!toolCall || typeof toolCall !== 'object') {
|
|
3667
|
+
continue;
|
|
3668
|
+
}
|
|
3669
|
+
const id = Reflect.get(toolCall, 'id');
|
|
3670
|
+
const toolFunction = Reflect.get(toolCall, 'function');
|
|
3671
|
+
if (typeof id !== 'string' || !toolFunction || typeof toolFunction !== 'object') {
|
|
3672
|
+
continue;
|
|
3673
|
+
}
|
|
3674
|
+
const name = Reflect.get(toolFunction, 'name');
|
|
3675
|
+
const rawArguments = Reflect.get(toolFunction, 'arguments');
|
|
3676
|
+
const content = typeof name === 'string' ? await executeChatTool(name, rawArguments, {
|
|
3677
|
+
assetDir,
|
|
3678
|
+
platform
|
|
3679
|
+
}) : '{}';
|
|
3680
|
+
openAiInput.push({
|
|
3681
|
+
call_id: id,
|
|
3682
|
+
output: content,
|
|
3683
|
+
type: 'function_call_output'
|
|
3684
|
+
});
|
|
3418
3685
|
}
|
|
3419
|
-
|
|
3420
|
-
const rawArguments = Reflect.get(toolFunction, 'arguments');
|
|
3421
|
-
const content = typeof name === 'string' ? await executeChatTool(name, rawArguments, {
|
|
3422
|
-
assetDir,
|
|
3423
|
-
platform
|
|
3424
|
-
}) : '{}';
|
|
3425
|
-
completionMessages.push({
|
|
3426
|
-
content,
|
|
3427
|
-
role: 'tool',
|
|
3428
|
-
tool_call_id: id
|
|
3429
|
-
});
|
|
3686
|
+
continue;
|
|
3430
3687
|
}
|
|
3431
|
-
|
|
3688
|
+
const content = Reflect.get(message, 'content');
|
|
3689
|
+
return {
|
|
3690
|
+
text: getTextContent(content),
|
|
3691
|
+
type: 'success'
|
|
3692
|
+
};
|
|
3432
3693
|
}
|
|
3433
|
-
const content = Reflect.get(message, 'content');
|
|
3434
3694
|
return {
|
|
3435
|
-
text:
|
|
3695
|
+
text: '',
|
|
3436
3696
|
type: 'success'
|
|
3437
3697
|
};
|
|
3438
3698
|
}
|
|
@@ -3568,10 +3828,18 @@ const getOpenRouterLimitInfo = async (openRouterApiKey, openRouterApiBaseUrl) =>
|
|
|
3568
3828
|
const usage = Reflect.get(data, 'usage');
|
|
3569
3829
|
const usageDaily = Reflect.get(data, 'usage_daily');
|
|
3570
3830
|
const normalizedLimitInfo = {
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3831
|
+
...(typeof limitRemaining === 'number' || limitRemaining === null ? {
|
|
3832
|
+
limitRemaining
|
|
3833
|
+
} : {}),
|
|
3834
|
+
...(typeof limitReset === 'string' || limitReset === null ? {
|
|
3835
|
+
limitReset
|
|
3836
|
+
} : {}),
|
|
3837
|
+
...(typeof usage === 'number' ? {
|
|
3838
|
+
usage
|
|
3839
|
+
} : {}),
|
|
3840
|
+
...(typeof usageDaily === 'number' ? {
|
|
3841
|
+
usageDaily
|
|
3842
|
+
} : {})
|
|
3575
3843
|
};
|
|
3576
3844
|
const hasLimitInfo = normalizedLimitInfo.limitRemaining !== undefined || normalizedLimitInfo.limitReset !== undefined || normalizedLimitInfo.usage !== undefined || normalizedLimitInfo.usageDaily !== undefined;
|
|
3577
3845
|
if (!hasLimitInfo) {
|
|
@@ -3616,11 +3884,17 @@ const getOpenRouterAssistantText = async (messages, modelId, openRouterApiKey, o
|
|
|
3616
3884
|
const limitInfo = await getOpenRouterLimitInfo(openRouterApiKey, openRouterApiBaseUrl);
|
|
3617
3885
|
return {
|
|
3618
3886
|
details: 'too-many-requests',
|
|
3619
|
-
limitInfo
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3887
|
+
...(limitInfo || retryAfter ? {
|
|
3888
|
+
limitInfo: {
|
|
3889
|
+
...limitInfo,
|
|
3890
|
+
...(retryAfter ? {
|
|
3891
|
+
retryAfter
|
|
3892
|
+
} : {})
|
|
3893
|
+
}
|
|
3894
|
+
} : {}),
|
|
3895
|
+
...(rawMessage ? {
|
|
3896
|
+
rawMessage
|
|
3897
|
+
} : {}),
|
|
3624
3898
|
statusCode: 429,
|
|
3625
3899
|
type: 'error'
|
|
3626
3900
|
};
|
|
@@ -3782,6 +4056,7 @@ const getAiResponse = async ({
|
|
|
3782
4056
|
assetDir,
|
|
3783
4057
|
messageId,
|
|
3784
4058
|
messages,
|
|
4059
|
+
mockAiResponseDelay = 800,
|
|
3785
4060
|
mockApiCommandId,
|
|
3786
4061
|
models,
|
|
3787
4062
|
onDataEvent,
|
|
@@ -3816,10 +4091,18 @@ const getAiResponse = async ({
|
|
|
3816
4091
|
} else if (openApiApiKey) {
|
|
3817
4092
|
const result = await getOpenApiAssistantText(messages, getOpenApiModelId(selectedModelId), openApiApiKey, openApiApiBaseUrl, assetDir, platform, {
|
|
3818
4093
|
includeObfuscation: passIncludeObfuscation,
|
|
3819
|
-
onDataEvent
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
4094
|
+
...(onDataEvent ? {
|
|
4095
|
+
onDataEvent
|
|
4096
|
+
} : {}),
|
|
4097
|
+
...(onEventStreamFinished ? {
|
|
4098
|
+
onEventStreamFinished
|
|
4099
|
+
} : {}),
|
|
4100
|
+
...(onTextChunk ? {
|
|
4101
|
+
onTextChunk
|
|
4102
|
+
} : {}),
|
|
4103
|
+
...(onToolCallsChunk ? {
|
|
4104
|
+
onToolCallsChunk
|
|
4105
|
+
} : {}),
|
|
3823
4106
|
stream: streamingEnabled
|
|
3824
4107
|
});
|
|
3825
4108
|
if (result.type === 'success') {
|
|
@@ -3860,7 +4143,7 @@ const getAiResponse = async ({
|
|
|
3860
4143
|
}
|
|
3861
4144
|
}
|
|
3862
4145
|
if (!text && !usesOpenApiModel && !usesOpenRouterModel) {
|
|
3863
|
-
text = await getMockAiResponse(userText);
|
|
4146
|
+
text = await getMockAiResponse(userText, mockAiResponseDelay);
|
|
3864
4147
|
}
|
|
3865
4148
|
const assistantTime = new Date().toLocaleTimeString([], {
|
|
3866
4149
|
hour: '2-digit',
|
|
@@ -3920,6 +4203,7 @@ const handleClickSaveOpenApiApiKey = async state => {
|
|
|
3920
4203
|
const assistantMessage = await getAiResponse({
|
|
3921
4204
|
assetDir: updatedState.assetDir,
|
|
3922
4205
|
messages: retryMessages,
|
|
4206
|
+
mockAiResponseDelay: updatedState.mockAiResponseDelay,
|
|
3923
4207
|
mockApiCommandId: updatedState.mockApiCommandId,
|
|
3924
4208
|
models: updatedState.models,
|
|
3925
4209
|
openApiApiBaseUrl: updatedState.openApiApiBaseUrl,
|
|
@@ -3999,6 +4283,7 @@ const handleClickSaveOpenRouterApiKey = async state => {
|
|
|
3999
4283
|
const assistantMessage = await getAiResponse({
|
|
4000
4284
|
assetDir: updatedState.assetDir,
|
|
4001
4285
|
messages: retryMessages,
|
|
4286
|
+
mockAiResponseDelay: updatedState.mockAiResponseDelay,
|
|
4002
4287
|
mockApiCommandId: updatedState.mockApiCommandId,
|
|
4003
4288
|
models: updatedState.models,
|
|
4004
4289
|
openApiApiBaseUrl: updatedState.openApiApiBaseUrl,
|
|
@@ -4091,13 +4376,6 @@ const handleTextChunkFunction = async (uid, assistantMessageId, chunk, handleTex
|
|
|
4091
4376
|
previousState: handleTextChunkState.previousState
|
|
4092
4377
|
};
|
|
4093
4378
|
}
|
|
4094
|
-
await appendChatViewEvent({
|
|
4095
|
-
content: chunk,
|
|
4096
|
-
messageId: assistantMessageId,
|
|
4097
|
-
sessionId: handleTextChunkState.latestState.selectedSessionId,
|
|
4098
|
-
timestamp: new Date().toISOString(),
|
|
4099
|
-
type: 'handle-response-chunk'
|
|
4100
|
-
});
|
|
4101
4379
|
const updatedText = assistantMessage.text + chunk;
|
|
4102
4380
|
const updatedSessions = updateMessageTextInSelectedSession(handleTextChunkState.latestState.sessions, handleTextChunkState.latestState.selectedSessionId, assistantMessageId, updatedText, true);
|
|
4103
4381
|
const nextState = {
|
|
@@ -4156,6 +4434,7 @@ const handleSubmit = async state => {
|
|
|
4156
4434
|
const {
|
|
4157
4435
|
assetDir,
|
|
4158
4436
|
composerValue,
|
|
4437
|
+
mockAiResponseDelay,
|
|
4159
4438
|
mockApiCommandId,
|
|
4160
4439
|
models,
|
|
4161
4440
|
nextMessageId,
|
|
@@ -4276,6 +4555,7 @@ const handleSubmit = async state => {
|
|
|
4276
4555
|
assetDir,
|
|
4277
4556
|
messageId: assistantMessageId,
|
|
4278
4557
|
messages,
|
|
4558
|
+
mockAiResponseDelay,
|
|
4279
4559
|
mockApiCommandId,
|
|
4280
4560
|
models,
|
|
4281
4561
|
onDataEvent: async value => {
|
|
@@ -4294,7 +4574,9 @@ const handleSubmit = async state => {
|
|
|
4294
4574
|
value: '[DONE]'
|
|
4295
4575
|
});
|
|
4296
4576
|
},
|
|
4297
|
-
|
|
4577
|
+
...(handleTextChunkFunctionRef ? {
|
|
4578
|
+
onTextChunk: handleTextChunkFunctionRef
|
|
4579
|
+
} : {}),
|
|
4298
4580
|
onToolCallsChunk: async toolCalls => {
|
|
4299
4581
|
handleTextChunkState = await handleToolCallsChunkFunction(state.uid, assistantMessageId, toolCalls, handleTextChunkState);
|
|
4300
4582
|
},
|
|
@@ -4815,13 +5097,6 @@ const loadPreferences = async () => {
|
|
|
4815
5097
|
};
|
|
4816
5098
|
};
|
|
4817
5099
|
|
|
4818
|
-
const toSummarySession = session => {
|
|
4819
|
-
return {
|
|
4820
|
-
id: session.id,
|
|
4821
|
-
messages: [],
|
|
4822
|
-
title: session.title
|
|
4823
|
-
};
|
|
4824
|
-
};
|
|
4825
5100
|
const loadSelectedSessionMessages = async (sessions, selectedSessionId) => {
|
|
4826
5101
|
if (!selectedSessionId) {
|
|
4827
5102
|
return sessions;
|
|
@@ -4837,6 +5112,14 @@ const loadSelectedSessionMessages = async (sessions, selectedSessionId) => {
|
|
|
4837
5112
|
return loadedSession;
|
|
4838
5113
|
});
|
|
4839
5114
|
};
|
|
5115
|
+
|
|
5116
|
+
const toSummarySession = session => {
|
|
5117
|
+
return {
|
|
5118
|
+
id: session.id,
|
|
5119
|
+
messages: [],
|
|
5120
|
+
title: session.title
|
|
5121
|
+
};
|
|
5122
|
+
};
|
|
4840
5123
|
const loadContent = async (state, savedState) => {
|
|
4841
5124
|
const savedSelectedModelId = getSavedSelectedModelId(savedState);
|
|
4842
5125
|
const savedViewMode = getSavedViewMode(savedState);
|
|
@@ -4888,6 +5171,11 @@ const loadContent = async (state, savedState) => {
|
|
|
4888
5171
|
};
|
|
4889
5172
|
};
|
|
4890
5173
|
|
|
5174
|
+
const mockOpenApiSetHttpErrorResponse = (state, statusCode, body) => {
|
|
5175
|
+
setHttpErrorResponse(statusCode, body);
|
|
5176
|
+
return state;
|
|
5177
|
+
};
|
|
5178
|
+
|
|
4891
5179
|
const mockOpenApiStreamFinish = state => {
|
|
4892
5180
|
finish();
|
|
4893
5181
|
return state;
|
|
@@ -5060,6 +5348,18 @@ const getModelOptionDOm = (model, selectedModelId) => {
|
|
|
5060
5348
|
}, text(getModelLabel(model))];
|
|
5061
5349
|
};
|
|
5062
5350
|
|
|
5351
|
+
const getChatSelectVirtualDom = (models, selectedModelId) => {
|
|
5352
|
+
const modelOptions = models.flatMap(model => getModelOptionDOm(model, selectedModelId));
|
|
5353
|
+
return [{
|
|
5354
|
+
childCount: models.length,
|
|
5355
|
+
className: Select,
|
|
5356
|
+
name: Model,
|
|
5357
|
+
onInput: HandleModelChange,
|
|
5358
|
+
type: Select$1,
|
|
5359
|
+
value: selectedModelId
|
|
5360
|
+
}, ...modelOptions];
|
|
5361
|
+
};
|
|
5362
|
+
|
|
5063
5363
|
const getSendButtonClassName = isSendDisabled => {
|
|
5064
5364
|
return isSendDisabled ? `${IconButton} ${SendButtonDisabled}` : `${IconButton}`;
|
|
5065
5365
|
};
|
|
@@ -5119,7 +5419,6 @@ const getUsageOverviewDom = (tokensUsed, tokensMax) => {
|
|
|
5119
5419
|
|
|
5120
5420
|
const getChatSendAreaDom = (composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight = 28, composerFontSize = 13, composerFontFamily = 'system-ui', composerLineHeight = 20) => {
|
|
5121
5421
|
const isSendDisabled = composerValue.trim() === '';
|
|
5122
|
-
const modelOptions = models.flatMap(model => getModelOptionDOm(model, selectedModelId));
|
|
5123
5422
|
return [{
|
|
5124
5423
|
childCount: 1,
|
|
5125
5424
|
className: ChatSendArea,
|
|
@@ -5135,21 +5434,13 @@ const getChatSendAreaDom = (composerValue, models, selectedModelId, usageOvervie
|
|
|
5135
5434
|
onFocus: HandleFocus,
|
|
5136
5435
|
onInput: HandleInput,
|
|
5137
5436
|
placeholder: composePlaceholder(),
|
|
5138
|
-
// style: `height:${composerHeight}px;font-size:${composerFontSize}px;font-family:${composerFontFamily};line-height:${composerLineHeight}px;`,
|
|
5139
5437
|
type: TextArea,
|
|
5140
5438
|
value: composerValue
|
|
5141
5439
|
}, {
|
|
5142
5440
|
childCount: usageOverviewEnabled ? 3 : 2,
|
|
5143
5441
|
className: ChatSendAreaBottom,
|
|
5144
5442
|
type: Div
|
|
5145
|
-
},
|
|
5146
|
-
childCount: models.length,
|
|
5147
|
-
className: Select,
|
|
5148
|
-
name: Model,
|
|
5149
|
-
onInput: HandleModelChange,
|
|
5150
|
-
type: Select$1,
|
|
5151
|
-
value: selectedModelId
|
|
5152
|
-
}, ...modelOptions, ...(usageOverviewEnabled ? getUsageOverviewDom(tokensUsed, tokensMax) : []), ...getSendButtonDom(isSendDisabled)];
|
|
5443
|
+
}, ...getChatSelectVirtualDom(models, selectedModelId), ...(usageOverviewEnabled ? getUsageOverviewDom(tokensUsed, tokensMax) : []), ...getSendButtonDom(isSendDisabled)];
|
|
5153
5444
|
};
|
|
5154
5445
|
|
|
5155
5446
|
const getBackButtonVirtualDom = () => {
|
|
@@ -5295,6 +5586,61 @@ const getMissingOpenRouterApiKeyDom = (openRouterApiKeyInput, openRouterApiKeySt
|
|
|
5295
5586
|
});
|
|
5296
5587
|
};
|
|
5297
5588
|
|
|
5589
|
+
const getOpenRouterRequestFailedDom = () => {
|
|
5590
|
+
return [{
|
|
5591
|
+
childCount: openRouterRequestFailureReasons.length,
|
|
5592
|
+
className: ChatOrderedList,
|
|
5593
|
+
type: Ol
|
|
5594
|
+
}, ...openRouterRequestFailureReasons.flatMap(reason => {
|
|
5595
|
+
return [{
|
|
5596
|
+
childCount: 1,
|
|
5597
|
+
className: ChatOrderedListItem,
|
|
5598
|
+
type: Li
|
|
5599
|
+
}, text(reason)];
|
|
5600
|
+
})];
|
|
5601
|
+
};
|
|
5602
|
+
|
|
5603
|
+
const getOpenRouterTooManyRequestsDom = () => {
|
|
5604
|
+
return [{
|
|
5605
|
+
childCount: openRouterTooManyRequestsReasons.length,
|
|
5606
|
+
className: ChatOrderedList,
|
|
5607
|
+
type: Ol
|
|
5608
|
+
}, ...openRouterTooManyRequestsReasons.flatMap(reason => {
|
|
5609
|
+
return [{
|
|
5610
|
+
childCount: 1,
|
|
5611
|
+
className: ChatOrderedListItem,
|
|
5612
|
+
type: Li
|
|
5613
|
+
}, text(reason)];
|
|
5614
|
+
})];
|
|
5615
|
+
};
|
|
5616
|
+
|
|
5617
|
+
const getToolCallArgumentPreview = rawArguments => {
|
|
5618
|
+
if (!rawArguments.trim()) {
|
|
5619
|
+
return '""';
|
|
5620
|
+
}
|
|
5621
|
+
let parsed;
|
|
5622
|
+
try {
|
|
5623
|
+
parsed = JSON.parse(rawArguments);
|
|
5624
|
+
} catch {
|
|
5625
|
+
return rawArguments;
|
|
5626
|
+
}
|
|
5627
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
5628
|
+
return rawArguments;
|
|
5629
|
+
}
|
|
5630
|
+
const path = Reflect.get(parsed, 'path');
|
|
5631
|
+
if (typeof path === 'string') {
|
|
5632
|
+
return `"${path}"`;
|
|
5633
|
+
}
|
|
5634
|
+
const keys = Object.keys(parsed);
|
|
5635
|
+
if (keys.length === 1) {
|
|
5636
|
+
const value = Reflect.get(parsed, keys[0]);
|
|
5637
|
+
if (typeof value === 'string') {
|
|
5638
|
+
return `"${value}"`;
|
|
5639
|
+
}
|
|
5640
|
+
}
|
|
5641
|
+
return rawArguments;
|
|
5642
|
+
};
|
|
5643
|
+
|
|
5298
5644
|
const orderedListItemRegex = /^\s*\d+\.\s+(.*)$/;
|
|
5299
5645
|
const parseMessageContent = rawMessage => {
|
|
5300
5646
|
if (rawMessage === '') {
|
|
@@ -5375,32 +5721,6 @@ const getMessageContentDom = nodes => {
|
|
|
5375
5721
|
});
|
|
5376
5722
|
};
|
|
5377
5723
|
|
|
5378
|
-
const getToolCallArgumentPreview = rawArguments => {
|
|
5379
|
-
if (!rawArguments.trim()) {
|
|
5380
|
-
return '""';
|
|
5381
|
-
}
|
|
5382
|
-
let parsed;
|
|
5383
|
-
try {
|
|
5384
|
-
parsed = JSON.parse(rawArguments);
|
|
5385
|
-
} catch {
|
|
5386
|
-
return rawArguments;
|
|
5387
|
-
}
|
|
5388
|
-
if (!parsed || typeof parsed !== 'object') {
|
|
5389
|
-
return rawArguments;
|
|
5390
|
-
}
|
|
5391
|
-
const path = Reflect.get(parsed, 'path');
|
|
5392
|
-
if (typeof path === 'string') {
|
|
5393
|
-
return `"${path}"`;
|
|
5394
|
-
}
|
|
5395
|
-
const keys = Object.keys(parsed);
|
|
5396
|
-
if (keys.length === 1) {
|
|
5397
|
-
const value = Reflect.get(parsed, keys[0]);
|
|
5398
|
-
if (typeof value === 'string') {
|
|
5399
|
-
return `"${value}"`;
|
|
5400
|
-
}
|
|
5401
|
-
}
|
|
5402
|
-
return rawArguments;
|
|
5403
|
-
};
|
|
5404
5724
|
const getToolCallsDom = message => {
|
|
5405
5725
|
if (message.role !== 'assistant' || !message.toolCalls || message.toolCalls.length === 0) {
|
|
5406
5726
|
return [];
|
|
@@ -5415,32 +5735,6 @@ const getToolCallsDom = message => {
|
|
|
5415
5735
|
}, text(label)];
|
|
5416
5736
|
});
|
|
5417
5737
|
};
|
|
5418
|
-
const getOpenRouterRequestFailedDom = () => {
|
|
5419
|
-
return [{
|
|
5420
|
-
childCount: openRouterRequestFailureReasons.length,
|
|
5421
|
-
className: ChatOrderedList,
|
|
5422
|
-
type: Ol
|
|
5423
|
-
}, ...openRouterRequestFailureReasons.flatMap(reason => {
|
|
5424
|
-
return [{
|
|
5425
|
-
childCount: 1,
|
|
5426
|
-
className: ChatOrderedListItem,
|
|
5427
|
-
type: Li
|
|
5428
|
-
}, text(reason)];
|
|
5429
|
-
})];
|
|
5430
|
-
};
|
|
5431
|
-
const getOpenRouterTooManyRequestsDom = () => {
|
|
5432
|
-
return [{
|
|
5433
|
-
childCount: openRouterTooManyRequestsReasons.length,
|
|
5434
|
-
className: ChatOrderedList,
|
|
5435
|
-
type: Ol
|
|
5436
|
-
}, ...openRouterTooManyRequestsReasons.flatMap(reason => {
|
|
5437
|
-
return [{
|
|
5438
|
-
childCount: 1,
|
|
5439
|
-
className: ChatOrderedListItem,
|
|
5440
|
-
type: Li
|
|
5441
|
-
}, text(reason)];
|
|
5442
|
-
})];
|
|
5443
|
-
};
|
|
5444
5738
|
const getChatMessageDom = (message, openRouterApiKeyInput, openApiApiKeyInput = '', openRouterApiKeyState = 'idle') => {
|
|
5445
5739
|
const roleClassName = message.role === 'user' ? MessageUser : MessageAssistant;
|
|
5446
5740
|
const isOpenApiApiKeyMissingMessage = message.role === 'assistant' && message.text === openApiApiKeyRequiredMessage;
|
|
@@ -5577,7 +5871,7 @@ const getChatModeUnsupportedVirtualDom = () => {
|
|
|
5577
5871
|
}, text(unknownViewMode())];
|
|
5578
5872
|
};
|
|
5579
5873
|
|
|
5580
|
-
const getChatVirtualDom = (sessions, selectedSessionId, composerValue, openRouterApiKeyInput, viewMode, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openApiApiKeyInput
|
|
5874
|
+
const getChatVirtualDom = (sessions, selectedSessionId, composerValue, openRouterApiKeyInput, viewMode, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openApiApiKeyInput, openRouterApiKeyState, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, chatListScrollTop, messagesScrollTop) => {
|
|
5581
5875
|
switch (viewMode) {
|
|
5582
5876
|
case 'detail':
|
|
5583
5877
|
return getChatModeDetailVirtualDom(sessions, selectedSessionId, composerValue, openRouterApiKeyInput, openApiApiKeyInput, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openRouterApiKeyState, composerHeight, composerFontSize, composerFontFamily, composerLineHeight, messagesScrollTop);
|
|
@@ -5746,6 +6040,7 @@ const reset = async state => {
|
|
|
5746
6040
|
...state,
|
|
5747
6041
|
composerHeight: getMinComposerHeightForState(state),
|
|
5748
6042
|
composerValue: '',
|
|
6043
|
+
mockAiResponseDelay: 0,
|
|
5749
6044
|
openRouterApiKey: '',
|
|
5750
6045
|
selectedModelId: 'test',
|
|
5751
6046
|
selectedSessionId: '',
|
|
@@ -5864,6 +6159,7 @@ const commandMap = {
|
|
|
5864
6159
|
'Chat.initialize': initialize,
|
|
5865
6160
|
'Chat.loadContent': wrapCommand(loadContent),
|
|
5866
6161
|
'Chat.loadContent2': wrapCommand(loadContent),
|
|
6162
|
+
'Chat.mockOpenApiSetHttpErrorResponse': wrapCommand(mockOpenApiSetHttpErrorResponse),
|
|
5867
6163
|
'Chat.mockOpenApiStreamFinish': wrapCommand(mockOpenApiStreamFinish),
|
|
5868
6164
|
'Chat.mockOpenApiStreamPushChunk': wrapCommand(mockOpenApiStreamPushChunk),
|
|
5869
6165
|
'Chat.mockOpenApiStreamReset': wrapCommand(mockOpenApiStreamReset),
|