From bc47110280ac80cba5f930c359ad48963e87f079 Mon Sep 17 00:00:00 2001 From: Gemini Bot Date: Thu, 14 May 2026 15:55:04 +0000 Subject: [PATCH] fix: restore Yes/No prefixes for web lookups and image generation --- src/features/ai-handler.ts | 14 ++++++++++---- src/features/summarizer.ts | 4 ++-- src/features/utils.ts | 20 ++++++++++++++++++++ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/features/ai-handler.ts b/src/features/ai-handler.ts index ff15942..e8a71d8 100644 --- a/src/features/ai-handler.ts +++ b/src/features/ai-handler.ts @@ -45,7 +45,7 @@ import { config } from '../config'; import { createProvider } from './llm/provider-factory'; import { HistoryBuilder } from './history-builder'; import { executeTool } from './tool-executor'; -import { markdownToSlack } from './utils'; +import { markdownToSlack, isBinaryQuestion } from './utils'; import { Content, Part } from '@google/generative-ai'; import { LLMMessage, LLMTool, LLMToolCall } from './llm/providers/types'; import { registerEventListeners } from '../listeners/events'; @@ -553,9 +553,15 @@ If the user asks for a summary or current state, base it ONLY on the saved RPG c if (calledUpdateRpg) msg.push('game state updated'); if (calledGenerateImage) msg.push('image request submitted'); const narrative = (currentResponse.text || '').trim(); + + // Check if it's a binary question + const currentQuestionText = typeof question === 'string' ? question : ''; + const isBinary = isBinaryQuestion(currentQuestionText); + const binaryPrefix = isBinary ? 'Yes. ' : ''; + const confirmation = narrative - ? `Acknowledged: ${msg.join(' and ')}.\n\n${narrative} ` - : `Acknowledged: ${msg.join(' and ')}.`; + ? `${binaryPrefix}Acknowledged: ${msg.join(' and ')}.\n\n${narrative} ` + : `${binaryPrefix}Acknowledged: ${msg.join(' and ')}.`; return { text: confirmation, confidence: 1.0, totalTokens: totalTokens }; } @@ -572,7 +578,7 @@ If the user asks for a summary or current state, base it ONLY on the saved RPG c break; } - const summary = await this.summarizer!.summarizeText(fetchedContent, typeof question === 'string' ? question : 'Image analysis request'); + const summary = await this.summarizer!.summarizeText(fetchedContent, typeof question === 'string' ? question : 'Image analysis request', finalPrompt); finalNarrative += (summary || '').trim() + '\n\n'; alreadySummarized = true; diff --git a/src/features/summarizer.ts b/src/features/summarizer.ts index 2906db8..bc81611 100644 --- a/src/features/summarizer.ts +++ b/src/features/summarizer.ts @@ -82,7 +82,7 @@ ${conversationText}`; } } - public async summarizeText(text: string, originalQuestion: string): Promise { + public async summarizeText(text: string, originalQuestion: string, systemPrompt?: string): Promise { // Simple character-based chunking with a safety margin. const chunkSize = Math.floor(this.config.openai.maxContextSize * 2.5); // 2.5 chars/token is a safer estimate const chunks: string[] = []; @@ -112,7 +112,7 @@ ${conversationText}`; const finalPrompt = `Based on the following summaries of a document, please provide a final answer to the user's original question.\n\nOriginal question: ${originalQuestion}\n\nSummaries:\n---\n${combinedSummaries}\n---`; const finalResult = await this.provider.chat(finalPrompt, { - systemPrompt: "You are a helpful assistant that synthesizes information." + systemPrompt: systemPrompt || "You are a helpful assistant that synthesizes information." }); return finalResult.text; diff --git a/src/features/utils.ts b/src/features/utils.ts index e91498c..b96399a 100644 --- a/src/features/utils.ts +++ b/src/features/utils.ts @@ -148,4 +148,24 @@ export function markdownToSlack(text: string): string { out = out.replace(/^(\s*)([*+-])\s+/gm, '$1• '); return out; +} + +/** + * Detects if a question is a binary (Yes/No) question. + * @param text The question text, potentially containing Slack scaffolding. + */ +export function isBinaryQuestion(text: string): boolean { + if (!text) return false; + + // 1. Strip Slack scaffolding: channel_id: ... | message: ... + const messageMatch = text.match(/\| message: (.*)$/); + const cleanedText = messageMatch ? messageMatch[1].trim() : text.trim(); + + if (!cleanedText) return false; + + // 2. Check if the first word matches the list from the system prompt + const firstWord = cleanedText.split(/\s+/)[0].replace(/[^a-zA-Z]/g, '').toLowerCase(); + const binaryIndicators = ['is', 'are', 'do', 'does', 'can', 'will', 'should', 'would', 'has', 'have', 'am']; + + return binaryIndicators.includes(firstWord); } \ No newline at end of file