mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-11-15 03:02:17 -05:00
overseer v2 5 (real tools)
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
module.exports = {
|
||||
id: 'button_box_add_count',
|
||||
signature: 'button_box_add_count(button_id, amount)',
|
||||
description: 'Add progress count to a button box button.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
button_id: { type: 'integer', minimum: 1, maximum: 4 },
|
||||
amount: { type: 'integer', minimum: 1, maximum: 25 },
|
||||
},
|
||||
required: ['button_id', 'amount'],
|
||||
additionalProperties: false,
|
||||
},
|
||||
availability(ctx = {}) {
|
||||
const mode = String(ctx.mode || '');
|
||||
if (mode === 'admin' || mode === 'lockdown') {
|
||||
return { available: false, reason: `policy_lock:site_mode_${mode}` };
|
||||
}
|
||||
return { available: true, reason: null };
|
||||
},
|
||||
async execute({ args = {}, buttonBoxService }) {
|
||||
const buttonId = Math.max(1, Math.min(4, Number(args?.button_id) || 0));
|
||||
const amount = Math.max(1, Math.min(25, Number(args?.amount) || 0));
|
||||
if (!buttonId) throw new Error('button_box_add_count requires args.button_id 1..4');
|
||||
if (!amount) throw new Error('button_box_add_count requires args.amount 1..25');
|
||||
const resp = await buttonBoxService.addButtonBoxCount(buttonId, amount);
|
||||
return { ok: true, button: resp };
|
||||
},
|
||||
};
|
||||
@@ -1,6 +1,15 @@
|
||||
module.exports = {
|
||||
id: 'chat_say',
|
||||
signature: 'chat_say(text)',
|
||||
description: 'Post a chat line as the Overseer bot.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
text: { type: 'string', minLength: 1, maxLength: 220 },
|
||||
},
|
||||
required: ['text'],
|
||||
additionalProperties: false,
|
||||
},
|
||||
availability() {
|
||||
return { available: true, reason: null };
|
||||
},
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
module.exports = {
|
||||
id: 'ha_set_entity',
|
||||
signature: 'ha_set_entity(entity_id, state)',
|
||||
description: 'Set Home Assistant controllable entity on/off.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
entity_id: { type: 'string', minLength: 1 },
|
||||
state: { type: 'string', enum: ['on', 'off'] },
|
||||
},
|
||||
required: ['entity_id', 'state'],
|
||||
additionalProperties: false,
|
||||
},
|
||||
availability(ctx = {}) {
|
||||
const mode = String(ctx.mode || '');
|
||||
if (mode === 'admin' || mode === 'lockdown') {
|
||||
@@ -15,6 +25,10 @@ module.exports = {
|
||||
async execute({ args = {}, homeAssistantService }) {
|
||||
const entityId = String(args?.entity_id || args?.entityId || '').trim();
|
||||
if (!entityId) throw new Error('ha_set_entity requires args.entity_id');
|
||||
const allowed = new Set(
|
||||
(homeAssistantService.getState()?.entities || []).map((entry) => String(entry?.id || '')).filter(Boolean),
|
||||
);
|
||||
if (!allowed.has(entityId)) throw new Error('ha_set_entity entity_id not configured');
|
||||
const state = String(args?.state || '').toLowerCase();
|
||||
if (state !== 'on' && state !== 'off') throw new Error('ha_set_entity requires args.state of on/off');
|
||||
await homeAssistantService.setEntityState(entityId, state, { source: 'overseerControl' });
|
||||
|
||||
@@ -8,6 +8,7 @@ const neatoSendHome = require('./neatoSendHome');
|
||||
const neatoLocate = require('./neatoLocate');
|
||||
const neatoClearErrors = require('./neatoClearErrors');
|
||||
const haSetEntity = require('./haSetEntity');
|
||||
const buttonBoxAddCount = require('./buttonBoxAddCount');
|
||||
|
||||
const TOOL_DEFINITIONS = [
|
||||
chatSay,
|
||||
@@ -20,37 +21,69 @@ const TOOL_DEFINITIONS = [
|
||||
neatoLocate,
|
||||
neatoClearErrors,
|
||||
haSetEntity,
|
||||
buttonBoxAddCount,
|
||||
];
|
||||
const TOOL_BY_ID = new Map(TOOL_DEFINITIONS.map((tool) => [tool.id, tool]));
|
||||
|
||||
function evaluateTools(context = {}) {
|
||||
const available = [];
|
||||
const availableIds = [];
|
||||
const blocked = [];
|
||||
TOOL_DEFINITIONS.forEach((tool) => {
|
||||
const result = typeof tool.availability === 'function' ? tool.availability(context) : { available: false, reason: 'unavailable' };
|
||||
if (result?.available) {
|
||||
available.push(tool.signature);
|
||||
availableIds.push(tool.id);
|
||||
return;
|
||||
}
|
||||
blocked.push({ tool: tool.signature, reason: result?.reason || 'unavailable' });
|
||||
blocked.push({ id: tool.id, tool: tool.signature, reason: result?.reason || 'unavailable' });
|
||||
});
|
||||
return { available, blocked };
|
||||
return { available, availableIds, blocked };
|
||||
}
|
||||
|
||||
async function executeToolAction(action = {}, context = {}) {
|
||||
const toolId = String(action?.tool || '').trim();
|
||||
const tool = TOOL_BY_ID.get(toolId);
|
||||
function buildOllamaTools(availableIds = []) {
|
||||
const allowed = new Set((availableIds || []).map((id) => String(id)));
|
||||
return TOOL_DEFINITIONS.filter((tool) => allowed.has(tool.id)).map((tool) => ({
|
||||
type: 'function',
|
||||
function: {
|
||||
name: tool.id,
|
||||
description: String(tool.description || tool.signature || tool.id),
|
||||
parameters: tool.parameters || {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
},
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
async function executeToolAction(toolId, args = {}, context = {}) {
|
||||
const key = String(toolId || '').trim();
|
||||
if (!key) throw new Error('Missing tool id');
|
||||
const tool = TOOL_BY_ID.get(key);
|
||||
if (!tool) {
|
||||
throw new Error(`Unknown tool: ${toolId}`);
|
||||
throw new Error(`Unknown tool: ${key}`);
|
||||
}
|
||||
if (typeof tool.execute !== 'function') {
|
||||
throw new Error(`Tool ${toolId} is not executable`);
|
||||
throw new Error(`Tool ${key} is not executable`);
|
||||
}
|
||||
return tool.execute({ ...context, args: action?.args || {} });
|
||||
return tool.execute({ ...context, args: args || {} });
|
||||
}
|
||||
|
||||
function getToolById(toolId) {
|
||||
return TOOL_BY_ID.get(String(toolId || '').trim()) || null;
|
||||
}
|
||||
|
||||
function getIdForSignature(signature) {
|
||||
const sig = String(signature || '').trim();
|
||||
const match = TOOL_DEFINITIONS.find((tool) => tool.signature === sig);
|
||||
return match?.id || null;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
TOOL_DEFINITIONS,
|
||||
evaluateTools,
|
||||
buildOllamaTools,
|
||||
executeToolAction,
|
||||
getToolById,
|
||||
getIdForSignature,
|
||||
};
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
module.exports = {
|
||||
id: 'lift_down',
|
||||
signature: 'lift_down()',
|
||||
description: 'Move the lift downward.',
|
||||
parameters: { type: 'object', properties: {}, additionalProperties: false },
|
||||
availability(ctx = {}) {
|
||||
const mode = String(ctx.mode || '');
|
||||
if (mode === 'admin' || mode === 'lockdown') {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
module.exports = {
|
||||
id: 'lift_up',
|
||||
signature: 'lift_up()',
|
||||
description: 'Move the lift upward.',
|
||||
parameters: { type: 'object', properties: {}, additionalProperties: false },
|
||||
availability(ctx = {}) {
|
||||
const mode = String(ctx.mode || '');
|
||||
if (mode === 'admin' || mode === 'lockdown') {
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
module.exports = {
|
||||
id: 'memory_read',
|
||||
signature: 'memory_read()',
|
||||
description: 'Read the Overseer persistent 3-slot memory.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {},
|
||||
additionalProperties: false,
|
||||
},
|
||||
availability() {
|
||||
return { available: true, reason: null };
|
||||
},
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
module.exports = {
|
||||
id: 'memory_write',
|
||||
signature: 'memory_write(slot, text)',
|
||||
description: 'Write one of 3 Overseer memory slots.',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
slot: { type: 'integer', minimum: 1, maximum: 3 },
|
||||
text: { type: 'string', minLength: 1, maxLength: 180 },
|
||||
},
|
||||
required: ['slot', 'text'],
|
||||
additionalProperties: false,
|
||||
},
|
||||
availability() {
|
||||
return { available: true, reason: null };
|
||||
},
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
module.exports = {
|
||||
id: 'neato_clear_errors',
|
||||
signature: 'neato_clear_errors()',
|
||||
description: 'Clear Neato errors.',
|
||||
parameters: { type: 'object', properties: {}, additionalProperties: false },
|
||||
availability(ctx = {}) {
|
||||
const mode = String(ctx.mode || '');
|
||||
if (mode === 'admin' || mode === 'lockdown') {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
module.exports = {
|
||||
id: 'neato_locate',
|
||||
signature: 'neato_locate()',
|
||||
description: 'Play Neato locate/chime action.',
|
||||
parameters: { type: 'object', properties: {}, additionalProperties: false },
|
||||
availability(ctx = {}) {
|
||||
const mode = String(ctx.mode || '');
|
||||
if (mode === 'admin' || mode === 'lockdown') {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
module.exports = {
|
||||
id: 'neato_send_home',
|
||||
signature: 'neato_send_home()',
|
||||
description: 'Send Neato back to base.',
|
||||
parameters: { type: 'object', properties: {}, additionalProperties: false },
|
||||
availability(ctx = {}) {
|
||||
const mode = String(ctx.mode || '');
|
||||
if (mode === 'admin' || mode === 'lockdown') {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
module.exports = {
|
||||
id: 'neato_start',
|
||||
signature: 'neato_start()',
|
||||
description: 'Start Neato cleaning cycle.',
|
||||
parameters: { type: 'object', properties: {}, additionalProperties: false },
|
||||
availability(ctx = {}) {
|
||||
const mode = String(ctx.mode || '');
|
||||
if (mode === 'admin' || mode === 'lockdown') {
|
||||
|
||||
Reference in New Issue
Block a user