From 0369b4e819a497e55badb95a42e18b5e7951ef78 Mon Sep 17 00:00:00 2001 From: seb Date: Tue, 6 Oct 2026 03:18:30 +0200 Subject: [PATCH] u --- src/services/conversationManager.js | 2 +- src/tools/web-search.js | 49 +++++++++++++++-------------- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/services/conversationManager.js b/src/services/conversationManager.js index 5045072..6358280 100644 --- a/src/services/conversationManager.js +++ b/src/services/conversationManager.js @@ -117,7 +117,7 @@ async function buildSystemPrompt(vfsRoot, googleAuthId) { '6. patch: Create, overwrite, or search-and-replace text in a VFS file. This is the only text write path — it also creates SKILL files.', '7. search_images: Search Google Images and store the candidates in the VFS as AVIF files.', '8. analyze_image: Have a vision model look at up to 9 images (VFS paths or "image/") and return its judgement. This is how you "see" — never claim to have inspected an image yourself.', - '9. web_search: Search the web using Google Search. Returns organic results, snippets, and knowledge graph. Supports time filters via `tbs` ("qdr:d" past day, "qdr:w" past week, "qdr:m" past month, "qdr:y" past year).', + '9. web_search: Search the web using Google Search. Returns organic results, snippets, and knowledge graph. Supports filtering by timePeriod ("day", "week", "month", "year") — always use "day" or "week" for news and recent events.', '10. url_get: Fetch and scrape the content and markdown of a web page/URL.', '11. pdf_read: Read and convert PDF or text files. Converts PDF to layout-preserved text ("txt") or renders pages into PNG images ("png") saved in the VFS images/ folder.', '12. reset_vfs: Delete files, images, and artifacts stored in the virtual filesystem (VFS) to free up storage or clean up. SKILL files are exempt and survive.', diff --git a/src/tools/web-search.js b/src/tools/web-search.js index 9027f9b..3b4300b 100644 --- a/src/tools/web-search.js +++ b/src/tools/web-search.js @@ -5,30 +5,30 @@ const SERPER_SEARCH_ENDPOINT = 'https://google.serper.dev/search'; const SEARCH_TIMEOUT_MS = 15_000; /** - * Normalizes user/model-supplied time filter (`tbs`) into Google's qdr syntax. + * Normalizes user/model-supplied time filter into Google's qdr syntax. * Supported: - * - "qdr:d" or "d" / "day" / "24h" -> "qdr:d" - * - "qdr:w" or "w" / "week" -> "qdr:w" - * - "qdr:m" or "m" / "month" -> "qdr:m" - * - "qdr:y" or "y" / "year" -> "qdr:y" - * - "qdr:h" or "h" / "hour" -> "qdr:h" + * - "day" / "24h" / "d" -> "qdr:d" + * - "week" / "w" -> "qdr:w" + * - "month" / "m" -> "qdr:m" + * - "year" / "y" -> "qdr:y" + * - "hour" / "h" -> "qdr:h" * - * @param {string|null} tbs + * @param {string|null} time * @returns {string|undefined} */ -function normalizeTbs(tbs) { - if (!tbs || typeof tbs !== 'string') return undefined; - const trimmed = tbs.trim().toLowerCase(); +function normalizeTbs(time) { + if (!time || typeof time !== 'string') return undefined; + const trimmed = time.trim().toLowerCase(); if (!trimmed) return undefined; + if (trimmed === 'day' || trimmed === 'd' || trimmed === '24h' || trimmed === 'today') return 'qdr:d'; + if (trimmed === 'week' || trimmed === 'w') return 'qdr:w'; + if (trimmed === 'month' || trimmed === 'm') return 'qdr:m'; + if (trimmed === 'year' || trimmed === 'y') return 'qdr:y'; + if (trimmed === 'hour' || trimmed === 'h') return 'qdr:h'; if (trimmed.startsWith('qdr:')) return trimmed; - if (trimmed === 'd' || trimmed === 'day' || trimmed === '24h') return 'qdr:d'; - if (trimmed === 'w' || trimmed === 'week') return 'qdr:w'; - if (trimmed === 'm' || trimmed === 'month') return 'qdr:m'; - if (trimmed === 'y' || trimmed === 'year') return 'qdr:y'; - if (trimmed === 'h' || trimmed === 'hour') return 'qdr:h'; - return trimmed; + return undefined; } /** @@ -91,8 +91,9 @@ export function createWebSearchTool({ googleAuthId }) { description: 'Search the web using Google Search via Serper.dev. ' + 'Returns raw search results as-is from Serper. ' + - 'Supports time filters via `tbs` ("qdr:d" for past day, "qdr:w" for past week, ' + - '"qdr:m" for past month, "qdr:y" for past year). Each page returns 10 results.', + 'Supports filtering fresh content with timePeriod ("day", "week", "month", "year"). ' + + 'Always use "day" or "week" when searching for news, recent events, or current status. ' + + 'Each page returns 10 results.', strict: false, parameters: { type: 'object', @@ -103,11 +104,13 @@ export function createWebSearchTool({ googleAuthId }) { type: 'string', description: 'Search query, e.g. "apple inc" or "vite vue3 release".', }, - tbs: { + timePeriod: { type: 'string', + enum: ['day', 'week', 'month', 'year'], description: - 'Time filter for results: "qdr:d" (past 24h / day), "qdr:w" (past week), ' + - '"qdr:m" (past month), "qdr:y" (past year). Short forms like "d", "w", "m", "y" are also accepted.', + 'Filter results by time period: "day" (past 24 hours), "week" (past week), ' + + '"month" (past month), or "year" (past year). ' + + 'Always use "day" or "week" when searching for news, recent events, or current status.', }, gl: { type: 'string', @@ -123,7 +126,7 @@ export function createWebSearchTool({ googleAuthId }) { }, }, }, - invoke: async ({ query, tbs, gl = 'de', hl = 'de', page = 1 } = {}, { signal } = {}) => { + invoke: async ({ query, timePeriod, tbs, gl = 'de', hl = 'de', page = 1 } = {}, { signal } = {}) => { const term = typeof query === 'string' ? query.trim() : ''; if (!term) { throw new ToolError('web_search requires a non-empty "query".'); @@ -134,7 +137,7 @@ export function createWebSearchTool({ googleAuthId }) { throw new ToolError(`"page" must be a positive integer (received ${page}).`); } - const normalizedTbs = normalizeTbs(tbs); + const normalizedTbs = normalizeTbs(timePeriod || tbs); let apiKey = null; try {