Skip to content

Commit 61db57a

Browse files
Add reasoning effort support for ChatGPT (#479)
1 parent 5f79be2 commit 61db57a

2 files changed

Lines changed: 135 additions & 1 deletion

File tree

  • apps/browser/src/content-scripts/send-prompt-content-script/chatbots
  • packages/shared/src/constants

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

Lines changed: 134 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,18 @@ export const chatgpt: Chatbot = {
1414
'div#prompt-textarea'
1515
) as HTMLElement
1616

17-
if (input_element) {
17+
const thread_header_button = document.querySelector(
18+
'div[data-testid="thread-header-right-actions"] > div:first-child button'
19+
)
20+
21+
const reasoning_effort_button = document.querySelector(
22+
'div[data-composer-transition-slot="trailing"] > div:first-child button'
23+
)
24+
25+
const is_ready =
26+
thread_header_button !== null || reasoning_effort_button !== null
27+
28+
if (input_element && is_ready) {
1829
input_element.innerText = ' '
1930
input_element.dispatchEvent(new Event('input', { bubbles: true }))
2031

@@ -28,6 +39,128 @@ export const chatgpt: Chatbot = {
2839
}
2940
check_for_element()
3041
})
42+
await new Promise((resolve) => setTimeout(resolve, 500))
43+
},
44+
set_reasoning_effort: async (chat) => {
45+
const reasoning_effort = chat.reasoning_effort
46+
if (!reasoning_effort) return
47+
48+
const reasoning_effort_values: Record<string, number> = {
49+
instant: 0,
50+
medium: 1,
51+
high: 2
52+
}
53+
54+
const target_value = reasoning_effort_values[reasoning_effort.toLowerCase()]
55+
56+
if (target_value === undefined) {
57+
report_initialization_error({
58+
function_name: 'set_reasoning_effort',
59+
log_message: `Unsupported reasoning effort "${reasoning_effort}"`
60+
})
61+
return
62+
}
63+
64+
const reasoning_effort_button = document.querySelector(
65+
'div[data-composer-transition-slot="trailing"] > div:first-child button'
66+
) as HTMLButtonElement
67+
68+
if (!reasoning_effort_button) {
69+
report_initialization_error({
70+
function_name: 'set_reasoning_effort',
71+
log_message: 'Reasoning effort button not found'
72+
})
73+
return
74+
}
75+
76+
reasoning_effort_button.dispatchEvent(
77+
new PointerEvent('pointerdown', {
78+
bubbles: true
79+
})
80+
)
81+
82+
await new Promise((resolve) => setTimeout(resolve, 500))
83+
84+
const slider = await new Promise<HTMLElement | null>((resolve) => {
85+
let attempts = 0
86+
87+
const check_for_slider = () => {
88+
const element = document.querySelector(
89+
'[data-model-reasoning-effort-slider] [role="slider"]'
90+
) as HTMLElement
91+
92+
if (element) {
93+
resolve(element)
94+
return
95+
}
96+
97+
attempts++
98+
99+
if (attempts >= 20) {
100+
resolve(null)
101+
return
102+
}
103+
104+
setTimeout(check_for_slider, 50)
105+
}
106+
107+
check_for_slider()
108+
})
109+
110+
if (!slider) {
111+
report_initialization_error({
112+
function_name: 'set_reasoning_effort',
113+
log_message: 'Reasoning effort slider not found'
114+
})
115+
return
116+
}
117+
118+
const slider_control = slider.closest('[role="menuitem"]') as HTMLElement
119+
120+
if (!slider_control) {
121+
report_initialization_error({
122+
function_name: 'set_reasoning_effort',
123+
log_message: 'Reasoning effort slider control not found'
124+
})
125+
return
126+
}
127+
128+
const current_value = Number(slider.getAttribute('aria-valuenow'))
129+
130+
if (Number.isNaN(current_value)) {
131+
report_initialization_error({
132+
function_name: 'set_reasoning_effort',
133+
log_message: 'Current reasoning effort value not found'
134+
})
135+
return
136+
}
137+
138+
slider_control.focus()
139+
140+
const difference = target_value - current_value
141+
const key = difference > 0 ? 'ArrowRight' : 'ArrowLeft'
142+
143+
for (let i = 0; i < Math.abs(difference); i++) {
144+
slider_control.dispatchEvent(
145+
new KeyboardEvent('keydown', {
146+
key,
147+
bubbles: true,
148+
cancelable: true
149+
})
150+
)
151+
152+
await new Promise((resolve) => requestAnimationFrame(resolve))
153+
}
154+
155+
slider_control.dispatchEvent(
156+
new KeyboardEvent('keydown', {
157+
key: 'Escape',
158+
bubbles: true,
159+
cancelable: true
160+
})
161+
)
162+
163+
await new Promise((resolve) => requestAnimationFrame(resolve))
31164
},
32165
set_options: async (chat) => {
33166
const options = chat.options

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export const CHATBOTS = {
5555
supports_url_override: true,
5656
url_override_label: 'Project URL',
5757
url_override_disabled_options: ['temporary'],
58+
supports_reasoning_effort: true,
5859
supported_reasoning_efforts: ['instant', 'medium', 'high'],
5960
supported_options: {
6061
temporary: 'Temporary',

0 commit comments

Comments
 (0)