openvibers/openvibe.chat Commits

Gate Vibe web search behind owner switch (#461)

OP OpenVibers committed 3 days ago · e632046bf4 · 3 files, +10 −2

Changes

ddiff --git a/server/config.js b/server/config.js
iindex 024bccc..f596612 100644
---- a/server/config.js
++++ b/server/config.js
@@@ -236,6 +236,8 @@ module.exports = {
// Vibe, OpenVibe's assistant (server/rooms/vibe.js): on unless CHAT_VIBE=0 (it also needs AI members on); a person
// gets this many answers a UTC day across all their Vibe chats.
vibe: process.env.CHAT_VIBE !== '0',
++ // C3 web search in Vibe's composer (the existing Search Fabric tool and cited results); owner enables it explicitly.
++ vibeWebSearch: bool(process.env.CHAT_VIBE_WEB_SEARCH_ENABLED, false),
vibeRepliesPerDay: Math.max(1, int(process.env.CHAT_VIBE_REPLIES_PER_DAY, 100)),
},
bench: {
ddiff --git a/server/rooms/ai-tools.js b/server/rooms/ai-tools.js
iindex d619705..b8f52a5 100644
---- a/server/rooms/ai-tools.js
++++ b/server/rooms/ai-tools.js
@@@ -115,7 +115,7 @@ const hasMemory = (member, room, memory) => !!memory && ownChat(member, room);
const definitions = (member, room = null, { memory = false } = {}) => [
...BASE,
...(member && member.link_service === 'food' && member.link_resource ? [PANTRY] : []),
-- ...(isVibe(member) ? [WEB] : []),
++ ...(isVibe(member) && require('../config').ai.vibeWebSearch ? [WEB] : []),
...(isWorkspace(room) ? [QUEUE, QUEUE_STATUS] : []),
...(hasMemory(member, room, memory) ? [REMEMBER, FORGET] : []),
...(ownChat(member, room) ? [SET_UP_AGENT, MY_AGENTS, SET_REMINDER, MY_REMINDERS, STOP_REMINDER, MY_DAY, START_TIMER, STOP_TIMER] : []),
@@@ -444,7 +444,7 @@ const RUNNERS = { search_openvibe: searchOpenvibe, read_page: readPage, web_sear
*/
async function runWithResult(name, raw, ctx = {}) {
const runner = RUNNERS[name];
-- if (!runner || (name === 'household_pantry' && !(ctx.member && ctx.member.link_service === 'food')) || (name === 'web_search' && !isVibe(ctx.member))
++ if (!runner || (name === 'household_pantry' && !(ctx.member && ctx.member.link_service === 'food')) || (name === 'web_search' && !(isVibe(ctx.member) && require('../config').ai.vibeWebSearch))
|| ((name === 'queue_task' || name === 'queue_status') && !isWorkspace(ctx.room))
|| ((name === 'remember' || name === 'forget') && !(hasMemory(ctx.member, ctx.room, ctx.memory) && ctx.user))
|| (['set_up_agent', 'my_agents', 'set_reminder', 'my_reminders', 'stop_reminder', 'my_day', 'start_timer', 'stop_timer'].includes(name) && !(ownChat(ctx.member, ctx.room) && ctx.user))) {
ddiff --git a/test/room-ai-tools.test.js b/test/room-ai-tools.test.js
iindex abd6767..e72329c 100644
---- a/test/room-ai-tools.test.js
++++ b/test/room-ai-tools.test.js
@@@ -25,6 +25,7 @@ t('boot', async () => {
aiClient = require('../server/ai/client');
aiTools = require('../server/rooms/ai-tools');
config = require('../server/config');
++ config.ai.vibeWebSearch = true; // enable the owner-gated Search Fabric tool for these fixtures
ann = h.addUser('ann', { subject: ids.newId('user') });
await h.ctx.upsertUser(h.live.users.get(ann.id));
aiClient._setClient({
@@@ -45,6 +46,11 @@ t('boot', async () => {
t('the tool list and the runners: bounded, fair, refusing what is not theirs', async () => {
const names = aiTools.definitions({}).map((d) => d.function.name);
assert.deepStrictEqual(names, ['search_openvibe', 'read_page', 'current_time', 'roll_dice', 'pick_one'], 'no pantry for an unlinked member');
++ config.ai.vibeWebSearch = false;
++ assert.ok(!aiTools.definitions({ handle: 'vibe' }).some((d) => d.function.name === 'web_search'), 'the web tool is absent while its owner switch is off');
++ const refused = await aiTools.runWithResult('web_search', '{"query":"latest"}', { member: { handle: 'vibe' } });
++ assert.match(refused.text, /no tool called web_search/, 'the runner also enforces the owner switch');
++ config.ai.vibeWebSearch = true;
// Both search tools take the Search Fabric's freshness window (10-30): "today" and "recently" reach Search.
const schemaOf = (name) => aiTools.definitions({ handle: 'vibe' }).find((d) => d.function.name === name).function.parameters;
for (const name of ['search_openvibe', 'web_search']) {