@lvce-editor/chat-view 6.8.0 → 6.10.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 +221 -291
- package/package.json +1 -1
|
@@ -1269,15 +1269,9 @@ const sendMessagePortToChatNetworkWorker = async port => {
|
|
|
1269
1269
|
const sendMessagePortToChatToolWorker = async port => {
|
|
1270
1270
|
await invokeAndTransfer('SendMessagePortToExtensionHostWorker.sendMessagePortToChatToolWorker', port, 'HandleMessagePort.handleMessagePort');
|
|
1271
1271
|
};
|
|
1272
|
-
const writeFile = async (uri, text) => {
|
|
1273
|
-
await invoke$1('FileSystem.writeFile', uri, text);
|
|
1274
|
-
};
|
|
1275
1272
|
const activateByEvent$1 = (event, assetDir, platform) => {
|
|
1276
1273
|
return invoke$1('ExtensionHostManagement.activateByEvent', event, assetDir, platform);
|
|
1277
1274
|
};
|
|
1278
|
-
const getWorkspacePath = () => {
|
|
1279
|
-
return invoke$1('Workspace.getPath');
|
|
1280
|
-
};
|
|
1281
1275
|
const getPreference = async key => {
|
|
1282
1276
|
return await invoke$1('Preferences.get', key);
|
|
1283
1277
|
};
|
|
@@ -3349,194 +3343,6 @@ const getTools = async () => {
|
|
|
3349
3343
|
return invoke$3('ChatTool.getTools');
|
|
3350
3344
|
};
|
|
3351
3345
|
|
|
3352
|
-
const executeAskQuestionTool = args => {
|
|
3353
|
-
const normalized = args && typeof args === 'object' ? args : {};
|
|
3354
|
-
const question = Reflect.get(normalized, 'question');
|
|
3355
|
-
const answers = Reflect.get(normalized, 'answers');
|
|
3356
|
-
return JSON.stringify({
|
|
3357
|
-
answers: Array.isArray(answers) ? answers.filter(answer => typeof answer === 'string') : [],
|
|
3358
|
-
ok: true,
|
|
3359
|
-
question: typeof question === 'string' ? question : ''
|
|
3360
|
-
});
|
|
3361
|
-
};
|
|
3362
|
-
|
|
3363
|
-
const getToolErrorPayload = error => {
|
|
3364
|
-
const rawStack = error && typeof error === 'object' ? Reflect.get(error, 'stack') : undefined;
|
|
3365
|
-
return {
|
|
3366
|
-
error: String(error),
|
|
3367
|
-
...(typeof rawStack === 'string' && rawStack.trim() ? {
|
|
3368
|
-
errorStack: rawStack,
|
|
3369
|
-
stack: rawStack
|
|
3370
|
-
} : {})
|
|
3371
|
-
};
|
|
3372
|
-
};
|
|
3373
|
-
|
|
3374
|
-
const executeGetWorkspaceUriTool = async (_args, _options) => {
|
|
3375
|
-
try {
|
|
3376
|
-
const workspaceUri = await getWorkspacePath();
|
|
3377
|
-
return JSON.stringify({
|
|
3378
|
-
workspaceUri
|
|
3379
|
-
});
|
|
3380
|
-
} catch (error) {
|
|
3381
|
-
return JSON.stringify(getToolErrorPayload(error));
|
|
3382
|
-
}
|
|
3383
|
-
};
|
|
3384
|
-
|
|
3385
|
-
const isAbsoluteUri$1 = value => {
|
|
3386
|
-
return /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(value);
|
|
3387
|
-
};
|
|
3388
|
-
const executeListFilesTool = async (args, _options) => {
|
|
3389
|
-
const uri = typeof args.uri === 'string' ? args.uri : '';
|
|
3390
|
-
if (!uri || !isAbsoluteUri$1(uri)) {
|
|
3391
|
-
return JSON.stringify({
|
|
3392
|
-
error: 'Invalid argument: uri must be an absolute URI.'
|
|
3393
|
-
});
|
|
3394
|
-
}
|
|
3395
|
-
try {
|
|
3396
|
-
const entries = await invoke$1('FileSystem.readDirWithFileTypes', uri);
|
|
3397
|
-
return JSON.stringify({
|
|
3398
|
-
entries,
|
|
3399
|
-
uri
|
|
3400
|
-
});
|
|
3401
|
-
} catch (error) {
|
|
3402
|
-
return JSON.stringify({
|
|
3403
|
-
...getToolErrorPayload(error),
|
|
3404
|
-
uri
|
|
3405
|
-
});
|
|
3406
|
-
}
|
|
3407
|
-
};
|
|
3408
|
-
|
|
3409
|
-
const isPathTraversalAttempt = path => {
|
|
3410
|
-
if (!path) {
|
|
3411
|
-
return false;
|
|
3412
|
-
}
|
|
3413
|
-
if (path.startsWith('/') || path.startsWith('\\')) {
|
|
3414
|
-
return true;
|
|
3415
|
-
}
|
|
3416
|
-
if (path.startsWith('file://')) {
|
|
3417
|
-
return true;
|
|
3418
|
-
}
|
|
3419
|
-
if (/^[a-zA-Z]:[\\/]/.test(path)) {
|
|
3420
|
-
return true;
|
|
3421
|
-
}
|
|
3422
|
-
const segments = path.split(/[\\/]/);
|
|
3423
|
-
return segments.includes('..');
|
|
3424
|
-
};
|
|
3425
|
-
|
|
3426
|
-
const normalizeRelativePath = path => {
|
|
3427
|
-
const segments = path.split(/[\\/]/).filter(segment => segment && segment !== '.');
|
|
3428
|
-
if (segments.length === 0) {
|
|
3429
|
-
return '.';
|
|
3430
|
-
}
|
|
3431
|
-
return segments.join('/');
|
|
3432
|
-
};
|
|
3433
|
-
|
|
3434
|
-
const isAbsoluteUri = value => {
|
|
3435
|
-
return /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(value);
|
|
3436
|
-
};
|
|
3437
|
-
const executeReadFileTool = async (args, _options) => {
|
|
3438
|
-
const uri = typeof args.uri === 'string' ? args.uri : '';
|
|
3439
|
-
if (uri) {
|
|
3440
|
-
if (!isAbsoluteUri(uri)) {
|
|
3441
|
-
return JSON.stringify({
|
|
3442
|
-
error: 'Invalid argument: uri must be an absolute URI.'
|
|
3443
|
-
});
|
|
3444
|
-
}
|
|
3445
|
-
try {
|
|
3446
|
-
const content = await readFile(uri);
|
|
3447
|
-
return JSON.stringify({
|
|
3448
|
-
content,
|
|
3449
|
-
uri
|
|
3450
|
-
});
|
|
3451
|
-
} catch (error) {
|
|
3452
|
-
return JSON.stringify({
|
|
3453
|
-
...getToolErrorPayload(error),
|
|
3454
|
-
uri
|
|
3455
|
-
});
|
|
3456
|
-
}
|
|
3457
|
-
}
|
|
3458
|
-
const filePath = typeof args.path === 'string' ? args.path : '';
|
|
3459
|
-
if (!filePath || isPathTraversalAttempt(filePath)) {
|
|
3460
|
-
return JSON.stringify({
|
|
3461
|
-
error: 'Access denied: path must be relative and stay within the open workspace folder.'
|
|
3462
|
-
});
|
|
3463
|
-
}
|
|
3464
|
-
const normalizedPath = normalizeRelativePath(filePath);
|
|
3465
|
-
try {
|
|
3466
|
-
const content = await readFile(normalizedPath);
|
|
3467
|
-
return JSON.stringify({
|
|
3468
|
-
content,
|
|
3469
|
-
path: normalizedPath
|
|
3470
|
-
});
|
|
3471
|
-
} catch (error) {
|
|
3472
|
-
return JSON.stringify({
|
|
3473
|
-
...getToolErrorPayload(error),
|
|
3474
|
-
path: normalizedPath
|
|
3475
|
-
});
|
|
3476
|
-
}
|
|
3477
|
-
};
|
|
3478
|
-
|
|
3479
|
-
const maxPayloadLength = 40_000;
|
|
3480
|
-
const executeRenderHtmlTool = async (args, _options) => {
|
|
3481
|
-
const html = typeof args.html === 'string' ? args.html : '';
|
|
3482
|
-
const css = typeof args.css === 'string' ? args.css : '';
|
|
3483
|
-
const title = typeof args.title === 'string' ? args.title : '';
|
|
3484
|
-
if (!html) {
|
|
3485
|
-
return JSON.stringify({
|
|
3486
|
-
error: 'Missing required argument: html'
|
|
3487
|
-
});
|
|
3488
|
-
}
|
|
3489
|
-
if (html.length > maxPayloadLength || css.length > maxPayloadLength) {
|
|
3490
|
-
return JSON.stringify({
|
|
3491
|
-
error: 'Payload too large: keep html/css under 40,000 characters each.'
|
|
3492
|
-
});
|
|
3493
|
-
}
|
|
3494
|
-
return JSON.stringify({
|
|
3495
|
-
css,
|
|
3496
|
-
html,
|
|
3497
|
-
ok: true,
|
|
3498
|
-
title
|
|
3499
|
-
});
|
|
3500
|
-
};
|
|
3501
|
-
|
|
3502
|
-
const executeWriteFileTool = async (args, _options) => {
|
|
3503
|
-
const filePath = typeof args.path === 'string' ? args.path : '';
|
|
3504
|
-
const content = typeof args.content === 'string' ? args.content : '';
|
|
3505
|
-
if (!filePath || isPathTraversalAttempt(filePath)) {
|
|
3506
|
-
return JSON.stringify({
|
|
3507
|
-
error: 'Access denied: path must be relative and stay within the open workspace folder.'
|
|
3508
|
-
});
|
|
3509
|
-
}
|
|
3510
|
-
const normalizedPath = normalizeRelativePath(filePath);
|
|
3511
|
-
try {
|
|
3512
|
-
await writeFile(normalizedPath, content);
|
|
3513
|
-
return JSON.stringify({
|
|
3514
|
-
ok: true,
|
|
3515
|
-
path: normalizedPath
|
|
3516
|
-
});
|
|
3517
|
-
} catch (error) {
|
|
3518
|
-
return JSON.stringify({
|
|
3519
|
-
...getToolErrorPayload(error),
|
|
3520
|
-
path: normalizedPath
|
|
3521
|
-
});
|
|
3522
|
-
}
|
|
3523
|
-
};
|
|
3524
|
-
|
|
3525
|
-
const parseToolArguments = rawArguments => {
|
|
3526
|
-
if (typeof rawArguments !== 'string') {
|
|
3527
|
-
return {};
|
|
3528
|
-
}
|
|
3529
|
-
try {
|
|
3530
|
-
const parsed = JSON.parse(rawArguments);
|
|
3531
|
-
if (!parsed || typeof parsed !== 'object') {
|
|
3532
|
-
return {};
|
|
3533
|
-
}
|
|
3534
|
-
return parsed;
|
|
3535
|
-
} catch {
|
|
3536
|
-
return {};
|
|
3537
|
-
}
|
|
3538
|
-
};
|
|
3539
|
-
|
|
3540
3346
|
const stringifyToolOutput = output => {
|
|
3541
3347
|
if (typeof output === 'string') {
|
|
3542
3348
|
return output;
|
|
@@ -3544,35 +3350,14 @@ const stringifyToolOutput = output => {
|
|
|
3544
3350
|
return JSON.stringify(output) ?? 'null';
|
|
3545
3351
|
};
|
|
3546
3352
|
const executeChatTool = async (name, rawArguments, options) => {
|
|
3547
|
-
if (options.useChatToolWorker) {
|
|
3548
|
-
|
|
3549
|
-
assetDir: options.assetDir,
|
|
3550
|
-
platform: options.platform
|
|
3551
|
-
});
|
|
3552
|
-
return stringifyToolOutput(workerOutput);
|
|
3553
|
-
}
|
|
3554
|
-
const args = parseToolArguments(rawArguments);
|
|
3555
|
-
if (name === 'read_file') {
|
|
3556
|
-
return executeReadFileTool(args);
|
|
3353
|
+
if (!options.useChatToolWorker) {
|
|
3354
|
+
throw new Error('Chat tools must be executed in a web worker environment. Please set useChatToolWorker to true in the options.');
|
|
3557
3355
|
}
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
if (name === 'list_files') {
|
|
3562
|
-
return executeListFilesTool(args);
|
|
3563
|
-
}
|
|
3564
|
-
if (name === 'getWorkspaceUri') {
|
|
3565
|
-
return executeGetWorkspaceUriTool();
|
|
3566
|
-
}
|
|
3567
|
-
if (name === 'render_html') {
|
|
3568
|
-
return executeRenderHtmlTool(args);
|
|
3569
|
-
}
|
|
3570
|
-
if (name === 'ask_question') {
|
|
3571
|
-
return executeAskQuestionTool(args);
|
|
3572
|
-
}
|
|
3573
|
-
return JSON.stringify({
|
|
3574
|
-
error: `Unknown tool: ${name}`
|
|
3356
|
+
const workerOutput = await execute(name, rawArguments, {
|
|
3357
|
+
assetDir: options.assetDir,
|
|
3358
|
+
platform: options.platform
|
|
3575
3359
|
});
|
|
3360
|
+
return stringifyToolOutput(workerOutput);
|
|
3576
3361
|
};
|
|
3577
3362
|
|
|
3578
3363
|
const getReadFileTool = () => {
|
|
@@ -7235,6 +7020,31 @@ Assistant: ${assistantText}`;
|
|
|
7235
7020
|
return title && !isDefaultSessionTitle(title) ? title : '';
|
|
7236
7021
|
};
|
|
7237
7022
|
|
|
7023
|
+
const isPathTraversalAttempt = path => {
|
|
7024
|
+
if (!path) {
|
|
7025
|
+
return false;
|
|
7026
|
+
}
|
|
7027
|
+
if (path.startsWith('/') || path.startsWith('\\')) {
|
|
7028
|
+
return true;
|
|
7029
|
+
}
|
|
7030
|
+
if (path.startsWith('file://')) {
|
|
7031
|
+
return true;
|
|
7032
|
+
}
|
|
7033
|
+
if (/^[a-zA-Z]:[\\/]/.test(path)) {
|
|
7034
|
+
return true;
|
|
7035
|
+
}
|
|
7036
|
+
const segments = path.split(/[\\/]/);
|
|
7037
|
+
return segments.includes('..');
|
|
7038
|
+
};
|
|
7039
|
+
|
|
7040
|
+
const normalizeRelativePath = path => {
|
|
7041
|
+
const segments = path.split(/[\\/]/).filter(segment => segment && segment !== '.');
|
|
7042
|
+
if (segments.length === 0) {
|
|
7043
|
+
return '.';
|
|
7044
|
+
}
|
|
7045
|
+
return segments.join('/');
|
|
7046
|
+
};
|
|
7047
|
+
|
|
7238
7048
|
const mentionRegex = /(^|\s)@([^\s]+)/g;
|
|
7239
7049
|
const maxMentionCount = 5;
|
|
7240
7050
|
const parseMentionedPaths = value => {
|
|
@@ -9288,12 +9098,14 @@ const ChatHeader = 'ChatHeader';
|
|
|
9288
9098
|
const Button = 'Button';
|
|
9289
9099
|
const ButtonPrimary = 'ButtonPrimary';
|
|
9290
9100
|
const ButtonSecondary = 'ButtonSecondary';
|
|
9101
|
+
const Deletion = 'Deletion';
|
|
9291
9102
|
const Empty = '';
|
|
9292
9103
|
const FileIcon = 'FileIcon';
|
|
9293
9104
|
const IconButton = 'IconButton';
|
|
9294
9105
|
const IconButtonDisabled = 'IconButtonDisabled';
|
|
9295
9106
|
const ImageElement = 'ImageElement';
|
|
9296
9107
|
const InputBox = 'InputBox';
|
|
9108
|
+
const Insertion = 'Insertion';
|
|
9297
9109
|
const Label = 'Label';
|
|
9298
9110
|
const LabelDetail = 'LabelDetail';
|
|
9299
9111
|
const ChatList = 'ChatList';
|
|
@@ -10014,6 +9826,76 @@ const getFileNameFromUri = uri => {
|
|
|
10014
9826
|
return fileName || uri;
|
|
10015
9827
|
};
|
|
10016
9828
|
|
|
9829
|
+
const isCompleteJson = value => {
|
|
9830
|
+
const trimmed = value.trim();
|
|
9831
|
+
if (!trimmed) {
|
|
9832
|
+
return false;
|
|
9833
|
+
}
|
|
9834
|
+
let depth = 0;
|
|
9835
|
+
let inString = false;
|
|
9836
|
+
let escaped = false;
|
|
9837
|
+
for (const char of trimmed) {
|
|
9838
|
+
if (inString) {
|
|
9839
|
+
if (escaped) {
|
|
9840
|
+
escaped = false;
|
|
9841
|
+
continue;
|
|
9842
|
+
}
|
|
9843
|
+
if (char === '\\') {
|
|
9844
|
+
escaped = true;
|
|
9845
|
+
continue;
|
|
9846
|
+
}
|
|
9847
|
+
if (char === '"') {
|
|
9848
|
+
inString = false;
|
|
9849
|
+
}
|
|
9850
|
+
continue;
|
|
9851
|
+
}
|
|
9852
|
+
if (char === '"') {
|
|
9853
|
+
inString = true;
|
|
9854
|
+
continue;
|
|
9855
|
+
}
|
|
9856
|
+
if (char === '{' || char === '[') {
|
|
9857
|
+
depth += 1;
|
|
9858
|
+
continue;
|
|
9859
|
+
}
|
|
9860
|
+
if (char === '}' || char === ']') {
|
|
9861
|
+
depth -= 1;
|
|
9862
|
+
if (depth < 0) {
|
|
9863
|
+
return false;
|
|
9864
|
+
}
|
|
9865
|
+
}
|
|
9866
|
+
}
|
|
9867
|
+
return depth === 0 && !inString && !escaped;
|
|
9868
|
+
};
|
|
9869
|
+
const getReadFileTarget = rawArguments => {
|
|
9870
|
+
// Tool arguments stream in chunks, so skip parsing until a full JSON payload is available.
|
|
9871
|
+
if (!isCompleteJson(rawArguments)) {
|
|
9872
|
+
return undefined;
|
|
9873
|
+
}
|
|
9874
|
+
let parsed;
|
|
9875
|
+
try {
|
|
9876
|
+
parsed = JSON.parse(rawArguments);
|
|
9877
|
+
} catch {
|
|
9878
|
+
return undefined;
|
|
9879
|
+
}
|
|
9880
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
9881
|
+
return undefined;
|
|
9882
|
+
}
|
|
9883
|
+
const uri = Reflect.get(parsed, 'uri');
|
|
9884
|
+
const path = Reflect.get(parsed, 'path');
|
|
9885
|
+
const uriValue = typeof uri === 'string' ? uri : '';
|
|
9886
|
+
const pathValue = typeof path === 'string' ? path : '';
|
|
9887
|
+
const title = uriValue || pathValue;
|
|
9888
|
+
if (!title) {
|
|
9889
|
+
return undefined;
|
|
9890
|
+
}
|
|
9891
|
+
// `read_file` tool calls now use absolute `uri`; keep `path` as a legacy fallback for old transcripts.
|
|
9892
|
+
const clickableUri = uriValue || pathValue;
|
|
9893
|
+
return {
|
|
9894
|
+
clickableUri,
|
|
9895
|
+
title
|
|
9896
|
+
};
|
|
9897
|
+
};
|
|
9898
|
+
|
|
10017
9899
|
const getToolCallArgumentPreview = rawArguments => {
|
|
10018
9900
|
if (!rawArguments.trim()) {
|
|
10019
9901
|
return '""';
|
|
@@ -10106,76 +9988,6 @@ const getToolCallAskQuestionVirtualDom = toolCall => {
|
|
|
10106
9988
|
}, text(answer.trim() ? answer : '(empty answer)')])];
|
|
10107
9989
|
};
|
|
10108
9990
|
|
|
10109
|
-
const isCompleteJson = value => {
|
|
10110
|
-
const trimmed = value.trim();
|
|
10111
|
-
if (!trimmed) {
|
|
10112
|
-
return false;
|
|
10113
|
-
}
|
|
10114
|
-
let depth = 0;
|
|
10115
|
-
let inString = false;
|
|
10116
|
-
let escaped = false;
|
|
10117
|
-
for (const char of trimmed) {
|
|
10118
|
-
if (inString) {
|
|
10119
|
-
if (escaped) {
|
|
10120
|
-
escaped = false;
|
|
10121
|
-
continue;
|
|
10122
|
-
}
|
|
10123
|
-
if (char === '\\') {
|
|
10124
|
-
escaped = true;
|
|
10125
|
-
continue;
|
|
10126
|
-
}
|
|
10127
|
-
if (char === '"') {
|
|
10128
|
-
inString = false;
|
|
10129
|
-
}
|
|
10130
|
-
continue;
|
|
10131
|
-
}
|
|
10132
|
-
if (char === '"') {
|
|
10133
|
-
inString = true;
|
|
10134
|
-
continue;
|
|
10135
|
-
}
|
|
10136
|
-
if (char === '{' || char === '[') {
|
|
10137
|
-
depth += 1;
|
|
10138
|
-
continue;
|
|
10139
|
-
}
|
|
10140
|
-
if (char === '}' || char === ']') {
|
|
10141
|
-
depth -= 1;
|
|
10142
|
-
if (depth < 0) {
|
|
10143
|
-
return false;
|
|
10144
|
-
}
|
|
10145
|
-
}
|
|
10146
|
-
}
|
|
10147
|
-
return depth === 0 && !inString && !escaped;
|
|
10148
|
-
};
|
|
10149
|
-
const getReadFileTarget = rawArguments => {
|
|
10150
|
-
// Tool arguments stream in chunks, so skip parsing until a full JSON payload is available.
|
|
10151
|
-
if (!isCompleteJson(rawArguments)) {
|
|
10152
|
-
return undefined;
|
|
10153
|
-
}
|
|
10154
|
-
let parsed;
|
|
10155
|
-
try {
|
|
10156
|
-
parsed = JSON.parse(rawArguments);
|
|
10157
|
-
} catch {
|
|
10158
|
-
return undefined;
|
|
10159
|
-
}
|
|
10160
|
-
if (!parsed || typeof parsed !== 'object') {
|
|
10161
|
-
return undefined;
|
|
10162
|
-
}
|
|
10163
|
-
const uri = Reflect.get(parsed, 'uri');
|
|
10164
|
-
const path = Reflect.get(parsed, 'path');
|
|
10165
|
-
const uriValue = typeof uri === 'string' ? uri : '';
|
|
10166
|
-
const pathValue = typeof path === 'string' ? path : '';
|
|
10167
|
-
const title = uriValue || pathValue;
|
|
10168
|
-
if (!title) {
|
|
10169
|
-
return undefined;
|
|
10170
|
-
}
|
|
10171
|
-
// `read_file` tool calls now use absolute `uri`; keep `path` as a legacy fallback for old transcripts.
|
|
10172
|
-
const clickableUri = uriValue || pathValue;
|
|
10173
|
-
return {
|
|
10174
|
-
clickableUri,
|
|
10175
|
-
title
|
|
10176
|
-
};
|
|
10177
|
-
};
|
|
10178
|
-
|
|
10179
9991
|
const getToolCallReadFileVirtualDom = toolCall => {
|
|
10180
9992
|
const target = getReadFileTarget(toolCall.arguments);
|
|
10181
9993
|
if (!target) {
|
|
@@ -10514,8 +10326,19 @@ const getToolCallDisplayName = name => {
|
|
|
10514
10326
|
}
|
|
10515
10327
|
return name;
|
|
10516
10328
|
};
|
|
10329
|
+
const hasIncompleteJsonArguments = rawArguments => {
|
|
10330
|
+
try {
|
|
10331
|
+
JSON.parse(rawArguments);
|
|
10332
|
+
return false;
|
|
10333
|
+
} catch {
|
|
10334
|
+
return true;
|
|
10335
|
+
}
|
|
10336
|
+
};
|
|
10517
10337
|
const getToolCallLabel = toolCall => {
|
|
10518
10338
|
const displayName = getToolCallDisplayName(toolCall.name);
|
|
10339
|
+
if (toolCall.name === 'write_file' && !toolCall.status && hasIncompleteJsonArguments(toolCall.arguments)) {
|
|
10340
|
+
return `${displayName} (in progress)`;
|
|
10341
|
+
}
|
|
10519
10342
|
const argumentPreview = getToolCallArgumentPreview(toolCall.arguments);
|
|
10520
10343
|
const statusLabel = getToolCallStatusLabel(toolCall);
|
|
10521
10344
|
if (argumentPreview === '{}') {
|
|
@@ -10546,6 +10369,101 @@ const getToolCallGetWorkspaceUriVirtualDom = toolCall => {
|
|
|
10546
10369
|
type: Span
|
|
10547
10370
|
}, text(fileName), ...(statusLabel ? [text(statusLabel)] : [])];
|
|
10548
10371
|
};
|
|
10372
|
+
const parseWriteFileLineCounts = rawResult => {
|
|
10373
|
+
if (!rawResult) {
|
|
10374
|
+
return {
|
|
10375
|
+
linesAdded: 0,
|
|
10376
|
+
linesDeleted: 0
|
|
10377
|
+
};
|
|
10378
|
+
}
|
|
10379
|
+
let parsed;
|
|
10380
|
+
try {
|
|
10381
|
+
parsed = JSON.parse(rawResult);
|
|
10382
|
+
} catch {
|
|
10383
|
+
return {
|
|
10384
|
+
linesAdded: 0,
|
|
10385
|
+
linesDeleted: 0
|
|
10386
|
+
};
|
|
10387
|
+
}
|
|
10388
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
10389
|
+
return {
|
|
10390
|
+
linesAdded: 0,
|
|
10391
|
+
linesDeleted: 0
|
|
10392
|
+
};
|
|
10393
|
+
}
|
|
10394
|
+
const linesAdded = Reflect.get(parsed, 'linesAdded');
|
|
10395
|
+
const linesDeleted = Reflect.get(parsed, 'linesDeleted');
|
|
10396
|
+
return {
|
|
10397
|
+
linesAdded: typeof linesAdded === 'number' ? Math.max(0, linesAdded) : 0,
|
|
10398
|
+
linesDeleted: typeof linesDeleted === 'number' ? Math.max(0, linesDeleted) : 0
|
|
10399
|
+
};
|
|
10400
|
+
};
|
|
10401
|
+
const getToolCallWriteFileVirtualDom = toolCall => {
|
|
10402
|
+
const target = getReadFileTarget(toolCall.arguments);
|
|
10403
|
+
if (!target) {
|
|
10404
|
+
return [];
|
|
10405
|
+
}
|
|
10406
|
+
const fileName = getFileNameFromUri(target.title);
|
|
10407
|
+
const statusLabel = getToolCallStatusLabel(toolCall);
|
|
10408
|
+
const {
|
|
10409
|
+
linesAdded,
|
|
10410
|
+
linesDeleted
|
|
10411
|
+
} = parseWriteFileLineCounts(toolCall.result);
|
|
10412
|
+
const fileNameClickableProps = target.clickableUri ? {
|
|
10413
|
+
'data-uri': target.clickableUri,
|
|
10414
|
+
onClick: HandleClickReadFile
|
|
10415
|
+
} : {};
|
|
10416
|
+
return [{
|
|
10417
|
+
childCount: statusLabel ? 6 : 5,
|
|
10418
|
+
className: ChatOrderedListItem,
|
|
10419
|
+
title: target.title,
|
|
10420
|
+
type: Li
|
|
10421
|
+
}, {
|
|
10422
|
+
childCount: 0,
|
|
10423
|
+
className: FileIcon,
|
|
10424
|
+
type: Div
|
|
10425
|
+
}, text('write_file '), {
|
|
10426
|
+
childCount: 1,
|
|
10427
|
+
className: ChatToolCallReadFileLink,
|
|
10428
|
+
...fileNameClickableProps,
|
|
10429
|
+
type: Span
|
|
10430
|
+
}, text(fileName), {
|
|
10431
|
+
childCount: 1,
|
|
10432
|
+
className: Insertion,
|
|
10433
|
+
type: Span
|
|
10434
|
+
}, text(` +${linesAdded}`), {
|
|
10435
|
+
childCount: 1,
|
|
10436
|
+
className: Deletion,
|
|
10437
|
+
type: Span
|
|
10438
|
+
}, text(` -${linesDeleted}`), ...(statusLabel ? [text(statusLabel)] : [])];
|
|
10439
|
+
};
|
|
10440
|
+
const getToolCallEditFileVirtualDom = toolCall => {
|
|
10441
|
+
const target = getReadFileTarget(toolCall.arguments);
|
|
10442
|
+
if (!target) {
|
|
10443
|
+
return [];
|
|
10444
|
+
}
|
|
10445
|
+
const fileName = getFileNameFromUri(target.title);
|
|
10446
|
+
const fileNameClickableProps = target.clickableUri ? {
|
|
10447
|
+
'data-uri': target.clickableUri,
|
|
10448
|
+
onClick: HandleClickReadFile
|
|
10449
|
+
} : {};
|
|
10450
|
+
return [{
|
|
10451
|
+
childCount: 3,
|
|
10452
|
+
className: ChatOrderedListItem,
|
|
10453
|
+
title: target.title,
|
|
10454
|
+
type: Li
|
|
10455
|
+
}, {
|
|
10456
|
+
childCount: 0,
|
|
10457
|
+
className: FileIcon,
|
|
10458
|
+
type: Div
|
|
10459
|
+
}, text('edit_file '), {
|
|
10460
|
+
childCount: 1,
|
|
10461
|
+
className: ChatToolCallReadFileLink,
|
|
10462
|
+
title: target.clickableUri,
|
|
10463
|
+
...fileNameClickableProps,
|
|
10464
|
+
type: Span
|
|
10465
|
+
}, text(fileName)];
|
|
10466
|
+
};
|
|
10549
10467
|
const getToolCallDom = toolCall => {
|
|
10550
10468
|
if (toolCall.name === 'getWorkspaceUri') {
|
|
10551
10469
|
const virtualDom = getToolCallGetWorkspaceUriVirtualDom(toolCall);
|
|
@@ -10559,6 +10477,18 @@ const getToolCallDom = toolCall => {
|
|
|
10559
10477
|
return virtualDom;
|
|
10560
10478
|
}
|
|
10561
10479
|
}
|
|
10480
|
+
if (toolCall.name === 'write_file') {
|
|
10481
|
+
const virtualDom = getToolCallWriteFileVirtualDom(toolCall);
|
|
10482
|
+
if (virtualDom.length > 0) {
|
|
10483
|
+
return virtualDom;
|
|
10484
|
+
}
|
|
10485
|
+
}
|
|
10486
|
+
if (toolCall.name === 'edit_file') {
|
|
10487
|
+
const virtualDom = getToolCallEditFileVirtualDom(toolCall);
|
|
10488
|
+
if (virtualDom.length > 0) {
|
|
10489
|
+
return virtualDom;
|
|
10490
|
+
}
|
|
10491
|
+
}
|
|
10562
10492
|
if (toolCall.name === 'render_html') {
|
|
10563
10493
|
const virtualDom = getToolCallRenderHtmlVirtualDom(toolCall);
|
|
10564
10494
|
if (virtualDom.length > 0) {
|