@lvce-editor/chat-view 1.16.0 → 1.18.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 +432 -160
- package/package.json +1 -1
|
@@ -1045,6 +1045,9 @@ const {
|
|
|
1045
1045
|
invokeAndTransfer,
|
|
1046
1046
|
set: set$1
|
|
1047
1047
|
} = create$2(RendererWorker);
|
|
1048
|
+
const readFile = async uri => {
|
|
1049
|
+
return invoke('FileSystem.readFile', uri);
|
|
1050
|
+
};
|
|
1048
1051
|
const sendMessagePortToExtensionHostWorker$1 = async (port, rpcId = 0) => {
|
|
1049
1052
|
const command = 'HandleMessagePort.handleMessagePort2';
|
|
1050
1053
|
await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToExtensionHostWorker', port, command, rpcId);
|
|
@@ -1309,6 +1312,10 @@ const getDefaultModels = () => {
|
|
|
1309
1312
|
id: defaultModelId,
|
|
1310
1313
|
name: 'test',
|
|
1311
1314
|
provider: 'test'
|
|
1315
|
+
}, {
|
|
1316
|
+
id: 'openapi/gpt-5-mini',
|
|
1317
|
+
name: 'GPT-5 Mini',
|
|
1318
|
+
provider: 'openApi'
|
|
1312
1319
|
}, {
|
|
1313
1320
|
id: 'openapi/gpt-4o-mini',
|
|
1314
1321
|
name: 'GPT-4o Mini',
|
|
@@ -1450,7 +1457,7 @@ const create = (uid, x, y, width, height, platform, assetDir) => {
|
|
|
1450
1457
|
};
|
|
1451
1458
|
|
|
1452
1459
|
const isEqual$1 = (oldState, newState) => {
|
|
1453
|
-
return oldState.initial === newState.initial;
|
|
1460
|
+
return oldState.initial === newState.initial && oldState.composerHeight === newState.composerHeight && oldState.composerLineHeight === newState.composerLineHeight && oldState.composerFontFamily === newState.composerFontFamily && oldState.composerFontSize === newState.composerFontSize;
|
|
1454
1461
|
};
|
|
1455
1462
|
|
|
1456
1463
|
const diffFocus = (oldState, newState) => {
|
|
@@ -2205,6 +2212,7 @@ const executeProvider = async ({
|
|
|
2205
2212
|
};
|
|
2206
2213
|
|
|
2207
2214
|
const CommandExecute = 'ExtensionHostCommand.executeCommand';
|
|
2215
|
+
const FileSystemWriteFile = 'ExtensionHostFileSystem.writeFile';
|
|
2208
2216
|
|
|
2209
2217
|
const normalizeLimitInfo = value => {
|
|
2210
2218
|
if (!value || typeof value !== 'object') {
|
|
@@ -2310,6 +2318,183 @@ const getMockOpenRouterAssistantText = async (messages, modelId, openRouterApiBa
|
|
|
2310
2318
|
}
|
|
2311
2319
|
};
|
|
2312
2320
|
|
|
2321
|
+
const OnFileSystem = 'onFileSystem';
|
|
2322
|
+
|
|
2323
|
+
const isPathTraversalAttempt = path => {
|
|
2324
|
+
if (!path) {
|
|
2325
|
+
return false;
|
|
2326
|
+
}
|
|
2327
|
+
if (path.startsWith('/') || path.startsWith('\\')) {
|
|
2328
|
+
return true;
|
|
2329
|
+
}
|
|
2330
|
+
if (path.startsWith('file://')) {
|
|
2331
|
+
return true;
|
|
2332
|
+
}
|
|
2333
|
+
if (/^[a-zA-Z]:[\\/]/.test(path)) {
|
|
2334
|
+
return true;
|
|
2335
|
+
}
|
|
2336
|
+
const segments = path.split(/[\\/]/);
|
|
2337
|
+
return segments.includes('..');
|
|
2338
|
+
};
|
|
2339
|
+
const normalizeRelativePath = path => {
|
|
2340
|
+
const segments = path.split(/[\\/]/).filter(segment => segment && segment !== '.');
|
|
2341
|
+
if (segments.length === 0) {
|
|
2342
|
+
return '.';
|
|
2343
|
+
}
|
|
2344
|
+
return segments.join('/');
|
|
2345
|
+
};
|
|
2346
|
+
const parseToolArguments = rawArguments => {
|
|
2347
|
+
if (typeof rawArguments !== 'string') {
|
|
2348
|
+
return {};
|
|
2349
|
+
}
|
|
2350
|
+
try {
|
|
2351
|
+
const parsed = JSON.parse(rawArguments);
|
|
2352
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
2353
|
+
return {};
|
|
2354
|
+
}
|
|
2355
|
+
return parsed;
|
|
2356
|
+
} catch {
|
|
2357
|
+
return {};
|
|
2358
|
+
}
|
|
2359
|
+
};
|
|
2360
|
+
const executeFileSystemCommand = async (method, params, options) => {
|
|
2361
|
+
return executeProvider({
|
|
2362
|
+
assetDir: options.assetDir,
|
|
2363
|
+
event: OnFileSystem,
|
|
2364
|
+
method,
|
|
2365
|
+
noProviderFoundMessage: 'No file system provider found',
|
|
2366
|
+
params,
|
|
2367
|
+
platform: options.platform
|
|
2368
|
+
});
|
|
2369
|
+
};
|
|
2370
|
+
const getBasicChatTools = () => {
|
|
2371
|
+
return [{
|
|
2372
|
+
function: {
|
|
2373
|
+
description: 'Read UTF-8 text content from a file inside the currently open workspace folder.',
|
|
2374
|
+
name: 'read_file',
|
|
2375
|
+
parameters: {
|
|
2376
|
+
additionalProperties: false,
|
|
2377
|
+
properties: {
|
|
2378
|
+
path: {
|
|
2379
|
+
description: 'Relative file path within the workspace (for example: src/index.ts).',
|
|
2380
|
+
type: 'string'
|
|
2381
|
+
}
|
|
2382
|
+
},
|
|
2383
|
+
required: ['path'],
|
|
2384
|
+
type: 'object'
|
|
2385
|
+
}
|
|
2386
|
+
},
|
|
2387
|
+
type: 'function'
|
|
2388
|
+
}, {
|
|
2389
|
+
function: {
|
|
2390
|
+
description: 'Write UTF-8 text content to a file inside the currently open workspace folder.',
|
|
2391
|
+
name: 'write_file',
|
|
2392
|
+
parameters: {
|
|
2393
|
+
additionalProperties: false,
|
|
2394
|
+
properties: {
|
|
2395
|
+
content: {
|
|
2396
|
+
description: 'New UTF-8 text content to write to the file.',
|
|
2397
|
+
type: 'string'
|
|
2398
|
+
},
|
|
2399
|
+
path: {
|
|
2400
|
+
description: 'Relative file path within the workspace (for example: src/index.ts).',
|
|
2401
|
+
type: 'string'
|
|
2402
|
+
}
|
|
2403
|
+
},
|
|
2404
|
+
required: ['path', 'content'],
|
|
2405
|
+
type: 'object'
|
|
2406
|
+
}
|
|
2407
|
+
},
|
|
2408
|
+
type: 'function'
|
|
2409
|
+
}, {
|
|
2410
|
+
function: {
|
|
2411
|
+
description: 'List direct children (files and folders) for a folder inside the currently open workspace folder.',
|
|
2412
|
+
name: 'list_files',
|
|
2413
|
+
parameters: {
|
|
2414
|
+
additionalProperties: false,
|
|
2415
|
+
properties: {
|
|
2416
|
+
path: {
|
|
2417
|
+
description: 'Relative folder path within the workspace. Use "." for the workspace root.',
|
|
2418
|
+
type: 'string'
|
|
2419
|
+
}
|
|
2420
|
+
},
|
|
2421
|
+
type: 'object'
|
|
2422
|
+
}
|
|
2423
|
+
},
|
|
2424
|
+
type: 'function'
|
|
2425
|
+
}];
|
|
2426
|
+
};
|
|
2427
|
+
const executeChatTool = async (name, rawArguments, options) => {
|
|
2428
|
+
const args = parseToolArguments(rawArguments);
|
|
2429
|
+
if (name === 'read_file') {
|
|
2430
|
+
const filePath = typeof args.path === 'string' ? args.path : '';
|
|
2431
|
+
if (!filePath || isPathTraversalAttempt(filePath)) {
|
|
2432
|
+
return JSON.stringify({
|
|
2433
|
+
error: 'Access denied: path must be relative and stay within the open workspace folder.'
|
|
2434
|
+
});
|
|
2435
|
+
}
|
|
2436
|
+
const normalizedPath = normalizeRelativePath(filePath);
|
|
2437
|
+
try {
|
|
2438
|
+
const content = await readFile(normalizedPath);
|
|
2439
|
+
return JSON.stringify({
|
|
2440
|
+
content,
|
|
2441
|
+
path: normalizedPath
|
|
2442
|
+
});
|
|
2443
|
+
} catch (error) {
|
|
2444
|
+
return JSON.stringify({
|
|
2445
|
+
error: String(error),
|
|
2446
|
+
path: normalizedPath
|
|
2447
|
+
});
|
|
2448
|
+
}
|
|
2449
|
+
}
|
|
2450
|
+
if (name === 'write_file') {
|
|
2451
|
+
const filePath = typeof args.path === 'string' ? args.path : '';
|
|
2452
|
+
const content = typeof args.content === 'string' ? args.content : '';
|
|
2453
|
+
if (!filePath || isPathTraversalAttempt(filePath)) {
|
|
2454
|
+
return JSON.stringify({
|
|
2455
|
+
error: 'Access denied: path must be relative and stay within the open workspace folder.'
|
|
2456
|
+
});
|
|
2457
|
+
}
|
|
2458
|
+
const normalizedPath = normalizeRelativePath(filePath);
|
|
2459
|
+
try {
|
|
2460
|
+
await executeFileSystemCommand(FileSystemWriteFile, ['file', normalizedPath, content], options);
|
|
2461
|
+
return JSON.stringify({
|
|
2462
|
+
ok: true,
|
|
2463
|
+
path: normalizedPath
|
|
2464
|
+
});
|
|
2465
|
+
} catch (error) {
|
|
2466
|
+
return JSON.stringify({
|
|
2467
|
+
error: String(error),
|
|
2468
|
+
path: normalizedPath
|
|
2469
|
+
});
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
if (name === 'list_files') {
|
|
2473
|
+
const folderPath = typeof args.path === 'string' && args.path ? args.path : '.';
|
|
2474
|
+
if (isPathTraversalAttempt(folderPath)) {
|
|
2475
|
+
return JSON.stringify({
|
|
2476
|
+
error: 'Access denied: path must be relative and stay within the open workspace folder.'
|
|
2477
|
+
});
|
|
2478
|
+
}
|
|
2479
|
+
const normalizedPath = normalizeRelativePath(folderPath);
|
|
2480
|
+
try {
|
|
2481
|
+
const entries = await invoke('FileSystem.readDirWithFileTypes', normalizedPath);
|
|
2482
|
+
return JSON.stringify({
|
|
2483
|
+
entries,
|
|
2484
|
+
path: normalizedPath
|
|
2485
|
+
});
|
|
2486
|
+
} catch (error) {
|
|
2487
|
+
return JSON.stringify({
|
|
2488
|
+
error: String(error),
|
|
2489
|
+
path: normalizedPath
|
|
2490
|
+
});
|
|
2491
|
+
}
|
|
2492
|
+
}
|
|
2493
|
+
return JSON.stringify({
|
|
2494
|
+
error: `Unknown tool: ${name}`
|
|
2495
|
+
});
|
|
2496
|
+
};
|
|
2497
|
+
|
|
2313
2498
|
const getOpenApiApiEndpoint = openApiApiBaseUrl => {
|
|
2314
2499
|
return `${openApiApiBaseUrl}/chat/completions`;
|
|
2315
2500
|
};
|
|
@@ -2358,84 +2543,121 @@ const getOpenApiErrorDetails = async response => {
|
|
|
2358
2543
|
errorType: typeof errorType === 'string' ? errorType : undefined
|
|
2359
2544
|
};
|
|
2360
2545
|
};
|
|
2361
|
-
const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApiApiBaseUrl) => {
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
}
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
}
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
}
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2546
|
+
const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApiApiBaseUrl, assetDir, platform) => {
|
|
2547
|
+
const completionMessages = messages.map(message => ({
|
|
2548
|
+
content: message.text,
|
|
2549
|
+
role: message.role
|
|
2550
|
+
}));
|
|
2551
|
+
const tools = getBasicChatTools();
|
|
2552
|
+
const maxToolIterations = 4;
|
|
2553
|
+
for (let i = 0; i <= maxToolIterations; i++) {
|
|
2554
|
+
let response;
|
|
2555
|
+
try {
|
|
2556
|
+
response = await fetch(getOpenApiApiEndpoint(openApiApiBaseUrl), {
|
|
2557
|
+
body: JSON.stringify({
|
|
2558
|
+
messages: completionMessages,
|
|
2559
|
+
model: modelId,
|
|
2560
|
+
tool_choice: 'auto',
|
|
2561
|
+
tools
|
|
2562
|
+
}),
|
|
2563
|
+
headers: {
|
|
2564
|
+
Authorization: `Bearer ${openApiApiKey}`,
|
|
2565
|
+
'Content-Type': 'application/json'
|
|
2566
|
+
},
|
|
2567
|
+
method: 'POST'
|
|
2568
|
+
});
|
|
2569
|
+
} catch {
|
|
2570
|
+
return {
|
|
2571
|
+
details: 'request-failed',
|
|
2572
|
+
type: 'error'
|
|
2573
|
+
};
|
|
2574
|
+
}
|
|
2575
|
+
if (!response.ok) {
|
|
2576
|
+
const {
|
|
2577
|
+
errorCode,
|
|
2578
|
+
errorMessage,
|
|
2579
|
+
errorType
|
|
2580
|
+
} = await getOpenApiErrorDetails(response);
|
|
2581
|
+
return {
|
|
2582
|
+
details: 'http-error',
|
|
2583
|
+
errorCode,
|
|
2584
|
+
errorMessage,
|
|
2585
|
+
errorType,
|
|
2586
|
+
statusCode: response.status,
|
|
2587
|
+
type: 'error'
|
|
2588
|
+
};
|
|
2589
|
+
}
|
|
2590
|
+
let parsed;
|
|
2591
|
+
try {
|
|
2592
|
+
parsed = await response.json();
|
|
2593
|
+
} catch {
|
|
2594
|
+
return {
|
|
2595
|
+
details: 'request-failed',
|
|
2596
|
+
type: 'error'
|
|
2597
|
+
};
|
|
2598
|
+
}
|
|
2599
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
2600
|
+
return {
|
|
2601
|
+
text: '',
|
|
2602
|
+
type: 'success'
|
|
2603
|
+
};
|
|
2604
|
+
}
|
|
2605
|
+
const choices = Reflect.get(parsed, 'choices');
|
|
2606
|
+
if (!Array.isArray(choices)) {
|
|
2607
|
+
return {
|
|
2608
|
+
text: '',
|
|
2609
|
+
type: 'success'
|
|
2610
|
+
};
|
|
2611
|
+
}
|
|
2612
|
+
const firstChoice = choices[0];
|
|
2613
|
+
if (!firstChoice || typeof firstChoice !== 'object') {
|
|
2614
|
+
return {
|
|
2615
|
+
text: '',
|
|
2616
|
+
type: 'success'
|
|
2617
|
+
};
|
|
2618
|
+
}
|
|
2619
|
+
const message = Reflect.get(firstChoice, 'message');
|
|
2620
|
+
if (!message || typeof message !== 'object') {
|
|
2621
|
+
return {
|
|
2622
|
+
text: '',
|
|
2623
|
+
type: 'success'
|
|
2624
|
+
};
|
|
2625
|
+
}
|
|
2626
|
+
const toolCalls = Reflect.get(message, 'tool_calls');
|
|
2627
|
+
if (Array.isArray(toolCalls) && toolCalls.length > 0) {
|
|
2628
|
+
completionMessages.push(message);
|
|
2629
|
+
for (const toolCall of toolCalls) {
|
|
2630
|
+
if (!toolCall || typeof toolCall !== 'object') {
|
|
2631
|
+
continue;
|
|
2632
|
+
}
|
|
2633
|
+
const id = Reflect.get(toolCall, 'id');
|
|
2634
|
+
const toolFunction = Reflect.get(toolCall, 'function');
|
|
2635
|
+
if (typeof id !== 'string' || !toolFunction || typeof toolFunction !== 'object') {
|
|
2636
|
+
continue;
|
|
2637
|
+
}
|
|
2638
|
+
const name = Reflect.get(toolFunction, 'name');
|
|
2639
|
+
const rawArguments = Reflect.get(toolFunction, 'arguments');
|
|
2640
|
+
const content = typeof name === 'string' ? await executeChatTool(name, rawArguments, {
|
|
2641
|
+
assetDir,
|
|
2642
|
+
platform
|
|
2643
|
+
}) : '{}';
|
|
2644
|
+
completionMessages.push({
|
|
2645
|
+
content,
|
|
2646
|
+
role: 'tool',
|
|
2647
|
+
tool_call_id: id
|
|
2648
|
+
});
|
|
2649
|
+
}
|
|
2650
|
+
continue;
|
|
2651
|
+
}
|
|
2652
|
+
const content = Reflect.get(message, 'content');
|
|
2430
2653
|
return {
|
|
2431
|
-
text:
|
|
2654
|
+
text: getTextContent(content),
|
|
2432
2655
|
type: 'success'
|
|
2433
2656
|
};
|
|
2434
2657
|
}
|
|
2435
|
-
const content = Reflect.get(message, 'content');
|
|
2436
2658
|
return {
|
|
2437
|
-
|
|
2438
|
-
type: '
|
|
2659
|
+
details: 'request-failed',
|
|
2660
|
+
type: 'error'
|
|
2439
2661
|
};
|
|
2440
2662
|
};
|
|
2441
2663
|
|
|
@@ -2575,91 +2797,128 @@ const getOpenRouterLimitInfo = async (openRouterApiKey, openRouterApiBaseUrl) =>
|
|
|
2575
2797
|
}
|
|
2576
2798
|
return normalizedLimitInfo;
|
|
2577
2799
|
};
|
|
2578
|
-
const getOpenRouterAssistantText = async (messages, modelId, openRouterApiKey, openRouterApiBaseUrl) => {
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
if (response.status === 429) {
|
|
2603
|
-
const retryAfter = response.headers?.get?.('retry-after') ?? null;
|
|
2604
|
-
const rawMessage = await getOpenRouterRaw429Message(response);
|
|
2605
|
-
const limitInfo = await getOpenRouterLimitInfo(openRouterApiKey, openRouterApiBaseUrl);
|
|
2800
|
+
const getOpenRouterAssistantText = async (messages, modelId, openRouterApiKey, openRouterApiBaseUrl, assetDir, platform) => {
|
|
2801
|
+
const completionMessages = messages.map(message => ({
|
|
2802
|
+
content: message.text,
|
|
2803
|
+
role: message.role
|
|
2804
|
+
}));
|
|
2805
|
+
const tools = getBasicChatTools();
|
|
2806
|
+
const maxToolIterations = 4;
|
|
2807
|
+
for (let i = 0; i <= maxToolIterations; i++) {
|
|
2808
|
+
let response;
|
|
2809
|
+
try {
|
|
2810
|
+
response = await fetch(getOpenRouterApiEndpoint(openRouterApiBaseUrl), {
|
|
2811
|
+
body: JSON.stringify({
|
|
2812
|
+
messages: completionMessages,
|
|
2813
|
+
model: modelId,
|
|
2814
|
+
tool_choice: 'auto',
|
|
2815
|
+
tools
|
|
2816
|
+
}),
|
|
2817
|
+
headers: {
|
|
2818
|
+
Authorization: `Bearer ${openRouterApiKey}`,
|
|
2819
|
+
'Content-Type': 'application/json'
|
|
2820
|
+
},
|
|
2821
|
+
method: 'POST'
|
|
2822
|
+
});
|
|
2823
|
+
} catch {
|
|
2606
2824
|
return {
|
|
2607
|
-
details: '
|
|
2608
|
-
limitInfo: limitInfo || retryAfter ? {
|
|
2609
|
-
...limitInfo,
|
|
2610
|
-
retryAfter
|
|
2611
|
-
} : undefined,
|
|
2612
|
-
rawMessage,
|
|
2613
|
-
statusCode: 429,
|
|
2825
|
+
details: 'request-failed',
|
|
2614
2826
|
type: 'error'
|
|
2615
2827
|
};
|
|
2616
2828
|
}
|
|
2829
|
+
if (!response.ok) {
|
|
2830
|
+
if (response.status === 429) {
|
|
2831
|
+
const retryAfter = response.headers?.get?.('retry-after') ?? null;
|
|
2832
|
+
const rawMessage = await getOpenRouterRaw429Message(response);
|
|
2833
|
+
const limitInfo = await getOpenRouterLimitInfo(openRouterApiKey, openRouterApiBaseUrl);
|
|
2834
|
+
return {
|
|
2835
|
+
details: 'too-many-requests',
|
|
2836
|
+
limitInfo: limitInfo || retryAfter ? {
|
|
2837
|
+
...limitInfo,
|
|
2838
|
+
retryAfter
|
|
2839
|
+
} : undefined,
|
|
2840
|
+
rawMessage,
|
|
2841
|
+
statusCode: 429,
|
|
2842
|
+
type: 'error'
|
|
2843
|
+
};
|
|
2844
|
+
}
|
|
2845
|
+
return {
|
|
2846
|
+
details: 'http-error',
|
|
2847
|
+
statusCode: response.status,
|
|
2848
|
+
type: 'error'
|
|
2849
|
+
};
|
|
2850
|
+
}
|
|
2851
|
+
let parsed;
|
|
2852
|
+
try {
|
|
2853
|
+
parsed = await response.json();
|
|
2854
|
+
} catch {
|
|
2855
|
+
return {
|
|
2856
|
+
details: 'request-failed',
|
|
2857
|
+
type: 'error'
|
|
2858
|
+
};
|
|
2859
|
+
}
|
|
2860
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
2861
|
+
return {
|
|
2862
|
+
text: '',
|
|
2863
|
+
type: 'success'
|
|
2864
|
+
};
|
|
2865
|
+
}
|
|
2866
|
+
const choices = Reflect.get(parsed, 'choices');
|
|
2867
|
+
if (!Array.isArray(choices)) {
|
|
2868
|
+
return {
|
|
2869
|
+
text: '',
|
|
2870
|
+
type: 'success'
|
|
2871
|
+
};
|
|
2872
|
+
}
|
|
2873
|
+
const firstChoice = choices[0];
|
|
2874
|
+
if (!firstChoice || typeof firstChoice !== 'object') {
|
|
2875
|
+
return {
|
|
2876
|
+
text: '',
|
|
2877
|
+
type: 'success'
|
|
2878
|
+
};
|
|
2879
|
+
}
|
|
2880
|
+
const message = Reflect.get(firstChoice, 'message');
|
|
2881
|
+
if (!message || typeof message !== 'object') {
|
|
2882
|
+
return {
|
|
2883
|
+
text: '',
|
|
2884
|
+
type: 'success'
|
|
2885
|
+
};
|
|
2886
|
+
}
|
|
2887
|
+
const toolCalls = Reflect.get(message, 'tool_calls');
|
|
2888
|
+
if (Array.isArray(toolCalls) && toolCalls.length > 0) {
|
|
2889
|
+
completionMessages.push(message);
|
|
2890
|
+
for (const toolCall of toolCalls) {
|
|
2891
|
+
if (!toolCall || typeof toolCall !== 'object') {
|
|
2892
|
+
continue;
|
|
2893
|
+
}
|
|
2894
|
+
const id = Reflect.get(toolCall, 'id');
|
|
2895
|
+
const toolFunction = Reflect.get(toolCall, 'function');
|
|
2896
|
+
if (typeof id !== 'string' || !toolFunction || typeof toolFunction !== 'object') {
|
|
2897
|
+
continue;
|
|
2898
|
+
}
|
|
2899
|
+
const name = Reflect.get(toolFunction, 'name');
|
|
2900
|
+
const rawArguments = Reflect.get(toolFunction, 'arguments');
|
|
2901
|
+
const content = typeof name === 'string' ? await executeChatTool(name, rawArguments, {
|
|
2902
|
+
assetDir,
|
|
2903
|
+
platform
|
|
2904
|
+
}) : '{}';
|
|
2905
|
+
completionMessages.push({
|
|
2906
|
+
content,
|
|
2907
|
+
role: 'tool',
|
|
2908
|
+
tool_call_id: id
|
|
2909
|
+
});
|
|
2910
|
+
}
|
|
2911
|
+
continue;
|
|
2912
|
+
}
|
|
2913
|
+
const content = Reflect.get(message, 'content');
|
|
2617
2914
|
return {
|
|
2618
|
-
|
|
2619
|
-
statusCode: response.status,
|
|
2620
|
-
type: 'error'
|
|
2621
|
-
};
|
|
2622
|
-
}
|
|
2623
|
-
let parsed;
|
|
2624
|
-
try {
|
|
2625
|
-
parsed = await response.json();
|
|
2626
|
-
} catch {
|
|
2627
|
-
return {
|
|
2628
|
-
details: 'request-failed',
|
|
2629
|
-
type: 'error'
|
|
2630
|
-
};
|
|
2631
|
-
}
|
|
2632
|
-
if (!parsed || typeof parsed !== 'object') {
|
|
2633
|
-
return {
|
|
2634
|
-
text: '',
|
|
2635
|
-
type: 'success'
|
|
2636
|
-
};
|
|
2637
|
-
}
|
|
2638
|
-
const choices = Reflect.get(parsed, 'choices');
|
|
2639
|
-
if (!Array.isArray(choices)) {
|
|
2640
|
-
return {
|
|
2641
|
-
text: '',
|
|
2642
|
-
type: 'success'
|
|
2643
|
-
};
|
|
2644
|
-
}
|
|
2645
|
-
const firstChoice = choices[0];
|
|
2646
|
-
if (!firstChoice || typeof firstChoice !== 'object') {
|
|
2647
|
-
return {
|
|
2648
|
-
text: '',
|
|
2649
|
-
type: 'success'
|
|
2650
|
-
};
|
|
2651
|
-
}
|
|
2652
|
-
const message = Reflect.get(firstChoice, 'message');
|
|
2653
|
-
if (!message || typeof message !== 'object') {
|
|
2654
|
-
return {
|
|
2655
|
-
text: '',
|
|
2915
|
+
text: getTextContent(content),
|
|
2656
2916
|
type: 'success'
|
|
2657
2917
|
};
|
|
2658
2918
|
}
|
|
2659
|
-
const content = Reflect.get(message, 'content');
|
|
2660
2919
|
return {
|
|
2661
|
-
|
|
2662
|
-
type: '
|
|
2920
|
+
details: 'request-failed',
|
|
2921
|
+
type: 'error'
|
|
2663
2922
|
};
|
|
2664
2923
|
};
|
|
2665
2924
|
|
|
@@ -2706,7 +2965,7 @@ const getOpenRouterErrorMessage = errorResult => {
|
|
|
2706
2965
|
}
|
|
2707
2966
|
};
|
|
2708
2967
|
|
|
2709
|
-
|
|
2968
|
+
// cspell:ignore openrouter
|
|
2710
2969
|
const getOpenRouterModelId = selectedModelId => {
|
|
2711
2970
|
const openRouterPrefix = 'openrouter/';
|
|
2712
2971
|
if (selectedModelId.toLowerCase().startsWith(openRouterPrefix)) {
|
|
@@ -2725,7 +2984,7 @@ const isOpenApiModel = (selectedModelId, models) => {
|
|
|
2725
2984
|
return normalizedModelId.startsWith('openapi/') || normalizedModelId.startsWith('openai/');
|
|
2726
2985
|
};
|
|
2727
2986
|
|
|
2728
|
-
|
|
2987
|
+
// cspell:ignore openrouter
|
|
2729
2988
|
|
|
2730
2989
|
const isOpenRouterModel = (selectedModelId, models) => {
|
|
2731
2990
|
const selectedModel = models.find(model => model.id === selectedModelId);
|
|
@@ -2756,7 +3015,7 @@ const getAiResponse = async ({
|
|
|
2756
3015
|
const usesOpenRouterModel = isOpenRouterModel(selectedModelId, models);
|
|
2757
3016
|
if (usesOpenApiModel) {
|
|
2758
3017
|
if (openApiApiKey) {
|
|
2759
|
-
const result = await getOpenApiAssistantText(messages, getOpenApiModelId(selectedModelId), openApiApiKey, openApiApiBaseUrl);
|
|
3018
|
+
const result = await getOpenApiAssistantText(messages, getOpenApiModelId(selectedModelId), openApiApiKey, openApiApiBaseUrl, assetDir, platform);
|
|
2760
3019
|
if (result.type === 'success') {
|
|
2761
3020
|
const {
|
|
2762
3021
|
text: assistantText
|
|
@@ -2781,7 +3040,7 @@ const getAiResponse = async ({
|
|
|
2781
3040
|
text = getOpenRouterErrorMessage(result);
|
|
2782
3041
|
}
|
|
2783
3042
|
} else if (openRouterApiKey) {
|
|
2784
|
-
const result = await getOpenRouterAssistantText(messages, modelId, openRouterApiKey, openRouterApiBaseUrl);
|
|
3043
|
+
const result = await getOpenRouterAssistantText(messages, modelId, openRouterApiKey, openRouterApiBaseUrl, assetDir, platform);
|
|
2785
3044
|
if (result.type === 'success') {
|
|
2786
3045
|
const {
|
|
2787
3046
|
text: assistantText
|
|
@@ -3146,7 +3405,7 @@ const OpenApiApiKeyInput = 'open-api-api-key';
|
|
|
3146
3405
|
const SaveOpenApiApiKey = 'save-openapi-api-key';
|
|
3147
3406
|
const OpenOpenApiApiKeySettings = 'open-openapi-api-key-settings';
|
|
3148
3407
|
|
|
3149
|
-
|
|
3408
|
+
// cspell:ignore openrouter
|
|
3150
3409
|
const OpenRouterApiKeyInput = 'open-router-api-key';
|
|
3151
3410
|
const SaveOpenRouterApiKey = 'save-openrouter-api-key';
|
|
3152
3411
|
const OpenOpenRouterApiKeySettings = 'open-openrouter-api-key-settings';
|
|
@@ -3393,7 +3652,10 @@ const handleModelChange = async (state, value) => {
|
|
|
3393
3652
|
};
|
|
3394
3653
|
|
|
3395
3654
|
const handleNewline = async state => {
|
|
3396
|
-
|
|
3655
|
+
const {
|
|
3656
|
+
composerValue
|
|
3657
|
+
} = state;
|
|
3658
|
+
return handleInput(state, Composer, `${composerValue}\n`);
|
|
3397
3659
|
};
|
|
3398
3660
|
|
|
3399
3661
|
const id = 7201;
|
|
@@ -3593,12 +3855,22 @@ const openMockSession = async (state, mockSessionId, mockChatMessages) => {
|
|
|
3593
3855
|
};
|
|
3594
3856
|
};
|
|
3595
3857
|
|
|
3858
|
+
const getCss = composerHeight => {
|
|
3859
|
+
return `:root {
|
|
3860
|
+
--ChatInputBoxHeight: ${composerHeight}px;
|
|
3861
|
+
}`;
|
|
3862
|
+
};
|
|
3863
|
+
|
|
3596
3864
|
// TODO render things like scrollbar height,scrollbar offset, textarea height,
|
|
3597
3865
|
// list height
|
|
3598
|
-
|
|
3599
|
-
`;
|
|
3866
|
+
|
|
3600
3867
|
const renderCss = (oldState, newState) => {
|
|
3601
|
-
|
|
3868
|
+
const {
|
|
3869
|
+
composerHeight,
|
|
3870
|
+
uid
|
|
3871
|
+
} = newState;
|
|
3872
|
+
const css = getCss(composerHeight);
|
|
3873
|
+
return [SetCss, uid, css];
|
|
3602
3874
|
};
|
|
3603
3875
|
|
|
3604
3876
|
const getFocusSelector = focus => {
|
|
@@ -3770,7 +4042,7 @@ const getChatSendAreaDom = (composerValue, models, selectedModelId, usageOvervie
|
|
|
3770
4042
|
onFocus: HandleFocus,
|
|
3771
4043
|
onInput: HandleInput,
|
|
3772
4044
|
placeholder: composePlaceholder(),
|
|
3773
|
-
style: `height:${composerHeight}px;font-size:${composerFontSize}px;font-family:${composerFontFamily};line-height:${composerLineHeight}px;`,
|
|
4045
|
+
// style: `height:${composerHeight}px;font-size:${composerFontSize}px;font-family:${composerFontFamily};line-height:${composerLineHeight}px;`,
|
|
3774
4046
|
type: TextArea,
|
|
3775
4047
|
value: composerValue
|
|
3776
4048
|
}, {
|