import { createRequire } from 'node:module'; import test from 'node:test'; import assert from 'node:assert/strict'; import { createRuntimeTools } from '../skills/runtime-tools.js'; import { assertSdkVersion } from '../daemon/qvac-master.js'; import { parseHudSidecar, VOICE_SYSTEM_PROMPT, voiceSystemPrompt, formatLocalClock } from '../skills/voice-prompt.js'; import { createPhase2Tools } from '../skills/phase2-tools.js'; import { createQvacTools } from '../skills/qvac-tools.js'; import { profile } from '../daemon/model-profiles.js'; test('runtime tools expose local QVAC and computer-use status', () => { const computer = { status: () => ({ active: true, steps_used: 2, backend: 'portal-ei' }) }; const camera = { status: () => ({ enabled: true, active: true, backend: 'portal' }) }; const tools = createRuntimeTools({ computer, camera }); const status = tools.find((tool) => tool.name === 'jarvis_status').execute({}); assert.equal(status.local, true); assert.equal(status.agentInference, 'local'); assert.equal(status.computer_use.active, true); assert.equal(status.camera.active, true); assert.equal(tools.find((tool) => tool.name === 'cu_status').execute({}).backend, 'portal-ei'); }); test('the copied harness uses the pinned QVAC 0.19.x SDK', () => { assert.match(assertSdkVersion(), /^0\.19\./); }); test('voice sidecars are removed from speech and retained for the HUD', () => { const parsed = parseHudSidecar('Done. {"title":"Done","chips":[]}'); assert.equal(parsed.spoken, 'Done.'); assert.equal(parsed.hud.title, 'Done'); }); test('web_search and fetch_page stop at the overall budget instead of hanging', async () => { const require = createRequire(import.meta.url); const tools = require('../vendor/agent-harness/agent/tools.js'); tools.setBrowserBackend({ call: () => new Promise(() => {}) }); try { const started = Date.now(); const search = await tools.runWebSearch('example', { timeoutMs: 80 }); const searchMs = Date.now() - started; assert.match(String(search.error), /timed out/i); assert.ok(searchMs >= 40, 'search returned too fast: ' + searchMs + 'ms'); assert.ok(searchMs < 500, 'search hung for ' + searchMs + 'ms'); const pageStarted = Date.now(); const page = await tools.fetchPage('https://example.com/article', 80); const pageMs = Date.now() - pageStarted; assert.match(String(page.error), /timed out/i); assert.ok(pageMs >= 40, 'fetch_page returned too fast: ' + pageMs + 'ms'); assert.ok(pageMs < 500, 'fetch_page hung for ' + pageMs + 'ms'); } finally { tools.setBrowserBackend(null); } }); test('web_fetch uses the Jarvis browser helper', async () => { const require = createRequire(import.meta.url); const tools = require('../vendor/agent-harness/agent/tools.js'); tools.setBrowserBackend({ call: () => new Promise(() => {}) }); try { const hung = await tools.webFetch('https://example.com/ip', 40); assert.match(String(hung.error), /timed out/i); assert.equal(hung.url, 'https://example.com/ip'); } finally { tools.setBrowserBackend(null); } tools.setBrowserBackend({ call: async (_action, payload) => ({ url: payload.url, status: 200, html: '203.0.113.8', text: '203.0.113.8' }), }); try { const ok = await tools.webFetch('https://ifconfig.me/ip', 200); assert.equal(ok.status, 200); assert.equal(ok.url, 'https://ifconfig.me/ip'); assert.match(ok.text, /203\.0\.113\.8/); assert.equal(ok.via, 'browser'); } finally { tools.setBrowserBackend(null); } }); test('web_search can pin an engine and fetch_page reads the opened page', async () => { const require = createRequire(import.meta.url); const tools = require('../vendor/agent-harness/agent/tools.js'); const unknown = await tools.runWebSearch('example', { engine: 'nope' }); assert.match(String(unknown.error), /unknown engine/); assert.ok(Array.isArray(unknown.engines)); tools.setBrowserBackend({ call: async (action, payload) => { if (action === 'search') return [{ url: 'https://en.wikipedia.org/wiki/Example.com', title: 'Example.com', source: payload.engine }]; return { url: payload.url, status: 200, html: '

Readable article scraped directly

', text: 'Readable article scraped directly' }; }, }); try { const wiki = await tools.runWebSearch('example.com', { engine: 'wikipedia', timeoutMs: 200 }); assert.equal(wiki[0].source, 'wikipedia'); assert.equal(wiki[0].title, 'Example.com'); assert.match(wiki[0].url, /wikipedia\.org\/wiki\/Example\.com/); const page = await tools.fetchPage('https://example.com/article', 200); assert.equal(page.via, 'browser'); assert.match(page.text, /Readable article scraped directly/); } finally { tools.setBrowserBackend(null); } }); test('public web search and fetch do not require confirmation', () => { const require = createRequire(import.meta.url); const policy = require('../vendor/agent-harness/agent/policy.js'); assert.equal(policy.needsPermission('web_fetch', 'ask'), false); assert.equal(policy.needsPermission('fetch_page', 'ask'), false); assert.equal(policy.needsPermission('google_search', 'ask'), false); assert.equal(policy.needsPermission('web_search', 'ask'), false); assert.equal(policy.needsPermission('wiki_search', 'ask'), false); assert.equal(policy.needsPermission('hn_search', 'ask'), false); assert.equal(policy.needsPermission('code_search', 'ask'), false); assert.equal(policy.needsPermission('run_terminal_cmd', 'ask'), true); assert.match(VOICE_SYSTEM_PROMPT, /Follow SOUL\.md, IDENTITY\.md, AGENTS\.md/); assert.match(VOICE_SYSTEM_PROMPT, /PERSONA\.md/); assert.doesNotMatch(VOICE_SYSTEM_PROMPT, /User personality notes/); assert.doesNotMatch(VOICE_SYSTEM_PROMPT, /\n## Acting\n/); assert.match(voiceSystemPrompt('Ada', 'Be dry. Skip filler.'), /Your name is Ada/); assert.match(voiceSystemPrompt('Ada', 'Be dry. Skip filler.'), /\n## Acting\nBe dry\. Skip filler\./); assert.match(voiceSystemPrompt('Ada', 'Be dry. Skip filler.'), /override SOUL\.md/); assert.doesNotMatch(voiceSystemPrompt('Ada', 'Be dry. Skip filler.'), /User personality notes/); assert.doesNotMatch(voiceSystemPrompt('Tony', 'Jarvis, you are acting as Tony Hinchcliffe.'), /You are Tony, a local Ubuntu GNOME voice assistant/); const roast = voiceSystemPrompt('Tony', 'Jarvis, you are acting as Tony Hinchcliffe, roast comedian.\nYou must never call yourself Jarvis.'); assert.match(roast, /Your name is Tony/); assert.match(roast, /## Acting/); assert.match(roast, /never call yourself Jarvis/); assert.match(roast, /still speak as Tony/); assert.equal(policy.needsPermission('write_file', 'ask'), true); assert.equal(policy.isIdentityPath('USER.md'), true); assert.equal(policy.isIdentityPath('PERSONA.md'), true); assert.equal(policy.isIdentityPath('memory/2026-09-12.md'), true); assert.equal(policy.isIdentityPath('/tmp/secret.txt'), false); }); test('voice prompt includes local 12-hour date and machine context', () => { const clock = formatLocalClock(new Date(2026, 8, 13, 20, 48, 0)); assert.match(clock, /Sunday, September 13, 2026, 8:48 PM/); assert.match(clock, /memory date is 2026-09-13/); const morning = formatLocalClock(new Date(2026, 8, 13, 0, 5, 0)); assert.match(morning, /12:05 AM/); const prompt = voiceSystemPrompt('Jarvis', '', new Date(2026, 8, 13, 20, 48, 0)); assert.match(prompt, /Sunday, September 13, 2026, 8:48 PM/); assert.match(prompt, /Trust this clock/); assert.match(prompt, /A M or P M/); assert.match(prompt, /This computer is /); assert.match(prompt, /The logged-in user is /); assert.match(prompt, /Home is /); }); test('voice prompt tells the model not to chain extra terminal commands', () => { assert.match(VOICE_SYSTEM_PROMPT, /call run_terminal_cmd once/); assert.match(VOICE_SYSTEM_PROMPT, /Do not chain extra commands/); assert.match(VOICE_SYSTEM_PROMPT, /Keep a space between every word/); assert.match(VOICE_SYSTEM_PROMPT, /Never wrap words in asterisks/); assert.match(VOICE_SYSTEM_PROMPT, /Quantum Verse Automatic Computer/); assert.match(VOICE_SYSTEM_PROMPT, /spell it as Q V A C/); assert.match(VOICE_SYSTEM_PROMPT, /Internet protocol addresses have no dots/); assert.match(VOICE_SYSTEM_PROMPT, /Spell them as separate letters/); assert.match(VOICE_SYSTEM_PROMPT, /web_search, google_search, fetch_page, web_fetch, wiki_search, hn_search, and code_search are removed/); assert.match(VOICE_SYSTEM_PROMPT, /The only way to the internet is the headed Jarvis Chromium window/); assert.match(VOICE_SYSTEM_PROMPT, /call browser again/); assert.doesNotMatch(VOICE_SYSTEM_PROMPT, /Use web_search to find pages/); assert.match(VOICE_SYSTEM_PROMPT, /headed Jarvis Chromium window/); assert.match(VOICE_SYSTEM_PROMPT, /challenge true/); assert.match(VOICE_SYSTEM_PROMPT, /Call browser instead of announcing it/); assert.match(VOICE_SYSTEM_PROMPT, /Actions are navigate/); assert.match(VOICE_SYSTEM_PROMPT, /refs change/); assert.match(VOICE_SYSTEM_PROMPT, /Never use cu_observe, cu_click, curl, or wget for websites/); assert.match(VOICE_SYSTEM_PROMPT, /Do not keep searching the same query/); assert.match(VOICE_SYSTEM_PROMPT, /call todo_write/); assert.match(VOICE_SYSTEM_PROMPT, /Do not repeat a sentence/); assert.match(VOICE_SYSTEM_PROMPT, /Do not stop in thoughts/); assert.match(VOICE_SYSTEM_PROMPT, /Do not use curl, wget/); assert.match(VOICE_SYSTEM_PROMPT, /ifconfig\.me\/ip/); assert.match(VOICE_SYSTEM_PROMPT, /The only way to the internet/); assert.match(VOICE_SYSTEM_PROMPT, /HTTP access is not allowed/); assert.match(VOICE_SYSTEM_PROMPT, /Tool names, tool arguments/); assert.match(VOICE_SYSTEM_PROMPT, /File tools may read any path they accept/); assert.match(VOICE_SYSTEM_PROMPT, /Allow now/); assert.match(VOICE_SYSTEM_PROMPT, /call cu_observe, then cu_find or a tree ref, then cu_click and cu_type/); assert.match(VOICE_SYSTEM_PROMPT, /Never paste tool JSON/); assert.match(VOICE_SYSTEM_PROMPT, /call webcam/); assert.match(VOICE_SYSTEM_PROMPT, /Allow now/); assert.match(VOICE_SYSTEM_PROMPT, /It is /); assert.match(VOICE_SYSTEM_PROMPT, /memory date is /); assert.match(VOICE_SYSTEM_PROMPT, /not sentient/); assert.match(VOICE_SYSTEM_PROMPT, /unconditional control/); assert.match(VOICE_SYSTEM_PROMPT, /only cortex for durable memory/); assert.match(VOICE_SYSTEM_PROMPT, /action write/); assert.match(VOICE_SYSTEM_PROMPT, /Do not call memory_search/); assert.match(VOICE_SYSTEM_PROMPT, /Do not ask permission/); assert.match(VOICE_SYSTEM_PROMPT, /Finish the request before you speak/); assert.match(VOICE_SYSTEM_PROMPT, /That is not an answer/); assert.doesNotMatch(VOICE_SYSTEM_PROMPT, /Never claim cloud access/); }); test('phase 2 registers safe local tools with permission metadata', async () => { const tools = createPhase2Tools({ cwd: process.cwd() }); assert.deepEqual(tools.map((tool) => tool.name), ['app_list', 'fs_search', 'fs_read', 'fs_write', 'memory_recall', 'memory_remember', 'rag_workspaces', 'capability_status']); assert.equal(tools.find((tool) => tool.name === 'fs_search').permission, 'read'); assert.ok((await tools.find((tool) => tool.name === 'fs_search').execute({ query: 'features' })).some((x) => x.endsWith('features.md'))); assert.deepEqual(await tools.find((tool) => tool.name === 'fs_write').execute({ file: 'nope.txt', contents: 'x', confirmed: false }), { confirmation_required: true, action: 'write', file: 'nope.txt' }); }); test('QVAC utility tools are exposed only through the master adapter', () => { assert.deepEqual(createQvacTools().map((tool) => tool.name), ['qvac_runtime_state', 'qvac_system_resources', 'qvac_assess_model_fit']); }); test('model profiles select one master model without creating another runtime', () => { assert.equal(profile('laptop-4gb-mm').model, 'qwen3.5-0.8b'); assert.equal(profile('laptop-4gb-mm').vision, true); assert.equal(profile('laptop-8gb-mm').model, 'qwen3.5-2b'); assert.equal(profile('laptop-8gb-mm').vision, true); assert.equal(profile('desktop-gpu').model, 'qwen3.5-9b'); assert.throws(() => profile('missing'), /unknown Jarvis model profile/); });