Updates
Rolling release / release (push) Successful in 8m31s

This commit is contained in:
2026-09-13 22:24:14 -04:00
parent 1ca4224377
commit a097adf4eb
62 changed files with 2707 additions and 957 deletions
+67
View File
@@ -11,6 +11,8 @@ import { PortalInputBackend } from '../computer-use/portal-input.js';
import { createComputerObserveTools } from '../skills/computer-observe.js';
import { createComputerActTools } from '../skills/computer-act.js';
import { createPhase2Tools, filesystemRoots } from '../skills/phase2-tools.js';
import { createBrowserTools } from '../skills/browser-tools.js';
import { createWebcamTools } from '../skills/webcam-tools.js';
import { VoiceStateMachine } from '../daemon/voice-state.js';
import { assertLocalEndpoint } from '../daemon/network-policy.js';
const require = createRequire(import.meta.url);
@@ -97,6 +99,71 @@ test('desktop observation and actuation do not wait for a second Allow after Gra
} finally { custom.clear(id); }
});
test('browser gateway is a public read and does not wait for confirmation', () => {
const id = 'browser-permission';
try {
custom.register(id, createBrowserTools({ browser: { call: async () => ({ ok: true }) } }));
assert.equal(custom.needsPermission(id, 'browser', 'ask'), false);
} finally { custom.clear(id); }
});
test('webcam is a read tool gated by the camera grant', async () => {
const id = 'webcam-permission';
const camera = { assertActive() { throw new Error('webcam grant is inactive'); }, device: '', setBackend() {}, backend: 'none' };
try {
custom.register(id, createWebcamTools({ camera, capture: { capture: async () => ({ path: '/tmp/x.png', via: 'portal' }) } }));
assert.equal(custom.needsPermission(id, 'webcam', 'ask'), false);
const [tool] = createWebcamTools({ camera });
const blocked = await tool.execute();
assert.match(blocked.error, /inactive/);
assert.match(blocked.next_action, /Allow now/);
camera.assertActive = () => {};
camera.setBackend = (via) => { camera.backend = via; };
const [live] = createWebcamTools({
camera,
capture: { capture: async () => ({ path: '/tmp/x.png', via: 'portal' }) },
});
const shot = await live.execute();
assert.equal(shot.ok, true);
assert.equal(shot.via, 'portal');
assert.deepEqual(shot.images, [{ path: '/tmp/x.png', mime: 'image/png' }]);
let dest = '';
const [encoded] = createWebcamTools({
camera,
capture: { capture: async () => ({ path: '/tmp/x.png', via: 'v4l2' }) },
normalizer: {
normalize: async (input, output) => {
dest = output;
return { path: output, mime: 'image/jpeg', width: 640, height: 480 };
},
},
});
const jpeg = await encoded.execute();
assert.match(dest, /\.jpg$/);
assert.equal(jpeg.mime, 'image/jpeg');
assert.deepEqual(jpeg.images, [{ path: dest, mime: 'image/jpeg' }]);
} finally { custom.clear(id); }
});
test('webcam stills become a user vision follow-up so QVAC has a question after the image', async () => {
const qvac = require('../vendor/agent-harness/lib/qvac.js');
const dir = await mkdtemp(path.join(tmpdir(), 'jarvis-webcam-vision-'));
const frame = path.join(dir, 'frame.webp');
await writeFile(frame, 'RIFF');
const history = qvac.prepareVisionHistory([
{ role: 'user', content: 'Do you see anything?' },
{ role: 'assistant', content: '', tool_calls: [{ name: 'webcam' }] },
{ role: 'tool', name: 'webcam', content: '{"ok":true}', images: [{ path: frame }] },
]);
const last = history.at(-1);
const tool = history.at(-2);
assert.equal(tool.role, 'tool');
assert.equal(tool.attachments, undefined);
assert.equal(last.role, 'user');
assert.equal(last.content, qvac.VISION_FOLLOWUP_QUESTION);
assert.deepEqual(last.attachments, [{ path: frame }]);
});
test('expired grants prevent desktop observation', async () => {
let now = 0; const computer = new ComputerUseSession({ clock: () => now }); computer.grant(); now = 180001;
const [observe] = createComputerObserveTools({ computer, observer: { observe: () => assert.fail('expired observation') } });