Files
AtreidesAssetsFree/server/mcp/control-tools.mjs
T
2026-10-29 11:57:29 +01:00

107 lines
3.8 KiB
JavaScript

// Generated, do not edit. sha256:588c505552ce949b88f55a05209c95d02e3be8d37929538a9fb8ef9f58643cd2
import { CONFIG, TARGETS, targetHash } from '../../shared/config.js';
import { placeLabel } from '../../shared/places.js';
import { installLocale } from '../installation.mjs';
import { assertScope } from '../ai/gate.js';
import { createCommand, getCommand } from '../data/commands.js';
import { flushChanges } from '../data/bus.js';
const DOELEN = Object.keys(TARGETS);
const doelenTekst = () => DOELEN
.map(naam => `${naam} - ${placeLabel(naam, installLocale())} (${targetHash(TARGETS[naam])})`).join(', ');
const KIJK_INTERVAL_MS = 400;
const wacht = (ms) => new Promise(r => setTimeout(r, ms));
async function wachtOpUitkomst(id, seconden) {
const einde = Date.now() + seconden * 1000;
let c = getCommand(id);
while (c && c.resolvedAt == null && Date.now() < einde) {
await wacht(KIJK_INTERVAL_MS);
c = getCommand(id);
}
return c;
}
async function stuurOpdracht(kind, payload = null) {
const verloopt = new Date(Date.now() + CONFIG.COMMANDS.CLAIM_SECONDS * 1000).toISOString();
const id = await createCommand({ kind, payload, expiresAt: verloopt });
flushChanges();
return wachtOpUitkomst(id, CONFIG.COMMANDS.CLAIM_SECONDS);
}
const NIET_OPEN =
'De app lijkt niet open te staan. Vraag de gebruiker of hij AssetApp opent en probeer het daarna '
+ 'opnieuw.';
const navigeerNaar = Object.freeze({
name: 'navigate_to',
title: 'Naar een plek in de app gaan, of zien waar de gebruiker is',
description:
'Brengt de gebruiker naar een plek in AssetApp; zonder target zegt hij waar de gebruiker nu kijkt, '
+ 'met de naam van die plek. Een sprong ziet de gebruiker aankomen en kan hij tegenhouden. Leest en '
+ 'wijzigt de administratie niet. Staat de app niet open, dan zegt het antwoord dat.',
inputSchema: Object.freeze({
type: 'object',
properties: {
target: {
type: 'string',
enum: DOELEN,
description: 'De plek. Weglaten om te horen waar de gebruiker is.',
},
},
additionalProperties: false,
}),
scope: 'control',
async run(args) {
assertScope('control');
if (!args || args.target === undefined) return waarKijktDeGebruiker();
const naam = typeof args.target === 'string' ? args.target : '';
if (!Object.hasOwn(TARGETS, naam)) {
return {
text: `'${naam}' is geen bekende plek. Kies er een uit: ${doelenTekst()}.`,
fieldsShared: [],
};
}
const doel = TARGETS[naam];
const uit = await stuurOpdracht('navigate',
{ route: doel.route, tab: doel.tab, sub: doel.sub, hash: targetHash(doel) });
const stand = uit ? uit.state : 'expired';
if (stand === 'done') {
return { text: `Gedaan. De gebruiker kijkt nu naar ${targetHash(doel)}.`, fieldsShared: [] };
}
if (stand === 'rejected') {
return {
text: `Niet uitgevoerd: ${uit.detail || 'de opdracht is afgewezen.'} Er is niet genavigeerd.`,
fieldsShared: [],
};
}
return { text: `Er is niet genavigeerd. ${NIET_OPEN}`, fieldsShared: [] };
},
});
const NAAM_PER_HASH = new Map(DOELEN.map(naam => [targetHash(TARGETS[naam]), naam]));
async function waarKijktDeGebruiker() {
const uit = await stuurOpdracht('locate');
if (!uit || uit.state !== 'done') return { text: NIET_OPEN, fieldsShared: [] };
const hash = typeof uit.detail === 'string' ? uit.detail : '';
const naam = NAAM_PER_HASH.get(hash);
if (naam) return { text: `De gebruiker kijkt naar ${naam}: ${placeLabel(naam, installLocale())} (${hash}).`, fieldsShared: [] };
return {
text: hash
? `De gebruiker kijkt naar ${hash}. Dat is geen van de plekken die navigate_to kent.`
: 'De app staat open, maar liet niet weten waar de gebruiker kijkt.',
fieldsShared: [],
};
}
export const CONTROL_TOOLS = Object.freeze([navigeerNaar]);