@lvce-editor/chat-view 6.7.0 → 6.8.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 +331 -44
- package/package.json +1 -1
|
@@ -1714,6 +1714,7 @@ const createDefaultState = () => {
|
|
|
1714
1714
|
name: '_blank',
|
|
1715
1715
|
uri: ''
|
|
1716
1716
|
}],
|
|
1717
|
+
questionToolEnabled: false,
|
|
1717
1718
|
renamingSessionId: '',
|
|
1718
1719
|
selectedModelId: defaultModelId,
|
|
1719
1720
|
selectedProjectId: defaultProjectId,
|
|
@@ -1729,10 +1730,10 @@ const createDefaultState = () => {
|
|
|
1729
1730
|
tokensUsed: 0,
|
|
1730
1731
|
uid: 0,
|
|
1731
1732
|
usageOverviewEnabled: false,
|
|
1732
|
-
useChatCoordinatorWorker:
|
|
1733
|
+
useChatCoordinatorWorker: false,
|
|
1733
1734
|
useChatMathWorker: true,
|
|
1734
1735
|
useChatNetworkWorkerForRequests: false,
|
|
1735
|
-
useChatToolWorker:
|
|
1736
|
+
useChatToolWorker: true,
|
|
1736
1737
|
useMockApi: false,
|
|
1737
1738
|
userName: '',
|
|
1738
1739
|
userSubscriptionPlan: '',
|
|
@@ -3344,6 +3345,20 @@ const getAiResponse$1 = async options => {
|
|
|
3344
3345
|
const execute = async (name, rawArguments, options) => {
|
|
3345
3346
|
return invoke$3('ChatTool.execute', name, rawArguments, options);
|
|
3346
3347
|
};
|
|
3348
|
+
const getTools = async () => {
|
|
3349
|
+
return invoke$3('ChatTool.getTools');
|
|
3350
|
+
};
|
|
3351
|
+
|
|
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
|
+
};
|
|
3347
3362
|
|
|
3348
3363
|
const getToolErrorPayload = error => {
|
|
3349
3364
|
const rawStack = error && typeof error === 'object' ? Reflect.get(error, 'stack') : undefined;
|
|
@@ -3522,12 +3537,19 @@ const parseToolArguments = rawArguments => {
|
|
|
3522
3537
|
}
|
|
3523
3538
|
};
|
|
3524
3539
|
|
|
3540
|
+
const stringifyToolOutput = output => {
|
|
3541
|
+
if (typeof output === 'string') {
|
|
3542
|
+
return output;
|
|
3543
|
+
}
|
|
3544
|
+
return JSON.stringify(output) ?? 'null';
|
|
3545
|
+
};
|
|
3525
3546
|
const executeChatTool = async (name, rawArguments, options) => {
|
|
3526
3547
|
if (options.useChatToolWorker) {
|
|
3527
|
-
|
|
3548
|
+
const workerOutput = await execute(name, rawArguments, {
|
|
3528
3549
|
assetDir: options.assetDir,
|
|
3529
3550
|
platform: options.platform
|
|
3530
3551
|
});
|
|
3552
|
+
return stringifyToolOutput(workerOutput);
|
|
3531
3553
|
}
|
|
3532
3554
|
const args = parseToolArguments(rawArguments);
|
|
3533
3555
|
if (name === 'read_file') {
|
|
@@ -3545,6 +3567,9 @@ const executeChatTool = async (name, rawArguments, options) => {
|
|
|
3545
3567
|
if (name === 'render_html') {
|
|
3546
3568
|
return executeRenderHtmlTool(args);
|
|
3547
3569
|
}
|
|
3570
|
+
if (name === 'ask_question') {
|
|
3571
|
+
return executeAskQuestionTool(args);
|
|
3572
|
+
}
|
|
3548
3573
|
return JSON.stringify({
|
|
3549
3574
|
error: `Unknown tool: ${name}`
|
|
3550
3575
|
});
|
|
@@ -3553,7 +3578,7 @@ const executeChatTool = async (name, rawArguments, options) => {
|
|
|
3553
3578
|
const getReadFileTool = () => {
|
|
3554
3579
|
return {
|
|
3555
3580
|
function: {
|
|
3556
|
-
description: 'Read UTF-8 text content from a file inside the currently open workspace folder. Only pass an absolute URI. When you reference files in your response, use markdown links like [index.ts](
|
|
3581
|
+
description: 'Read UTF-8 text content from a file inside the currently open workspace folder. Only pass an absolute URI. When you reference files in your response, use markdown links like [index.ts](vscode-references:///workspace/src/index.ts).',
|
|
3557
3582
|
name: 'read_file',
|
|
3558
3583
|
parameters: {
|
|
3559
3584
|
additionalProperties: false,
|
|
@@ -3656,8 +3681,53 @@ const getRenderHtmlTool = () => {
|
|
|
3656
3681
|
type: 'function'
|
|
3657
3682
|
};
|
|
3658
3683
|
};
|
|
3659
|
-
const
|
|
3660
|
-
return
|
|
3684
|
+
const getAskQuestionTool = () => {
|
|
3685
|
+
return {
|
|
3686
|
+
function: {
|
|
3687
|
+
description: 'Ask the user a multiple-choice question in the chat UI. Use this when you need a user decision before continuing. Provide short answer options.',
|
|
3688
|
+
name: 'ask_question',
|
|
3689
|
+
parameters: {
|
|
3690
|
+
additionalProperties: false,
|
|
3691
|
+
properties: {
|
|
3692
|
+
answers: {
|
|
3693
|
+
description: 'List of answer options shown to the user.',
|
|
3694
|
+
items: {
|
|
3695
|
+
type: 'string'
|
|
3696
|
+
},
|
|
3697
|
+
type: 'array'
|
|
3698
|
+
},
|
|
3699
|
+
question: {
|
|
3700
|
+
description: 'The question text shown to the user.',
|
|
3701
|
+
type: 'string'
|
|
3702
|
+
}
|
|
3703
|
+
},
|
|
3704
|
+
required: ['question', 'answers'],
|
|
3705
|
+
type: 'object'
|
|
3706
|
+
}
|
|
3707
|
+
},
|
|
3708
|
+
type: 'function'
|
|
3709
|
+
};
|
|
3710
|
+
};
|
|
3711
|
+
|
|
3712
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
3713
|
+
const withQuestionTool = (tools, questionToolEnabled) => {
|
|
3714
|
+
if (!questionToolEnabled) {
|
|
3715
|
+
return tools;
|
|
3716
|
+
}
|
|
3717
|
+
for (const tool of tools) {
|
|
3718
|
+
if (tool.function.name === 'ask_question') {
|
|
3719
|
+
return tools;
|
|
3720
|
+
}
|
|
3721
|
+
}
|
|
3722
|
+
return [...tools, getAskQuestionTool()];
|
|
3723
|
+
};
|
|
3724
|
+
const getBasicChatTools = async (questionToolEnabled = false) => {
|
|
3725
|
+
const fallbackTools = [getReadFileTool(), getWriteFileTool(), getListFilesTool(), getGetWorkspaceUriTool(), getRenderHtmlTool()];
|
|
3726
|
+
try {
|
|
3727
|
+
return withQuestionTool(await getTools(), questionToolEnabled);
|
|
3728
|
+
} catch {
|
|
3729
|
+
return withQuestionTool(fallbackTools, questionToolEnabled);
|
|
3730
|
+
}
|
|
3661
3731
|
};
|
|
3662
3732
|
|
|
3663
3733
|
const getClientRequestIdHeader = () => {
|
|
@@ -4767,9 +4837,10 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
|
|
|
4767
4837
|
onEventStreamFinished,
|
|
4768
4838
|
onTextChunk,
|
|
4769
4839
|
onToolCallsChunk,
|
|
4840
|
+
questionToolEnabled = false,
|
|
4770
4841
|
stream,
|
|
4771
4842
|
useChatNetworkWorkerForRequests = false,
|
|
4772
|
-
useChatToolWorker =
|
|
4843
|
+
useChatToolWorker = true,
|
|
4773
4844
|
webSearchEnabled = false
|
|
4774
4845
|
} = options ?? {
|
|
4775
4846
|
stream: false
|
|
@@ -4778,7 +4849,7 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
|
|
|
4778
4849
|
content: message.text,
|
|
4779
4850
|
role: message.role
|
|
4780
4851
|
}));
|
|
4781
|
-
const tools = getBasicChatTools();
|
|
4852
|
+
const tools = await getBasicChatTools(questionToolEnabled);
|
|
4782
4853
|
const maxToolIterations = 4;
|
|
4783
4854
|
let previousResponseId;
|
|
4784
4855
|
for (let i = 0; i <= maxToolIterations; i++) {
|
|
@@ -5356,12 +5427,12 @@ const getOpenRouterLimitInfo = async (openRouterApiKey, openRouterApiBaseUrl, us
|
|
|
5356
5427
|
}
|
|
5357
5428
|
return normalizedLimitInfo;
|
|
5358
5429
|
};
|
|
5359
|
-
const getOpenRouterAssistantText = async (messages, modelId, openRouterApiKey, openRouterApiBaseUrl, assetDir, platform, useChatNetworkWorkerForRequests = false, useChatToolWorker = false) => {
|
|
5430
|
+
const getOpenRouterAssistantText = async (messages, modelId, openRouterApiKey, openRouterApiBaseUrl, assetDir, platform, useChatNetworkWorkerForRequests = false, useChatToolWorker = true, questionToolEnabled = false) => {
|
|
5360
5431
|
const completionMessages = messages.map(message => ({
|
|
5361
5432
|
content: message.text,
|
|
5362
5433
|
role: message.role
|
|
5363
5434
|
}));
|
|
5364
|
-
const tools = getBasicChatTools();
|
|
5435
|
+
const tools = await getBasicChatTools(questionToolEnabled);
|
|
5365
5436
|
const maxToolIterations = 4;
|
|
5366
5437
|
for (let i = 0; i <= maxToolIterations; i++) {
|
|
5367
5438
|
let parsed;
|
|
@@ -5683,11 +5754,12 @@ const getAiResponse = async ({
|
|
|
5683
5754
|
openRouterApiKey,
|
|
5684
5755
|
passIncludeObfuscation = false,
|
|
5685
5756
|
platform,
|
|
5757
|
+
questionToolEnabled = false,
|
|
5686
5758
|
selectedModelId,
|
|
5687
5759
|
streamingEnabled = true,
|
|
5688
5760
|
useChatCoordinatorWorker = false,
|
|
5689
5761
|
useChatNetworkWorkerForRequests = false,
|
|
5690
|
-
useChatToolWorker =
|
|
5762
|
+
useChatToolWorker = true,
|
|
5691
5763
|
useMockApi,
|
|
5692
5764
|
userText,
|
|
5693
5765
|
webSearchEnabled = false
|
|
@@ -5710,6 +5782,7 @@ const getAiResponse = async ({
|
|
|
5710
5782
|
openRouterApiKey,
|
|
5711
5783
|
passIncludeObfuscation,
|
|
5712
5784
|
platform,
|
|
5785
|
+
questionToolEnabled,
|
|
5713
5786
|
selectedModelId,
|
|
5714
5787
|
streamingEnabled,
|
|
5715
5788
|
useChatNetworkWorkerForRequests,
|
|
@@ -5761,7 +5834,7 @@ const getAiResponse = async ({
|
|
|
5761
5834
|
capture({
|
|
5762
5835
|
headers,
|
|
5763
5836
|
method: 'POST',
|
|
5764
|
-
payload: getOpenAiParams(openAiInput, modelId, streamingEnabled, passIncludeObfuscation, getBasicChatTools(), webSearchEnabled, previousResponseId),
|
|
5837
|
+
payload: getOpenAiParams(openAiInput, modelId, streamingEnabled, passIncludeObfuscation, await getBasicChatTools(questionToolEnabled), webSearchEnabled, previousResponseId),
|
|
5765
5838
|
url: getOpenApiApiEndpoint(openApiApiBaseUrl)
|
|
5766
5839
|
});
|
|
5767
5840
|
const result = await getMockOpenApiAssistantText(streamingEnabled, onTextChunk, onToolCallsChunk, onDataEvent, onEventStreamFinished);
|
|
@@ -5805,6 +5878,7 @@ const getAiResponse = async ({
|
|
|
5805
5878
|
...(onToolCallsChunk ? {
|
|
5806
5879
|
onToolCallsChunk
|
|
5807
5880
|
} : {}),
|
|
5881
|
+
questionToolEnabled,
|
|
5808
5882
|
stream: streamingEnabled,
|
|
5809
5883
|
useChatNetworkWorkerForRequests,
|
|
5810
5884
|
useChatToolWorker,
|
|
@@ -5834,7 +5908,7 @@ const getAiResponse = async ({
|
|
|
5834
5908
|
text = getOpenRouterErrorMessage(result);
|
|
5835
5909
|
}
|
|
5836
5910
|
} else if (openRouterApiKey) {
|
|
5837
|
-
const result = await getOpenRouterAssistantText(messages, modelId, openRouterApiKey, openRouterApiBaseUrl, assetDir, platform, useChatNetworkWorkerForRequests, useChatToolWorker);
|
|
5911
|
+
const result = await getOpenRouterAssistantText(messages, modelId, openRouterApiKey, openRouterApiBaseUrl, assetDir, platform, useChatNetworkWorkerForRequests, useChatToolWorker, questionToolEnabled);
|
|
5838
5912
|
if (result.type === 'success') {
|
|
5839
5913
|
const {
|
|
5840
5914
|
text: assistantText
|
|
@@ -6051,7 +6125,7 @@ const isAlphaNumeric = value => {
|
|
|
6051
6125
|
};
|
|
6052
6126
|
const sanitizeLinkUrl = url => {
|
|
6053
6127
|
const normalized = url.trim().toLowerCase();
|
|
6054
|
-
if (normalized.startsWith('http://') || normalized.startsWith('https://') || normalized.startsWith('file://')) {
|
|
6128
|
+
if (normalized.startsWith('http://') || normalized.startsWith('https://') || normalized.startsWith('file://') || normalized.startsWith('vscode-references://')) {
|
|
6055
6129
|
return url;
|
|
6056
6130
|
}
|
|
6057
6131
|
return '#';
|
|
@@ -6063,6 +6137,73 @@ const sanitizeImageUrl = url => {
|
|
|
6063
6137
|
}
|
|
6064
6138
|
return '#';
|
|
6065
6139
|
};
|
|
6140
|
+
const isOpenBracket = value => {
|
|
6141
|
+
return value === '(' || value === '[' || value === '{';
|
|
6142
|
+
};
|
|
6143
|
+
const isCloseBracket = value => {
|
|
6144
|
+
return value === ')' || value === ']' || value === '}';
|
|
6145
|
+
};
|
|
6146
|
+
const findRawUrlEnd = (value, start) => {
|
|
6147
|
+
let index = start;
|
|
6148
|
+
while (index < value.length) {
|
|
6149
|
+
const current = value[index];
|
|
6150
|
+
if (current === ' ' || current === '\n' || current === '\r' || current === '\t' || current === '"' || current === "'" || current === '`' || current === '<' || current === '>') {
|
|
6151
|
+
break;
|
|
6152
|
+
}
|
|
6153
|
+
index++;
|
|
6154
|
+
}
|
|
6155
|
+
return index;
|
|
6156
|
+
};
|
|
6157
|
+
const trimRawUrlEnd = url => {
|
|
6158
|
+
let end = url.length;
|
|
6159
|
+
while (end > 0) {
|
|
6160
|
+
const current = url[end - 1];
|
|
6161
|
+
if (current === '.' || current === ',' || current === ':' || current === ';' || current === '!' || current === '?') {
|
|
6162
|
+
end--;
|
|
6163
|
+
continue;
|
|
6164
|
+
}
|
|
6165
|
+
if (isCloseBracket(current)) {
|
|
6166
|
+
const inner = url.slice(0, end - 1);
|
|
6167
|
+
let openCount = 0;
|
|
6168
|
+
let closeCount = 0;
|
|
6169
|
+
for (let i = 0; i < inner.length; i++) {
|
|
6170
|
+
if (isOpenBracket(inner[i])) {
|
|
6171
|
+
openCount++;
|
|
6172
|
+
} else if (isCloseBracket(inner[i])) {
|
|
6173
|
+
closeCount++;
|
|
6174
|
+
}
|
|
6175
|
+
}
|
|
6176
|
+
if (closeCount >= openCount) {
|
|
6177
|
+
end--;
|
|
6178
|
+
continue;
|
|
6179
|
+
}
|
|
6180
|
+
}
|
|
6181
|
+
break;
|
|
6182
|
+
}
|
|
6183
|
+
return url.slice(0, end);
|
|
6184
|
+
};
|
|
6185
|
+
const parseRawLinkToken = (value, start) => {
|
|
6186
|
+
if (!value.startsWith('https://', start) && !value.startsWith('http://', start)) {
|
|
6187
|
+
return undefined;
|
|
6188
|
+
}
|
|
6189
|
+
if (start >= 2 && value[start - 1] === '(' && value[start - 2] === ']') {
|
|
6190
|
+
return undefined;
|
|
6191
|
+
}
|
|
6192
|
+
const end = findRawUrlEnd(value, start);
|
|
6193
|
+
const rawUrl = value.slice(start, end);
|
|
6194
|
+
const href = trimRawUrlEnd(rawUrl);
|
|
6195
|
+
if (!href) {
|
|
6196
|
+
return undefined;
|
|
6197
|
+
}
|
|
6198
|
+
return {
|
|
6199
|
+
length: href.length,
|
|
6200
|
+
node: {
|
|
6201
|
+
href: sanitizeLinkUrl(href),
|
|
6202
|
+
text: href,
|
|
6203
|
+
type: 'link'
|
|
6204
|
+
}
|
|
6205
|
+
};
|
|
6206
|
+
};
|
|
6066
6207
|
const parseLinkToken = (value, start) => {
|
|
6067
6208
|
if (value[start] !== '[') {
|
|
6068
6209
|
return undefined;
|
|
@@ -6291,7 +6432,7 @@ const parseMathToken = (value, start) => {
|
|
|
6291
6432
|
return undefined;
|
|
6292
6433
|
};
|
|
6293
6434
|
const parseInlineToken = (value, start) => {
|
|
6294
|
-
return parseImageToken(value, start) || parseLinkToken(value, start) || parseBoldToken(value, start) || parseItalicToken(value, start) || parseLinkToken(value, start) || parseBoldToken(value, start) || parseItalicToken(value, start) || parseStrikethroughToken(value, start) || parseInlineCodeToken(value, start) || parseMathToken(value, start);
|
|
6435
|
+
return parseImageToken(value, start) || parseLinkToken(value, start) || parseRawLinkToken(value, start) || parseBoldToken(value, start) || parseItalicToken(value, start) || parseLinkToken(value, start) || parseBoldToken(value, start) || parseItalicToken(value, start) || parseStrikethroughToken(value, start) || parseInlineCodeToken(value, start) || parseMathToken(value, start);
|
|
6295
6436
|
};
|
|
6296
6437
|
const parseInlineNodes = value => {
|
|
6297
6438
|
const nodes = [];
|
|
@@ -7394,6 +7535,7 @@ const handleSubmit = async state => {
|
|
|
7394
7535
|
openRouterApiKey,
|
|
7395
7536
|
passIncludeObfuscation,
|
|
7396
7537
|
platform,
|
|
7538
|
+
questionToolEnabled,
|
|
7397
7539
|
selectedModelId,
|
|
7398
7540
|
selectedSessionId,
|
|
7399
7541
|
sessions,
|
|
@@ -7562,6 +7704,9 @@ const handleSubmit = async state => {
|
|
|
7562
7704
|
openRouterApiKey,
|
|
7563
7705
|
passIncludeObfuscation,
|
|
7564
7706
|
platform,
|
|
7707
|
+
...(typeof questionToolEnabled === 'boolean' ? {
|
|
7708
|
+
questionToolEnabled
|
|
7709
|
+
} : {}),
|
|
7565
7710
|
selectedModelId,
|
|
7566
7711
|
streamingEnabled,
|
|
7567
7712
|
useChatCoordinatorWorker,
|
|
@@ -7875,11 +8020,18 @@ const handleClickNew = async state => {
|
|
|
7875
8020
|
return focusInput(clearedState);
|
|
7876
8021
|
};
|
|
7877
8022
|
|
|
8023
|
+
const normalizeFileReferenceUri = uri => {
|
|
8024
|
+
if (uri.startsWith('vscode-references://')) {
|
|
8025
|
+
return `file://${uri.slice('vscode-references://'.length)}`;
|
|
8026
|
+
}
|
|
8027
|
+
return uri;
|
|
8028
|
+
};
|
|
7878
8029
|
const handleClickReadFile = async uri => {
|
|
7879
8030
|
if (!uri) {
|
|
7880
8031
|
return;
|
|
7881
8032
|
}
|
|
7882
|
-
|
|
8033
|
+
const normalizedUri = normalizeFileReferenceUri(uri);
|
|
8034
|
+
await invoke$1('Main.openUri', normalizedUri);
|
|
7883
8035
|
};
|
|
7884
8036
|
|
|
7885
8037
|
const handleClickSessionDebug = async state => {
|
|
@@ -8406,9 +8558,9 @@ const loadUseChatNetworkWorkerForRequests = async () => {
|
|
|
8406
8558
|
const loadUseChatToolWorker = async () => {
|
|
8407
8559
|
try {
|
|
8408
8560
|
const savedUseChatToolWorker = await get('chatView.useChatToolWorker');
|
|
8409
|
-
return typeof savedUseChatToolWorker === 'boolean' ? savedUseChatToolWorker :
|
|
8561
|
+
return typeof savedUseChatToolWorker === 'boolean' ? savedUseChatToolWorker : true;
|
|
8410
8562
|
} catch {
|
|
8411
|
-
return
|
|
8563
|
+
return true;
|
|
8412
8564
|
}
|
|
8413
8565
|
};
|
|
8414
8566
|
|
|
@@ -9045,6 +9197,29 @@ const getCss = (composerHeight, listItemHeight, chatMessageFontSize, chatMessage
|
|
|
9045
9197
|
.TokenProperty {
|
|
9046
9198
|
color: var(--ColorChartsOrange, #ef9f76);
|
|
9047
9199
|
}
|
|
9200
|
+
|
|
9201
|
+
.ChatToolCallQuestionText {
|
|
9202
|
+
margin-bottom: 6px;
|
|
9203
|
+
}
|
|
9204
|
+
|
|
9205
|
+
.ChatToolCallQuestionOptions {
|
|
9206
|
+
display: flex;
|
|
9207
|
+
flex-wrap: wrap;
|
|
9208
|
+
gap: 6px;
|
|
9209
|
+
}
|
|
9210
|
+
|
|
9211
|
+
.ChatToolCallQuestionOption {
|
|
9212
|
+
background: color-mix(in srgb, var(--ColorBadgeBackground, #2f3640) 70%, transparent);
|
|
9213
|
+
border: 1px solid color-mix(in srgb, var(--ColorBorder, #3a3d41) 70%, transparent);
|
|
9214
|
+
border-radius: 999px;
|
|
9215
|
+
color: var(--ColorForeground, #d5dbe3);
|
|
9216
|
+
display: inline-block;
|
|
9217
|
+
max-width: 100%;
|
|
9218
|
+
overflow: hidden;
|
|
9219
|
+
padding: 2px 8px;
|
|
9220
|
+
text-overflow: ellipsis;
|
|
9221
|
+
white-space: nowrap;
|
|
9222
|
+
}
|
|
9048
9223
|
`;
|
|
9049
9224
|
if (!renderHtmlCss.trim()) {
|
|
9050
9225
|
return baseCss;
|
|
@@ -9147,6 +9322,9 @@ const ChatMessageContent = 'ChatMessageContent';
|
|
|
9147
9322
|
const ChatToolCalls = 'ChatToolCalls';
|
|
9148
9323
|
const ChatToolCallsLabel = 'ChatToolCallsLabel';
|
|
9149
9324
|
const ChatToolCallReadFileLink = 'ChatToolCallReadFileLink';
|
|
9325
|
+
const ChatToolCallQuestionOption = 'ChatToolCallQuestionOption';
|
|
9326
|
+
const ChatToolCallQuestionOptions = 'ChatToolCallQuestionOptions';
|
|
9327
|
+
const ChatToolCallQuestionText = 'ChatToolCallQuestionText';
|
|
9150
9328
|
const ChatToolCallRenderHtmlLabel = 'ChatToolCallRenderHtmlLabel';
|
|
9151
9329
|
const ChatToolCallRenderHtmlContent = 'ChatToolCallRenderHtmlContent';
|
|
9152
9330
|
const ChatToolCallRenderHtmlBody = 'ChatToolCallRenderHtmlBody';
|
|
@@ -9337,8 +9515,9 @@ const getImageAltText = alt => {
|
|
|
9337
9515
|
}
|
|
9338
9516
|
return `${alt} (image could not be loaded)`;
|
|
9339
9517
|
};
|
|
9340
|
-
const
|
|
9341
|
-
|
|
9518
|
+
const isFileReferenceUri = href => {
|
|
9519
|
+
const normalized = href.trim().toLowerCase();
|
|
9520
|
+
return normalized.startsWith('file://') || normalized.startsWith('vscode-references://');
|
|
9342
9521
|
};
|
|
9343
9522
|
const getInlineNodeDom = (inlineNode, useChatMathWorker = false) => {
|
|
9344
9523
|
if (inlineNode.type === 'text') {
|
|
@@ -9385,7 +9564,7 @@ const getInlineNodeDom = (inlineNode, useChatMathWorker = false) => {
|
|
|
9385
9564
|
if (inlineNode.type === 'math-inline-dom') {
|
|
9386
9565
|
return inlineNode.dom;
|
|
9387
9566
|
}
|
|
9388
|
-
if (
|
|
9567
|
+
if (isFileReferenceUri(inlineNode.href)) {
|
|
9389
9568
|
return [{
|
|
9390
9569
|
childCount: 1,
|
|
9391
9570
|
className: ChatMessageLink,
|
|
@@ -9486,6 +9665,19 @@ const pythonRules = [{
|
|
|
9486
9665
|
className: TokenKeyword,
|
|
9487
9666
|
regex: /\b(?:def|class|return|if|elif|else|for|while|in|import|from|as|with|try|except|finally|raise|lambda|yield|pass|break|continue|True|False|None|and|or|not|is)\b/
|
|
9488
9667
|
}];
|
|
9668
|
+
const jsonRules = [{
|
|
9669
|
+
className: TokenProperty,
|
|
9670
|
+
regex: /"[^"\\]*(?:\\.[^"\\]*)*"(?=\s*:)/
|
|
9671
|
+
}, {
|
|
9672
|
+
className: TokenString,
|
|
9673
|
+
regex: /"[^"\\]*(?:\\.[^"\\]*)*"/
|
|
9674
|
+
}, {
|
|
9675
|
+
className: TokenNumber,
|
|
9676
|
+
regex: /-?\b\d+\.?\d*(?:[eE][+-]?\d+)?\b/
|
|
9677
|
+
}, {
|
|
9678
|
+
className: TokenKeyword,
|
|
9679
|
+
regex: /\b(?:true|false|null)\b/
|
|
9680
|
+
}];
|
|
9489
9681
|
const tokenize = (code, rules) => {
|
|
9490
9682
|
const tokens = [];
|
|
9491
9683
|
let pos = 0;
|
|
@@ -9542,6 +9734,9 @@ const highlightCode = (code, language) => {
|
|
|
9542
9734
|
if (normalized === 'py' || normalized === 'python') {
|
|
9543
9735
|
return tokenize(code, pythonRules);
|
|
9544
9736
|
}
|
|
9737
|
+
if (normalized === 'json') {
|
|
9738
|
+
return tokenize(code, jsonRules);
|
|
9739
|
+
}
|
|
9545
9740
|
return [{
|
|
9546
9741
|
className: '',
|
|
9547
9742
|
text: code
|
|
@@ -9810,6 +10005,15 @@ const getOpenRouterTooManyRequestsDom = () => {
|
|
|
9810
10005
|
})];
|
|
9811
10006
|
};
|
|
9812
10007
|
|
|
10008
|
+
const RE_QUERY_OR_HASH = /[?#].*$/;
|
|
10009
|
+
const RE_TRAILING_SLASH = /\/$/;
|
|
10010
|
+
const getFileNameFromUri = uri => {
|
|
10011
|
+
const stripped = uri.replace(RE_QUERY_OR_HASH, '').replace(RE_TRAILING_SLASH, '');
|
|
10012
|
+
const slashIndex = Math.max(stripped.lastIndexOf('/'), stripped.lastIndexOf('\\\\'));
|
|
10013
|
+
const fileName = slashIndex === -1 ? stripped : stripped.slice(slashIndex + 1);
|
|
10014
|
+
return fileName || uri;
|
|
10015
|
+
};
|
|
10016
|
+
|
|
9813
10017
|
const getToolCallArgumentPreview = rawArguments => {
|
|
9814
10018
|
if (!rawArguments.trim()) {
|
|
9815
10019
|
return '""';
|
|
@@ -9837,13 +10041,69 @@ const getToolCallArgumentPreview = rawArguments => {
|
|
|
9837
10041
|
return rawArguments;
|
|
9838
10042
|
};
|
|
9839
10043
|
|
|
9840
|
-
const
|
|
9841
|
-
|
|
9842
|
-
|
|
9843
|
-
|
|
9844
|
-
|
|
9845
|
-
|
|
9846
|
-
|
|
10044
|
+
const getToolCallStatusLabel = toolCall => {
|
|
10045
|
+
if (toolCall.status === 'not-found') {
|
|
10046
|
+
return ' (not-found)';
|
|
10047
|
+
}
|
|
10048
|
+
if (toolCall.status === 'error') {
|
|
10049
|
+
if (toolCall.errorMessage) {
|
|
10050
|
+
return ` (error: ${toolCall.errorMessage})`;
|
|
10051
|
+
}
|
|
10052
|
+
return ' (error)';
|
|
10053
|
+
}
|
|
10054
|
+
return '';
|
|
10055
|
+
};
|
|
10056
|
+
|
|
10057
|
+
const parseAskQuestionArguments = rawArguments => {
|
|
10058
|
+
let parsed;
|
|
10059
|
+
try {
|
|
10060
|
+
parsed = JSON.parse(rawArguments);
|
|
10061
|
+
} catch {
|
|
10062
|
+
return {
|
|
10063
|
+
answers: [],
|
|
10064
|
+
question: ''
|
|
10065
|
+
};
|
|
10066
|
+
}
|
|
10067
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
10068
|
+
return {
|
|
10069
|
+
answers: [],
|
|
10070
|
+
question: ''
|
|
10071
|
+
};
|
|
10072
|
+
}
|
|
10073
|
+
const question = Reflect.get(parsed, 'question');
|
|
10074
|
+
const rawAnswers = Reflect.get(parsed, 'answers');
|
|
10075
|
+
const rawChoices = Reflect.get(parsed, 'choices');
|
|
10076
|
+
const rawOptions = Reflect.get(parsed, 'options');
|
|
10077
|
+
const arrayValue = Array.isArray(rawAnswers) ? rawAnswers : Array.isArray(rawChoices) ? rawChoices : Array.isArray(rawOptions) ? rawOptions : [];
|
|
10078
|
+
const answers = arrayValue.filter(value => typeof value === 'string');
|
|
10079
|
+
return {
|
|
10080
|
+
answers,
|
|
10081
|
+
question: typeof question === 'string' ? question : ''
|
|
10082
|
+
};
|
|
10083
|
+
};
|
|
10084
|
+
const getToolCallAskQuestionVirtualDom = toolCall => {
|
|
10085
|
+
const parsed = parseAskQuestionArguments(toolCall.arguments);
|
|
10086
|
+
const statusLabel = getToolCallStatusLabel(toolCall);
|
|
10087
|
+
const questionLabel = parsed.question.trim() ? parsed.question : '(empty question)';
|
|
10088
|
+
const answers = parsed.answers.length > 0 ? parsed.answers : ['(no answers)'];
|
|
10089
|
+
const childCount = 2;
|
|
10090
|
+
return [{
|
|
10091
|
+
childCount,
|
|
10092
|
+
className: ChatOrderedListItem,
|
|
10093
|
+
type: Li
|
|
10094
|
+
}, {
|
|
10095
|
+
childCount: 1,
|
|
10096
|
+
className: ChatToolCallQuestionText,
|
|
10097
|
+
type: Div
|
|
10098
|
+
}, text(`ask_question: ${questionLabel}${statusLabel}`), {
|
|
10099
|
+
childCount: answers.length,
|
|
10100
|
+
className: ChatToolCallQuestionOptions,
|
|
10101
|
+
type: Div
|
|
10102
|
+
}, ...answers.flatMap(answer => [{
|
|
10103
|
+
childCount: 1,
|
|
10104
|
+
className: ChatToolCallQuestionOption,
|
|
10105
|
+
type: Span
|
|
10106
|
+
}, text(answer.trim() ? answer : '(empty answer)')])];
|
|
9847
10107
|
};
|
|
9848
10108
|
|
|
9849
10109
|
const isCompleteJson = value => {
|
|
@@ -9916,19 +10176,6 @@ const getReadFileTarget = rawArguments => {
|
|
|
9916
10176
|
};
|
|
9917
10177
|
};
|
|
9918
10178
|
|
|
9919
|
-
const getToolCallStatusLabel = toolCall => {
|
|
9920
|
-
if (toolCall.status === 'not-found') {
|
|
9921
|
-
return ' (not-found)';
|
|
9922
|
-
}
|
|
9923
|
-
if (toolCall.status === 'error') {
|
|
9924
|
-
if (toolCall.errorMessage) {
|
|
9925
|
-
return ` (error: ${toolCall.errorMessage})`;
|
|
9926
|
-
}
|
|
9927
|
-
return ' (error)';
|
|
9928
|
-
}
|
|
9929
|
-
return '';
|
|
9930
|
-
};
|
|
9931
|
-
|
|
9932
10179
|
const getToolCallReadFileVirtualDom = toolCall => {
|
|
9933
10180
|
const target = getReadFileTarget(toolCall.arguments);
|
|
9934
10181
|
if (!target) {
|
|
@@ -10269,9 +10516,6 @@ const getToolCallDisplayName = name => {
|
|
|
10269
10516
|
};
|
|
10270
10517
|
const getToolCallLabel = toolCall => {
|
|
10271
10518
|
const displayName = getToolCallDisplayName(toolCall.name);
|
|
10272
|
-
if (toolCall.name === 'getWorkspaceUri' && toolCall.result) {
|
|
10273
|
-
return `${displayName} ${toolCall.result}`;
|
|
10274
|
-
}
|
|
10275
10519
|
const argumentPreview = getToolCallArgumentPreview(toolCall.arguments);
|
|
10276
10520
|
const statusLabel = getToolCallStatusLabel(toolCall);
|
|
10277
10521
|
if (argumentPreview === '{}') {
|
|
@@ -10279,7 +10523,36 @@ const getToolCallLabel = toolCall => {
|
|
|
10279
10523
|
}
|
|
10280
10524
|
return `${displayName} ${argumentPreview}${statusLabel}`;
|
|
10281
10525
|
};
|
|
10526
|
+
const getToolCallGetWorkspaceUriVirtualDom = toolCall => {
|
|
10527
|
+
if (!toolCall.result) {
|
|
10528
|
+
return [];
|
|
10529
|
+
}
|
|
10530
|
+
const statusLabel = getToolCallStatusLabel(toolCall);
|
|
10531
|
+
const fileName = getFileNameFromUri(toolCall.result);
|
|
10532
|
+
return [{
|
|
10533
|
+
childCount: statusLabel ? 4 : 3,
|
|
10534
|
+
className: ChatOrderedListItem,
|
|
10535
|
+
title: toolCall.result,
|
|
10536
|
+
type: Li
|
|
10537
|
+
}, {
|
|
10538
|
+
childCount: 0,
|
|
10539
|
+
className: FileIcon,
|
|
10540
|
+
type: Div
|
|
10541
|
+
}, text('get_workspace_uri '), {
|
|
10542
|
+
childCount: 1,
|
|
10543
|
+
className: ChatToolCallReadFileLink,
|
|
10544
|
+
'data-uri': toolCall.result,
|
|
10545
|
+
onClick: HandleClickReadFile,
|
|
10546
|
+
type: Span
|
|
10547
|
+
}, text(fileName), ...(statusLabel ? [text(statusLabel)] : [])];
|
|
10548
|
+
};
|
|
10282
10549
|
const getToolCallDom = toolCall => {
|
|
10550
|
+
if (toolCall.name === 'getWorkspaceUri') {
|
|
10551
|
+
const virtualDom = getToolCallGetWorkspaceUriVirtualDom(toolCall);
|
|
10552
|
+
if (virtualDom.length > 0) {
|
|
10553
|
+
return virtualDom;
|
|
10554
|
+
}
|
|
10555
|
+
}
|
|
10283
10556
|
if (toolCall.name === 'read_file' || toolCall.name === 'list_files' || toolCall.name === 'list_file') {
|
|
10284
10557
|
const virtualDom = getToolCallReadFileVirtualDom(toolCall);
|
|
10285
10558
|
if (virtualDom.length > 0) {
|
|
@@ -10292,6 +10565,12 @@ const getToolCallDom = toolCall => {
|
|
|
10292
10565
|
return virtualDom;
|
|
10293
10566
|
}
|
|
10294
10567
|
}
|
|
10568
|
+
if (toolCall.name === 'ask_question') {
|
|
10569
|
+
const virtualDom = getToolCallAskQuestionVirtualDom(toolCall);
|
|
10570
|
+
if (virtualDom.length > 0) {
|
|
10571
|
+
return virtualDom;
|
|
10572
|
+
}
|
|
10573
|
+
}
|
|
10295
10574
|
const label = getToolCallLabel(toolCall);
|
|
10296
10575
|
return [{
|
|
10297
10576
|
childCount: 1,
|
|
@@ -11151,6 +11430,13 @@ const setEmitStreamingFunctionCallEvents = (state, emitStreamingFunctionCallEven
|
|
|
11151
11430
|
};
|
|
11152
11431
|
};
|
|
11153
11432
|
|
|
11433
|
+
const setQuestionToolEnabled = (state, questionToolEnabled) => {
|
|
11434
|
+
return {
|
|
11435
|
+
...state,
|
|
11436
|
+
questionToolEnabled
|
|
11437
|
+
};
|
|
11438
|
+
};
|
|
11439
|
+
|
|
11154
11440
|
const setStreamingEnabled = (state, streamingEnabled) => {
|
|
11155
11441
|
return {
|
|
11156
11442
|
...state,
|
|
@@ -11272,6 +11558,7 @@ const commandMap = {
|
|
|
11272
11558
|
'Chat.setChatList': wrapCommand(setChatList),
|
|
11273
11559
|
'Chat.setEmitStreamingFunctionCallEvents': wrapCommand(setEmitStreamingFunctionCallEvents),
|
|
11274
11560
|
'Chat.setOpenRouterApiKey': wrapCommand(setOpenRouterApiKey),
|
|
11561
|
+
'Chat.setQuestionToolEnabled': wrapCommand(setQuestionToolEnabled),
|
|
11275
11562
|
'Chat.setStreamingEnabled': wrapCommand(setStreamingEnabled),
|
|
11276
11563
|
'Chat.setUseChatCoordinatorWorker': wrapCommand(setUseChatCoordinatorWorker),
|
|
11277
11564
|
'Chat.setUseChatMathWorker': wrapCommand(setUseChatMathWorker),
|