Skip to content

Commit ad12bd9

Browse files
committed
Update Copilot chatbot integration for copilot.com/chat with new reasoning effort and option support
- https://copilot.microsoft.com should be changed and updated to use https://copilot.com/chat instead - wait 3 seconds - the new input field: [Pasted text], reasoning effort can be changed by clicking on the button [Pasted text] (also wait for its appearance in [Fragment]). When clicked the dropdown appears: [Pasted text] - message is never entered [Pasted text] - add 'temporary' option [Pasted text] - fix 'apply response' button placement [Pasted text] - assess if stop button is alright: [Pasted text] (find the button by its internal svg) ├── apps │ └── browser │ └── src │ ├── content-scripts │ │ └── send-prompt-content-script │ │ ├── chatbots │ │ │ ├── ai-studio.ts │ │ │ ├── arena.ts │ │ │ ├── chatgpt.ts │ │ │ ├── claude.ts │ │ │ ├── copilot.ts │ │ │ ├── deepseek.ts │ │ │ ├── doubao.ts │ │ │ ├── gemini.ts │ │ │ ├── github-copilot.ts │ │ │ ├── grok.ts │ │ │ ├── hugging-chat.ts │ │ │ ├── index.ts │ │ │ ├── kimi.ts │ │ │ ├── meta.ts │ │ │ ├── mistral.ts │ │ │ ├── open-webui.ts │ │ │ ├── openrouter.ts │ │ │ ├── qwen.ts │ │ │ ├── together.ts │ │ │ ├── yuanbao.ts │ │ │ └── z-ai.ts │ │ └── send-prompt-content-script.ts │ └── manifest.json └── packages └── shared └── src └── constants └── chatbots.ts
1 parent 641e321 commit ad12bd9

4 files changed

Lines changed: 110 additions & 13 deletions

File tree

‎apps/browser/src/content-scripts/send-prompt-content-script/chatbots/copilot.ts‎

