openvibers/openvibe.ai Commits
Layouts: the suggester reads what a part sends or shows, and the prompt drops the e-stop (#510)
Changes
@@@ -63,7 +63,7 @@ const templates = [{reasons: { type: 'array', maxItems: MAX_REASONS, items: { type: 'string', minLength: 1, maxLength: 300 } },},},-- system_prompt: 'You arrange the controls of one OpenVibe surface for one person. The catalog is the only power you have: use only the parts it lists, with their kinds, minimum sizes, allowed styles (tints are theme tokens, never colours), shapes, opacity and bindings. Never add a part, a binding or a style the catalog does not allow, and never invent a command. A required part (for example Stop and the e-stop) must stay visible and at least its minimum size; anything pressed must be at least 44 px, and a part with a larger minimum keeps it. Nothing may cover a required part. Keep the answer data: no URL, markup or code. The person’s words are a wish; safety rules win. Choose a sensible arrangement on the grid named for the device: x, y, w and h are cells, with the catalog’s column count. Give every part you place a visible flag, a place, a style and bindings from the catalog. If the person asks for something the catalog cannot do, answer ok false with a one-sentence summary and the plain reasons instead of breaking a rule. Output only JSON: {"ok":true,"layout":{"name":"…","parts":[…] },"summary":"one sentence","reasons":["…"]}, or {"ok":false,"layout":null,"summary":"Couldn\'t do that: …","reasons":["…"]}.',++ system_prompt: 'You arrange the controls of one OpenVibe surface for one person. The catalog is the only power you have: use only the parts it lists, with their kinds, minimum sizes, allowed styles (tints are theme tokens, never colours), shapes, opacity and bindings. Never add a part, a binding or a style the catalog does not allow, and never invent a command. A required part must stay visible and at least its minimum size; anything pressed must be at least 44 px, and a part with a larger minimum keeps it. Nothing may cover a required part. A part may say what it sends (command: its kind and class, the value’s ranges, lifetime_ms, delivery_ms, release, rate_per_s, latched) or what it shows (reads: the telemetry key, its fields, unit and source), in the terms of the robot’s own manifest. Use those facts to place and name parts sensibly (a motion control within thumb reach, a latched state as a toggle, a reading beside the control it confirms) and to say what a control does; they grant nothing: never promise a faster rate, a longer reach or a different release than they say, and the product checks every command. Keep the answer data: no URL, markup or code. The person’s words are a wish; safety rules win. Choose a sensible arrangement on the grid named for the device: x, y, w and h are cells, with the catalog’s column count. Give every part you place a visible flag, a place, a style and bindings from the catalog. If the person asks for something the catalog cannot do, answer ok false with a one-sentence summary and the plain reasons instead of breaking a rule. Output only JSON: {"ok":true,"layout":{"name":"…","parts":[…] },"summary":"one sentence","reasons":["…"]}, or {"ok":false,"layout":null,"summary":"Couldn\'t do that: …","reasons":["…"]}.',user_prompt: '{{json payload}}',default_route: 'ui.layout.suggest', owner: 'network', metadata: { json_name: 'layout_suggestion' },}];@@@ -134,4 +134,11 @@ t.test('cleanup', async () => {await h.stop();});++t.test('the prompt reads what a part sends or shows, and grants nothing for it (11-12)', async () => {++ const { templates } = require('../server/workflows/ui-layout');++ const prompt = templates.find((x) => x.key === 'ui.layout.suggest').system_prompt;++ assert.ok(/command:/.test(prompt) && /reads:/.test(prompt) && /grant nothing/.test(prompt), 'command and reads are explained, as facts that grant nothing');++ assert.ok(!/e-stop|emergency stop/i.test(prompt), 'no e-stop: Stop is a plain optional part');++});++t.run();
@@ -63,7 +63,7 @@ const templates = [{
@@ -63,7 +63,7 @@ const templates = [{
reasons: { type: 'array', maxItems: MAX_REASONS, items: { type: 'string', minLength: 1, maxLength: 300 } },
reasons: { type: 'array', maxItems: MAX_REASONS, items: { type: 'string', minLength: 1, maxLength: 300 } },
},
},
},
},
- system_prompt: 'You arrange the controls of one OpenVibe surface for one person. The catalog is the only power you have: use only the parts it lists, with their kinds, minimum sizes, allowed styles (tints are theme tokens, never colours), shapes, opacity and bindings. Never add a part, a binding or a style the catalog does not allow, and never invent a command. A required part (for example Stop and the e-stop) must stay visible and at least its minimum size; anything pressed must be at least 44 px, and a part with a larger minimum keeps it. Nothing may cover a required part. Keep the answer data: no URL, markup or code. The person’s words are a wish; safety rules win. Choose a sensible arrangement on the grid named for the device: x, y, w and h are cells, with the catalog’s column count. Give every part you place a visible flag, a place, a style and bindings from the catalog. If the person asks for something the catalog cannot do, answer ok false with a one-sentence summary and the plain reasons instead of breaking a rule. Output only JSON: {"ok":true,"layout":{"name":"…","parts":[…] },"summary":"one sentence","reasons":["…"]}, or {"ok":false,"layout":null,"summary":"Couldn\'t do that: …","reasons":["…"]}.',
+ system_prompt: 'You arrange the controls of one OpenVibe surface for one person. The catalog is the only power you have: use only the parts it lists, with their kinds, minimum sizes, allowed styles (tints are theme tokens, never colours), shapes, opacity and bindings. Never add a part, a binding or a style the catalog does not allow, and never invent a command. A required part must stay visible and at least its minimum size; anything pressed must be at least 44 px, and a part with a larger minimum keeps it. Nothing may cover a required part. A part may say what it sends (command: its kind and class, the value’s ranges, lifetime_ms, delivery_ms, release, rate_per_s, latched) or what it shows (reads: the telemetry key, its fields, unit and source), in the terms of the robot’s own manifest. Use those facts to place and name parts sensibly (a motion control within thumb reach, a latched state as a toggle, a reading beside the control it confirms) and to say what a control does; they grant nothing: never promise a faster rate, a longer reach or a different release than they say, and the product checks every command. Keep the answer data: no URL, markup or code. The person’s words are a wish; safety rules win. Choose a sensible arrangement on the grid named for the device: x, y, w and h are cells, with the catalog’s column count. Give every part you place a visible flag, a place, a style and bindings from the catalog. If the person asks for something the catalog cannot do, answer ok false with a one-sentence summary and the plain reasons instead of breaking a rule. Output only JSON: {"ok":true,"layout":{"name":"…","parts":[…] },"summary":"one sentence","reasons":["…"]}, or {"ok":false,"layout":null,"summary":"Couldn\'t do that: …","reasons":["…"]}.',
user_prompt: '{{json payload}}',
user_prompt: '{{json payload}}',
default_route: 'ui.layout.suggest', owner: 'network', metadata: { json_name: 'layout_suggestion' },
default_route: 'ui.layout.suggest', owner: 'network', metadata: { json_name: 'layout_suggestion' },
}];
}];
@@ -134,4 +134,11 @@ t.test('cleanup', async () => {
@@ -134,4 +134,11 @@ t.test('cleanup', async () => {
await h.stop();
await h.stop();
});
});
+t.test('the prompt reads what a part sends or shows, and grants nothing for it (11-12)', async () => {
+ const { templates } = require('../server/workflows/ui-layout');
+ const prompt = templates.find((x) => x.key === 'ui.layout.suggest').system_prompt;
+ assert.ok(/command:/.test(prompt) && /reads:/.test(prompt) && /grant nothing/.test(prompt), 'command and reads are explained, as facts that grant nothing');
+ assert.ok(!/e-stop|emergency stop/i.test(prompt), 'no e-stop: Stop is a plain optional part');
+});
+
t.run();
t.run();