__tests__/role-devices.test.js
Rama main · réplica de lectura del repositorio original.
/*
* ONE ROLE, ONE METHOD PER DEVICE.
*
* A role had a single `require`, and that quietly decided which machine could ever run it:
* capcut-video-editor asks for `{cdp, click_xy, drag, upload_file}`, so the phone was excluded
* forever — though a phone could do the same job by long-pressing and dragging with a finger. One
* requirement was really two statements squashed together: what the WORK needs, and how THIS KIND
* of machine does it.
*
* The second half is the one that matters most here: a hand-over carries the method for the device
* that took the job and NOTHING else. "Drag the clip onto the timeline" and "long-press the clip,
* then drag with your finger" are both correct, and only one of them is correct HERE. Sending both
* is how an agent starts guessing, and guessing is what cost seventy steps on a video editor.
*/
import { describe, it, expect } from 'vitest';
import { normDevices, variantsOf, chooseVariant, playbookFor, whyNothingFits, KINDS } from '../src/roleDevices.js';
import { normRequire } from '../src/userRoles.js';
const DESK = 'Drag the clip from the library onto the timeline.';
const PHONE = 'Long-press the clip, then drag it down with your finger.';
const capcut = () => ({
prompt: 'Open CapCut, import the clip, trim it, export it.',
require: { cdp: true, features: ['click_xy', 'drag', 'upload_file'] },
devices: normDevices({
desktop: { require: { cdp: true, features: ['drag', 'upload_file'] }, method: DESK },
android: { require: { mobileApp: true, features: ['native_tap'] }, method: PHONE },
}, normRequire),
});
/** A ring where only the named platforms are online. */
const ringWith = (...platforms) => (need) => (
platforms.includes(need.platform)
? { deviceId: `d-${need.platform}`, name: `the ${need.platform}`, reason: 'matched' }
: { deviceId: null, reason: `no online device has ${JSON.stringify(need)}`, candidates: [] });
describe('the device section', () => {
it('keeps only device kinds the ring itself knows', () => {
const d = normDevices({ desktop: { method: 'a' }, toaster: { method: 'b' } }, normRequire);
expect(Object.keys(d)).toEqual(['desktop']);
expect(KINDS).toEqual(['desktop', 'android', 'cluster']);
});
it('sets a variant\'s platform from its KEY and never from its body', () => {
/* Writing platform again inside devices.android is redundant at best and a contradiction at
worst, and a contradiction here would route phone work to a desktop. */
const d = normDevices({ android: { require: { platform: 'desktop', mobileApp: true } } }, normRequire);
expect(d.android.require.platform).toBe('android');
});
it('drops a variant that says nothing at all', () => {
/* Keeping it would make the role look device-aware while behaving exactly as it did. */
expect(normDevices({ desktop: {} }, normRequire)).toBeNull();
expect(normDevices({ desktop: { method: ' ' } }, normRequire)).toBeNull();
});
it('refuses junk rather than half-storing it', () => {
for (const v of [null, undefined, 'x', 7, []]) expect(normDevices(v, normRequire)).toBeNull();
});
it('caps a method so a role cannot become a document', () => {
const d = normDevices({ desktop: { method: 'x'.repeat(9000) } }, normRequire);
expect(d.desktop.method.length).toBe(8000);
});
});
describe('the ways a role can run', () => {
it('tries device variants BEFORE the general requirement', () => {
/* A role that took the trouble to say how the desktop does this work means that method, not
the generic requirement it was originally written with. */
expect(variantsOf(capcut()).map((v) => v.kind)).toEqual(['desktop', 'android', 'any']);
});
it('is unchanged for a role with no device section — one variant, the old requirement', () => {
const r = { prompt: 'p', require: { cdp: true } };
const v = variantsOf(r);
expect(v).toHaveLength(1);
expect(v[0]).toMatchObject({ kind: 'any', require: { cdp: true }, method: '' });
});
it('gives a role with no requirement at all a single empty variant', () => {
const v = variantsOf({ prompt: 'p' });
expect(v).toHaveLength(1);
expect(v[0].require).toBeNull();
});
});
describe('choosing the variant a real device can run', () => {
it('takes the desktop when only the desktop is connected', () => {
const c = chooseVariant(capcut(), ringWith('desktop'));
expect(c.variant.kind).toBe('desktop');
});
it('takes the PHONE when only the phone is connected — the case that used to be impossible', () => {
/* The single requirement asked for cdp, which no phone has, so the role was desktop-only by
omission even where the work was perfectly doable on a phone. */
const c = chooseVariant(capcut(), ringWith('android'));
expect(c.variant.kind).toBe('android');
});
it('needs no device at all for a role that requires nothing', () => {
const c = chooseVariant({ prompt: 'p' }, () => { throw new Error('must not ask the ring'); });
expect(c.variant.kind).toBe('any');
expect(c.route).toBeNull();
});
it('reports every way it tried when nothing fits', () => {
const c = chooseVariant(capcut(), ringWith());
expect(c.variant).toBeNull();
expect(c.tried.map((t) => t.kind)).toEqual(['desktop', 'android', 'any']);
const why = whyNothingFits(c.tried);
expect(why).toMatch(/your desktop:/);
expect(why).toMatch(/your phone:/);
expect(why).toMatch(/its general requirement:/);
});
it('survives a router that throws instead of answering', () => {
const c = chooseVariant(capcut(), () => { throw new Error('ring is down'); });
expect(c.variant).toBeNull();
expect(whyNothingFits(c.tried)).toMatch(/ring is down/);
});
it('says something usable when a role states no way to run at all', () => {
expect(whyNothingFits([])).toMatch(/states no way to run it/);
});
});
describe('the playbook handed to the device', () => {
it('carries the base method plus THIS device\'s, and not the other one', () => {
const r = capcut();
const desk = playbookFor(r, chooseVariant(r, ringWith('desktop')).variant);
expect(desk).toContain(r.prompt);
expect(desk).toContain(DESK);
expect(desk).not.toContain(PHONE);
const phone = playbookFor(r, chooseVariant(r, ringWith('android')).variant);
expect(phone).toContain(PHONE);
expect(phone).not.toContain(DESK);
});
it('says out loud that this is the method that applies here', () => {
/* So the agent does not weigh it against something it half-remembers. */
const r = capcut();
expect(playbookFor(r, chooseVariant(r, ringWith('desktop')).variant))
.toMatch(/ON THIS DEVICE \(your desktop\) — this is the method that applies here, and the only one:/);
});
it('is exactly the base prompt when the variant adds no method', () => {
const r = { prompt: 'just do it', require: { cdp: true } };
expect(playbookFor(r, variantsOf(r)[0])).toBe('just do it');
});
it('is the method alone when a role has no base prompt', () => {
const r = { devices: normDevices({ desktop: { method: DESK } }, normRequire) };
expect(playbookFor(r, variantsOf(r)[0])).toContain(DESK);
});
it('survives being handed nothing', () => {
expect(playbookFor(null, null)).toBe('');
expect(playbookFor({ prompt: 'p' }, null)).toBe('p');
});
});