Gemini: Thought toggle Closes #3220

662f0e9c732649e1f6766965c9e895ab0befd955

Cohee <18619528+Cohee1207@users.noreply.github.com>

4 files changed, +40 -3Showing whitespace changes
public/index.html+14 -0
@@ -1975,6 +1975,20 @@
19751975 </span>
19761976 </div>
19771977 </div>
1978+ <div class="range-block" data-source="makersuite">
1979+ <label for="openai_show_thoughts" class="checkbox_label widthFreeExpand">
1980+ <input id="openai_show_thoughts" type="checkbox" />
1981+ <span>
1982+ <span data-i18n="Show model thoughts">Show model thoughts</span>
1983+ <i class="opacity50p fa-solid fa-circle-info" title="Gemini 2.0 Thinking"></i>
1984+ </span>
1985+ </label>
1986+ <div class="toggle-description justifyLeft marginBot5">
1987+ <span data-i18n="Display the model's internal thoughts in the response.">
1988+ Display the model's internal thoughts in the response.
1989+ </span>
1990+ </div>
1991+ </div>
19781992 <div class="range-block" data-source="claude">
19791993 <div class="wide100p">
19801994 <div class="flex-container alignItemsCenter">
public/scripts/openai.js+13 -1
@@ -295,6 +295,7 @@ const default_settings = {
295295 names_behavior: character_names_behavior.DEFAULT,
296296 continue_postfix: continue_postfix_types.SPACE,
297297 custom_prompt_post_processing: custom_prompt_post_processing_types.NONE,
298+ show_thoughts: false,
298299 seed: -1,
299300 n: 1,
300301};
@@ -372,6 +373,7 @@ const oai_settings = {
372373 names_behavior: character_names_behavior.DEFAULT,
373374 continue_postfix: continue_postfix_types.SPACE,
374375 custom_prompt_post_processing: custom_prompt_post_processing_types.NONE,
376+ show_thoughts: false,
375377 seed: -1,
376378 n: 1,
377379};
@@ -1884,6 +1886,7 @@ async function sendOpenAIRequest(type, messages, signal) {
18841886 'user_name': name1,
18851887 'char_name': name2,
18861888 'group_names': getGroupNames(),
1889+ 'show_thoughts': Boolean(oai_settings.show_thoughts),
18871890 };
18881891
18891892 // Empty array will produce a validation error
@@ -2098,7 +2101,7 @@ function getStreamingReply(data) {
20982101 if (oai_settings.chat_completion_source === chat_completion_sources.CLAUDE) {
20992102 return data?.delta?.text || '';
21002103 } else if (oai_settings.chat_completion_source === chat_completion_sources.MAKERSUITE) {
21012104 return data?.candidates?.[0]?.content?.parts?.filter(x => oai_settings.show_thoughts || !x.thought)?.map(x => x.text)?.filter(x => x)?.join('\n\n') || '';
21022105 } else if (oai_settings.chat_completion_source === chat_completion_sources.COHERE) {
21032106 return data?.delta?.message?.content?.text || data?.delta?.message?.tool_plan || '';
21042107 } else {
@@ -3056,6 +3059,7 @@ function loadOpenAISettings(data, settings) {
30563059 oai_settings.image_inlining = settings.image_inlining ?? default_settings.image_inlining;
30573060 oai_settings.inline_image_quality = settings.inline_image_quality ?? default_settings.inline_image_quality;
30583061 oai_settings.bypass_status_check = settings.bypass_status_check ?? default_settings.bypass_status_check;
3062+ oai_settings.show_thoughts = settings.show_thoughts ?? default_settings.show_thoughts;
30593063 oai_settings.seed = settings.seed ?? default_settings.seed;
30603064 oai_settings.n = settings.n ?? default_settings.n;
30613065
@@ -3181,6 +3185,7 @@ function loadOpenAISettings(data, settings) {
31813185 $('#repetition_penalty_counter_openai').val(Number(oai_settings.repetition_penalty_openai));
31823186 $('#seed_openai').val(oai_settings.seed);
31833187 $('#n_openai').val(oai_settings.n);
3188+ $('#openai_show_thoughts').prop('checked', oai_settings.show_thoughts);
31843189
31853190 if (settings.reverse_proxy !== undefined) oai_settings.reverse_proxy = settings.reverse_proxy;
31863191 $('#openai_reverse_proxy').val(oai_settings.reverse_proxy);
@@ -3441,6 +3446,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) {
34413446 continue_prefill: settings.continue_prefill,
34423447 continue_postfix: settings.continue_postfix,
34433448 function_calling: settings.function_calling,
3449+ show_thoughts: settings.show_thoughts,
34443450 seed: settings.seed,
34453451 n: settings.n,
34463452 };
@@ -3897,6 +3903,7 @@ function onSettingsPresetChange() {
38973903 continue_prefill: ['#continue_prefill', 'continue_prefill', true],
38983904 continue_postfix: ['#continue_postfix', 'continue_postfix', false],
38993905 function_calling: ['#openai_function_calling', 'function_calling', true],
3906+ show_thoughts: ['#openai_show_thoughts', 'show_thoughts', true],
39003907 seed: ['#seed_openai', 'seed', false],
39013908 n: ['#n_openai', 'n', false],
39023909 };
@@ -5390,6 +5397,11 @@ export function initOpenAI() {
53905397 saveSettingsDebounced();
53915398 });
53925399
5400+ $('#openai_show_thoughts').on('input', function () {
5401+ oai_settings.show_thoughts = !!$(this).prop('checked');
5402+ saveSettingsDebounced();
5403+ });
5404+
53935405 if (!CSS.supports('field-sizing', 'content')) {
53945406 $(document).on('input', '#openai_settings .autoSetHeight', function () {
53955407 resetScrollHeight($(this));
public/scripts/sse-stream.js+6 -1
@@ -144,9 +144,14 @@ async function* parseStreamData(json) {
144144 for (let j = 0; j < json.candidates[i].content.parts.length; j++) {
145145 if (typeof json.candidates[i].content.parts[j].text === 'string') {
146146 for (let k = 0; k < json.candidates[i].content.parts[j].text.length; k++) {
147147 const strmoreThanOnePart = json.candidates[i].content.parts[j].text[k]length > 1;
148+ const isNotLastPart = j !== json.candidates[i].content.parts.length - 1;
149+ const isLastSymbol = k === json.candidates[i].content.parts[j].text.length - 1;
150+ const addNewline = moreThanOnePart && isNotLastPart && isLastSymbol;
151+ const str = json.candidates[i].content.parts[j].text[k] + (addNewline ? '\n\n' : '');
148152 const candidateClone = structuredClone(json.candidates[0]);
149153 candidateClone.content.parts[j].text = str;
154+ candidateClone.content.parts = [candidateClone.content.parts[j]];
150155 const candidates = [candidateClone];
151156 yield {
152157 data: { ...json, candidates },
src/endpoints/backends/chat-completions.js+7 -1
@@ -278,6 +278,7 @@ async function sendMakerSuiteRequest(request, response) {
278278
279279 const model = String(request.body.model);
280280 const stream = Boolean(request.body.stream);
281+ const showThoughts = Boolean(request.body.show_thoughts);
281282
282283 const generationConfig = {
283284 stopSequences: request.body.stop,
@@ -325,7 +326,8 @@ async function sendMakerSuiteRequest(request, response) {
325326 controller.abort();
326327 });
327328
328329 const apiVersionisThinking = model.includes('v1betathinking');
330+ const apiVersion = isThinking ? 'v1alpha' : 'v1beta';
329331 const responseType = (stream ? 'streamGenerateContent' : 'generateContent');
330332
331333 const generateResponse = await fetch(`${apiUrl.toString().replace(/\/$/, '')}/${apiVersion}/models/${model}:${responseType}?key=${apiKey}${stream ? '&alt=sse' : ''}`, {
@@ -369,6 +371,10 @@ async function sendMakerSuiteRequest(request, response) {
369371 const responseContent = candidates[0].content ?? candidates[0].output;
370372 console.log('Google AI Studio response:', responseContent);
371373
374+ if (Array.isArray(responseContent?.parts) && isThinking && !showThoughts) {
375+ responseContent.parts = responseContent.parts.filter(part => !part.thought);
376+ }
377+
372378 const responseText = typeof responseContent === 'string' ? responseContent : responseContent?.parts?.map(part => part.text)?.join('\n\n');
373379 if (!responseText) {
374380 let message = 'Google AI Studio Candidate text empty';