-
Notifications
You must be signed in to change notification settings - Fork 34.8k
Add URL handler for chat message #263913
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add URL handler for chat message #263913
Conversation
@digitarald @aeschli Something I've been wanting for a while was to be able to use a URL to enter a prompt message in chat. Usage scenario is to use integrate this in our docs or other repos like I've based the code off of the Can you review this PR and check whether the functionality makes sense? |
@@ -850,6 +851,7 @@ registerWorkbenchContribution2(ChatTransferContribution.ID, ChatTransferContribu | |||
registerWorkbenchContribution2(ChatContextContributions.ID, ChatContextContributions, WorkbenchPhase.AfterRestored); | |||
registerWorkbenchContribution2(ChatResponseResourceFileSystemProvider.ID, ChatResponseResourceFileSystemProvider, WorkbenchPhase.AfterRestored); | |||
registerWorkbenchContribution2(PromptUrlHandler.ID, PromptUrlHandler, WorkbenchPhase.BlockRestore); | |||
registerWorkbenchContribution2(ChatMessageUrlHandler.ID, ChatMessageUrlHandler, WorkbenchPhase.BlockRestore); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there is no good reason to block restore here, please pick another later phase.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bpasero Good point. I'd suggest AfterRestored
rather than Eventually
because this is in immediate response to a user action. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah after restored sounds good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@aeschli Should we also update the PromptUrlHandler
registration to happen after restored?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is with the code that is commented out?
I have a full review coming |
// import { IChatModeService } from '../common/chatModes.js'; | ||
import { ILogService } from '../../../../platform/log/common/log.js'; | ||
// import { IHostService } from '../../../services/host/browser/host.js'; | ||
// import { mainWindow } from '../../../../base/browser/window.js'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can these imports be cleaned up?
// @IChatModeService private readonly chatModeService: IChatModeService, | ||
@ILogService private readonly logService: ILogService, | ||
// @IHostService private readonly hostService: IHostService, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove comments
export class ChatMessageUrlHandler extends Disposable implements IWorkbenchContribution, IURLHandler { | ||
|
||
static readonly ID = 'workbench.contrib.chatMessageUrlHandler'; | ||
private static readonly MAX_PROMPT_LENGTH = 10000; // characters |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could encode the fast it's characters into the variable to prevent bitrot: MAX_PROMPT_CHAR_LENGTH
// Verify that workspace is trusted | ||
const trusted = await this.workspaceTrustRequestService.requestWorkspaceTrust({ | ||
message: localize('copilotWorkspaceTrust', "Copilot is currently only supported in trusted workspaces.") | ||
}); | ||
|
||
if (!trusted) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove comment, it's obvious from context
// Decode and clean prompt text | ||
const decodedPrompt = this.sanitizePromptText(decodeURIComponent(promptText)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment obvious from context
detail.appendMarkdown(localize('confirmChatMessageSecurity', | ||
"\n\nIf you did not initiate this request, it may represent an attempted attack on your system. Unless you took an explicit action to initiate this request, you should press 'No'.")); | ||
|
||
const { confirmed } = await this.dialogService.confirm({ | ||
type: 'info', | ||
primaryButton: localize({ key: 'yesButton', comment: ['&& denotes a mnemonic'] }, "&&Yes"), | ||
cancelButton: localize('noButton', "No"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's possible the No
could be localized differently in the button and the message
const detail = new MarkdownString('', { supportHtml: true }); | ||
detail.appendMarkdown(localize('confirmChatMessageDetail', "This will insert the following text into chat:\n\n")); | ||
detail.appendMarkdown(`\`\`\`\n${previewText}\n\`\`\``); | ||
detail.appendMarkdown(localize('confirmChatMessageSecurity', | ||
"\n\nIf you did not initiate this request, it may represent an attempted attack on your system. Unless you took an explicit action to initiate this request, you should press 'No'.")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: appending like this is less efficient on memory/gc. How about this?
new MarkdownString([
'first',
'second',
'third'
].join('\n\n')
markdownDetails: [{ | ||
markdown: detail | ||
}] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you rename detail
to markdown
you could make this line markdownDetails: [{ markdown }]
// Remove control characters except tab (9), newline (10), carriage return (13) | ||
cleanText = cleanText.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g, ''); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't this be handled by InvisibleCharacters.isInvisibleCharacter
?
// Normalize multiple whitespace to single spaces and trim | ||
return cleanText.replace(/\s+/g, ' ').trim(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could whitespace be important to the query?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted to be on the safe side as a request could use blanks as a filler to obfuscate malicious content near the end and outside of the viewport.
@ntrogh we typically only label PRs with |
@ntrogh I really like this idea, is this going to be done in another PR? |
This URL handler allows external applications to insert messages into the VS Code chat interface via URLs. The chat message is inserted in the chat input field but is not submitted. The user is prompted if they want to insert the specific prompt in chat.
URL Format
Parameters
prompt
(required): The text to insert into the chat input field (URL encoded)mode
(optional): The chat mode to set. Defaults to 'agent'. Supports both built-in modes ('ask', 'edit', 'agent') and custom chat modes defined in.chatmode
filesExamples
Test steps
code-oss:chat-message?prompt=Test%20prompt
code-oss:chat-message?prompt=Hello&mode=ask
The handler should: