openvibers/openvibe.chat Commits

Vibe: a guessed freshness window does not hide the Work listing (#261)

OP OpenVibers committed 15 days ago · 623ff4e9be · 2 files, +17 −7

The bare query 'remote video editing jobs' has no time words, but the model can pass freshness day; the automatic short-query retry kept that window and still found nothing, so the answer said OpenVibe had no job. When the query names no time of its own, the retry now drops the guessed window and finds the Work listing, reporting freshness_dropped so the model can date it. Queries that say today, recently or posted keep the window.

Changes

ddiff --git a/server/rooms/ai-tools.js b/server/rooms/ai-tools.js
iindex 60e9e0a..5e63698 100644
---- a/server/rooms/ai-tools.js
++++ b/server/rooms/ai-tools.js
@@@ -119,6 +119,9 @@ const OWNERS = [
[/\b(news|headlines?)\b/i, 'news'],
];
const ownerOf = (q) => (OWNERS.find(([re]) => re.test(String(q || ''))) || [])[1] || null;
++// A query that names its own time ("posted recently", "today") keeps the freshness window on the retry; one that does
++// not (the bare "remote video editing jobs") lets the retry look outside the window the model guessed (11-01).
++const TEMPORAL = /\b(today|tonight|now|latest|recent|recently|new|posted|this\s+(week|month|year)|week|month|year|day)\b/i;
/** The 2–3 key nouns of a request, or null when it is already that short ("video editor", "mechanical keyboard"). */
function shortenQuery(q) {
const words = String(q || '').toLowerCase().replace(/[^\p{L}\p{N}\s'-]+/gu, ' ').split(/\s+/).filter(Boolean);
@@@ -153,10 +156,12 @@ async function searchOpenvibe(args, { fetchImpl = null, searchClient = null } =
const short = shortenQuery(query);
if (short) {
const owner = wanted || ownerOf(query);
-- const retryBody = await fabricSearch.query({ q: short, scopes: ['network'], limit, ...window, ...(owner ? { owner } : {}), signal: AbortSignal.timeout(8000) }, opts);
++ const retryWindow = TEMPORAL.test(query) ? window : {};
++ const dropped = freshness && !retryWindow.freshness ? freshness : null;
++ const retryBody = await fabricSearch.query({ q: short, scopes: ['network'], limit, ...retryWindow, ...(owner ? { owner } : {}), signal: AbortSignal.timeout(8000) }, opts);
const retried = (Array.isArray(retryBody.results) ? retryBody.results : []).slice(0, limit).map((r) => fabricSearch.resultOf(r));
-- if (retried.length) return { query: short, original_query: query, retried_with: short, ...window, ...(owner ? { owner } : {}), citations: fabricSearch.citationsOf(retried), results: retried, note: `Nothing matched "${query}". A retry with "${short}" found ${retried.length}; answer from that, or say plainly if it is not what they asked for.` };
-- return { query, original_query: query, retried_with: short, ...window, ...(owner ? { owner } : {}), citations: [], results: [], note: nothingNote(query, short) };
++ if (retried.length) return { query: short, original_query: query, retried_with: short, ...retryWindow, ...(dropped ? { freshness_dropped: dropped } : {}), ...(owner ? { owner } : {}), citations: fabricSearch.citationsOf(retried), results: retried, note: `Nothing matched "${query}"${dropped ? ` in the last ${dropped}` : ''}. A retry with "${short}"${dropped ? ' without that window' : ''} found ${retried.length}; answer from that, or say plainly if it is not what they asked for.` };
++ return { query, original_query: query, retried_with: short, ...retryWindow, ...(dropped ? { freshness_dropped: dropped } : {}), ...(owner ? { owner } : {}), citations: [], results: [], note: nothingNote(query, short) };
}
return { query, ...window, ...product, citations: [], results: [], note: nothingNote(query) };
} catch (err) {
ddiff --git a/test/room-ai-tools.test.js b/test/room-ai-tools.test.js
iindex 9fa4b8c..e9c9522 100644
---- a/test/room-ai-tools.test.js
++++ b/test/room-ai-tools.test.js
@@@ -148,13 +148,12 @@ t('the tool list and the runners: bounded, fair, refusing what is not theirs', a
assert.match(none.note, /2–3 key nouns/, 'the one hint: a shorter query');
assert.match(none.note, /video editor/, 'the job-title example the starter chip needs');
// "remote video editing jobs" finds nothing: one automatic retry with the nouns, narrowed to Work, before the model spends a round.
++ const job = { scope: 'network', kind: 'document', owner: 'work', type: 'job', title: 'Intern Video Editing & Support at Bettermile', snippet: 'Video editing, remote-friendly', url: 'https://openvibe.work/jobs/job_1', published_at: '2026-10-26T00:00:00Z' };
const retrySeen = [];
const retryFake = async (url) => {
retrySeen.push(new URL(String(url)));
const q = retrySeen[retrySeen.length - 1].searchParams.get('q');
-- const results = q === 'video editing'
-- ? [{ scope: 'network', kind: 'document', owner: 'work', type: 'job', title: 'Intern Video Editing & Support at Bettermile', snippet: 'Video editing, remote-friendly', url: 'https://openvibe.work/jobs/job_1', published_at: '2026-10-26T00:00:00Z' }]
-- : [];
++ const results = q === 'video editing' ? [job] : [];
return new Response(JSON.stringify({ results }), { status: 200, headers: { 'content-type': 'application/json' } });
};
const retried = await aiTools._runners.search_openvibe({ query: 'Find remote video editing jobs posted recently', freshness: 'week' }, { fetchImpl: retryFake });
@@@ -163,7 +162,13 @@ t('the tool list and the runners: bounded, fair, refusing what is not theirs', a
assert.deepStrictEqual([retrySeen[1].searchParams.get('q'), retrySeen[1].searchParams.get('owner'), retrySeen[1].searchParams.get('freshness')], ['video editing', 'work', 'week']);
assert.deepStrictEqual([retried.query, retried.original_query, retried.results.length], ['video editing', 'Find remote video editing jobs posted recently', 1]);
assert.match(retried.note, /retry with "video editing" found 1/);
-- // ...and when the retry finds nothing either, the note says both queries and still gives the hint.
++ // A bare query with no time words: a window the model guessed is dropped for the retry, so the Work job is found.
++ const bareSeen = [];
++ const bare = await aiTools._runners.search_openvibe({ query: 'remote video editing jobs', owner: 'work', freshness: 'day' }, { fetchImpl: async (url) => { bareSeen.push(new URL(String(url))); const q = bareSeen[bareSeen.length - 1].searchParams.get('q'); return new Response(JSON.stringify({ results: q === 'video editing' ? [job] : [] }), { status: 200, headers: { 'content-type': 'application/json' } }); } });
++ assert.deepStrictEqual([bareSeen[0].searchParams.get('freshness'), bareSeen[1].searchParams.get('freshness')], ['day', null], 'no time word: the retry looks outside the guessed window');
++ assert.deepStrictEqual([bare.freshness_dropped, bare.results.length], ['day', 1]);
++ assert.match(bare.note, /in the last day/);
++ // ...and when both find nothing, the note still gives the hint.
const bothEmpty = await aiTools._runners.search_openvibe({ query: 'remote video editing jobs', freshness: 'day' }, { fetchImpl: async () => new Response(JSON.stringify({ results: [] }), { status: 200, headers: { 'content-type': 'application/json' } }) });
assert.match(bothEmpty.note, /"remote video editing jobs" and a retry with "video editing" both found nothing/);
assert.match(bothEmpty.note, /2–3 key nouns/);