@lvce-editor/chat-view 1.15.0 → 1.16.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 +377 -162
- package/package.json +1 -1
|
@@ -1179,9 +1179,45 @@ const terminate = () => {
|
|
|
1179
1179
|
globalThis.close();
|
|
1180
1180
|
};
|
|
1181
1181
|
|
|
1182
|
+
const measureTextBlockHeight = async (text, fontFamily, fontSize, lineHeight, width) => {
|
|
1183
|
+
return invoke('MeasureTextBlockHeight.measureTextBlockHeight', text, fontSize, fontFamily, lineHeight, width);
|
|
1184
|
+
};
|
|
1185
|
+
|
|
1186
|
+
const getComposerWidth = width => {
|
|
1187
|
+
return Math.max(1, width - 32);
|
|
1188
|
+
};
|
|
1189
|
+
const getMinComposerHeight = lineHeight => {
|
|
1190
|
+
return lineHeight + 8;
|
|
1191
|
+
};
|
|
1192
|
+
const estimateComposerHeight = (value, lineHeight) => {
|
|
1193
|
+
const lineCount = value.split('\n').length;
|
|
1194
|
+
return lineCount * lineHeight + 8;
|
|
1195
|
+
};
|
|
1196
|
+
const getComposerHeight = async (state, value, width = state.width) => {
|
|
1197
|
+
const {
|
|
1198
|
+
composerFontFamily,
|
|
1199
|
+
composerFontSize,
|
|
1200
|
+
composerLineHeight
|
|
1201
|
+
} = state;
|
|
1202
|
+
const minimumHeight = getMinComposerHeight(composerLineHeight);
|
|
1203
|
+
const content = value || ' ';
|
|
1204
|
+
const composerWidth = getComposerWidth(width);
|
|
1205
|
+
try {
|
|
1206
|
+
const measuredHeight = await measureTextBlockHeight(content, composerFontFamily, composerFontSize, composerLineHeight, composerWidth);
|
|
1207
|
+
const height = Math.ceil(measuredHeight) + 8;
|
|
1208
|
+
return Math.max(minimumHeight, height);
|
|
1209
|
+
} catch {
|
|
1210
|
+
return Math.max(minimumHeight, estimateComposerHeight(value, composerLineHeight));
|
|
1211
|
+
}
|
|
1212
|
+
};
|
|
1213
|
+
const getMinComposerHeightForState = state => {
|
|
1214
|
+
return getMinComposerHeight(state.composerLineHeight);
|
|
1215
|
+
};
|
|
1216
|
+
|
|
1182
1217
|
const clearInput = async state => {
|
|
1183
1218
|
return {
|
|
1184
1219
|
...state,
|
|
1220
|
+
composerHeight: getMinComposerHeightForState(state),
|
|
1185
1221
|
composerValue: ''
|
|
1186
1222
|
};
|
|
1187
1223
|
};
|
|
@@ -1237,6 +1273,9 @@ const sendMessage = () => {
|
|
|
1237
1273
|
const save = () => {
|
|
1238
1274
|
return i18nString('Save');
|
|
1239
1275
|
};
|
|
1276
|
+
const saving = () => {
|
|
1277
|
+
return i18nString('Saving...');
|
|
1278
|
+
};
|
|
1240
1279
|
const getOpenRouterApiKey = () => {
|
|
1241
1280
|
return i18nString('Get API Key');
|
|
1242
1281
|
};
|
|
@@ -1270,6 +1309,18 @@ const getDefaultModels = () => {
|
|
|
1270
1309
|
id: defaultModelId,
|
|
1271
1310
|
name: 'test',
|
|
1272
1311
|
provider: 'test'
|
|
1312
|
+
}, {
|
|
1313
|
+
id: 'openapi/gpt-4o-mini',
|
|
1314
|
+
name: 'GPT-4o Mini',
|
|
1315
|
+
provider: 'openApi'
|
|
1316
|
+
}, {
|
|
1317
|
+
id: 'openapi/gpt-4o',
|
|
1318
|
+
name: 'GPT-4o',
|
|
1319
|
+
provider: 'openApi'
|
|
1320
|
+
}, {
|
|
1321
|
+
id: 'openapi/gpt-4.1-mini',
|
|
1322
|
+
name: 'GPT-4.1 Mini',
|
|
1323
|
+
provider: 'openApi'
|
|
1273
1324
|
}, {
|
|
1274
1325
|
id: 'codex-5.3',
|
|
1275
1326
|
name: 'Codex 5.3',
|
|
@@ -1323,8 +1374,14 @@ const getDefaultModels = () => {
|
|
|
1323
1374
|
const createDefaultState = () => {
|
|
1324
1375
|
const defaultSessionId = 'session-1';
|
|
1325
1376
|
const defaultModelId = 'test';
|
|
1377
|
+
const composerFontSize = 13;
|
|
1378
|
+
const composerLineHeight = 20;
|
|
1326
1379
|
return {
|
|
1327
1380
|
assetDir: '',
|
|
1381
|
+
composerFontFamily: 'system-ui',
|
|
1382
|
+
composerFontSize,
|
|
1383
|
+
composerHeight: composerLineHeight + 8,
|
|
1384
|
+
composerLineHeight,
|
|
1328
1385
|
composerValue: '',
|
|
1329
1386
|
errorCount: 0,
|
|
1330
1387
|
focus: 'composer',
|
|
@@ -1346,6 +1403,7 @@ const createDefaultState = () => {
|
|
|
1346
1403
|
openRouterApiKey: '',
|
|
1347
1404
|
openRouterApiKeyInput: '',
|
|
1348
1405
|
openRouterApiKeysSettingsUrl: 'https://openrouter.ai/settings/keys',
|
|
1406
|
+
openRouterApiKeyState: 'idle',
|
|
1349
1407
|
platform: 0,
|
|
1350
1408
|
renamingSessionId: '',
|
|
1351
1409
|
selectedModelId: defaultModelId,
|
|
@@ -2118,6 +2176,15 @@ const openRouterTooManyRequestsMessage = 'OpenRouter rate limit reached (429). P
|
|
|
2118
2176
|
const openRouterRequestFailureReasons = ['ContentSecurityPolicyViolation: Check DevTools for details.', 'OpenRouter server offline: Check DevTools for details.', 'Check your internet connection.'];
|
|
2119
2177
|
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.'];
|
|
2120
2178
|
|
|
2179
|
+
const delay = async ms => {
|
|
2180
|
+
await new Promise(resolve => setTimeout(resolve, ms));
|
|
2181
|
+
};
|
|
2182
|
+
|
|
2183
|
+
const getMockAiResponse = async userMessage => {
|
|
2184
|
+
await delay(800);
|
|
2185
|
+
return `Mock AI response: I received "${userMessage}".`;
|
|
2186
|
+
};
|
|
2187
|
+
|
|
2121
2188
|
const activateByEvent = (event, assetDir, platform) => {
|
|
2122
2189
|
// @ts-ignore
|
|
2123
2190
|
return activateByEvent$1(event, assetDir, platform);
|
|
@@ -2139,13 +2206,108 @@ const executeProvider = async ({
|
|
|
2139
2206
|
|
|
2140
2207
|
const CommandExecute = 'ExtensionHostCommand.executeCommand';
|
|
2141
2208
|
|
|
2142
|
-
const
|
|
2143
|
-
|
|
2209
|
+
const normalizeLimitInfo = value => {
|
|
2210
|
+
if (!value || typeof value !== 'object') {
|
|
2211
|
+
return undefined;
|
|
2212
|
+
}
|
|
2213
|
+
const limitRemaining = Reflect.get(value, 'limitRemaining');
|
|
2214
|
+
const limitReset = Reflect.get(value, 'limitReset');
|
|
2215
|
+
const retryAfter = Reflect.get(value, 'retryAfter');
|
|
2216
|
+
const usage = Reflect.get(value, 'usage');
|
|
2217
|
+
const usageDaily = Reflect.get(value, 'usageDaily');
|
|
2218
|
+
const normalized = {
|
|
2219
|
+
limitRemaining: typeof limitRemaining === 'number' || limitRemaining === null ? limitRemaining : undefined,
|
|
2220
|
+
limitReset: typeof limitReset === 'string' || limitReset === null ? limitReset : undefined,
|
|
2221
|
+
retryAfter: typeof retryAfter === 'string' || retryAfter === null ? retryAfter : undefined,
|
|
2222
|
+
usage: typeof usage === 'number' ? usage : undefined,
|
|
2223
|
+
usageDaily: typeof usageDaily === 'number' ? usageDaily : undefined
|
|
2224
|
+
};
|
|
2225
|
+
const hasDetails = normalized.limitRemaining !== undefined || normalized.limitReset !== undefined || normalized.retryAfter !== undefined || normalized.usage !== undefined || normalized.usageDaily !== undefined;
|
|
2226
|
+
return hasDetails ? normalized : undefined;
|
|
2144
2227
|
};
|
|
2145
2228
|
|
|
2146
|
-
const
|
|
2147
|
-
|
|
2148
|
-
|
|
2229
|
+
const normalizeMockResult = value => {
|
|
2230
|
+
if (typeof value === 'string') {
|
|
2231
|
+
return {
|
|
2232
|
+
text: value,
|
|
2233
|
+
type: 'success'
|
|
2234
|
+
};
|
|
2235
|
+
}
|
|
2236
|
+
if (!value || typeof value !== 'object') {
|
|
2237
|
+
return {
|
|
2238
|
+
details: 'request-failed',
|
|
2239
|
+
type: 'error'
|
|
2240
|
+
};
|
|
2241
|
+
}
|
|
2242
|
+
const type = Reflect.get(value, 'type');
|
|
2243
|
+
if (type === 'success') {
|
|
2244
|
+
const text = Reflect.get(value, 'text');
|
|
2245
|
+
if (typeof text === 'string') {
|
|
2246
|
+
return {
|
|
2247
|
+
text,
|
|
2248
|
+
type: 'success'
|
|
2249
|
+
};
|
|
2250
|
+
}
|
|
2251
|
+
return {
|
|
2252
|
+
details: 'request-failed',
|
|
2253
|
+
type: 'error'
|
|
2254
|
+
};
|
|
2255
|
+
}
|
|
2256
|
+
if (type === 'error') {
|
|
2257
|
+
const details = Reflect.get(value, 'details');
|
|
2258
|
+
if (details === 'request-failed' || details === 'too-many-requests' || details === 'http-error') {
|
|
2259
|
+
const rawMessage = Reflect.get(value, 'rawMessage');
|
|
2260
|
+
const statusCode = Reflect.get(value, 'statusCode');
|
|
2261
|
+
return {
|
|
2262
|
+
details,
|
|
2263
|
+
limitInfo: normalizeLimitInfo(Reflect.get(value, 'limitInfo')),
|
|
2264
|
+
rawMessage: typeof rawMessage === 'string' ? rawMessage : undefined,
|
|
2265
|
+
statusCode: typeof statusCode === 'number' ? statusCode : undefined,
|
|
2266
|
+
type: 'error'
|
|
2267
|
+
};
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
const text = Reflect.get(value, 'text');
|
|
2271
|
+
if (typeof text === 'string') {
|
|
2272
|
+
return {
|
|
2273
|
+
text,
|
|
2274
|
+
type: 'success'
|
|
2275
|
+
};
|
|
2276
|
+
}
|
|
2277
|
+
return {
|
|
2278
|
+
details: 'request-failed',
|
|
2279
|
+
type: 'error'
|
|
2280
|
+
};
|
|
2281
|
+
};
|
|
2282
|
+
|
|
2283
|
+
const getMockOpenRouterAssistantText = async (messages, modelId, openRouterApiBaseUrl, openRouterApiKey, mockApiCommandId, assetDir, platform) => {
|
|
2284
|
+
if (!mockApiCommandId) {
|
|
2285
|
+
return {
|
|
2286
|
+
details: 'request-failed',
|
|
2287
|
+
type: 'error'
|
|
2288
|
+
};
|
|
2289
|
+
}
|
|
2290
|
+
try {
|
|
2291
|
+
const result = await executeProvider({
|
|
2292
|
+
assetDir,
|
|
2293
|
+
event: `onCommand:${mockApiCommandId}`,
|
|
2294
|
+
method: CommandExecute,
|
|
2295
|
+
noProviderFoundMessage: 'No mock api command found',
|
|
2296
|
+
params: [mockApiCommandId, {
|
|
2297
|
+
messages,
|
|
2298
|
+
modelId,
|
|
2299
|
+
openRouterApiBaseUrl,
|
|
2300
|
+
openRouterApiKey
|
|
2301
|
+
}],
|
|
2302
|
+
platform
|
|
2303
|
+
});
|
|
2304
|
+
return normalizeMockResult(result);
|
|
2305
|
+
} catch {
|
|
2306
|
+
return {
|
|
2307
|
+
details: 'request-failed',
|
|
2308
|
+
type: 'error'
|
|
2309
|
+
};
|
|
2310
|
+
}
|
|
2149
2311
|
};
|
|
2150
2312
|
|
|
2151
2313
|
const getOpenApiApiEndpoint = openApiApiBaseUrl => {
|
|
@@ -2173,6 +2335,29 @@ const getTextContent = content => {
|
|
|
2173
2335
|
return textParts.join('\n');
|
|
2174
2336
|
};
|
|
2175
2337
|
|
|
2338
|
+
const getOpenApiErrorDetails = async response => {
|
|
2339
|
+
let parsed;
|
|
2340
|
+
try {
|
|
2341
|
+
parsed = await response.json();
|
|
2342
|
+
} catch {
|
|
2343
|
+
return {};
|
|
2344
|
+
}
|
|
2345
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
2346
|
+
return {};
|
|
2347
|
+
}
|
|
2348
|
+
const error = Reflect.get(parsed, 'error');
|
|
2349
|
+
if (!error || typeof error !== 'object') {
|
|
2350
|
+
return {};
|
|
2351
|
+
}
|
|
2352
|
+
const errorCode = Reflect.get(error, 'code');
|
|
2353
|
+
const errorMessage = Reflect.get(error, 'message');
|
|
2354
|
+
const errorType = Reflect.get(error, 'type');
|
|
2355
|
+
return {
|
|
2356
|
+
errorCode: typeof errorCode === 'string' ? errorCode : undefined,
|
|
2357
|
+
errorMessage: typeof errorMessage === 'string' ? errorMessage : undefined,
|
|
2358
|
+
errorType: typeof errorType === 'string' ? errorType : undefined
|
|
2359
|
+
};
|
|
2360
|
+
};
|
|
2176
2361
|
const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApiApiBaseUrl) => {
|
|
2177
2362
|
let response;
|
|
2178
2363
|
try {
|
|
@@ -2197,8 +2382,16 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
|
|
|
2197
2382
|
};
|
|
2198
2383
|
}
|
|
2199
2384
|
if (!response.ok) {
|
|
2385
|
+
const {
|
|
2386
|
+
errorCode,
|
|
2387
|
+
errorMessage,
|
|
2388
|
+
errorType
|
|
2389
|
+
} = await getOpenApiErrorDetails(response);
|
|
2200
2390
|
return {
|
|
2201
2391
|
details: 'http-error',
|
|
2392
|
+
errorCode,
|
|
2393
|
+
errorMessage,
|
|
2394
|
+
errorType,
|
|
2202
2395
|
statusCode: response.status,
|
|
2203
2396
|
type: 'error'
|
|
2204
2397
|
};
|
|
@@ -2246,6 +2439,51 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
|
|
|
2246
2439
|
};
|
|
2247
2440
|
};
|
|
2248
2441
|
|
|
2442
|
+
const getOpenApiErrorMessage = errorResult => {
|
|
2443
|
+
switch (errorResult.details) {
|
|
2444
|
+
case 'http-error':
|
|
2445
|
+
{
|
|
2446
|
+
const errorMessage = errorResult.errorMessage?.trim();
|
|
2447
|
+
const hasErrorCode = typeof errorResult.errorCode === 'string' && errorResult.errorCode.length > 0;
|
|
2448
|
+
const hasErrorType = typeof errorResult.errorType === 'string' && errorResult.errorType.length > 0;
|
|
2449
|
+
if (errorResult.statusCode === 429) {
|
|
2450
|
+
let prefix = 'OpenAI rate limit exceeded (429)';
|
|
2451
|
+
if (hasErrorCode) {
|
|
2452
|
+
prefix = `OpenAI rate limit exceeded (429: ${errorResult.errorCode})`;
|
|
2453
|
+
}
|
|
2454
|
+
if (hasErrorType) {
|
|
2455
|
+
prefix += ` [${errorResult.errorType}]`;
|
|
2456
|
+
}
|
|
2457
|
+
prefix += '.';
|
|
2458
|
+
if (!errorMessage) {
|
|
2459
|
+
return prefix;
|
|
2460
|
+
}
|
|
2461
|
+
return `${prefix} ${errorMessage}`;
|
|
2462
|
+
}
|
|
2463
|
+
if (typeof errorResult.statusCode === 'number') {
|
|
2464
|
+
let prefix = `OpenAI request failed (status ${errorResult.statusCode})`;
|
|
2465
|
+
if (hasErrorCode) {
|
|
2466
|
+
prefix += `: ${errorResult.errorCode}`;
|
|
2467
|
+
}
|
|
2468
|
+
if (hasErrorType) {
|
|
2469
|
+
prefix += ` [${errorResult.errorType}]`;
|
|
2470
|
+
}
|
|
2471
|
+
prefix += '.';
|
|
2472
|
+
if (!errorMessage) {
|
|
2473
|
+
return prefix;
|
|
2474
|
+
}
|
|
2475
|
+
return `${prefix} ${errorMessage}`;
|
|
2476
|
+
}
|
|
2477
|
+
if (errorMessage) {
|
|
2478
|
+
return `OpenAI request failed. ${errorMessage}`;
|
|
2479
|
+
}
|
|
2480
|
+
return openApiRequestFailedMessage;
|
|
2481
|
+
}
|
|
2482
|
+
case 'request-failed':
|
|
2483
|
+
return openApiRequestFailedMessage;
|
|
2484
|
+
}
|
|
2485
|
+
};
|
|
2486
|
+
|
|
2249
2487
|
const getOpenApiModelId = selectedModelId => {
|
|
2250
2488
|
const openApiPrefix = 'openapi/';
|
|
2251
2489
|
const openAiPrefix = 'openai/';
|
|
@@ -2425,36 +2663,6 @@ const getOpenRouterAssistantText = async (messages, modelId, openRouterApiKey, o
|
|
|
2425
2663
|
};
|
|
2426
2664
|
};
|
|
2427
2665
|
|
|
2428
|
-
/* eslint-disable @cspell/spellchecker */
|
|
2429
|
-
const getOpenRouterModelId = selectedModelId => {
|
|
2430
|
-
const openRouterPrefix = 'openrouter/';
|
|
2431
|
-
if (selectedModelId.toLowerCase().startsWith(openRouterPrefix)) {
|
|
2432
|
-
return selectedModelId.slice(openRouterPrefix.length);
|
|
2433
|
-
}
|
|
2434
|
-
return selectedModelId;
|
|
2435
|
-
};
|
|
2436
|
-
|
|
2437
|
-
const isOpenApiModel = (selectedModelId, models) => {
|
|
2438
|
-
const selectedModel = models.find(model => model.id === selectedModelId);
|
|
2439
|
-
const normalizedProvider = selectedModel?.provider?.toLowerCase();
|
|
2440
|
-
if (normalizedProvider === 'openapi' || normalizedProvider === 'openai' || normalizedProvider === 'open-ai') {
|
|
2441
|
-
return true;
|
|
2442
|
-
}
|
|
2443
|
-
const normalizedModelId = selectedModelId.toLowerCase();
|
|
2444
|
-
return normalizedModelId.startsWith('openapi/') || normalizedModelId.startsWith('openai/');
|
|
2445
|
-
};
|
|
2446
|
-
|
|
2447
|
-
/* eslint-disable @cspell/spellchecker */
|
|
2448
|
-
|
|
2449
|
-
const isOpenRouterModel = (selectedModelId, models) => {
|
|
2450
|
-
const selectedModel = models.find(model => model.id === selectedModelId);
|
|
2451
|
-
const normalizedProvider = selectedModel?.provider?.toLowerCase();
|
|
2452
|
-
if (normalizedProvider === 'openrouter' || normalizedProvider === 'open-router') {
|
|
2453
|
-
return true;
|
|
2454
|
-
}
|
|
2455
|
-
return selectedModelId.toLowerCase().startsWith('openrouter/');
|
|
2456
|
-
};
|
|
2457
|
-
|
|
2458
2666
|
const getOpenRouterTooManyRequestsMessage = errorResult => {
|
|
2459
2667
|
const details = [];
|
|
2460
2668
|
if (errorResult.rawMessage) {
|
|
@@ -2487,6 +2695,7 @@ const getOpenRouterTooManyRequestsMessage = errorResult => {
|
|
|
2487
2695
|
}
|
|
2488
2696
|
return `${openRouterTooManyRequestsMessage} ${details.join(' ')}`;
|
|
2489
2697
|
};
|
|
2698
|
+
|
|
2490
2699
|
const getOpenRouterErrorMessage = errorResult => {
|
|
2491
2700
|
switch (errorResult.details) {
|
|
2492
2701
|
case 'http-error':
|
|
@@ -2496,115 +2705,52 @@ const getOpenRouterErrorMessage = errorResult => {
|
|
|
2496
2705
|
return getOpenRouterTooManyRequestsMessage(errorResult);
|
|
2497
2706
|
}
|
|
2498
2707
|
};
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
};
|
|
2506
|
-
const normalizeLimitInfo = value => {
|
|
2507
|
-
if (!value || typeof value !== 'object') {
|
|
2508
|
-
return undefined;
|
|
2708
|
+
|
|
2709
|
+
/* eslint-disable @cspell/spellchecker */
|
|
2710
|
+
const getOpenRouterModelId = selectedModelId => {
|
|
2711
|
+
const openRouterPrefix = 'openrouter/';
|
|
2712
|
+
if (selectedModelId.toLowerCase().startsWith(openRouterPrefix)) {
|
|
2713
|
+
return selectedModelId.slice(openRouterPrefix.length);
|
|
2509
2714
|
}
|
|
2510
|
-
|
|
2511
|
-
const limitReset = Reflect.get(value, 'limitReset');
|
|
2512
|
-
const retryAfter = Reflect.get(value, 'retryAfter');
|
|
2513
|
-
const usage = Reflect.get(value, 'usage');
|
|
2514
|
-
const usageDaily = Reflect.get(value, 'usageDaily');
|
|
2515
|
-
const normalized = {
|
|
2516
|
-
limitRemaining: typeof limitRemaining === 'number' || limitRemaining === null ? limitRemaining : undefined,
|
|
2517
|
-
limitReset: typeof limitReset === 'string' || limitReset === null ? limitReset : undefined,
|
|
2518
|
-
retryAfter: typeof retryAfter === 'string' || retryAfter === null ? retryAfter : undefined,
|
|
2519
|
-
usage: typeof usage === 'number' ? usage : undefined,
|
|
2520
|
-
usageDaily: typeof usageDaily === 'number' ? usageDaily : undefined
|
|
2521
|
-
};
|
|
2522
|
-
const hasDetails = normalized.limitRemaining !== undefined || normalized.limitReset !== undefined || normalized.retryAfter !== undefined || normalized.usage !== undefined || normalized.usageDaily !== undefined;
|
|
2523
|
-
return hasDetails ? normalized : undefined;
|
|
2715
|
+
return selectedModelId;
|
|
2524
2716
|
};
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
}
|
|
2532
|
-
if (!value || typeof value !== 'object') {
|
|
2533
|
-
return {
|
|
2534
|
-
details: 'request-failed',
|
|
2535
|
-
type: 'error'
|
|
2536
|
-
};
|
|
2537
|
-
}
|
|
2538
|
-
const type = Reflect.get(value, 'type');
|
|
2539
|
-
if (type === 'success') {
|
|
2540
|
-
const text = Reflect.get(value, 'text');
|
|
2541
|
-
if (typeof text === 'string') {
|
|
2542
|
-
return {
|
|
2543
|
-
text,
|
|
2544
|
-
type: 'success'
|
|
2545
|
-
};
|
|
2546
|
-
}
|
|
2547
|
-
return {
|
|
2548
|
-
details: 'request-failed',
|
|
2549
|
-
type: 'error'
|
|
2550
|
-
};
|
|
2551
|
-
}
|
|
2552
|
-
if (type === 'error') {
|
|
2553
|
-
const details = Reflect.get(value, 'details');
|
|
2554
|
-
if (details === 'request-failed' || details === 'too-many-requests' || details === 'http-error') {
|
|
2555
|
-
const rawMessage = Reflect.get(value, 'rawMessage');
|
|
2556
|
-
const statusCode = Reflect.get(value, 'statusCode');
|
|
2557
|
-
return {
|
|
2558
|
-
details,
|
|
2559
|
-
limitInfo: normalizeLimitInfo(Reflect.get(value, 'limitInfo')),
|
|
2560
|
-
rawMessage: typeof rawMessage === 'string' ? rawMessage : undefined,
|
|
2561
|
-
statusCode: typeof statusCode === 'number' ? statusCode : undefined,
|
|
2562
|
-
type: 'error'
|
|
2563
|
-
};
|
|
2564
|
-
}
|
|
2565
|
-
}
|
|
2566
|
-
const text = Reflect.get(value, 'text');
|
|
2567
|
-
if (typeof text === 'string') {
|
|
2568
|
-
return {
|
|
2569
|
-
text,
|
|
2570
|
-
type: 'success'
|
|
2571
|
-
};
|
|
2717
|
+
|
|
2718
|
+
const isOpenApiModel = (selectedModelId, models) => {
|
|
2719
|
+
const selectedModel = models.find(model => model.id === selectedModelId);
|
|
2720
|
+
const normalizedProvider = selectedModel?.provider?.toLowerCase();
|
|
2721
|
+
if (normalizedProvider === 'openapi' || normalizedProvider === 'openai' || normalizedProvider === 'open-ai') {
|
|
2722
|
+
return true;
|
|
2572
2723
|
}
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
type: 'error'
|
|
2576
|
-
};
|
|
2724
|
+
const normalizedModelId = selectedModelId.toLowerCase();
|
|
2725
|
+
return normalizedModelId.startsWith('openapi/') || normalizedModelId.startsWith('openai/');
|
|
2577
2726
|
};
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
const result = await executeProvider({
|
|
2587
|
-
assetDir,
|
|
2588
|
-
event: `onCommand:${mockApiCommandId}`,
|
|
2589
|
-
method: CommandExecute,
|
|
2590
|
-
noProviderFoundMessage: 'No mock api command found',
|
|
2591
|
-
params: [mockApiCommandId, {
|
|
2592
|
-
messages,
|
|
2593
|
-
modelId,
|
|
2594
|
-
openRouterApiBaseUrl,
|
|
2595
|
-
openRouterApiKey
|
|
2596
|
-
}],
|
|
2597
|
-
platform
|
|
2598
|
-
});
|
|
2599
|
-
return normalizeMockResult(result);
|
|
2600
|
-
} catch {
|
|
2601
|
-
return {
|
|
2602
|
-
details: 'request-failed',
|
|
2603
|
-
type: 'error'
|
|
2604
|
-
};
|
|
2727
|
+
|
|
2728
|
+
/* eslint-disable @cspell/spellchecker */
|
|
2729
|
+
|
|
2730
|
+
const isOpenRouterModel = (selectedModelId, models) => {
|
|
2731
|
+
const selectedModel = models.find(model => model.id === selectedModelId);
|
|
2732
|
+
const normalizedProvider = selectedModel?.provider?.toLowerCase();
|
|
2733
|
+
if (normalizedProvider === 'openrouter' || normalizedProvider === 'open-router') {
|
|
2734
|
+
return true;
|
|
2605
2735
|
}
|
|
2736
|
+
return selectedModelId.toLowerCase().startsWith('openrouter/');
|
|
2606
2737
|
};
|
|
2607
|
-
|
|
2738
|
+
|
|
2739
|
+
const getAiResponse = async ({
|
|
2740
|
+
assetDir,
|
|
2741
|
+
messages,
|
|
2742
|
+
mockApiCommandId,
|
|
2743
|
+
models,
|
|
2744
|
+
nextMessageId,
|
|
2745
|
+
openApiApiBaseUrl,
|
|
2746
|
+
openApiApiKey,
|
|
2747
|
+
openRouterApiBaseUrl,
|
|
2748
|
+
openRouterApiKey,
|
|
2749
|
+
platform,
|
|
2750
|
+
selectedModelId,
|
|
2751
|
+
useMockApi,
|
|
2752
|
+
userText
|
|
2753
|
+
}) => {
|
|
2608
2754
|
let text = '';
|
|
2609
2755
|
const usesOpenApiModel = isOpenApiModel(selectedModelId, models);
|
|
2610
2756
|
const usesOpenRouterModel = isOpenRouterModel(selectedModelId, models);
|
|
@@ -2706,7 +2852,21 @@ const handleClickSaveOpenApiApiKey = async state => {
|
|
|
2706
2852
|
return updatedState;
|
|
2707
2853
|
}
|
|
2708
2854
|
const retryMessages = session.messages.slice(0, -1);
|
|
2709
|
-
const assistantMessage = await getAiResponse(
|
|
2855
|
+
const assistantMessage = await getAiResponse({
|
|
2856
|
+
assetDir: updatedState.assetDir,
|
|
2857
|
+
messages: retryMessages,
|
|
2858
|
+
mockApiCommandId: updatedState.mockApiCommandId,
|
|
2859
|
+
models: updatedState.models,
|
|
2860
|
+
nextMessageId: updatedState.nextMessageId,
|
|
2861
|
+
openApiApiBaseUrl: updatedState.openApiApiBaseUrl,
|
|
2862
|
+
openApiApiKey: updatedState.openApiApiKey,
|
|
2863
|
+
openRouterApiBaseUrl: updatedState.openRouterApiBaseUrl,
|
|
2864
|
+
openRouterApiKey: updatedState.openRouterApiKey,
|
|
2865
|
+
platform: updatedState.platform,
|
|
2866
|
+
selectedModelId: updatedState.selectedModelId,
|
|
2867
|
+
useMockApi: updatedState.useMockApi,
|
|
2868
|
+
userText: previousUserMessage.text
|
|
2869
|
+
});
|
|
2710
2870
|
const updatedSession = {
|
|
2711
2871
|
...session,
|
|
2712
2872
|
messages: [...session.messages.slice(0, -1), assistantMessage]
|
|
@@ -2746,7 +2906,18 @@ const handleClickSaveOpenRouterApiKey = async state => {
|
|
|
2746
2906
|
if (!openRouterApiKey) {
|
|
2747
2907
|
return state;
|
|
2748
2908
|
}
|
|
2749
|
-
const
|
|
2909
|
+
const optimisticState = {
|
|
2910
|
+
...state,
|
|
2911
|
+
openRouterApiKeyState: 'saving'
|
|
2912
|
+
};
|
|
2913
|
+
set(state.uid, state, optimisticState);
|
|
2914
|
+
// @ts-ignore
|
|
2915
|
+
await invoke('Chat.rerender');
|
|
2916
|
+
const persistedState = await setOpenRouterApiKey(optimisticState, openRouterApiKey);
|
|
2917
|
+
const updatedState = {
|
|
2918
|
+
...persistedState,
|
|
2919
|
+
openRouterApiKeyState: 'idle'
|
|
2920
|
+
};
|
|
2750
2921
|
const session = updatedState.sessions.find(item => item.id === updatedState.selectedSessionId);
|
|
2751
2922
|
if (!session) {
|
|
2752
2923
|
return updatedState;
|
|
@@ -2761,9 +2932,21 @@ const handleClickSaveOpenRouterApiKey = async state => {
|
|
|
2761
2932
|
return updatedState;
|
|
2762
2933
|
}
|
|
2763
2934
|
const retryMessages = session.messages.slice(0, -1);
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2935
|
+
const assistantMessage = await getAiResponse({
|
|
2936
|
+
assetDir: updatedState.assetDir,
|
|
2937
|
+
messages: retryMessages,
|
|
2938
|
+
mockApiCommandId: updatedState.mockApiCommandId,
|
|
2939
|
+
models: updatedState.models,
|
|
2940
|
+
nextMessageId: updatedState.nextMessageId,
|
|
2941
|
+
openApiApiBaseUrl: updatedState.openApiApiBaseUrl,
|
|
2942
|
+
openApiApiKey: updatedState.openApiApiKey,
|
|
2943
|
+
openRouterApiBaseUrl: updatedState.openRouterApiBaseUrl,
|
|
2944
|
+
openRouterApiKey,
|
|
2945
|
+
platform: updatedState.platform,
|
|
2946
|
+
selectedModelId: updatedState.selectedModelId,
|
|
2947
|
+
useMockApi: updatedState.useMockApi,
|
|
2948
|
+
userText: previousUserMessage.text
|
|
2949
|
+
});
|
|
2767
2950
|
const updatedSession = {
|
|
2768
2951
|
...session,
|
|
2769
2952
|
messages: [...session.messages.slice(0, -1), assistantMessage]
|
|
@@ -2778,6 +2961,7 @@ const handleClickSaveOpenRouterApiKey = async state => {
|
|
|
2778
2961
|
return {
|
|
2779
2962
|
...updatedState,
|
|
2780
2963
|
nextMessageId: updatedState.nextMessageId + 1,
|
|
2964
|
+
openRouterApiKeyState: 'idle',
|
|
2781
2965
|
sessions: updatedSessions
|
|
2782
2966
|
};
|
|
2783
2967
|
};
|
|
@@ -2845,6 +3029,7 @@ const handleSubmit = async state => {
|
|
|
2845
3029
|
await saveChatSession(newSession);
|
|
2846
3030
|
optimisticState = focusInput({
|
|
2847
3031
|
...state,
|
|
3032
|
+
composerHeight: getMinComposerHeightForState(state),
|
|
2848
3033
|
composerValue: '',
|
|
2849
3034
|
inputSource: 'script',
|
|
2850
3035
|
lastSubmittedSessionId: newSessionId,
|
|
@@ -2869,6 +3054,7 @@ const handleSubmit = async state => {
|
|
|
2869
3054
|
}
|
|
2870
3055
|
optimisticState = focusInput({
|
|
2871
3056
|
...state,
|
|
3057
|
+
composerHeight: getMinComposerHeightForState(state),
|
|
2872
3058
|
composerValue: '',
|
|
2873
3059
|
inputSource: 'script',
|
|
2874
3060
|
lastSubmittedSessionId: selectedSessionId,
|
|
@@ -2881,7 +3067,21 @@ const handleSubmit = async state => {
|
|
|
2881
3067
|
await invoke('Chat.rerender');
|
|
2882
3068
|
const selectedOptimisticSession = optimisticState.sessions.find(session => session.id === optimisticState.selectedSessionId);
|
|
2883
3069
|
const messages = selectedOptimisticSession?.messages ?? [];
|
|
2884
|
-
const assistantMessage = await getAiResponse(
|
|
3070
|
+
const assistantMessage = await getAiResponse({
|
|
3071
|
+
assetDir,
|
|
3072
|
+
messages,
|
|
3073
|
+
mockApiCommandId,
|
|
3074
|
+
models,
|
|
3075
|
+
nextMessageId: optimisticState.nextMessageId,
|
|
3076
|
+
openApiApiBaseUrl,
|
|
3077
|
+
openApiApiKey,
|
|
3078
|
+
openRouterApiBaseUrl,
|
|
3079
|
+
openRouterApiKey,
|
|
3080
|
+
platform,
|
|
3081
|
+
selectedModelId,
|
|
3082
|
+
useMockApi,
|
|
3083
|
+
userText
|
|
3084
|
+
});
|
|
2885
3085
|
const updatedSessions = optimisticState.sessions.map(session => {
|
|
2886
3086
|
if (session.id !== optimisticState.selectedSessionId) {
|
|
2887
3087
|
return session;
|
|
@@ -3086,8 +3286,10 @@ const handleInput = async (state, name, value, inputSource = 'user') => {
|
|
|
3086
3286
|
if (name !== Composer) {
|
|
3087
3287
|
return state;
|
|
3088
3288
|
}
|
|
3289
|
+
const composerHeight = await getComposerHeight(state, value);
|
|
3089
3290
|
return {
|
|
3090
3291
|
...state,
|
|
3292
|
+
composerHeight,
|
|
3091
3293
|
composerValue: value,
|
|
3092
3294
|
inputSource
|
|
3093
3295
|
};
|
|
@@ -3152,6 +3354,7 @@ const submitRename = async state => {
|
|
|
3152
3354
|
}
|
|
3153
3355
|
return {
|
|
3154
3356
|
...state,
|
|
3357
|
+
composerHeight: getMinComposerHeightForState(state),
|
|
3155
3358
|
composerValue: '',
|
|
3156
3359
|
inputSource: 'script',
|
|
3157
3360
|
renamingSessionId: '',
|
|
@@ -3549,7 +3752,7 @@ const getUsageOverviewDom = (tokensUsed, tokensMax) => {
|
|
|
3549
3752
|
}, text(usageLabel)];
|
|
3550
3753
|
};
|
|
3551
3754
|
|
|
3552
|
-
const getChatSendAreaDom = (composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax) => {
|
|
3755
|
+
const getChatSendAreaDom = (composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight = 28, composerFontSize = 13, composerFontFamily = 'system-ui', composerLineHeight = 20) => {
|
|
3553
3756
|
const isSendDisabled = composerValue.trim() === '';
|
|
3554
3757
|
const modelOptions = models.flatMap(model => getModelOptionDOm(model, selectedModelId));
|
|
3555
3758
|
return [{
|
|
@@ -3567,7 +3770,7 @@ const getChatSendAreaDom = (composerValue, models, selectedModelId, usageOvervie
|
|
|
3567
3770
|
onFocus: HandleFocus,
|
|
3568
3771
|
onInput: HandleInput,
|
|
3569
3772
|
placeholder: composePlaceholder(),
|
|
3570
|
-
|
|
3773
|
+
style: `height:${composerHeight}px;font-size:${composerFontSize}px;font-family:${composerFontFamily};line-height:${composerLineHeight}px;`,
|
|
3571
3774
|
type: TextArea,
|
|
3572
3775
|
value: composerValue
|
|
3573
3776
|
}, {
|
|
@@ -3662,7 +3865,9 @@ const getMissingApiKeyDom = ({
|
|
|
3662
3865
|
inputValue,
|
|
3663
3866
|
openSettingsButtonName,
|
|
3664
3867
|
placeholder,
|
|
3665
|
-
|
|
3868
|
+
saveButtonDisabled = false,
|
|
3869
|
+
saveButtonName,
|
|
3870
|
+
saveButtonText = save()
|
|
3666
3871
|
}) => {
|
|
3667
3872
|
return [{
|
|
3668
3873
|
childCount: 2,
|
|
@@ -3682,10 +3887,11 @@ const getMissingApiKeyDom = ({
|
|
|
3682
3887
|
}, {
|
|
3683
3888
|
childCount: 1,
|
|
3684
3889
|
className: mergeClassNames(Button, ButtonPrimary),
|
|
3890
|
+
disabled: saveButtonDisabled,
|
|
3685
3891
|
name: saveButtonName,
|
|
3686
3892
|
onClick: HandleClick,
|
|
3687
3893
|
type: Button$1
|
|
3688
|
-
}, text(
|
|
3894
|
+
}, text(saveButtonText), {
|
|
3689
3895
|
childCount: 1,
|
|
3690
3896
|
className: mergeClassNames(Button, ButtonSecondary),
|
|
3691
3897
|
name: openSettingsButtonName,
|
|
@@ -3705,14 +3911,17 @@ const getMissingOpenApiApiKeyDom = openApiApiKeyInput => {
|
|
|
3705
3911
|
});
|
|
3706
3912
|
};
|
|
3707
3913
|
|
|
3708
|
-
const getMissingOpenRouterApiKeyDom = openRouterApiKeyInput => {
|
|
3914
|
+
const getMissingOpenRouterApiKeyDom = (openRouterApiKeyInput, openRouterApiKeyState = 'idle') => {
|
|
3915
|
+
const isSaving = openRouterApiKeyState === 'saving';
|
|
3709
3916
|
return getMissingApiKeyDom({
|
|
3710
3917
|
getApiKeyText: getOpenRouterApiKey(),
|
|
3711
3918
|
inputName: OpenRouterApiKeyInput,
|
|
3712
3919
|
inputValue: openRouterApiKeyInput,
|
|
3713
3920
|
openSettingsButtonName: OpenOpenRouterApiKeySettings,
|
|
3714
3921
|
placeholder: openRouterApiKeyPlaceholder(),
|
|
3715
|
-
|
|
3922
|
+
saveButtonDisabled: isSaving,
|
|
3923
|
+
saveButtonName: SaveOpenRouterApiKey,
|
|
3924
|
+
saveButtonText: isSaving ? saving() : save()
|
|
3716
3925
|
});
|
|
3717
3926
|
};
|
|
3718
3927
|
|
|
@@ -3742,7 +3951,7 @@ const getOpenRouterTooManyRequestsDom = () => {
|
|
|
3742
3951
|
}, text(reason)];
|
|
3743
3952
|
})];
|
|
3744
3953
|
};
|
|
3745
|
-
const getChatMessageDom = (message, openRouterApiKeyInput, openApiApiKeyInput = '') => {
|
|
3954
|
+
const getChatMessageDom = (message, openRouterApiKeyInput, openApiApiKeyInput = '', openRouterApiKeyState = 'idle') => {
|
|
3746
3955
|
const roleClassName = message.role === 'user' ? MessageUser : MessageAssistant;
|
|
3747
3956
|
const isOpenApiApiKeyMissingMessage = message.role === 'assistant' && message.text === openApiApiKeyRequiredMessage;
|
|
3748
3957
|
const isOpenRouterApiKeyMissingMessage = message.role === 'assistant' && message.text === openRouterApiKeyRequiredMessage;
|
|
@@ -3761,7 +3970,7 @@ const getChatMessageDom = (message, openRouterApiKeyInput, openApiApiKeyInput =
|
|
|
3761
3970
|
childCount: 1,
|
|
3762
3971
|
className: Markdown,
|
|
3763
3972
|
type: P
|
|
3764
|
-
}, text(message.text), ...(isOpenApiApiKeyMissingMessage ? getMissingOpenApiApiKeyDom(openApiApiKeyInput) : []), ...(isOpenRouterApiKeyMissingMessage ? getMissingOpenRouterApiKeyDom(openRouterApiKeyInput) : []), ...(isOpenRouterRequestFailedMessage ? getOpenRouterRequestFailedDom() : []), ...(isOpenRouterTooManyRequestsMessage ? getOpenRouterTooManyRequestsDom() : [])];
|
|
3973
|
+
}, text(message.text), ...(isOpenApiApiKeyMissingMessage ? getMissingOpenApiApiKeyDom(openApiApiKeyInput) : []), ...(isOpenRouterApiKeyMissingMessage ? getMissingOpenRouterApiKeyDom(openRouterApiKeyInput, openRouterApiKeyState) : []), ...(isOpenRouterRequestFailedMessage ? getOpenRouterRequestFailedDom() : []), ...(isOpenRouterTooManyRequestsMessage ? getOpenRouterTooManyRequestsDom() : [])];
|
|
3765
3974
|
};
|
|
3766
3975
|
|
|
3767
3976
|
const getEmptyMessagesDom = () => {
|
|
@@ -3772,7 +3981,7 @@ const getEmptyMessagesDom = () => {
|
|
|
3772
3981
|
}, text(startConversation())];
|
|
3773
3982
|
};
|
|
3774
3983
|
|
|
3775
|
-
const getMessagesDom = (messages, openRouterApiKeyInput, openApiApiKeyInput = '') => {
|
|
3984
|
+
const getMessagesDom = (messages, openRouterApiKeyInput, openApiApiKeyInput = '', openRouterApiKeyState = 'idle') => {
|
|
3776
3985
|
if (messages.length === 0) {
|
|
3777
3986
|
return getEmptyMessagesDom();
|
|
3778
3987
|
}
|
|
@@ -3780,10 +3989,10 @@ const getMessagesDom = (messages, openRouterApiKeyInput, openApiApiKeyInput = ''
|
|
|
3780
3989
|
childCount: messages.length,
|
|
3781
3990
|
className: 'ChatMessages',
|
|
3782
3991
|
type: Div
|
|
3783
|
-
}, ...messages.flatMap(message => getChatMessageDom(message, openRouterApiKeyInput, openApiApiKeyInput))];
|
|
3992
|
+
}, ...messages.flatMap(message => getChatMessageDom(message, openRouterApiKeyInput, openApiApiKeyInput, openRouterApiKeyState))];
|
|
3784
3993
|
};
|
|
3785
3994
|
|
|
3786
|
-
const getChatModeDetailVirtualDom = (sessions, selectedSessionId, composerValue, openRouterApiKeyInput, openApiApiKeyInput, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax) => {
|
|
3995
|
+
const getChatModeDetailVirtualDom = (sessions, selectedSessionId, composerValue, openRouterApiKeyInput, openApiApiKeyInput, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openRouterApiKeyState = 'idle', composerHeight = 28, composerFontSize = 13, composerFontFamily = 'system-ui', composerLineHeight = 20) => {
|
|
3787
3996
|
const selectedSession = sessions.find(session => session.id === selectedSessionId);
|
|
3788
3997
|
const selectedSessionTitle = selectedSession?.title || chatTitle();
|
|
3789
3998
|
const messages = selectedSession ? selectedSession.messages : [];
|
|
@@ -3791,7 +4000,7 @@ const getChatModeDetailVirtualDom = (sessions, selectedSessionId, composerValue,
|
|
|
3791
4000
|
childCount: 3,
|
|
3792
4001
|
className: mergeClassNames(Viewlet, Chat),
|
|
3793
4002
|
type: Div
|
|
3794
|
-
}, ...getChatHeaderDomDetailMode(selectedSessionTitle), ...getMessagesDom(messages, openRouterApiKeyInput, openApiApiKeyInput), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax)];
|
|
4003
|
+
}, ...getChatHeaderDomDetailMode(selectedSessionTitle), ...getMessagesDom(messages, openRouterApiKeyInput, openApiApiKeyInput, openRouterApiKeyState), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight, composerFontSize, composerFontFamily, composerLineHeight)];
|
|
3795
4004
|
};
|
|
3796
4005
|
|
|
3797
4006
|
const getChatHeaderListModeDom = () => {
|
|
@@ -3860,12 +4069,12 @@ const getChatListDom = (sessions, selectedSessionId) => {
|
|
|
3860
4069
|
}, ...sessions.flatMap(getSessionDom)];
|
|
3861
4070
|
};
|
|
3862
4071
|
|
|
3863
|
-
const getChatModeListVirtualDom = (sessions, selectedSessionId, composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax) => {
|
|
4072
|
+
const getChatModeListVirtualDom = (sessions, selectedSessionId, composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight = 28, composerFontSize = 13, composerFontFamily = 'system-ui', composerLineHeight = 20) => {
|
|
3864
4073
|
return [{
|
|
3865
4074
|
childCount: 3,
|
|
3866
4075
|
className: mergeClassNames(Viewlet, Chat),
|
|
3867
4076
|
type: Div
|
|
3868
|
-
}, ...getChatHeaderListModeDom(), ...getChatListDom(sessions), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax)];
|
|
4077
|
+
}, ...getChatHeaderListModeDom(), ...getChatListDom(sessions), ...getChatSendAreaDom(composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight, composerFontSize, composerFontFamily, composerLineHeight)];
|
|
3869
4078
|
};
|
|
3870
4079
|
|
|
3871
4080
|
const getChatModeUnsupportedVirtualDom = () => {
|
|
@@ -3875,12 +4084,12 @@ const getChatModeUnsupportedVirtualDom = () => {
|
|
|
3875
4084
|
}, text(unknownViewMode())];
|
|
3876
4085
|
};
|
|
3877
4086
|
|
|
3878
|
-
const getChatVirtualDom = (sessions, selectedSessionId, composerValue, openRouterApiKeyInput, viewMode, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openApiApiKeyInput = '') => {
|
|
4087
|
+
const getChatVirtualDom = (sessions, selectedSessionId, composerValue, openRouterApiKeyInput, viewMode, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openApiApiKeyInput = '', openRouterApiKeyState = 'idle', composerHeight = 28, composerFontSize = 13, composerFontFamily = 'system-ui', composerLineHeight = 20) => {
|
|
3879
4088
|
switch (viewMode) {
|
|
3880
4089
|
case 'detail':
|
|
3881
|
-
return getChatModeDetailVirtualDom(sessions, selectedSessionId, composerValue, openRouterApiKeyInput, openApiApiKeyInput, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax);
|
|
4090
|
+
return getChatModeDetailVirtualDom(sessions, selectedSessionId, composerValue, openRouterApiKeyInput, openApiApiKeyInput, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openRouterApiKeyState, composerHeight, composerFontSize, composerFontFamily, composerLineHeight);
|
|
3882
4091
|
case 'list':
|
|
3883
|
-
return getChatModeListVirtualDom(sessions, selectedSessionId, composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax);
|
|
4092
|
+
return getChatModeListVirtualDom(sessions, selectedSessionId, composerValue, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, composerHeight, composerFontSize, composerFontFamily, composerLineHeight);
|
|
3884
4093
|
default:
|
|
3885
4094
|
return getChatModeUnsupportedVirtualDom();
|
|
3886
4095
|
}
|
|
@@ -3888,11 +4097,16 @@ const getChatVirtualDom = (sessions, selectedSessionId, composerValue, openRoute
|
|
|
3888
4097
|
|
|
3889
4098
|
const renderItems = (oldState, newState) => {
|
|
3890
4099
|
const {
|
|
4100
|
+
composerFontFamily,
|
|
4101
|
+
composerFontSize,
|
|
4102
|
+
composerHeight,
|
|
4103
|
+
composerLineHeight,
|
|
3891
4104
|
composerValue,
|
|
3892
4105
|
initial,
|
|
3893
4106
|
models,
|
|
3894
4107
|
openApiApiKeyInput,
|
|
3895
4108
|
openRouterApiKeyInput,
|
|
4109
|
+
openRouterApiKeyState,
|
|
3896
4110
|
selectedModelId,
|
|
3897
4111
|
selectedSessionId,
|
|
3898
4112
|
sessions,
|
|
@@ -3905,7 +4119,7 @@ const renderItems = (oldState, newState) => {
|
|
|
3905
4119
|
if (initial) {
|
|
3906
4120
|
return [SetDom2, uid, []];
|
|
3907
4121
|
}
|
|
3908
|
-
const dom = getChatVirtualDom(sessions, selectedSessionId, composerValue, openRouterApiKeyInput, viewMode, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openApiApiKeyInput);
|
|
4122
|
+
const dom = getChatVirtualDom(sessions, selectedSessionId, composerValue, openRouterApiKeyInput, viewMode, models, selectedModelId, usageOverviewEnabled, tokensUsed, tokensMax, openApiApiKeyInput, openRouterApiKeyState, composerHeight, composerFontSize, composerFontFamily, composerLineHeight);
|
|
3909
4123
|
return [SetDom2, uid, dom];
|
|
3910
4124
|
};
|
|
3911
4125
|
|
|
@@ -4016,6 +4230,7 @@ const reset = async state => {
|
|
|
4016
4230
|
await clearChatSessions();
|
|
4017
4231
|
return {
|
|
4018
4232
|
...state,
|
|
4233
|
+
composerHeight: getMinComposerHeightForState(state),
|
|
4019
4234
|
composerValue: '',
|
|
4020
4235
|
openRouterApiKey: '',
|
|
4021
4236
|
selectedSessionId: '',
|