Lines changed: 102 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { CHATBOTS } from '@shared/constants/chatbots'
12
import { Chatbot } from '../types/chatbot'
23
import {
34
add_apply_response_button,
@@ -9,7 +10,10 @@ export const copilot: Chatbot = {
910
wait_until_ready: async () => {
1011
await new Promise((resolve) => {
1112
const check_for_element = () => {
12-
if (document.querySelector('textarea')) {
13+
if (
14+
document.getElementById('gptModeSwitcher') &&
15+
document.getElementById('m365-chat-editor-target-element')
16+
) {
1317
resolve(null)
1418
} else {
1519
setTimeout(check_for_element, 100)
@@ -18,19 +22,106 @@ export const copilot: Chatbot = {
1822
check_for_element()
1923
})
2024
},
25+
set_options: async (chat) => {
26+
const options = chat.options
27+
if (!options) return
28+
29+
const supported_options = CHATBOTS['Copilot'].supported_options
30+
for (const option of options) {
31+
if (option == 'temporary' && supported_options?.['temporary']) {
32+
const temporary_button = document.querySelector(
33+
'button[aria-label="Temporary chat"]'
34+
) as HTMLButtonElement
35+
36+
if (!temporary_button) {
37+
report_initialization_error({
38+
function_name: 'set_options',
39+
log_message: 'Temporary chat button not found'
40+
})
41+
return
42+
}
43+
44+
if (temporary_button.getAttribute('aria-pressed') != 'true') {
45+
temporary_button.click()
46+
await new Promise((r) => requestAnimationFrame(r))
47+
}
48+
}
49+
}
50+
},
51+
set_reasoning_effort: async (chat) => {
52+
const reasoning_effort = chat.reasoning_effort
53+
if (!reasoning_effort) return
54+
55+
const mode_switcher = document.getElementById(
56+
'gptModeSwitcher'
57+
) as HTMLButtonElement
58+
if (!mode_switcher) {
59+
report_initialization_error({
60+
function_name: 'set_reasoning_effort',
61+
log_message: 'Mode switcher not found for Copilot'
62+
})
63+
return
64+
}
65+
66+
mode_switcher.click()
67+
await new Promise((resolve) => setTimeout(resolve, 500))
68+
69+
const popover = document.querySelector('.fui-MenuPopover')
70+
if (!popover) {
71+
report_initialization_error({
72+
function_name: 'set_reasoning_effort',
73+
log_message: 'Mode switcher popover not found'
74+
})
75+
return
76+
}
77+
78+
const menu_items = Array.from(popover.querySelectorAll('[role="menuitem"]'))
79+
80+
let target_text = ''
81+
if (reasoning_effort.toLowerCase() == 'auto') {
82+
target_text = 'auto'
83+
} else if (reasoning_effort.toLowerCase() == 'quick') {
84+
target_text = 'quick response'
85+
} else if (reasoning_effort.toLowerCase() == 'deep') {
86+
target_text = 'think deeper'
87+
}
88+
89+
const target_item = menu_items.find((item) => {
90+
const title = item.querySelector('h4')?.textContent?.trim().toLowerCase()
91+
return title == target_text
92+
}) as HTMLElement
93+
94+
if (target_item) {
95+
target_item.click()
96+
} else {
97+
document.dispatchEvent(
98+
new KeyboardEvent('keydown', { key: 'Escape', bubbles: true })
99+
)
100+
}
101+
102+
await new Promise((resolve) => requestAnimationFrame(resolve))
103+
},
21104
enter_message: async (params) => {
22-
const input_element = document.querySelector(
23-
'textarea'
24-
) as HTMLTextAreaElement
105+
const input_element = document.getElementById(
106+
'm365-chat-editor-target-element'
107+
) as HTMLElement
25108
if (!input_element) {
26109
report_initialization_error({
27110
function_name: 'enter_message',
28-
log_message: 'Message input textarea not found for Copilot'
111+
log_message: 'Message input element not found for Copilot'
29112
})
30113
return
31114
}
32-
input_element.value = params.message
33-
input_element.dispatchEvent(new Event('input', { bubbles: true }))
115+
116+
input_element.focus()
117+
118+
input_element.dispatchEvent(
119+
new InputEvent('input', {
120+
bubbles: true,
121+
inputType: 'insertText',
122+
data: params.message
123+
})
124+
)
34125
},
35126
setup_observer: (params) => {
36127
const add_buttons = (footer: Element) => {
@@ -40,7 +131,7 @@ export const copilot: Chatbot = {
40131
footer,
41132
perform_copy: (f) => {
42133
const copy_button = f.querySelector(
43-
'button[data-testid="copy-ai-message-button"]'
134+
'button[data-testid="CopyButtonTestId"]'
44135
) as HTMLElement
45136
if (!copy_button) {
46137
report_initialization_error({
@@ -58,8 +149,9 @@ export const copilot: Chatbot = {
58149
observe_for_responses({
59150
chatbot_name: 'Copilot',
60151
is_generating: () =>
61-
!!document.querySelector('button[data-testid="stop-button"]'),
62-
footer_selector: 'div[data-testid="message-item-reactions"]',
152+
!!document.querySelector('button svg rect[rx="2.5"]'),
153+
footer_selector:
154+
'.fai-CopilotMessage__actions > div > div > div > div > div',
63155
add_buttons: params.inject_button ? add_buttons : undefined
64156
})
65157
}

‎apps/browser/src/content-scripts/send-prompt-content-script/send-prompt-content-script.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ const is_openrouter = current_url.startsWith(openrouter_url)
4242
const chatgpt_url = 'https://chatgpt.com/'
4343
const is_chatgpt = current_url.startsWith(chatgpt_url)
4444

45-
const copilot_url = 'https://copilot.microsoft.com/'
45+
const copilot_url = 'https://copilot.com/chat'
4646
const is_copilot = current_url.startsWith(copilot_url)
4747

4848
const github_copilot_url = 'https://github.com/copilot'

‎apps/browser/src/manifest.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"https://aistudio.google.com/*",
2828
"https://chatgpt.com/*",
2929
"https://claude.ai/*",
30-
"https://copilot.microsoft.com/",
30+
"https://copilot.com/chat",
3131
"https://chat.deepseek.com/",
3232
"https://www.doubao.com/chat/",
3333
"https://gemini.google.com/*",

‎packages/shared/src/constants/chatbots.ts‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,12 @@ export const CHATBOTS = {
7272
}
7373
} as Chatbot,
7474
Copilot: {
75-
url: 'https://copilot.microsoft.com/'
75+
url: 'https://copilot.com/chat',
76+
supports_reasoning_effort: true,
77+
supported_reasoning_efforts: ['Auto', 'Quick', 'Deep'],
78+
supported_options: {
79+
temporary: 'Temporary chat'
80+
}
7681
} as Chatbot,
7782
DeepSeek: {
7883
url: 'https://chat.deepseek.com/',

0 commit comments

Comments
 (0)